mirror of
https://github.com/thegeeklab/wp-opentofu.git
synced 2024-11-23 07:00:40 +00:00
first commit after fork
This commit is contained in:
parent
24156d51b0
commit
fc8c16ac5e
2
.dictionary
Normal file
2
.dictionary
Normal file
@ -0,0 +1,2 @@
|
||||
OpenTofu
|
||||
wp-opentofu
|
@ -1,3 +0,0 @@
|
||||
.git
|
||||
build-docker.sh
|
||||
CHANGELOG.md
|
12
.drone.yml
12
.drone.yml
@ -1,12 +0,0 @@
|
||||
workspace:
|
||||
base: /go
|
||||
path: src/github.com/drone-plugins/drone-terraform
|
||||
|
||||
pipeline:
|
||||
test:
|
||||
image: golang:1.9
|
||||
environment:
|
||||
- CGO_ENABLED=0
|
||||
commands:
|
||||
- go test -cover -coverprofile=coverage.out
|
||||
- go build -ldflags "-s -w -X main.revision=$(git rev-parse HEAD)" -a
|
26
.editorconfig
Normal file
26
.editorconfig
Normal file
@ -0,0 +1,26 @@
|
||||
# https://editorconfig.org/
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.{go,mod}]
|
||||
indent_style = tab
|
||||
tab_width = 4
|
||||
|
||||
[*.star]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[LICENSE]
|
||||
indent_size = unset
|
71
.github/settings.yml
vendored
Normal file
71
.github/settings.yml
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
repository:
|
||||
name: wp-opentofu
|
||||
description: Woodpecker CI plugin to manage infrastructure with OpenTofu
|
||||
homepage: https://woodpecker-plugins.geekdocs.de/plugins/wp-opentofu
|
||||
topics: woodpecker-ci, woodpecker, woodpecker-plugin
|
||||
|
||||
private: false
|
||||
has_issues: true
|
||||
has_wiki: false
|
||||
has_downloads: true
|
||||
|
||||
default_branch: main
|
||||
|
||||
allow_squash_merge: true
|
||||
allow_merge_commit: true
|
||||
allow_rebase_merge: true
|
||||
|
||||
labels:
|
||||
- name: bug
|
||||
color: d73a4a
|
||||
description: Something isn't working
|
||||
- name: documentation
|
||||
color: 0075ca
|
||||
description: Improvements or additions to documentation
|
||||
- name: duplicate
|
||||
color: cfd3d7
|
||||
description: This issue or pull request already exists
|
||||
- name: enhancement
|
||||
color: a2eeef
|
||||
description: New feature or request
|
||||
- name: good first issue
|
||||
color: 7057ff
|
||||
description: Good for newcomers
|
||||
- name: help wanted
|
||||
color: 008672
|
||||
description: Extra attention is needed
|
||||
- name: invalid
|
||||
color: e4e669
|
||||
description: This doesn't seem right
|
||||
- name: question
|
||||
color: d876e3
|
||||
description: Further information is requested
|
||||
- name: wontfix
|
||||
color: ffffff
|
||||
description: This will not be worked on
|
||||
|
||||
branches:
|
||||
- name: main
|
||||
protection:
|
||||
required_pull_request_reviews: null
|
||||
required_status_checks:
|
||||
strict: false
|
||||
contexts:
|
||||
- ci/woodpecker/pr/test
|
||||
- ci/woodpecker/pr/build-package
|
||||
- ci/woodpecker/pr/build-container
|
||||
- ci/woodpecker/pr/docs
|
||||
enforce_admins: false
|
||||
required_linear_history: true
|
||||
restrictions: null
|
||||
- name: docs
|
||||
protection:
|
||||
required_pull_request_reviews: null
|
||||
required_status_checks: null
|
||||
enforce_admins: true
|
||||
required_linear_history: true
|
||||
restrictions:
|
||||
apps: []
|
||||
users: []
|
||||
teams:
|
||||
- bot
|
30
.gitignore
vendored
30
.gitignore
vendored
@ -1,27 +1,7 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
/dist
|
||||
/release
|
||||
/wp-opentofu*
|
||||
docs/data/data-raw.yaml
|
||||
|
||||
coverage.out
|
||||
drone-terraform
|
||||
CHANGELOG.md
|
||||
|
47
.gitsv/config.yml
Normal file
47
.gitsv/config.yml
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
version: "1.1"
|
||||
|
||||
versioning:
|
||||
update-major: []
|
||||
update-minor: [feat]
|
||||
update-patch: [fix, perf, refactor, chore, test, ci, docs]
|
||||
|
||||
tag:
|
||||
pattern: "v%d.%d.%d"
|
||||
|
||||
release-notes:
|
||||
sections:
|
||||
- name: Features
|
||||
commit-types: [feat]
|
||||
section-type: commits
|
||||
- name: Bug Fixes
|
||||
commit-types: [fix]
|
||||
section-type: commits
|
||||
- name: Performance Improvements
|
||||
commit-types: [perf]
|
||||
section-type: commits
|
||||
- name: Code Refactoring
|
||||
commit-types: [refactor]
|
||||
section-type: commits
|
||||
- name: Others
|
||||
commit-types: [chore]
|
||||
section-type: commits
|
||||
- name: Testing
|
||||
commit-types: [test]
|
||||
section-type: commits
|
||||
- name: CI Pipeline
|
||||
commit-types: [ci]
|
||||
section-type: commits
|
||||
- name: Documentation
|
||||
commit-types: [docs]
|
||||
section-type: commits
|
||||
- name: BREAKING CHANGES
|
||||
section-type: breaking-changes
|
||||
|
||||
commit-message:
|
||||
footer:
|
||||
issue:
|
||||
key: issue
|
||||
add-value-prefix: "#"
|
||||
issue:
|
||||
regex: "#?[0-9]+"
|
101
.golangci.yml
Normal file
101
.golangci.yml
Normal file
@ -0,0 +1,101 @@
|
||||
linters:
|
||||
enable-all: false
|
||||
disable-all: true
|
||||
enable:
|
||||
- errcheck
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- staticcheck
|
||||
- typecheck
|
||||
- unused
|
||||
- asasalint
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- bodyclose
|
||||
- containedctx
|
||||
- contextcheck
|
||||
- decorder
|
||||
- dogsled
|
||||
- dupl
|
||||
- dupword
|
||||
- durationcheck
|
||||
- errchkjson
|
||||
- errname
|
||||
- errorlint
|
||||
- execinquery
|
||||
- exhaustive
|
||||
- exportloopref
|
||||
- forcetypeassert
|
||||
- ginkgolinter
|
||||
- gocheckcompilerdirectives
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gocognit
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- godot
|
||||
- godox
|
||||
- goerr113
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goheader
|
||||
- goimports
|
||||
- gomnd
|
||||
- gomoddirectives
|
||||
- gomodguard
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- grouper
|
||||
- importas
|
||||
- interfacebloat
|
||||
- ireturn
|
||||
- lll
|
||||
- loggercheck
|
||||
- maintidx
|
||||
- makezero
|
||||
- misspell
|
||||
- musttag
|
||||
- nakedret
|
||||
- nestif
|
||||
- nilerr
|
||||
- nilnil
|
||||
- nlreturn
|
||||
- noctx
|
||||
- nolintlint
|
||||
- nonamedreturns
|
||||
- nosprintfhostport
|
||||
- prealloc
|
||||
- predeclared
|
||||
- promlinter
|
||||
- reassign
|
||||
- revive
|
||||
# - rowserrcheck
|
||||
# - sqlclosecheck
|
||||
# - structcheck
|
||||
- stylecheck
|
||||
- tagliatelle
|
||||
- tenv
|
||||
- testableexamples
|
||||
- thelper
|
||||
- tparallel
|
||||
- unconvert
|
||||
- unparam
|
||||
- usestdlibvars
|
||||
# - wastedassign
|
||||
- whitespace
|
||||
- wsl
|
||||
- zerologlint
|
||||
fast: false
|
||||
|
||||
run:
|
||||
timeout: 3m
|
||||
|
||||
linters-settings:
|
||||
tagliatelle:
|
||||
case:
|
||||
rules:
|
||||
json: kebab
|
||||
gofumpt:
|
||||
extra-rules: true
|
6
.markdownlint.yml
Normal file
6
.markdownlint.yml
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
default: True
|
||||
MD013: False
|
||||
MD041: False
|
||||
MD004:
|
||||
style: dash
|
2
.prettierignore
Normal file
2
.prettierignore
Normal file
@ -0,0 +1,2 @@
|
||||
*.tpl.md
|
||||
LICENSE
|
69
.woodpecker/build-container.yml
Normal file
69
.woodpecker/build-container.yml
Normal file
@ -0,0 +1,69 @@
|
||||
---
|
||||
when:
|
||||
- event: [pull_request, tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
- event: [push]
|
||||
branch:
|
||||
- renovate/*
|
||||
|
||||
steps:
|
||||
- name: dryrun
|
||||
image: quay.io/thegeeklab/wp-docker-buildx:3
|
||||
settings:
|
||||
containerfile: Containerfile.multiarch
|
||||
dry_run: true
|
||||
platforms:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
provenance: false
|
||||
repo: ${CI_REPO}
|
||||
when:
|
||||
- event: [pull_request]
|
||||
|
||||
- name: publish-dockerhub
|
||||
image: quay.io/thegeeklab/wp-docker-buildx:3
|
||||
group: container
|
||||
settings:
|
||||
auto_tag: true
|
||||
containerfile: Containerfile.multiarch
|
||||
password:
|
||||
from_secret: docker_password
|
||||
platforms:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
provenance: false
|
||||
repo: ${CI_REPO}
|
||||
username:
|
||||
from_secret: docker_username
|
||||
when:
|
||||
- event: [tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
- name: publish-quay
|
||||
image: quay.io/thegeeklab/wp-docker-buildx:3
|
||||
group: container
|
||||
settings:
|
||||
auto_tag: true
|
||||
containerfile: Containerfile.multiarch
|
||||
password:
|
||||
from_secret: quay_password
|
||||
platforms:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
provenance: false
|
||||
registry: quay.io
|
||||
repo: quay.io/${CI_REPO}
|
||||
username:
|
||||
from_secret: quay_username
|
||||
when:
|
||||
- event: [tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
depends_on:
|
||||
- test
|
44
.woodpecker/build-package.yml
Normal file
44
.woodpecker/build-package.yml
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
when:
|
||||
- event: [pull_request, tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
- event: [push]
|
||||
branch:
|
||||
- renovate/*
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: docker.io/techknowlogick/xgo:go-1.21.x
|
||||
commands:
|
||||
- ln -s $(pwd) /source
|
||||
- make release
|
||||
|
||||
- name: executable
|
||||
image: quay.io/thegeeklab/alpine-tools
|
||||
commands:
|
||||
- $(find dist/ -executable -type f -iname ${CI_REPO_NAME}-linux-amd64) --help
|
||||
|
||||
- name: changelog
|
||||
image: quay.io/thegeeklab/git-sv
|
||||
commands:
|
||||
- git sv current-version
|
||||
- git sv release-notes -t ${CI_COMMIT_TAG:-next} -o CHANGELOG.md
|
||||
- cat CHANGELOG.md
|
||||
|
||||
- name: publish-github
|
||||
image: docker.io/plugins/github-release
|
||||
settings:
|
||||
api_key:
|
||||
from_secret: github_token
|
||||
files:
|
||||
- dist/*
|
||||
note: CHANGELOG.md
|
||||
overwrite: true
|
||||
title: ${CI_COMMIT_TAG}
|
||||
when:
|
||||
- event: [tag]
|
||||
|
||||
depends_on:
|
||||
- test
|
83
.woodpecker/docs.yml
Normal file
83
.woodpecker/docs.yml
Normal file
@ -0,0 +1,83 @@
|
||||
---
|
||||
when:
|
||||
- event: [pull_request, tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
- event: [push]
|
||||
branch:
|
||||
- renovate/*
|
||||
|
||||
steps:
|
||||
- name: markdownlint
|
||||
image: quay.io/thegeeklab/markdownlint-cli
|
||||
group: test
|
||||
commands:
|
||||
- markdownlint 'README.md' 'CONTRIBUTING.md'
|
||||
|
||||
- name: spellcheck
|
||||
image: quay.io/thegeeklab/alpine-tools
|
||||
group: test
|
||||
commands:
|
||||
- spellchecker --files 'docs/**/*.md' 'README.md' 'CONTRIBUTING.md' -d .dictionary -p spell indefinite-article syntax-urls
|
||||
environment:
|
||||
FORCE_COLOR: "true"
|
||||
|
||||
- name: link-validation
|
||||
image: docker.io/lycheeverse/lychee
|
||||
group: test
|
||||
commands:
|
||||
- lychee --no-progress --format detailed docs/content README.md
|
||||
|
||||
- name: publish
|
||||
image: quay.io/thegeeklab/wp-git-action
|
||||
settings:
|
||||
action:
|
||||
- pages
|
||||
author_email: bot@thegeeklab.de
|
||||
author_name: thegeeklab-bot
|
||||
branch: docs
|
||||
message: "[skip ci] auto-update documentation"
|
||||
netrc_password:
|
||||
from_secret: github_token
|
||||
pages_directory: docs/
|
||||
when:
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
status: [success, failure]
|
||||
|
||||
- name: pushrm-dockerhub
|
||||
image: docker.io/chko/docker-pushrm:1
|
||||
secrets:
|
||||
- source: docker_password
|
||||
target: DOCKER_PASS
|
||||
- source: docker_username
|
||||
target: DOCKER_USER
|
||||
environment:
|
||||
PUSHRM_FILE: README.md
|
||||
PUSHRM_SHORT: Woodpecker CI plugin to manage infrastructure with OpenTofu
|
||||
PUSHRM_TARGET: ${CI_REPO}
|
||||
when:
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
status: [success]
|
||||
|
||||
- name: pushrm-quay
|
||||
image: docker.io/chko/docker-pushrm:1
|
||||
secrets:
|
||||
- source: quay_token
|
||||
target: APIKEY__QUAY_IO
|
||||
environment:
|
||||
PUSHRM_FILE: README.md
|
||||
PUSHRM_TARGET: quay.io/${CI_REPO}
|
||||
when:
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
status: [success]
|
||||
|
||||
depends_on:
|
||||
- build-package
|
||||
- build-container
|
26
.woodpecker/notify.yml
Normal file
26
.woodpecker/notify.yml
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
when:
|
||||
- event: [tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
runs_on: [success, failure]
|
||||
|
||||
steps:
|
||||
- name: matrix
|
||||
image: quay.io/thegeeklab/wp-matrix
|
||||
settings:
|
||||
homeserver:
|
||||
from_secret: matrix_homeserver
|
||||
password:
|
||||
from_secret: matrix_password
|
||||
roomid:
|
||||
from_secret: matrix_roomid
|
||||
username:
|
||||
from_secret: matrix_username
|
||||
when:
|
||||
- status: [success, failure]
|
||||
|
||||
depends_on:
|
||||
- docs
|
20
.woodpecker/test.yml
Normal file
20
.woodpecker/test.yml
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
when:
|
||||
- event: [pull_request, tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
- event: [push]
|
||||
branch:
|
||||
- renovate/*
|
||||
|
||||
steps:
|
||||
- name: lint
|
||||
image: docker.io/library/golang:1.21
|
||||
commands:
|
||||
- make lint
|
||||
|
||||
- name: test
|
||||
image: docker.io/library/golang:1.21
|
||||
commands:
|
||||
- make test
|
120
CHANGELOG.md
120
CHANGELOG.md
@ -1,120 +0,0 @@
|
||||
## 8.3-1.0.2 (2021-07-09)
|
||||
* Update embedded TF to `1.0.2`
|
||||
* A continuation of `v0.15` release line but now following semver
|
||||
* Please refer to [Terraform v1.0 Compatibility Promises](https://www.terraform.io/docs/language/v1-compatibility-promises.html)
|
||||
|
||||
## 8.3-0.15.1 (2021-07-09)
|
||||
* fix: remove -lock and -lock-timeout for terraform init - https://github.com/jmccann/drone-terraform/pull/130
|
||||
|
||||
## 8.2-0.15.1 (2021-06-02)
|
||||
* fix: `-force` -> `-auto-approve` - https://github.com/jmccann/drone-terraform/pull/128
|
||||
|
||||
## 8.1-0.15.1 (2021-04-27)
|
||||
* added ability to [disable refresh](https://github.com/jmccann/drone-terraform/pull/120)
|
||||
|
||||
## 8.0-0.15.1 (2021-04-27)
|
||||
* Update embedded TF to `0.15.1`
|
||||
* Please refer to [Terraform v15 Migration Guide](https://www.terraform.io/upgrade-guides/0-15.html)
|
||||
* Update other deps
|
||||
|
||||
## 7.0-0.14.11 (2021-04-27)
|
||||
* Update embedded TF to `0.14.11`
|
||||
* Please refer to [Terraform v14 Migration Guide](https://www.terraform.io/upgrade-guides/0-14.html)
|
||||
|
||||
## 6.4-0.13.2 (2020-09-11)
|
||||
* Update embedded TF to `0.13.2`
|
||||
|
||||
## 6.4-0.13.1 (2020-09-11)
|
||||
* minor version bump due to major version change of terraform
|
||||
* Update embedded TF to `0.13.1`
|
||||
* added curl
|
||||
|
||||
## 6.3-0.12.20 (2020-02-12)
|
||||
* add ability to load creds from `env_file` parameter (https://github.com/jmccann/drone-terraform/pull/107). Thanks @neemiasjnr!
|
||||
|
||||
## 6.2-0.12.20 (2020-02-05)
|
||||
* Update embedded TF to `0.12.20`
|
||||
* Update alpine to 3.11 in docker image (https://github.com/jmccann/drone-terraform/pull/109). Thanks @sgerrand!
|
||||
|
||||
## 6.2-0.12.16 (2019-11-26)
|
||||
* Update embedded TF to `0.12.16`
|
||||
|
||||
## 6.2-0.12.11 (2019-11-26)
|
||||
* tfValidate vars and var-file argument removal #106 Thanks @gsingh1
|
||||
|
||||
## 6.1-0.12.11 (2019-10-18)
|
||||
* Update embedded TF to `0.12.11`
|
||||
|
||||
## 6.1-0.12.10 (2019-10-15)
|
||||
* Update embedded TF to `0.12.10`
|
||||
|
||||
## 6.1-0.12.8 (2019-09-06)
|
||||
* Support for parallel execution (https://github.com/jmccann/drone-terraform/pull/94). Thanks @caioquirino!
|
||||
* Updated golang to 1.13
|
||||
|
||||
## 6.0-0.12.8 (2019-09-06)
|
||||
* Update embedded TF to `0.12.8`
|
||||
|
||||
## 6.0-0.12.6 (2019-08-05)
|
||||
* Update embedded TF to `0.12.6`
|
||||
|
||||
## 6.0-0.12.4 (2019-07-12)
|
||||
* Update embedded TF to `0.12.4`
|
||||
|
||||
## 6.0-0.12.1 (2019-06-05)
|
||||
* Version bump plugin to `6.0` since terraform `0.12` has breaking changes
|
||||
* Update embedded TF to `0.12.1`
|
||||
|
||||
## 5.3-0.11.14 (2019-08-05)
|
||||
* Update embedded TF to `0.11.14`
|
||||
|
||||
## 5.2-0.11.13 (2019-03-27)
|
||||
* Update embedded TF to `0.11.13`
|
||||
|
||||
## 5.2-0.11.11 (2019-02-22)
|
||||
* Add `fmt` action
|
||||
|
||||
## 5.1-0.11.11 (2019-01-18)
|
||||
* Update embedded TF to `0.11.11`
|
||||
|
||||
## 5.1-0.11.8 (2018-10-11)
|
||||
* Update embedded TF to `0.11.8`
|
||||
|
||||
## 5.1-0.11.7 (2018-07-31)
|
||||
* Add `vars` and `var_files` to destroy operation
|
||||
|
||||
## 5.0-0.11.7 (2018-04-25)
|
||||
**BREAKING CHANGE**
|
||||
* Removed `destroy` param
|
||||
* Removed `plan` param
|
||||
* Added `actions` param to provide a list of actions to perform.
|
||||
See [DOCS.md](DOCS.md) for more info and examples.
|
||||
|
||||
## 4.1-0.11.7 (2018-04-25)
|
||||
* Add .netrc support
|
||||
* Update embedded TF to `0.11.7`
|
||||
|
||||
## 4.0-0.11.3 (2018-02-07)
|
||||
* Update embedded TF to `0.11.3`
|
||||
|
||||
## 4.0-0.10.8 (2018-02-07)
|
||||
* Pass `-var-file` to validate command
|
||||
* Update embedded TF to `0.10.8`
|
||||
|
||||
## 4.0-0.10.7 (2017-10-20)
|
||||
* Persist state locking config (https://github.com/jmccann/drone-terraform/pull/55)
|
||||
* Update embedded TF to `0.10.7`
|
||||
|
||||
## 4.0-0.10.3 (2017-09-06)
|
||||
**Breaking Change**
|
||||
* Update embedded TF to 0.10.3
|
||||
* In order to support validate in TF 0.10.3 add `vars` to validate command.
|
||||
This is not compatible with older versions of TF.
|
||||
|
||||
## 3.0-0.9.11 (2017-09-06)
|
||||
**Breaking Change**
|
||||
* Removed `secrets` key
|
||||
|
||||
**Added Features**
|
||||
* Added support for `destroy`
|
||||
* Add ability to specify TF version to use via `tf_version`
|
31
CONTRIBUTING.md
Normal file
31
CONTRIBUTING.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Contributing
|
||||
|
||||
## Security
|
||||
|
||||
If you think you have found a **security issue**, please do not mention it in this repository.
|
||||
Instead, send an email to `security@thegeeklab.de` with as many details as possible so it can be handled confidential.
|
||||
|
||||
## Bug Reports and Feature Requests
|
||||
|
||||
If you have found a **bug** or have a **feature request** please use the search first in case a similar issue already exists.
|
||||
If not, please create an issue in this repository
|
||||
|
||||
## Code
|
||||
|
||||
If you would like to fix a bug or implement a feature, please fork the repository and create a Pull Request.
|
||||
|
||||
Before you start any Pull Request, it is recommended that you create an issue to discuss first if you have any
|
||||
doubts about requirement or implementation. That way you can be sure that the maintainer(s) agree on what to change and how,
|
||||
and you can hopefully get a quick merge afterwards.
|
||||
|
||||
Pull Requests can only be merged once all status checks are green.
|
||||
|
||||
## Do not force push to your Pull Request branch
|
||||
|
||||
Please do not force push to your Pull Requests branch after you have created your Pull Request, as doing so makes it harder for us to review your work.
|
||||
Pull Requests will always be squashed by us when we merge your work. Commit as many times as you need in your Pull Request branch.
|
||||
|
||||
## Re-requesting a review
|
||||
|
||||
Please do not ping your reviewer(s) by mentioning them in a new comment. Instead, use the re-request review functionality.
|
||||
Read more about this in the [GitHub docs, Re-requesting a review](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/incorporating-feedback-in-your-pull-request#re-requesting-a-review).
|
37
Containerfile.multiarch
Normal file
37
Containerfile.multiarch
Normal file
@ -0,0 +1,37 @@
|
||||
FROM --platform=$BUILDPLATFORM docker.io/golang:1.21@sha256:7b575fe0d9c2e01553b04d9de8ffea6d35ca3ab3380d2a8db2acc8f0f1519a53 as build
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
||||
ADD . /src
|
||||
WORKDIR /src
|
||||
|
||||
RUN make build
|
||||
|
||||
FROM docker.io/alpine:3.19
|
||||
|
||||
LABEL maintainer="Robert Kaussow <mail@thegeeklab.de>"
|
||||
LABEL org.opencontainers.image.authors="Robert Kaussow <mail@thegeeklab.de>"
|
||||
LABEL org.opencontainers.image.title="wp-opentofu"
|
||||
LABEL org.opencontainers.image.url="https://github.com/thegeeklab/wp-opentofu"
|
||||
LABEL org.opencontainers.image.source="https://github.com/thegeeklab/wp-opentofu"
|
||||
LABEL org.opencontainers.image.documentation="https://github.com/thegeeklab/wp-opentofu"
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG TOFU_VERSION
|
||||
|
||||
# renovate: datasource=github-releases depName=opentofu/opentofu
|
||||
ENV TOFU_VERSION="${TOFU_VERSION:-v1.6.0}"
|
||||
|
||||
RUN apk --update add --virtual .build-deps curl libarchive-tools && \
|
||||
curl -SsfL "https://github.com/opentofu/opentofu/releases/download/${TOFU_VERSION}/tofu_${TOFU_VERSION##v}_linux_amd64.zip" | \
|
||||
bsdtar -xf - -C /usr/local/bin tofu && \
|
||||
chmod 755 /usr/local/bin/tofu && \
|
||||
apk del .build-deps && \
|
||||
rm -rf /var/cache/apk/* && \
|
||||
rm -rf /tmp/* && \
|
||||
rm -rf /root/.cache/
|
||||
|
||||
COPY --from=build /src/dist/wp-opentofu /bin/wp-opentofu
|
||||
ENTRYPOINT ["/bin/wp-opentofu"]
|
274
DOCS.md
274
DOCS.md
@ -1,274 +0,0 @@
|
||||
---
|
||||
date: 2016-01-01T00:00:00+00:00
|
||||
title: Terraform
|
||||
author: jmccann
|
||||
tags: [ infrastructure, build tool ]
|
||||
repo: jmccann/drone-terraform
|
||||
logo: terraform.svg
|
||||
image: jmccann/drone-terraform
|
||||
---
|
||||
|
||||
The Terraform plugin applies the infrastructure configuration contained within the repository. The below pipeline configuration demonstrates simple usage which will run a `validate`, `plan` and `apply`:
|
||||
|
||||
```yaml
|
||||
pipeline:
|
||||
terraform:
|
||||
image: jmccann/drone-terraform:5
|
||||
```
|
||||
|
||||
Example configuration passing `vars` to terraform commands:
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
terraform:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ vars:
|
||||
+ app_name: my-project
|
||||
+ app_version: 1.0.0
|
||||
```
|
||||
|
||||
Example of explicitly specifying `actions` to perform a dry run.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
terraform:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ actions:
|
||||
+ - validate
|
||||
+ - plan
|
||||
```
|
||||
|
||||
Example configuration passing secrets to terraform. Please read
|
||||
https://www.terraform.io/docs/configuration/variables.html#environment-variables
|
||||
for more details.
|
||||
|
||||
**Drone 0.6+**:
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
terraform:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ secrets:
|
||||
+ - source: terraform_secret
|
||||
+ target: tf_var_my_secret
|
||||
```
|
||||
|
||||
**Drone 0.5**:
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
terraform_1:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ environment:
|
||||
+ TF_VAR_MY_SECRET: ${TERRAFORM_SECRET}
|
||||
|
||||
terraform_2:
|
||||
image: jmccann/drone-terraform:5
|
||||
plan: false
|
||||
+ sensitive: true
|
||||
+ vars:
|
||||
+ my_secret: ${TERRAFORM_SECRET}
|
||||
```
|
||||
|
||||
You may be passing sensitive vars to your terraform commands. If you do not want
|
||||
the terraform commands to display in your drone logs then set `sensitive` to `true`.
|
||||
The output from the commands themselves will still display, it just won't show
|
||||
what command is actually being ran.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
terraform:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ sensitive: true
|
||||
```
|
||||
|
||||
Example configuration for overriding the terraform version. This will increase
|
||||
plugin execution time as it will download/unpack the version of terraform
|
||||
specified instead of using the embedded version that is included.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
terraform:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ tf_version: 0.10.3
|
||||
```
|
||||
|
||||
Example configuration with state tracked via remote. You will need a
|
||||
[backend configuration](https://www.terraform.io/docs/backends/config.html)
|
||||
specified in a `.tf` file. You can then pass additional options via the `.drone.yml`.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
terraform:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ init_options:
|
||||
+ backend-config:
|
||||
+ - "bucket=my-terraform-config-bucket"
|
||||
+ - "key=tf-states/my-project"
|
||||
+ - "region=us-east-1"
|
||||
```
|
||||
|
||||
You may want to run terraform against internal resources, like an internal
|
||||
OpenStack deployment. Sometimes these resources are signed by an internal
|
||||
CA Certificate. You can inject your CA Certificate into the plugin by using
|
||||
`ca_certs` key as described above. Below is an example.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
terraform:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ ca_cert: |
|
||||
+ -----BEGIN CERTIFICATE-----
|
||||
+ asdfsadf
|
||||
+ asdfsadf
|
||||
+ -----END CERTIFICATE-------
|
||||
```
|
||||
|
||||
You may want to assume another role before running the terraform commands.
|
||||
This is useful for cross account access, where a central account has privileges
|
||||
to assume roles in other accounts. Using the current credentials, this role will
|
||||
be assumed and exported to environment variables.
|
||||
See [the discussion](https://github.com/hashicorp/terraform/issues/1275) in the Terraform issues.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
terraform:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ role_arn_to_assume: arn:aws:iam::account-of-role-to-assume:role/name-of-role
|
||||
```
|
||||
|
||||
You may want to change directories before applying the terraform commands.
|
||||
This parameter is useful if you have multiple environments in different folders
|
||||
and you want to use different drone configurations to apply different environments.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
terraform:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ root_dir: some/path/here
|
||||
```
|
||||
|
||||
You may want to only target a specific list of resources within your terraform
|
||||
code. To achieve this you can specify the `targets` parameter. If left undefined
|
||||
all resources will be planned/applied against as the default behavior.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
terraform:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ targets:
|
||||
+ - aws_security_group.generic_sg
|
||||
+ - aws_security_group.app_sg
|
||||
```
|
||||
|
||||
You may want to limit the number of concurrent operations as Terraform walks its graph.
|
||||
If you want to change Terraform's default parallelism (currently equal to 10) then set the `parallelism` parameter.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
terraform:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ parallelism: 2
|
||||
```
|
||||
|
||||
Destroying the service can be done by specifying `plan-destroy` and `destroy` actions. Keep in mind that Fastly won't allow a service with active version be destroyed. Use `force_destroy` option in the service definition for terraform to handle it.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
destroy:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ actions:
|
||||
+ - plan-destroy
|
||||
+ - destroy
|
||||
```
|
||||
|
||||
Formatting the Terraform configuration files can be done by specifying the `fmt` action. Use `fmt_options` parameter to handle formatting options.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
fmt:
|
||||
image: jmccann/drone-terraform:5
|
||||
+ actions:
|
||||
+ - fmt
|
||||
+ fmt_options:
|
||||
+ write: false
|
||||
+ diff: true
|
||||
+ check: true
|
||||
```
|
||||
|
||||
You may want to run some executions in parallel without having racing condition problems with the .terraform dir and
|
||||
plan's output file.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
backend-service:
|
||||
image: jmccann/drone-terraform:<version>
|
||||
+ tf_data_dir: .backend-service.terraform
|
||||
frontend-service:
|
||||
image: jmccann/drone-terraform:<version>
|
||||
+ tf_data_dir: .frontend-service.terraform
|
||||
```
|
||||
|
||||
# Parameter Reference
|
||||
|
||||
actions
|
||||
: List of terraform actions to perform with the plugin. List includes:
|
||||
`fmt`, `validate`, `plan`, `apply`, `plan-destroy`, `destroy`.
|
||||
|
||||
init_options
|
||||
: contains the configuration for the Terraform backend.
|
||||
|
||||
init_options.backend-config
|
||||
: This specifies additional configuration to merge for the backend. This can be
|
||||
specified multiple times. Flags specified later in the line override those
|
||||
specified earlier if they conflict.
|
||||
|
||||
init_options.lock
|
||||
: Lock the state file when locking is supported. Default `true`.
|
||||
|
||||
init_options.lock-timeout
|
||||
: Duration to wait for a state lock. Default `0s`.
|
||||
|
||||
fmt_options
|
||||
: contains the configuration for the fmt action.
|
||||
|
||||
fmt_options.list
|
||||
: List files whose formatting differs (disabled if using STDIN). Default `true`.
|
||||
|
||||
fmt_options.write
|
||||
: Write result to source file instead of STDOUT (disabled if using STDIN or -check). Default `true`.
|
||||
|
||||
fmt_options.diff
|
||||
: Display diffs of formatting changes. Default `false`.
|
||||
|
||||
fmt_options.check
|
||||
: Check if the input is formatted. Exit status will be 0 if all input is properly formatted and non-zero otherwise. Default `false`.
|
||||
|
||||
vars
|
||||
: a map of variables to pass to the Terraform `plan` and `apply` commands.
|
||||
Each value is passed as a `-var <key>=<value>` option.
|
||||
|
||||
var_files
|
||||
: a list of variable files to pass to the Terraform `plan` and `apply` commands.
|
||||
Each value is passed as a `-var-file <value>` option.
|
||||
|
||||
ca_cert
|
||||
: ca cert to add to your environment to allow terraform to use internal/private resources
|
||||
|
||||
sensitive
|
||||
: (default: `false`) - Whether or not to suppress terraform commands to stdout.
|
||||
|
||||
role_arn_to_assume
|
||||
: A role to assume before running the terraform commands.
|
||||
|
||||
root_dir
|
||||
: The root directory where the terraform files live. When unset, the top level directory will be assumed.
|
||||
|
||||
parallelism
|
||||
: The number of concurrent operations as Terraform walks its graph.
|
||||
|
||||
tf_data_dir
|
||||
: changes the location where Terraform keeps its per-working-directory data, such as the current remote backend configuration.
|
||||
|
||||
disable_refresh
|
||||
: (default: `false`) - whether or not to disable refreshing state before `plan` and `apply` commands.
|
33
Dockerfile
33
Dockerfile
@ -1,33 +0,0 @@
|
||||
# Docker image for the Drone Terraform plugin
|
||||
#
|
||||
# docker build -t jmccann/drone-terraform:latest .
|
||||
FROM golang:1.16-alpine AS builder
|
||||
|
||||
RUN apk add --no-cache git
|
||||
|
||||
WORKDIR /tmp/drone-terraform
|
||||
|
||||
COPY go.mod go.mod
|
||||
COPY go.sum go.sum
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -o /go/bin/drone-terraform
|
||||
|
||||
FROM alpine:3.13
|
||||
|
||||
RUN apk add --no-cache \
|
||||
ca-certificates \
|
||||
git \
|
||||
wget \
|
||||
curl \
|
||||
openssh-client
|
||||
|
||||
ARG terraform_version
|
||||
RUN wget -q https://releases.hashicorp.com/terraform/${terraform_version}/terraform_${terraform_version}_linux_amd64.zip -O terraform.zip && \
|
||||
unzip terraform.zip -d /bin && \
|
||||
rm -f terraform.zip
|
||||
|
||||
COPY --from=builder /go/bin/drone-terraform /bin/
|
||||
ENTRYPOINT ["/bin/drone-terraform"]
|
7
LICENSE
7
LICENSE
@ -1,4 +1,5 @@
|
||||
Apache License
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
@ -178,7 +179,7 @@ Apache License
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
@ -186,7 +187,7 @@ Apache License
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
Copyright 2023 Robert Kaussow <mail@thegeeklab.de>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
46
MAINTAINERS
46
MAINTAINERS
@ -1,46 +0,0 @@
|
||||
[people]
|
||||
[people.bradrydzewski]
|
||||
name = "Brad Rydzewski"
|
||||
email = "brad@drone.io"
|
||||
login = "bradrydzewski"
|
||||
[people.Bugagazavr]
|
||||
name = "Kirill"
|
||||
email = ""
|
||||
login = "Bugagazavr"
|
||||
[people.donny-dont]
|
||||
name = "Don Olmstead"
|
||||
email = "donny-dont@gmail.com"
|
||||
login = "donny-dont"
|
||||
[people.jackspirou]
|
||||
name = "Jack Spirou"
|
||||
email = ""
|
||||
login = "jackspirou"
|
||||
[people.msteinert]
|
||||
name = "Mike Steinert"
|
||||
email = ""
|
||||
login = "msteinert"
|
||||
[people.nlf]
|
||||
name = "Nathan LaFreniere"
|
||||
email = ""
|
||||
login = "nlf"
|
||||
[people.tboerger]
|
||||
name = "Thomas Boerger"
|
||||
email = "thomas@webhippie.de"
|
||||
login = "tboerger"
|
||||
[people.athieriot]
|
||||
name = "Aurélien Thieriot"
|
||||
email = "a.thieriot@gmail.com"
|
||||
login = "athieriot"
|
||||
|
||||
[org]
|
||||
[org.core]
|
||||
people = [
|
||||
"bradrydzewski",
|
||||
"Bugagazavr",
|
||||
"donny-dont",
|
||||
"jackspirou",
|
||||
"msteinert",
|
||||
"nlf",
|
||||
"tboerger",
|
||||
"athieriot"
|
||||
]
|
115
Makefile
115
Makefile
@ -1,34 +1,107 @@
|
||||
.PHONY: all clean deps fmt vet test docker
|
||||
# renovate: datasource=github-releases depName=mvdan/gofumpt
|
||||
GOFUMPT_PACKAGE_VERSION := v0.6.0
|
||||
# renovate: datasource=github-releases depName=golangci/golangci-lint
|
||||
GOLANGCI_LINT_PACKAGE_VERSION := v1.55.2
|
||||
|
||||
EXECUTABLE ?= drone-terraform
|
||||
IMAGE ?= plugins/$(EXECUTABLE)
|
||||
COMMIT ?= $(shell git rev-parse --short HEAD)
|
||||
EXECUTABLE := wp-opentofu
|
||||
|
||||
LDFLAGS = -X "main.buildCommit=$(COMMIT)"
|
||||
PACKAGES = $(shell go list ./... | grep -v /vendor/)
|
||||
DIST := dist
|
||||
DIST_DIRS := $(DIST)
|
||||
IMPORT := github.com/thegeeklab/$(EXECUTABLE)
|
||||
|
||||
all: deps build test
|
||||
GO ?= go
|
||||
CWD ?= $(shell pwd)
|
||||
PACKAGES ?= $(shell go list ./...)
|
||||
SOURCES ?= $(shell find . -name "*.go" -type f)
|
||||
|
||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@$(GOFUMPT_PACKAGE_VERSION)
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_PACKAGE_VERSION)
|
||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||
GOTESTSUM_PACKAGE ?= gotest.tools/gotestsum@latest
|
||||
|
||||
GENERATE ?=
|
||||
XGO_VERSION := go-1.21.x
|
||||
XGO_TARGETS ?= linux/amd64,linux/arm64
|
||||
|
||||
TARGETOS ?= linux
|
||||
TARGETARCH ?= amd64
|
||||
ifneq ("$(TARGETVARIANT)","")
|
||||
GOARM ?= $(subst v,,$(TARGETVARIANT))
|
||||
endif
|
||||
TAGS ?= netgo
|
||||
|
||||
ifndef VERSION
|
||||
ifneq ($(CI_COMMIT_TAG),)
|
||||
VERSION ?= $(subst v,,$(CI_COMMIT_TAG))
|
||||
else
|
||||
VERSION ?= $(shell git rev-parse --short HEAD)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef DATE
|
||||
DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%S%z")
|
||||
endif
|
||||
|
||||
LDFLAGS += -s -w -X "main.BuildVersion=$(VERSION)" -X "main.BuildDate=$(DATE)"
|
||||
|
||||
.PHONY: all
|
||||
all: clean build
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
go clean -i ./...
|
||||
|
||||
deps:
|
||||
go get -t ./...
|
||||
$(GO) clean -i ./...
|
||||
rm -rf $(DIST_DIRS)
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
go fmt $(PACKAGES)
|
||||
$(GO) run $(GOFUMPT_PACKAGE) -extra -w $(SOURCES)
|
||||
|
||||
vet:
|
||||
go vet $(PACKAGES)
|
||||
.PHONY: golangci-lint
|
||||
golangci-lint:
|
||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
|
||||
|
||||
.PHONY: lint
|
||||
lint: golangci-lint
|
||||
|
||||
.PHONY: generate
|
||||
generate:
|
||||
$(GO) generate $(GENERATE)
|
||||
|
||||
.PHONY: generate-docs
|
||||
generate-docs:
|
||||
$(GO) generate ./cmd/$(EXECUTABLE)/flags.go
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
@for PKG in $(PACKAGES); do go test -cover -coverprofile $$GOPATH/src/$$PKG/coverage.out $$PKG || exit 1; done;
|
||||
$(GO) run $(GOTESTSUM_PACKAGE) --no-color=false -- -coverprofile=coverage.out $(PACKAGES)
|
||||
|
||||
docker:
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags '-s -w $(LDFLAGS)'
|
||||
docker build --rm -t $(IMAGE) .
|
||||
.PHONY: build
|
||||
build: $(DIST)/$(EXECUTABLE)
|
||||
|
||||
$(EXECUTABLE): $(wildcard *.go)
|
||||
go build -ldflags '-s -w $(LDFLAGS)'
|
||||
$(DIST)/$(EXECUTABLE): $(SOURCES)
|
||||
GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) GOARM=$(GOARM) $(GO) build -v -tags '$(TAGS)' -ldflags '-extldflags "-static" $(LDFLAGS)' -o $@ ./cmd/$(EXECUTABLE)
|
||||
|
||||
build: $(EXECUTABLE)
|
||||
$(DIST_DIRS):
|
||||
mkdir -p $(DIST_DIRS)
|
||||
|
||||
.PHONY: xgo
|
||||
xgo: | $(DIST_DIRS)
|
||||
$(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -v -ldflags '-extldflags "-static" $(LDFLAGS)' -tags '$(TAGS)' -targets '$(XGO_TARGETS)' -out $(EXECUTABLE) --pkg cmd/$(EXECUTABLE) .
|
||||
cp /build/* $(CWD)/$(DIST)
|
||||
ls -l $(CWD)/$(DIST)
|
||||
|
||||
.PHONY: checksum
|
||||
checksum:
|
||||
cd $(DIST); $(foreach file,$(wildcard $(DIST)/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
|
||||
ls -l $(CWD)/$(DIST)
|
||||
|
||||
.PHONY: release
|
||||
release: xgo checksum
|
||||
|
||||
.PHONY: deps
|
||||
deps:
|
||||
$(GO) mod download
|
||||
$(GO) install $(GOFUMPT_PACKAGE)
|
||||
$(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||
$(GO) install $(XGO_PACKAGE)
|
||||
$(GO) install $(GOTESTSUM_PACKAGE)
|
||||
|
49
README.md
49
README.md
@ -1,42 +1,21 @@
|
||||
# drone-terraform
|
||||
# wp-opentofu
|
||||
|
||||
[![Build Status](http://beta.drone.io/api/badges/jmccann/drone-terraform/status.svg)](http://beta.drone.io/jmccann/drone-terraform)
|
||||
Woodpecker CI plugin to manage infrastructure with OpenTofu
|
||||
|
||||
Drone plugin to execute Terraform plan and apply. For the usage information and
|
||||
a listing of the available options please take a look at [the docs](https://github.com/jmccann/drone-terraform/blob/master/DOCS.md).
|
||||
[![Build Status](https://ci.thegeeklab.de/api/badges/thegeeklab/wp-opentofu/status.svg)](https://ci.thegeeklab.de/repos/thegeeklab/wp-opentofu)
|
||||
[![Docker Hub](https://img.shields.io/badge/dockerhub-latest-blue.svg?logo=docker&logoColor=white)](https://hub.docker.com/r/thegeeklab/wp-opentofu)
|
||||
[![Quay.io](https://img.shields.io/badge/quay-latest-blue.svg?logo=docker&logoColor=white)](https://quay.io/repository/thegeeklab/wp-opentofu)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/thegeeklab/wp-opentofu)](https://goreportcard.com/report/github.com/thegeeklab/wp-opentofu)
|
||||
[![GitHub contributors](https://img.shields.io/github/contributors/thegeeklab/wp-opentofu)](https://github.com/thegeeklab/wp-opentofu/graphs/contributors)
|
||||
[![Source: GitHub](https://img.shields.io/badge/source-github-blue.svg?logo=github&logoColor=white)](https://github.com/thegeeklab/wp-opentofu)
|
||||
[![License: Apache-2.0](https://img.shields.io/github/license/thegeeklab/wp-opentofu)](https://github.com/thegeeklab/wp-opentofu/blob/main/LICENSE)
|
||||
|
||||
## Build
|
||||
Woodpecker CI plugin to manage infrastructure with [OpenTofu](https://github.com/opentofu/opentofu). This plugin is a fork of [jmccann/drone-terraform](https://github.com/jmccann/drone-terraform). You can find the full documentation at [https://woodpecker-plugins.geekdocs.de](https://woodpecker-plugins.geekdocs.de/plugins/wp-opentofu).
|
||||
|
||||
Build the binary with the following commands:
|
||||
## Contributors
|
||||
|
||||
```
|
||||
export GO111MODULE=on
|
||||
go mod download
|
||||
go test
|
||||
go build
|
||||
```
|
||||
Special thanks to all [contributors](https://github.com/thegeeklab/wp-opentofu/graphs/contributors). If you would like to contribute, please see the [instructions](https://github.com/thegeeklab/wp-opentofu/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## Docker
|
||||
## License
|
||||
|
||||
Build the docker image with the following commands:
|
||||
|
||||
```
|
||||
docker build --rm=true \
|
||||
-t jmccann/drone-terraform \
|
||||
--build-arg terraform_version=0.12.0 .
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Execute from the working directory:
|
||||
|
||||
```
|
||||
docker run --rm \
|
||||
-v $(pwd):$(pwd) \
|
||||
-w $(pwd) \
|
||||
jmccann/drone-terraform:latest --plan
|
||||
```
|
||||
|
||||
## Drone 0.4
|
||||
|
||||
Legacy `drone-terraform` plugin exists @ `jmccann/drone-terraform:0.4`
|
||||
This project is licensed under the Apache-2.0 License - see the [LICENSE](https://github.com/thegeeklab/wp-opentofu/blob/main/LICENSE) file for details.
|
||||
|
@ -1,40 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
tag=$1
|
||||
|
||||
if [ -z $tag ]; then
|
||||
echo "please provide a tag arg"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
major=$(echo $tag | awk -F. '{print $1}')
|
||||
minor=$(echo $tag | awk -F. '{print $2}')
|
||||
|
||||
tf_ver="1.0.2"
|
||||
|
||||
echo "Confirm building images for:"
|
||||
echo " MAJOR: ${major}"
|
||||
echo " MINOR: ${minor}"
|
||||
echo " TF_VERSION: ${tf_ver}"
|
||||
|
||||
read -p "Proceed? [Y/N] " ans
|
||||
|
||||
if [[ "$ans" != "Y" && "$ans" != "y" ]]; then
|
||||
echo "Cancelling"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
set -x
|
||||
docker build -t jmccann/drone-terraform:latest --build-arg terraform_version=${tf_ver} .
|
||||
|
||||
docker tag jmccann/drone-terraform:latest jmccann/drone-terraform:${major}
|
||||
docker tag jmccann/drone-terraform:latest jmccann/drone-terraform:${major}.${minor}
|
||||
docker tag jmccann/drone-terraform:latest jmccann/drone-terraform:${major}.${minor}-${tf_ver}
|
||||
|
||||
docker push jmccann/drone-terraform:latest
|
||||
docker push jmccann/drone-terraform:${major}
|
||||
docker push jmccann/drone-terraform:${major}.${minor}
|
||||
docker push jmccann/drone-terraform:${major}.${minor}-${tf_ver}
|
||||
set +x
|
58
cmd/wp-ansible/docs.go
Normal file
58
cmd/wp-ansible/docs.go
Normal file
@ -0,0 +1,58 @@
|
||||
//go:build generate
|
||||
// +build generate
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/thegeeklab/wp-opentofu/plugin"
|
||||
"github.com/thegeeklab/wp-plugin-go/docs"
|
||||
wp "github.com/thegeeklab/wp-plugin-go/plugin"
|
||||
wp_template "github.com/thegeeklab/wp-plugin-go/template"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
//go:embed templates/docs-data.yaml.tmpl
|
||||
var yamlTemplate embed.FS
|
||||
|
||||
func main() {
|
||||
settings := &plugin.Settings{}
|
||||
app := &cli.App{
|
||||
Flags: settingsFlags(settings, wp.FlagsPluginCategory),
|
||||
}
|
||||
|
||||
out, err := toYAML(app)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fi, err := os.Create("../../docs/data/data-raw.yaml")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fi.Close()
|
||||
if _, err := fi.WriteString(out); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func toYAML(app *cli.App) (string, error) {
|
||||
var w bytes.Buffer
|
||||
|
||||
yamlTmpl, err := template.New("docs").Funcs(wp_template.LoadFuncMap()).ParseFS(yamlTemplate, "templates/docs-data.yaml.tmpl")
|
||||
if err != nil {
|
||||
fmt.Println(yamlTmpl)
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := yamlTmpl.ExecuteTemplate(&w, "docs-data.yaml.tmpl", docs.GetTemplateData(app)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return w.String(), nil
|
||||
}
|
76
cmd/wp-ansible/flags.go
Normal file
76
cmd/wp-ansible/flags.go
Normal file
@ -0,0 +1,76 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/thegeeklab/wp-opentofu/plugin"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// SettingsFlags has the cli.Flags for the plugin.Settings.
|
||||
//
|
||||
//go:generate go run docs.go flags.go
|
||||
func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringSliceFlag{
|
||||
Name: "action",
|
||||
Usage: "tofu actions to execute",
|
||||
EnvVars: []string{"PLUGIN_ACTION"},
|
||||
Value: cli.NewStringSlice("validate", "plan", "apply"),
|
||||
Destination: &settings.Action,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "init-options",
|
||||
Usage: "tofu init command options, see https://opentofu.org/docs/cli/commands/init/",
|
||||
EnvVars: []string{"PLUGIN_INIT_OPTIONS"},
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "fmt-options",
|
||||
Usage: "options for the fmt command, see https://opentofu.org/docs/cli/commands/fmt/",
|
||||
EnvVars: []string{"PLUGIN_FMT_OPTIONS"},
|
||||
Category: category,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "parallelism",
|
||||
Usage: "number of concurrent operations",
|
||||
EnvVars: []string{"PLUGIN_PARALLELISM"},
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "root-dir",
|
||||
Usage: "root directory where the tofu files live",
|
||||
EnvVars: []string{"PLUGIN_ROOT_DIR"},
|
||||
Destination: &settings.RootDir,
|
||||
Category: category,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "no-log",
|
||||
Usage: "suppress tofu command output",
|
||||
EnvVars: []string{"PLUGIN_NO_LOG"},
|
||||
Destination: &settings.NoLog,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "targets",
|
||||
Usage: "targets to run `apply` or `plan` action on",
|
||||
EnvVars: []string{"PLUGIN_TARGETS"},
|
||||
Destination: &settings.Targets,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "version",
|
||||
Usage: "tofu version to use",
|
||||
EnvVars: []string{"PLUGIN_VERSION"},
|
||||
Destination: &settings.Version,
|
||||
Category: category,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "refresh",
|
||||
Usage: "enables refreshing of the state before `plan` and `apply` commands",
|
||||
EnvVars: []string{"PLUGIN_REFRESH"},
|
||||
Destination: &settings.Refresh,
|
||||
Value: true,
|
||||
Category: category,
|
||||
},
|
||||
}
|
||||
}
|
28
cmd/wp-ansible/main.go
Normal file
28
cmd/wp-ansible/main.go
Normal file
@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thegeeklab/wp-opentofu/plugin"
|
||||
|
||||
wp "github.com/thegeeklab/wp-plugin-go/plugin"
|
||||
)
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
var (
|
||||
BuildVersion = "devel"
|
||||
BuildDate = "00000000"
|
||||
)
|
||||
|
||||
func main() {
|
||||
settings := &plugin.Settings{}
|
||||
options := wp.Options{
|
||||
Name: "wp-opentofu",
|
||||
Description: "Manage infrastructure with OpenTofu",
|
||||
Version: BuildVersion,
|
||||
VersionMetadata: fmt.Sprintf("date=%s", BuildDate),
|
||||
Flags: settingsFlags(settings, wp.FlagsPluginCategory),
|
||||
}
|
||||
|
||||
plugin.New(options, settings).Run()
|
||||
}
|
18
cmd/wp-ansible/templates/docs-data.yaml.tmpl
Normal file
18
cmd/wp-ansible/templates/docs-data.yaml.tmpl
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
{{- if .GlobalArgs }}
|
||||
properties:
|
||||
{{- range $v := .GlobalArgs }}
|
||||
- name: {{ $v.Name }}
|
||||
{{- with $v.Description }}
|
||||
description: |
|
||||
{{ . | ToSentence }}
|
||||
{{- end }}
|
||||
{{- with $v.Type }}
|
||||
type: {{ . }}
|
||||
{{- end }}
|
||||
{{- with $v.Default }}
|
||||
defaultValue: {{ . }}
|
||||
{{- end }}
|
||||
required: {{ default false $v.Required }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
59
docs/content/_index.md
Normal file
59
docs/content/_index.md
Normal file
@ -0,0 +1,59 @@
|
||||
---
|
||||
title: wp-opentofu
|
||||
---
|
||||
|
||||
[![Build Status](https://ci.thegeeklab.de/api/badges/thegeeklab/wp-opentofu/status.svg)](https://ci.thegeeklab.de/repos/thegeeklab/wp-opentofu)
|
||||
[![Docker Hub](https://img.shields.io/badge/dockerhub-latest-blue.svg?logo=docker&logoColor=white)](https://hub.docker.com/r/thegeeklab/wp-opentofu)
|
||||
[![Quay.io](https://img.shields.io/badge/quay-latest-blue.svg?logo=docker&logoColor=white)](https://quay.io/repository/thegeeklab/wp-opentofu)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/thegeeklab/wp-opentofu)](https://goreportcard.com/report/github.com/thegeeklab/wp-opentofu)
|
||||
[![GitHub contributors](https://img.shields.io/github/contributors/thegeeklab/wp-opentofu)](https://github.com/thegeeklab/wp-opentofu/graphs/contributors)
|
||||
[![Source: GitHub](https://img.shields.io/badge/source-github-blue.svg?logo=github&logoColor=white)](https://github.com/thegeeklab/wp-opentofu)
|
||||
[![License: Apache-2.0](https://img.shields.io/github/license/thegeeklab/wp-opentofu)](https://github.com/thegeeklab/wp-opentofu/blob/main/LICENSE)
|
||||
|
||||
Woodpecker CI plugin to manage infrastructure with [OpenTofu](https://github.com/opentofu/opentofu).
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- spellchecker-disable -->
|
||||
{{< toc >}}
|
||||
<!-- spellchecker-enable -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## Usage
|
||||
|
||||
```YAML
|
||||
steps:
|
||||
- name: tofu
|
||||
image: quay.io/thegeeklab/wp-opentofu
|
||||
settings:
|
||||
actions:
|
||||
- validate
|
||||
- plan
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- spellchecker-disable -->
|
||||
{{< propertylist name=wp-opentofu.data sort=name >}}
|
||||
<!-- spellchecker-enable -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## Build
|
||||
|
||||
Build the binary with the following command:
|
||||
|
||||
```Shell
|
||||
make build
|
||||
```
|
||||
|
||||
Build the Container image with the following command:
|
||||
|
||||
```Shell
|
||||
docker build --file Containerfile.multiarch --tag thegeeklab/wp-opentofu .
|
||||
```
|
||||
|
||||
## Test
|
||||
|
||||
```Shell
|
||||
|
||||
```
|
211
docs/data/data.yaml
Normal file
211
docs/data/data.yaml
Normal file
@ -0,0 +1,211 @@
|
||||
---
|
||||
properties:
|
||||
- name: become
|
||||
description: |
|
||||
Enable privilege escalation.
|
||||
type: bool
|
||||
defaultValue: false
|
||||
required: false
|
||||
|
||||
- name: become_method
|
||||
description: |
|
||||
Privilege escalation method to use.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: become_user
|
||||
description: |
|
||||
Privilege escalation user to use.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: check
|
||||
description: |
|
||||
Run a check, do not apply any changes.
|
||||
type: bool
|
||||
defaultValue: false
|
||||
required: false
|
||||
|
||||
- name: connection
|
||||
description: |
|
||||
Connection type to use.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: diff
|
||||
description: |
|
||||
Show the differences. Be careful when using it in public CI environments as it can print secrets.
|
||||
type: bool
|
||||
defaultValue: false
|
||||
required: false
|
||||
|
||||
- name: extra_vars
|
||||
description: |
|
||||
Set additional variables as `key=value`.
|
||||
type: list
|
||||
required: false
|
||||
|
||||
- name: flush_cache
|
||||
description: |
|
||||
Clear the fact cache for every host in inventory.
|
||||
type: bool
|
||||
defaultValue: false
|
||||
required: false
|
||||
|
||||
- name: force_handlers
|
||||
description: |
|
||||
Run handlers even if a task fails.
|
||||
type: bool
|
||||
defaultValue: false
|
||||
required: false
|
||||
|
||||
- name: forks
|
||||
description: |
|
||||
Specify number of parallel processes to use.
|
||||
type: integer
|
||||
defaultValue: 5
|
||||
required: false
|
||||
|
||||
- name: galaxy_requirements
|
||||
description: |
|
||||
Path to galaxy requirements file.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: inventory
|
||||
description: |
|
||||
Path to inventory file.
|
||||
type: list
|
||||
required: false
|
||||
|
||||
- name: limit
|
||||
description: |
|
||||
Limit selected hosts to an additional pattern.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: list_hosts
|
||||
description: |
|
||||
Outputs a list of matching hosts.
|
||||
type: bool
|
||||
defaultValue: false
|
||||
required: false
|
||||
|
||||
- name: list_tags
|
||||
description: |
|
||||
List all available tags.
|
||||
type: bool
|
||||
defaultValue: false
|
||||
required: false
|
||||
|
||||
- name: list_tasks
|
||||
description: |
|
||||
List all tasks that would be executed.
|
||||
type: bool
|
||||
defaultValue: false
|
||||
required: false
|
||||
|
||||
- name: module_path
|
||||
description: |
|
||||
Prepend paths to module library.
|
||||
type: list
|
||||
required: false
|
||||
|
||||
- name: playbook
|
||||
description: |
|
||||
List of playbooks to apply.
|
||||
type: list
|
||||
required: false
|
||||
|
||||
- name: private_key
|
||||
description: |
|
||||
SSH private key used to authenticate the connection.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: python_requirements
|
||||
description: |
|
||||
Path to python requirements file.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: scp_extra_args
|
||||
description: |
|
||||
Specify extra arguments to pass to SCP connections only.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: sftp_extra_args
|
||||
description: |
|
||||
Specify extra arguments to pass to SFTP connections only.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: skip_tags
|
||||
description: |
|
||||
Only run plays and tasks whose tags do not match.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: ssh_common_args
|
||||
description: |
|
||||
Specify common arguments to pass to SFTP, SCP and SSH connections.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: ssh_extra_args
|
||||
description: |
|
||||
Specify extra arguments to pass to SSH connections only.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: start_at_task
|
||||
description: |
|
||||
Start the playbook at the task matching this name.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: syntax_check
|
||||
description: |
|
||||
Perform a syntax check on the playbook.
|
||||
type: bool
|
||||
defaultValue: false
|
||||
required: false
|
||||
|
||||
- name: tags
|
||||
description: |
|
||||
Only run plays and tasks tagged with these values.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: timeout
|
||||
description: |
|
||||
Override the connection timeout in seconds.
|
||||
type: integer
|
||||
defaultValue: 0
|
||||
required: false
|
||||
|
||||
- name: user
|
||||
description: |
|
||||
Connect as this user.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: vault_id
|
||||
description: |
|
||||
The vault identity to use.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: vault_password
|
||||
description: |
|
||||
The vault password to use.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
- name: verbose
|
||||
description: |
|
||||
Level of verbosity, 0 up to 4.
|
||||
type: integer
|
||||
defaultValue: 0
|
||||
required: false
|
37
go.mod
37
go.mod
@ -1,14 +1,31 @@
|
||||
module github.com/jmccann/drone-terraform
|
||||
module github.com/thegeeklab/wp-opentofu
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/Sirupsen/logrus v0.0.0-20160829202321-3ec0642a7fb6
|
||||
github.com/aws/aws-sdk-go v0.0.0-20161007224333-c0d7d3282e4c
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db
|
||||
github.com/go-ini/ini v1.21.1
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/urfave/cli v0.0.0-20161006035353-55f715e28c46
|
||||
golang.org/x/sys v0.0.0-20161006025142-8d1157a43547
|
||||
github.com/Masterminds/semver/v3 v3.2.1
|
||||
github.com/thegeeklab/wp-plugin-go v1.5.0
|
||||
github.com/urfave/cli/v2 v2.27.1
|
||||
golang.org/x/sys v0.16.0
|
||||
)
|
||||
|
||||
go 1.13
|
||||
require (
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/google/uuid v1.1.1 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
github.com/imdario/mergo v0.3.11 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/rs/zerolog v1.31.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
)
|
||||
|
119
go.sum
119
go.sum
@ -1,19 +1,100 @@
|
||||
github.com/Sirupsen/logrus v0.0.0-20160829202321-3ec0642a7fb6 h1:Tp6VdyWz8sPuNnRbgf5jqIOV/zoG4mA5nBHtJyFb4Hc=
|
||||
github.com/Sirupsen/logrus v0.0.0-20160829202321-3ec0642a7fb6/go.mod h1:rmk17hk6i8ZSAJkSDa7nOxamrG+SP4P0mm+DAvExv4U=
|
||||
github.com/aws/aws-sdk-go v0.0.0-20161007224333-c0d7d3282e4c h1:IF3li2sCc78JFAsluLt9iiCCOnWkMYG9FApcWnq4Sv0=
|
||||
github.com/aws/aws-sdk-go v0.0.0-20161007224333-c0d7d3282e4c/go.mod h1:ZRmQr0FajVIyZ4ZzBYKG5P3ZqPz9IHG41ZoMu1ADI3k=
|
||||
github.com/franela/goblin v0.0.0-20170111051028-2fa789fd0c6b h1:pFXMOmYgv60RqCPRU9v+jprPw88/oor7dQDykOfi17A=
|
||||
github.com/franela/goblin v0.0.0-20170111051028-2fa789fd0c6b/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db h1:gb2Z18BhTPJPpLQWj4T+rfKHYCHxRHCtRxhKKjRidVw=
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
github.com/go-ini/ini v1.21.1 h1:+QXUYsI7Tfxc64oD6R5BxU/Aq+UwGkyjH4W/hMNG7bg=
|
||||
github.com/go-ini/ini v1.21.1/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7 h1:SMvOWPJCES2GdFracYbBQh93GXac8fq7HeN6JnpduB8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/joho/godotenv v0.0.0-20150907010228-4ed13390c0ac h1:wF2VgtpbaLqhBHV9FxVWzgzgv8VcCjZ66Bl/+F6cpT0=
|
||||
github.com/joho/godotenv v0.0.0-20150907010228-4ed13390c0ac/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/urfave/cli v0.0.0-20161006035353-55f715e28c46 h1:EztUvugq7AA7F3lYLmtFQyvKdcY5pisPt10DqPjRCL8=
|
||||
github.com/urfave/cli v0.0.0-20161006035353-55f715e28c46/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
golang.org/x/sys v0.0.0-20161006025142-8d1157a43547/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
|
||||
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
|
||||
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/thegeeklab/wp-plugin-go v1.5.0 h1:fA/kQwQrntjxdxePKKGecMRnPbj1xwpy6D2JrrPD2qA=
|
||||
github.com/thegeeklab/wp-plugin-go v1.5.0/go.mod h1:ULBD5SNC7bkIB/UbLMQpcPWj7iZObCTWg8bqXf1zqsA=
|
||||
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
|
||||
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI=
|
||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
33
logo.svg
33
logo.svg
@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="722.000000pt" height="722.000000pt" viewBox="0 0 722.000000 722.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.13, written by Peter Selinger 2001-2015
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,722.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M3769 7206 c-3 -3 -221 -32 -484 -65 -264 -33 -496 -62 -515 -64 -19
|
||||
-3 -159 -43 -310 -89 -195 -59 -291 -93 -330 -117 -306 -190 -812 -498 -836
|
||||
-510 -22 -11 -57 -54 -111 -136 -44 -66 -236 -358 -428 -650 -191 -291 -359
|
||||
-541 -372 -556 -12 -14 -23 -31 -23 -39 0 -17 -319 -1119 -330 -1140 -5 -9 -9
|
||||
-119 -10 -245 l-1 -230 121 -535 c121 -532 122 -536 186 -678 35 -78 64 -148
|
||||
64 -155 0 -7 94 -168 208 -359 l209 -346 251 -237 c246 -231 254 -237 359
|
||||
-289 60 -29 423 -206 808 -393 l700 -340 245 -12 c135 -7 382 -12 549 -12
|
||||
l305 0 285 53 285 53 760 437 c419 240 766 441 771 446 6 5 218 342 470 748
|
||||
l460 739 81 435 c45 239 81 437 79 440 -2 3 -37 280 -80 615 -42 336 -81 618
|
||||
-86 628 -15 28 -195 547 -204 587 -4 19 -15 44 -25 55 -18 21 -405 570 -436
|
||||
621 -11 16 -84 92 -164 169 -80 76 -215 208 -301 292 -86 84 -161 153 -166
|
||||
153 -6 0 -271 124 -589 276 -319 152 -601 286 -629 299 -32 15 -169 46 -380
|
||||
85 -410 78 -379 73 -386 66z m-1526 -2150 l567 -319 0 -668 c0 -368 -3 -669
|
||||
-6 -669 -3 0 -273 150 -600 333 l-594 332 0 673 0 674 33 -19 c17 -11 287
|
||||
-162 600 -337z m1273 -718 l594 -333 0 -673 0 -674 -42 24 c-24 13 -294 165
|
||||
-600 337 l-558 313 0 669 c0 368 3 669 6 669 3 0 273 -150 600 -332z m1892
|
||||
-339 l-3 -671 -595 -334 -595 -334 -3 667 c-1 430 1 670 8 677 12 12 1172 665
|
||||
1183 666 4 0 6 -302 5 -671z m-1892 -1121 l593 -333 1 -672 c0 -370 -1 -673
|
||||
-3 -673 -2 0 -271 150 -598 334 l-594 334 -3 671 c-1 369 1 671 4 671 4 0 273
|
||||
-150 600 -332z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.9 KiB |
184
main.go
184
main.go
@ -1,184 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var revision string // build number set at compile-time
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "terraform plugin"
|
||||
app.Usage = "terraform plugin"
|
||||
app.Action = run
|
||||
app.Version = revision
|
||||
app.Flags = []cli.Flag{
|
||||
|
||||
//
|
||||
// plugin args
|
||||
//
|
||||
|
||||
cli.StringSliceFlag{
|
||||
Name: "actions",
|
||||
Usage: "a list of actions to have terraform perform",
|
||||
EnvVar: "PLUGIN_ACTIONS",
|
||||
Value: &cli.StringSlice{"validate", "plan", "apply"},
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "ca_cert",
|
||||
Usage: "ca cert to add to your environment to allow terraform to use internal/private resources",
|
||||
EnvVar: "PLUGIN_CA_CERT",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "env_file",
|
||||
Usage: "pass filename to source it and load variables into current shell",
|
||||
EnvVar: "PLUGIN_ENV_FILE",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "init_options",
|
||||
Usage: "options for the init command. See https://www.terraform.io/docs/commands/init.html",
|
||||
EnvVar: "PLUGIN_INIT_OPTIONS",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "fmt_options",
|
||||
Usage: "options for the fmt command. See https://www.terraform.io/docs/commands/fmt.html",
|
||||
EnvVar: "PLUGIN_FMT_OPTIONS",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "parallelism",
|
||||
Usage: "The number of concurrent operations as Terraform walks its graph",
|
||||
EnvVar: "PLUGIN_PARALLELISM",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "netrc.machine",
|
||||
Usage: "netrc machine",
|
||||
EnvVar: "DRONE_NETRC_MACHINE",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "netrc.username",
|
||||
Usage: "netrc username",
|
||||
EnvVar: "DRONE_NETRC_USERNAME",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "netrc.password",
|
||||
Usage: "netrc password",
|
||||
EnvVar: "DRONE_NETRC_PASSWORD",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "role_arn_to_assume",
|
||||
Usage: "A role to assume before running the terraform commands",
|
||||
EnvVar: "PLUGIN_ROLE_ARN_TO_ASSUME",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "root_dir",
|
||||
Usage: "The root directory where the terraform files live. When unset, the top level directory will be assumed",
|
||||
EnvVar: "PLUGIN_ROOT_DIR",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "secrets",
|
||||
Usage: "a map of secrets to pass to the Terraform `plan` and `apply` commands. Each value is passed as a `<key>=<ENV>` option",
|
||||
EnvVar: "PLUGIN_SECRETS",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "sensitive",
|
||||
Usage: "whether or not to suppress terraform commands to stdout",
|
||||
EnvVar: "PLUGIN_SENSITIVE",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "targets",
|
||||
Usage: "targets to run apply or plan on",
|
||||
EnvVar: "PLUGIN_TARGETS",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tf.version",
|
||||
Usage: "terraform version to use",
|
||||
EnvVar: "PLUGIN_TF_VERSION",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "vars",
|
||||
Usage: "a map of variables to pass to the Terraform `plan` and `apply` commands. Each value is passed as a `<key>=<value>` option",
|
||||
EnvVar: "PLUGIN_VARS",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "var_files",
|
||||
Usage: "a list of var files to use. Each value is passed as -var-file=<value>",
|
||||
EnvVar: "PLUGIN_VAR_FILES",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tf_data_dir",
|
||||
Usage: "changes the location where Terraform keeps its per-working-directory data, such as the current remote backend configuration",
|
||||
EnvVar: "PLUGIN_TF_DATA_DIR",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "disable_refresh",
|
||||
Usage: "whether or not to disable refreshing state before `plan` and `apply` commands",
|
||||
EnvVar: "PLUGIN_DISABLE_REFRESH",
|
||||
},
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func run(c *cli.Context) error {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"Revision": revision,
|
||||
}).Info("Drone Terraform Plugin Version")
|
||||
|
||||
if c.String("env_file") != "" {
|
||||
_ = godotenv.Load(c.String("env_file"))
|
||||
}
|
||||
|
||||
var vars map[string]string
|
||||
if c.String("vars") != "" {
|
||||
if err := json.Unmarshal([]byte(c.String("vars")), &vars); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
var secrets map[string]string
|
||||
if c.String("secrets") != "" {
|
||||
if err := json.Unmarshal([]byte(c.String("secrets")), &secrets); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
initOptions := InitOptions{}
|
||||
json.Unmarshal([]byte(c.String("init_options")), &initOptions)
|
||||
fmtOptions := FmtOptions{}
|
||||
json.Unmarshal([]byte(c.String("fmt_options")), &fmtOptions)
|
||||
|
||||
plugin := Plugin{
|
||||
Config: Config{
|
||||
Actions: c.StringSlice("actions"),
|
||||
Vars: vars,
|
||||
Secrets: secrets,
|
||||
InitOptions: initOptions,
|
||||
FmtOptions: fmtOptions,
|
||||
Cacert: c.String("ca_cert"),
|
||||
Sensitive: c.Bool("sensitive"),
|
||||
RoleARN: c.String("role_arn_to_assume"),
|
||||
RootDir: c.String("root_dir"),
|
||||
Parallelism: c.Int("parallelism"),
|
||||
Targets: c.StringSlice("targets"),
|
||||
VarFiles: c.StringSlice("var_files"),
|
||||
TerraformDataDir: c.String("tf_data_dir"),
|
||||
DisableRefresh: c.Bool("disable_refresh"),
|
||||
},
|
||||
Netrc: Netrc{
|
||||
Login: c.String("netrc.username"),
|
||||
Machine: c.String("netrc.machine"),
|
||||
Password: c.String("netrc.password"),
|
||||
},
|
||||
Terraform: Terraform{
|
||||
Version: c.String("tf.version"),
|
||||
},
|
||||
}
|
||||
|
||||
return plugin.Exec()
|
||||
}
|
415
plugin.go
415
plugin.go
@ -1,415 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
)
|
||||
|
||||
type (
|
||||
// Config holds input parameters for the plugin
|
||||
Config struct {
|
||||
Actions []string
|
||||
Vars map[string]string
|
||||
Secrets map[string]string
|
||||
InitOptions InitOptions
|
||||
FmtOptions FmtOptions
|
||||
Cacert string
|
||||
Sensitive bool
|
||||
RoleARN string
|
||||
RootDir string
|
||||
Parallelism int
|
||||
Targets []string
|
||||
VarFiles []string
|
||||
TerraformDataDir string
|
||||
DisableRefresh bool
|
||||
}
|
||||
|
||||
// Netrc is credentials for cloning
|
||||
Netrc struct {
|
||||
Machine string
|
||||
Login string
|
||||
Password string
|
||||
}
|
||||
|
||||
// InitOptions include options for the Terraform's init command
|
||||
InitOptions struct {
|
||||
BackendConfig []string `json:"backend-config"`
|
||||
Lock *bool `json:"lock"`
|
||||
LockTimeout string `json:"lock-timeout"`
|
||||
}
|
||||
|
||||
// FmtOptions fmt options for the Terraform's fmt command
|
||||
FmtOptions struct {
|
||||
List *bool `json:"list"`
|
||||
Write *bool `json:"write"`
|
||||
Diff *bool `json:"diff"`
|
||||
Check *bool `json:"check"`
|
||||
}
|
||||
|
||||
// Plugin represents the plugin instance to be executed
|
||||
Plugin struct {
|
||||
Config Config
|
||||
Netrc Netrc
|
||||
Terraform Terraform
|
||||
}
|
||||
)
|
||||
|
||||
// Exec executes the plugin
|
||||
func (p Plugin) Exec() error {
|
||||
// Install specified version of terraform
|
||||
if p.Terraform.Version != "" {
|
||||
err := installTerraform(p.Terraform.Version)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if p.Config.RoleARN != "" && !credsSet() {
|
||||
assumeRole(p.Config.RoleARN)
|
||||
}
|
||||
|
||||
// writing the .netrc file with Github credentials in it.
|
||||
err := writeNetrc(p.Netrc.Machine, p.Netrc.Login, p.Netrc.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
terraformDataDir := ".terraform"
|
||||
if p.Config.TerraformDataDir != "" {
|
||||
terraformDataDir = p.Config.TerraformDataDir
|
||||
os.Setenv("TF_DATA_DIR", p.Config.TerraformDataDir)
|
||||
}
|
||||
|
||||
var commands []*exec.Cmd
|
||||
|
||||
commands = append(commands, exec.Command("terraform", "version"))
|
||||
|
||||
CopyTfEnv()
|
||||
|
||||
if p.Config.Cacert != "" {
|
||||
commands = append(commands, installCaCert(p.Config.Cacert))
|
||||
}
|
||||
|
||||
commands = append(commands, deleteCache(terraformDataDir))
|
||||
commands = append(commands, initCommand(p.Config.InitOptions))
|
||||
commands = append(commands, getModules())
|
||||
|
||||
// Add commands listed from Actions
|
||||
for _, action := range p.Config.Actions {
|
||||
switch action {
|
||||
case "fmt":
|
||||
commands = append(commands, tfFmt(p.Config))
|
||||
case "validate":
|
||||
commands = append(commands, tfValidate())
|
||||
case "plan":
|
||||
commands = append(commands, tfPlan(p.Config, false))
|
||||
case "plan-destroy":
|
||||
commands = append(commands, tfPlan(p.Config, true))
|
||||
case "apply":
|
||||
commands = append(commands, tfApply(p.Config))
|
||||
case "destroy":
|
||||
commands = append(commands, tfDestroy(p.Config))
|
||||
default:
|
||||
return fmt.Errorf("valid actions are: fmt, validate, plan, apply, plan-destroy, destroy. You provided %s", action)
|
||||
}
|
||||
}
|
||||
|
||||
commands = append(commands, deleteCache(terraformDataDir))
|
||||
|
||||
for _, c := range commands {
|
||||
if c.Dir == "" {
|
||||
wd, err := os.Getwd()
|
||||
if err == nil {
|
||||
c.Dir = wd
|
||||
}
|
||||
}
|
||||
if p.Config.RootDir != "" {
|
||||
c.Dir = c.Dir + "/" + p.Config.RootDir
|
||||
}
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
if !p.Config.Sensitive {
|
||||
trace(c)
|
||||
}
|
||||
|
||||
err := c.Run()
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Fatal("Failed to execute a command")
|
||||
}
|
||||
logrus.Debug("Command completed successfully")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CopyTfEnv creates copies of TF_VAR_ to lowercase
|
||||
func CopyTfEnv() {
|
||||
tfVar := regexp.MustCompile(`^TF_VAR_.*$`)
|
||||
for _, e := range os.Environ() {
|
||||
pair := strings.SplitN(e, "=", 2)
|
||||
if tfVar.MatchString(pair[0]) {
|
||||
name := strings.Split(pair[0], "TF_VAR_")
|
||||
os.Setenv(fmt.Sprintf("TF_VAR_%s", strings.ToLower(name[1])), pair[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func credsSet() bool {
|
||||
awsTokens := []string{"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"}
|
||||
for _, token := range awsTokens {
|
||||
if os.Getenv(token) == "" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func assumeRole(roleArn string) {
|
||||
client := sts.New(session.New())
|
||||
duration := time.Hour * 1
|
||||
stsProvider := &stscreds.AssumeRoleProvider{
|
||||
Client: client,
|
||||
Duration: duration,
|
||||
RoleARN: roleArn,
|
||||
RoleSessionName: "drone",
|
||||
}
|
||||
|
||||
value, err := credentials.NewCredentials(stsProvider).Get()
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Fatal("Error assuming role!")
|
||||
}
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", value.AccessKeyID)
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", value.SecretAccessKey)
|
||||
os.Setenv("AWS_SESSION_TOKEN", value.SessionToken)
|
||||
}
|
||||
|
||||
func deleteCache(terraformDataDir string) *exec.Cmd {
|
||||
return exec.Command(
|
||||
"rm",
|
||||
"-rf",
|
||||
terraformDataDir,
|
||||
)
|
||||
}
|
||||
|
||||
func getModules() *exec.Cmd {
|
||||
return exec.Command(
|
||||
"terraform",
|
||||
"get",
|
||||
)
|
||||
}
|
||||
|
||||
func initCommand(config InitOptions) *exec.Cmd {
|
||||
args := []string{
|
||||
"init",
|
||||
}
|
||||
|
||||
for _, v := range config.BackendConfig {
|
||||
args = append(args, fmt.Sprintf("-backend-config=%s", v))
|
||||
}
|
||||
|
||||
// Fail Terraform execution on prompt
|
||||
args = append(args, "-input=false")
|
||||
|
||||
return exec.Command(
|
||||
"terraform",
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
func installCaCert(cacert string) *exec.Cmd {
|
||||
ioutil.WriteFile("/usr/local/share/ca-certificates/ca_cert.crt", []byte(cacert), 0644)
|
||||
return exec.Command(
|
||||
"update-ca-certificates",
|
||||
)
|
||||
}
|
||||
|
||||
func trace(cmd *exec.Cmd) {
|
||||
fmt.Println("$", strings.Join(cmd.Args, " "))
|
||||
}
|
||||
|
||||
func tfApply(config Config) *exec.Cmd {
|
||||
args := []string{
|
||||
"apply",
|
||||
}
|
||||
for _, v := range config.Targets {
|
||||
args = append(args, "--target", fmt.Sprintf("%s", v))
|
||||
}
|
||||
if config.Parallelism > 0 {
|
||||
args = append(args, fmt.Sprintf("-parallelism=%d", config.Parallelism))
|
||||
}
|
||||
if config.InitOptions.Lock != nil {
|
||||
args = append(args, fmt.Sprintf("-lock=%t", *config.InitOptions.Lock))
|
||||
}
|
||||
if config.InitOptions.LockTimeout != "" {
|
||||
args = append(args, fmt.Sprintf("-lock-timeout=%s", config.InitOptions.LockTimeout))
|
||||
}
|
||||
if config.DisableRefresh {
|
||||
args = append(args, "-refresh=false")
|
||||
}
|
||||
args = append(args, getTfoutPath())
|
||||
|
||||
return exec.Command(
|
||||
"terraform",
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
func tfDestroy(config Config) *exec.Cmd {
|
||||
args := []string{
|
||||
"destroy",
|
||||
}
|
||||
for _, v := range config.Targets {
|
||||
args = append(args, fmt.Sprintf("-target=%s", v))
|
||||
}
|
||||
args = append(args, varFiles(config.VarFiles)...)
|
||||
args = append(args, vars(config.Vars)...)
|
||||
if config.Parallelism > 0 {
|
||||
args = append(args, fmt.Sprintf("-parallelism=%d", config.Parallelism))
|
||||
}
|
||||
if config.InitOptions.Lock != nil {
|
||||
args = append(args, fmt.Sprintf("-lock=%t", *config.InitOptions.Lock))
|
||||
}
|
||||
if config.InitOptions.LockTimeout != "" {
|
||||
args = append(args, fmt.Sprintf("-lock-timeout=%s", config.InitOptions.LockTimeout))
|
||||
}
|
||||
args = append(args, "-auto-approve")
|
||||
return exec.Command(
|
||||
"terraform",
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
func tfPlan(config Config, destroy bool) *exec.Cmd {
|
||||
args := []string{
|
||||
"plan",
|
||||
}
|
||||
|
||||
if destroy {
|
||||
args = append(args, "-destroy")
|
||||
} else {
|
||||
args = append(args, fmt.Sprintf("-out=%s", getTfoutPath()))
|
||||
}
|
||||
|
||||
for _, v := range config.Targets {
|
||||
args = append(args, "--target", fmt.Sprintf("%s", v))
|
||||
}
|
||||
args = append(args, varFiles(config.VarFiles)...)
|
||||
args = append(args, vars(config.Vars)...)
|
||||
if config.Parallelism > 0 {
|
||||
args = append(args, fmt.Sprintf("-parallelism=%d", config.Parallelism))
|
||||
}
|
||||
if config.InitOptions.Lock != nil {
|
||||
args = append(args, fmt.Sprintf("-lock=%t", *config.InitOptions.Lock))
|
||||
}
|
||||
if config.InitOptions.LockTimeout != "" {
|
||||
args = append(args, fmt.Sprintf("-lock-timeout=%s", config.InitOptions.LockTimeout))
|
||||
}
|
||||
if config.DisableRefresh {
|
||||
args = append(args, "-refresh=false")
|
||||
}
|
||||
return exec.Command(
|
||||
"terraform",
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
func tfValidate() *exec.Cmd {
|
||||
return exec.Command(
|
||||
"terraform",
|
||||
"validate",
|
||||
)
|
||||
}
|
||||
|
||||
func tfFmt(config Config) *exec.Cmd {
|
||||
args := []string{
|
||||
"fmt",
|
||||
}
|
||||
if config.FmtOptions.List != nil {
|
||||
args = append(args, fmt.Sprintf("-list=%t", *config.FmtOptions.List))
|
||||
}
|
||||
if config.FmtOptions.Write != nil {
|
||||
args = append(args, fmt.Sprintf("-write=%t", *config.FmtOptions.Write))
|
||||
}
|
||||
if config.FmtOptions.Diff != nil {
|
||||
args = append(args, fmt.Sprintf("-diff=%t", *config.FmtOptions.Diff))
|
||||
}
|
||||
if config.FmtOptions.Check != nil {
|
||||
args = append(args, fmt.Sprintf("-check=%t", *config.FmtOptions.Check))
|
||||
}
|
||||
return exec.Command(
|
||||
"terraform",
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
func getTfoutPath() string {
|
||||
terraformDataDir := os.Getenv("TF_DATA_DIR")
|
||||
if terraformDataDir == ".terraform" || terraformDataDir == "" {
|
||||
return "plan.tfout"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s.plan.tfout", terraformDataDir)
|
||||
}
|
||||
|
||||
func vars(vs map[string]string) []string {
|
||||
var args []string
|
||||
for k, v := range vs {
|
||||
args = append(args, "-var", fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func varFiles(vfs []string) []string {
|
||||
var args []string
|
||||
for _, v := range vfs {
|
||||
args = append(args, fmt.Sprintf("-var-file=%s", v))
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// helper function to write a netrc file.
|
||||
// The following code comes from the official Git plugin for Drone:
|
||||
// https://github.com/drone-plugins/drone-git/blob/8386effd2fe8c8695cf979427f8e1762bd805192/utils.go#L43-L68
|
||||
func writeNetrc(machine, login, password string) error {
|
||||
if machine == "" {
|
||||
return nil
|
||||
}
|
||||
out := fmt.Sprintf(
|
||||
netrcFile,
|
||||
machine,
|
||||
login,
|
||||
password,
|
||||
)
|
||||
|
||||
home := "/root"
|
||||
u, err := user.Current()
|
||||
if err == nil {
|
||||
home = u.HomeDir
|
||||
}
|
||||
path := filepath.Join(home, ".netrc")
|
||||
return ioutil.WriteFile(path, []byte(out), 0600)
|
||||
}
|
||||
|
||||
const netrcFile = `
|
||||
machine %s
|
||||
login %s
|
||||
password %s
|
||||
`
|
112
plugin/impl.go
Normal file
112
plugin/impl.go
Normal file
@ -0,0 +1,112 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/thegeeklab/wp-plugin-go/trace"
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrTaintedPath = errors.New("filepath is tainted")
|
||||
ErrMaxSizeSizeLimit = errors.New("max size limit of decoded data exceeded")
|
||||
ErrActionUnknown = errors.New("action not found")
|
||||
ErrInvalidVersion = errors.New("invalid version string")
|
||||
)
|
||||
|
||||
const (
|
||||
maxDecompressionSize = 1024
|
||||
defaultDirPerm = 0o755
|
||||
)
|
||||
|
||||
//nolint:revive
|
||||
func (p *Plugin) run(ctx context.Context) error {
|
||||
if err := p.Validate(); err != nil {
|
||||
return fmt.Errorf("validation failed: %w", err)
|
||||
}
|
||||
|
||||
if err := p.Execute(); err != nil {
|
||||
return fmt.Errorf("execution failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate handles the settings validation of the plugin.
|
||||
func (p *Plugin) Validate() error {
|
||||
p.Settings.DataDir = ".terraform"
|
||||
if value, ok := os.LookupEnv("TF_DATA_DIR"); ok {
|
||||
p.Settings.DataDir = value
|
||||
}
|
||||
|
||||
p.Settings.OutFile = "plan.tfout"
|
||||
if p.Settings.DataDir == ".terraform" {
|
||||
p.Settings.OutFile = fmt.Sprintf("%s.plan.tfout", p.Settings.DataDir)
|
||||
}
|
||||
|
||||
if p.Settings.Version != "" {
|
||||
err := installPackage(p.Plugin.Network.Context, p.Plugin.Network.Client, p.Settings.Version, maxDecompressionSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Execute provides the implementation of the plugin.
|
||||
func (p *Plugin) Execute() error {
|
||||
commands := []*execabs.Cmd{
|
||||
p.versionCommand(),
|
||||
}
|
||||
|
||||
commands = append(commands, p.initCommand())
|
||||
commands = append(commands, p.getModulesCommand())
|
||||
|
||||
for _, action := range p.Settings.Action.Value() {
|
||||
switch action {
|
||||
case "fmt":
|
||||
commands = append(commands, p.fmtCommand())
|
||||
case "validate":
|
||||
commands = append(commands, p.validateCommand())
|
||||
case "plan":
|
||||
commands = append(commands, p.planCommand(false))
|
||||
case "plan-destroy":
|
||||
commands = append(commands, p.planCommand(true))
|
||||
case "apply":
|
||||
commands = append(commands, p.applyCommand())
|
||||
case "destroy":
|
||||
commands = append(commands, p.destroyCommand())
|
||||
default:
|
||||
return fmt.Errorf("%w: %s", ErrActionUnknown, action)
|
||||
}
|
||||
}
|
||||
|
||||
if err := deleteCache(p.Settings.DataDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, cmd := range commands {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if p.Settings.RootDir != "" {
|
||||
cmd.Dir = p.Settings.RootDir
|
||||
}
|
||||
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
if !p.Settings.NoLog {
|
||||
trace.Cmd(cmd)
|
||||
}
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return deleteCache(p.Settings.DataDir)
|
||||
}
|
57
plugin/plugin.go
Normal file
57
plugin/plugin.go
Normal file
@ -0,0 +1,57 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
wp "github.com/thegeeklab/wp-plugin-go/plugin"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Plugin implements provide the plugin.
|
||||
type Plugin struct {
|
||||
*wp.Plugin
|
||||
Settings *Settings
|
||||
}
|
||||
|
||||
// Settings for the Plugin.
|
||||
type Settings struct {
|
||||
Action cli.StringSlice
|
||||
|
||||
Version string
|
||||
InitOptions InitOptions
|
||||
FmtOptions FmtOptions
|
||||
|
||||
RootDir string
|
||||
DataDir string
|
||||
OutFile string
|
||||
Parallelism int
|
||||
Targets cli.StringSlice
|
||||
Refresh bool
|
||||
NoLog bool
|
||||
}
|
||||
|
||||
// InitOptions include options for the OpenTofu init command.
|
||||
type InitOptions struct {
|
||||
BackendConfig []string `json:"backend-config"`
|
||||
Lock *bool `json:"lock"`
|
||||
LockTimeout string `json:"lock-timeout"`
|
||||
}
|
||||
|
||||
// FmtOptions fmt options for the OpenTofu fmt command.
|
||||
type FmtOptions struct {
|
||||
List *bool `json:"list"`
|
||||
Write *bool `json:"write"`
|
||||
Diff *bool `json:"diff"`
|
||||
Check *bool `json:"check"`
|
||||
}
|
||||
|
||||
func New(options wp.Options, settings *Settings) *Plugin {
|
||||
p := &Plugin{}
|
||||
|
||||
if options.Execute == nil {
|
||||
options.Execute = p.run
|
||||
}
|
||||
|
||||
p.Plugin = wp.New(options)
|
||||
p.Settings = settings
|
||||
|
||||
return p
|
||||
}
|
180
plugin/tofu.go
Normal file
180
plugin/tofu.go
Normal file
@ -0,0 +1,180 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
const (
|
||||
tofuBin = "/usr/local/bin/tofu"
|
||||
)
|
||||
|
||||
func (p *Plugin) versionCommand() *execabs.Cmd {
|
||||
args := []string{
|
||||
"version",
|
||||
}
|
||||
|
||||
return execabs.Command(
|
||||
tofuBin,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
func (p *Plugin) initCommand() *execabs.Cmd {
|
||||
args := []string{
|
||||
"init",
|
||||
}
|
||||
|
||||
for _, v := range p.Settings.InitOptions.BackendConfig {
|
||||
args = append(args, fmt.Sprintf("-backend-config=%s", v))
|
||||
}
|
||||
|
||||
// Fail tofu execution on prompt
|
||||
args = append(args, "-input=false")
|
||||
|
||||
return execabs.Command(
|
||||
tofuBin,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
func (p *Plugin) getModulesCommand() *execabs.Cmd {
|
||||
return execabs.Command(
|
||||
tofuBin,
|
||||
"get",
|
||||
)
|
||||
}
|
||||
|
||||
func (p *Plugin) validateCommand() *execabs.Cmd {
|
||||
return execabs.Command(
|
||||
tofuBin,
|
||||
"validate",
|
||||
)
|
||||
}
|
||||
|
||||
func (p *Plugin) fmtCommand() *execabs.Cmd {
|
||||
args := []string{
|
||||
"fmt",
|
||||
}
|
||||
|
||||
if p.Settings.FmtOptions.List != nil {
|
||||
args = append(args, fmt.Sprintf("-list=%t", *p.Settings.FmtOptions.List))
|
||||
}
|
||||
|
||||
if p.Settings.FmtOptions.Write != nil {
|
||||
args = append(args, fmt.Sprintf("-write=%t", *p.Settings.FmtOptions.Write))
|
||||
}
|
||||
|
||||
if p.Settings.FmtOptions.Diff != nil {
|
||||
args = append(args, fmt.Sprintf("-diff=%t", *p.Settings.FmtOptions.Diff))
|
||||
}
|
||||
|
||||
if p.Settings.FmtOptions.Check != nil {
|
||||
args = append(args, fmt.Sprintf("-check=%t", *p.Settings.FmtOptions.Check))
|
||||
}
|
||||
|
||||
return execabs.Command(
|
||||
tofuBin,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
func (p *Plugin) planCommand(destroy bool) *execabs.Cmd {
|
||||
args := []string{
|
||||
"plan",
|
||||
}
|
||||
|
||||
if destroy {
|
||||
args = append(args, "-destroy")
|
||||
} else {
|
||||
args = append(args, fmt.Sprintf("-out=%s", p.Settings.OutFile))
|
||||
}
|
||||
|
||||
for _, value := range p.Settings.Targets.Value() {
|
||||
args = append(args, "--target", value)
|
||||
}
|
||||
|
||||
if p.Settings.Parallelism > 0 {
|
||||
args = append(args, fmt.Sprintf("-parallelism=%d", p.Settings.Parallelism))
|
||||
}
|
||||
|
||||
if p.Settings.InitOptions.Lock != nil {
|
||||
args = append(args, fmt.Sprintf("-lock=%t", *p.Settings.InitOptions.Lock))
|
||||
}
|
||||
|
||||
if p.Settings.InitOptions.LockTimeout != "" {
|
||||
args = append(args, fmt.Sprintf("-lock-timeout=%s", p.Settings.InitOptions.LockTimeout))
|
||||
}
|
||||
|
||||
if !p.Settings.Refresh {
|
||||
args = append(args, "-refresh=false")
|
||||
}
|
||||
|
||||
return execabs.Command(
|
||||
tofuBin,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
func (p *Plugin) applyCommand() *execabs.Cmd {
|
||||
args := []string{
|
||||
"apply",
|
||||
}
|
||||
|
||||
for _, v := range p.Settings.Targets.Value() {
|
||||
args = append(args, "--target", v)
|
||||
}
|
||||
|
||||
if p.Settings.Parallelism > 0 {
|
||||
args = append(args, fmt.Sprintf("-parallelism=%d", p.Settings.Parallelism))
|
||||
}
|
||||
|
||||
if p.Settings.InitOptions.Lock != nil {
|
||||
args = append(args, fmt.Sprintf("-lock=%t", *p.Settings.InitOptions.Lock))
|
||||
}
|
||||
|
||||
if p.Settings.InitOptions.LockTimeout != "" {
|
||||
args = append(args, fmt.Sprintf("-lock-timeout=%s", p.Settings.InitOptions.LockTimeout))
|
||||
}
|
||||
|
||||
if !p.Settings.Refresh {
|
||||
args = append(args, "-refresh=false")
|
||||
}
|
||||
|
||||
args = append(args, p.Settings.OutFile)
|
||||
|
||||
return execabs.Command(
|
||||
tofuBin,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
func (p *Plugin) destroyCommand() *execabs.Cmd {
|
||||
args := []string{
|
||||
"destroy",
|
||||
}
|
||||
|
||||
for _, v := range p.Settings.Targets.Value() {
|
||||
args = append(args, fmt.Sprintf("-target=%s", v))
|
||||
}
|
||||
|
||||
if p.Settings.Parallelism > 0 {
|
||||
args = append(args, fmt.Sprintf("-parallelism=%d", p.Settings.Parallelism))
|
||||
}
|
||||
|
||||
if p.Settings.InitOptions.Lock != nil {
|
||||
args = append(args, fmt.Sprintf("-lock=%t", *p.Settings.InitOptions.Lock))
|
||||
}
|
||||
|
||||
if p.Settings.InitOptions.LockTimeout != "" {
|
||||
args = append(args, fmt.Sprintf("-lock-timeout=%s", p.Settings.InitOptions.LockTimeout))
|
||||
}
|
||||
|
||||
args = append(args, "-auto-approve")
|
||||
|
||||
return execabs.Command(
|
||||
tofuBin,
|
||||
args...,
|
||||
)
|
||||
}
|
151
plugin/utils.go
Normal file
151
plugin/utils.go
Normal file
@ -0,0 +1,151 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
)
|
||||
|
||||
func installPackage(ctx context.Context, client *http.Client, version string, maxSize int64) error {
|
||||
// Sanitize user input
|
||||
if _, err := semver.NewVersion(version); err != nil {
|
||||
return fmt.Errorf("%w: %v", ErrInvalidVersion, version)
|
||||
}
|
||||
|
||||
err := downloadPackage(
|
||||
ctx,
|
||||
client,
|
||||
"/tmp/tofu.zip",
|
||||
fmt.Sprintf(
|
||||
"https://github.com/opentofu/opentofu/releases/download/%s/tofu_%s_linux_amd64.zip",
|
||||
version,
|
||||
strings.TrimPrefix(version, ""),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return unzip("/tmp/tofu.zip", "/bin", maxSize)
|
||||
}
|
||||
|
||||
func downloadPackage(ctx context.Context, client *http.Client, filepath, url string) error {
|
||||
// Create the file
|
||||
out, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
// Get the data
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Writer the body to file
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func unzip(src, dest string, maxSize int64) error {
|
||||
r, err := zip.OpenReader(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := r.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
_ = os.MkdirAll(dest, defaultDirPerm)
|
||||
|
||||
// Closure to address file descriptors issue with all the deferred .Close() methods
|
||||
extractAndWriteFile := func(f *zip.File) error {
|
||||
rc, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := rc.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
path, err := sanitizeArchivePath(dest, f.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f.FileInfo().IsDir() { //nolint: nestif
|
||||
_ = os.MkdirAll(path, f.Mode())
|
||||
} else {
|
||||
_ = os.MkdirAll(filepath.Dir(path), f.Mode())
|
||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := f.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
written, err := io.CopyN(f, rc, maxSize)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if written == maxSize {
|
||||
return fmt.Errorf("%w: %d", ErrMaxSizeSizeLimit, maxSize)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, f := range r.File {
|
||||
err := extractAndWriteFile(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sanitizeArchivePath(d, t string) (string, error) {
|
||||
value := filepath.Join(d, t)
|
||||
if strings.HasPrefix(value, filepath.Clean(d)) {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("%w: %v", ErrTaintedPath, t)
|
||||
}
|
||||
|
||||
func deleteCache(path string) error {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return os.Remove(path)
|
||||
}
|
301
plugin_test.go
301
plugin_test.go
@ -1,301 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
. "github.com/franela/goblin"
|
||||
)
|
||||
|
||||
func TestPlugin(t *testing.T) {
|
||||
g := Goblin(t)
|
||||
|
||||
g.Describe("CopyTfEnv", func() {
|
||||
g.It("Should create copies of TF_VAR_ to lowercase", func() {
|
||||
// Set some initial TF_VAR_ that are uppercase
|
||||
os.Setenv("TF_VAR_SOMETHING", "some value")
|
||||
os.Setenv("TF_VAR_SOMETHING_ELSE", "some other value")
|
||||
os.Setenv("TF_VAR_BASE64", "dGVzdA==")
|
||||
|
||||
CopyTfEnv()
|
||||
|
||||
// Make sure new env vars exist with proper values
|
||||
g.Assert(os.Getenv("TF_VAR_something")).Equal("some value")
|
||||
g.Assert(os.Getenv("TF_VAR_something_else")).Equal("some other value")
|
||||
g.Assert(os.Getenv("TF_VAR_base64")).Equal("dGVzdA==")
|
||||
})
|
||||
})
|
||||
|
||||
g.Describe("credsSet", func() {
|
||||
tests := []struct {
|
||||
name string
|
||||
args map[string]string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
"Should return true when all credentials were set",
|
||||
map[string]string{"AWS_ACCESS_KEY_ID": "x", "AWS_SECRET_ACCESS_KEY": "x", "AWS_SESSION_TOKEN": "x"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Should return false when access key id is missing",
|
||||
map[string]string{"AWS_SECRET_ACCESS_KEY": "x", "AWS_SESSION_TOKEN": "x"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Should return false when secret access key is missing",
|
||||
map[string]string{"AWS_ACCESS_KEY_ID": "x", "AWS_SESSION_TOKEN": "x"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Should return false when session token is missing",
|
||||
map[string]string{"AWS_ACCESS_KEY_ID": "x", "AWS_SECRET_ACCESS_KEY": "x"},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
g.It(tt.name, func() {
|
||||
for k, v := range tt.args {
|
||||
os.Setenv(k, v)
|
||||
}
|
||||
g.Assert(credsSet()).Equal(tt.want)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
g.Describe("tfApply", func() {
|
||||
g.It("Should return correct apply commands given the arguments", func() {
|
||||
type args struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *exec.Cmd
|
||||
}{
|
||||
{
|
||||
"default",
|
||||
args{config: Config{}},
|
||||
exec.Command("terraform", "apply", "plan.tfout"),
|
||||
},
|
||||
{
|
||||
"with parallelism",
|
||||
args{config: Config{Parallelism: 5}},
|
||||
exec.Command("terraform", "apply", "-parallelism=5", "plan.tfout"),
|
||||
},
|
||||
{
|
||||
"with targets",
|
||||
args{config: Config{Targets: []string{"target1", "target2"}}},
|
||||
exec.Command("terraform", "apply", "--target", "target1", "--target", "target2", "plan.tfout"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
g.Assert(tfApply(tt.args.config).Args).Equal(tt.want.Args)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
g.Describe("tfDestroy", func() {
|
||||
g.It("Should return correct destroy commands given the arguments", func() {
|
||||
type args struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *exec.Cmd
|
||||
}{
|
||||
{
|
||||
"default",
|
||||
args{config: Config{}},
|
||||
exec.Command("terraform", "destroy", "-auto-approve"),
|
||||
},
|
||||
{
|
||||
"with parallelism",
|
||||
args{config: Config{Parallelism: 5}},
|
||||
exec.Command("terraform", "destroy", "-parallelism=5", "-auto-approve"),
|
||||
},
|
||||
{
|
||||
"with targets",
|
||||
args{config: Config{Targets: []string{"target1", "target2"}}},
|
||||
exec.Command("terraform", "destroy", "-target=target1", "-target=target2", "-auto-approve"),
|
||||
},
|
||||
{
|
||||
"with vars",
|
||||
args{config: Config{Vars: map[string]string{"username": "someuser", "password": "1pass"}}},
|
||||
exec.Command("terraform", "destroy", "-var", "username=someuser", "-var", "password=1pass", "-auto-approve"),
|
||||
},
|
||||
{
|
||||
"with var-files",
|
||||
args{config: Config{VarFiles: []string{"common.tfvars", "prod.tfvars"}}},
|
||||
exec.Command("terraform", "destroy", "-var-file=common.tfvars", "-var-file=prod.tfvars", "-auto-approve"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
g.Assert(tfDestroy(tt.args.config)).Equal(tt.want)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
g.Describe("tfValidate", func() {
|
||||
g.It("Should return correct validate command", func() {
|
||||
tests := []struct {
|
||||
name string
|
||||
want *exec.Cmd
|
||||
}{
|
||||
{
|
||||
"default",
|
||||
exec.Command("terraform", "validate"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
g.Assert(tfValidate()).Equal(tt.want)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
g.Describe("tfPlan", func() {
|
||||
g.It("Should return correct plan commands given the arguments", func() {
|
||||
type args struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
destroy bool
|
||||
want *exec.Cmd
|
||||
}{
|
||||
{
|
||||
"default",
|
||||
args{config: Config{}},
|
||||
false,
|
||||
exec.Command("terraform", "plan", "-out=plan.tfout"),
|
||||
},
|
||||
{
|
||||
"destroy",
|
||||
args{config: Config{}},
|
||||
true,
|
||||
exec.Command("terraform", "plan", "-destroy"),
|
||||
},
|
||||
{
|
||||
"with vars",
|
||||
args{config: Config{Vars: map[string]string{"username": "someuser", "password": "1pass"}}},
|
||||
false,
|
||||
exec.Command("terraform", "plan", "-out=plan.tfout", "-var", "username=someuser", "-var", "password=1pass"),
|
||||
},
|
||||
{
|
||||
"with var-files",
|
||||
args{config: Config{VarFiles: []string{"common.tfvars", "prod.tfvars"}}},
|
||||
false,
|
||||
exec.Command("terraform", "plan", "-out=plan.tfout", "-var-file=common.tfvars", "-var-file=prod.tfvars"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
g.Assert(tfPlan(tt.args.config, tt.destroy)).Equal(tt.want)
|
||||
}
|
||||
})
|
||||
})
|
||||
g.Describe("tfFmt", func() {
|
||||
g.It("Should return correct fmt commands given the arguments", func() {
|
||||
type args struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
affirmative := true
|
||||
negative := false
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *exec.Cmd
|
||||
}{
|
||||
{
|
||||
"default",
|
||||
args{config: Config{}},
|
||||
exec.Command("terraform", "fmt"),
|
||||
},
|
||||
{
|
||||
"with list",
|
||||
args{config: Config{FmtOptions: FmtOptions{List: &affirmative}}},
|
||||
exec.Command("terraform", "fmt", "-list=true"),
|
||||
},
|
||||
{
|
||||
"with write",
|
||||
args{config: Config{FmtOptions: FmtOptions{Write: &affirmative}}},
|
||||
exec.Command("terraform", "fmt", "-write=true"),
|
||||
},
|
||||
{
|
||||
"with diff",
|
||||
args{config: Config{FmtOptions: FmtOptions{Diff: &affirmative}}},
|
||||
exec.Command("terraform", "fmt", "-diff=true"),
|
||||
},
|
||||
{
|
||||
"with check",
|
||||
args{config: Config{FmtOptions: FmtOptions{Check: &affirmative}}},
|
||||
exec.Command("terraform", "fmt", "-check=true"),
|
||||
},
|
||||
{
|
||||
"with combination",
|
||||
args{config: Config{FmtOptions: FmtOptions{
|
||||
List: &negative,
|
||||
Write: &negative,
|
||||
Diff: &affirmative,
|
||||
Check: &affirmative,
|
||||
}}},
|
||||
exec.Command("terraform", "fmt", "-list=false", "-write=false", "-diff=true", "-check=true"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
g.Assert(tfFmt(tt.args.config)).Equal(tt.want)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
g.Describe("tfDataDir", func() {
|
||||
g.It("Should override the terraform data dir environment variable when provided", func() {
|
||||
type args struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *exec.Cmd
|
||||
}{
|
||||
{
|
||||
"with TerraformDataDir",
|
||||
args{config: Config{TerraformDataDir: ".overriden_terraform_dir"}},
|
||||
exec.Command("terraform", "apply", ".overriden_terraform_dir.plan.tfout"),
|
||||
},
|
||||
{
|
||||
"with TerraformDataDir value as .terraform",
|
||||
args{config: Config{TerraformDataDir: ".terraform"}},
|
||||
exec.Command("terraform", "apply", "plan.tfout"),
|
||||
},
|
||||
{
|
||||
"without TerraformDataDir",
|
||||
args{config: Config{}},
|
||||
exec.Command("terraform", "apply", "plan.tfout"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
os.Setenv("TF_DATA_DIR", tt.args.config.TerraformDataDir)
|
||||
applied := tfApply(tt.args.config)
|
||||
|
||||
g.Assert(applied).Equal(tt.want)
|
||||
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
4
renovate.json
Normal file
4
renovate.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["github>thegeeklab/renovate-presets:golang"]
|
||||
}
|
114
terraform.go
114
terraform.go
@ -1,114 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type (
|
||||
// Terraform holds input parameters for terraform
|
||||
Terraform struct {
|
||||
Version string
|
||||
}
|
||||
)
|
||||
|
||||
func installTerraform(version string) error {
|
||||
err := downloadTerraform(version)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return Unzip("/var/tmp/terraform.zip", "/bin")
|
||||
}
|
||||
|
||||
func downloadTerraform(version string) error {
|
||||
return downloadFile("/var/tmp/terraform.zip", fmt.Sprintf("https://releases.hashicorp.com/terraform/%s/terraform_%s_linux_amd64.zip", version, version))
|
||||
}
|
||||
|
||||
func downloadFile(filepath string, url string) error {
|
||||
// Create the file
|
||||
out, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
// Get the data
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Writer the body to file
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unzip a file to a destination
|
||||
func Unzip(src, dest string) error {
|
||||
r, err := zip.OpenReader(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := r.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
os.MkdirAll(dest, 0755)
|
||||
|
||||
// Closure to address file descriptors issue with all the deferred .Close() methods
|
||||
extractAndWriteFile := func(f *zip.File) error {
|
||||
rc, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := rc.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
path := filepath.Join(dest, f.Name)
|
||||
|
||||
if f.FileInfo().IsDir() {
|
||||
os.MkdirAll(path, f.Mode())
|
||||
} else {
|
||||
os.MkdirAll(filepath.Dir(path), f.Mode())
|
||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := f.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
_, err = io.Copy(f, rc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, f := range r.File {
|
||||
err := extractAndWriteFile(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user