diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d30619e0c0dddf8f3d4dae6fb628dbcdfc9ae17e..0d8c836d6bf12914246f7f9412dfa1feddd57083 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,3 +1,10 @@ +workflow: + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_COMMIT_TAG + - if: $CI_COMMIT_REF_PROTECTED == "true" + include: - local: tests/unit.gitlab-ci.yml - local: tests/integration.gitlab-ci.yml diff --git a/.gitlab/README.md b/.gitlab/README.md index 571b01348e79f607e1396eadf19448248d6786df..b16477ee5295d408b841b12de32ea1a59609b1f4 100644 --- a/.gitlab/README.md +++ b/.gitlab/README.md @@ -30,7 +30,7 @@ include: - component: gitlab.com/components/opentofu/full-pipeline@<VERSION> inputs: # The version must currently be specified explicitly as an input, - # to find the correctly associated images. # This can be removed + # to find the correctly associated images. # This can be removed # once https://gitlab.com/gitlab-org/gitlab/-/issues/438275 is solved. version: <VERSION> opentofu_version: <OPENTOFU_VERSION> @@ -46,7 +46,7 @@ include: - component: gitlab.com/components/opentofu/full-pipeline@~latest inputs: # The version must currently be specified explicitly as an input, - # to find the correctly associated images. # This can be removed + # to find the correctly associated images. # This can be removed # once https://gitlab.com/gitlab-org/gitlab/-/issues/438275 is solved. version: latest opentofu_version: 1.6.0 @@ -60,7 +60,7 @@ include: - component: gitlab.com/components/opentofu/full-pipeline@0.0.0-alpha1 inputs: # The version must currently be specified explicitly as an input, - # to find the correctly associated images. # This can be removed + # to find the correctly associated images. # This can be removed # once https://gitlab.com/gitlab-org/gitlab/-/issues/438275 is solved. version: 0.0.0-alpha1 opentofu_version: 1.6.0 @@ -68,6 +68,34 @@ include: stages: [validate, test, build, deploy, cleanup] ``` +Instead of including the `full-pipeline`, it's also possible to include individual jobs +and compose your own pipeline, for example, to just run the `fmt` job you can do: + +```yaml +include: + - component: gitlab.com/components/opentofu/fmt@latest + inputs: + # The version must currently be specified explicitly as an input, + # to find the correctly associated images. # This can be removed + # once https://gitlab.com/gitlab-org/gitlab/-/issues/438275 is solved. + version: latest + opentofu_version: 1.6.0 + root_dir: tofu/ +``` + +Have a look at the [`full-pipeline`](templates/full-pipeline.yml) for how it's constructed. + +The following job components exist: + +- [`fmt`](templates/fmt.yml) +- [`validate`](templates/validate.yml) +- [`plan`](templates/plan.yml) +- [`apply`](templates/apply.yml) +- [`destroy`](templates/destroy.yml) +- [`delete-state`](templates/delete-state.yml) + +Have a look at the individual template spec to learn about the available inputs. + ### Inputs | Name | Default | Description | diff --git a/Makefile b/Makefile index 44619cdaf25ad9abb3edcf3d03800050cd4d369b..a764c3921511aa7c3c4023a2d4985491c17b9145 100644 --- a/Makefile +++ b/Makefile @@ -29,26 +29,17 @@ backports: @echo "Generating $(BACKPORTS_BASE_FILE) ..." @mkdir -p $(BACKPORTS_BASE_DIR) @cp $(BACKPORTS_DIR)/.Base.gitlab-ci.yml $(BACKPORTS_BASE_FILE) - @sed '1,/^---$$/d' templates/full-pipeline.yml >> $(BACKPORTS_BASE_FILE) - @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.stage_validate \]\]/validate/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.stage_build \]\]/build/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.stage_deploy \]\]/deploy/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.stage_cleanup \]\]/cleanup/' + @sed '1,/^---$$/d' templates/fmt.yml | sed -e 's/$$\[\[ inputs.as \]\]/.opentofu:fmt/' | sed -e 's/$$\[\[ inputs.stage \]\]/validate/' | sed -e 's/$$\[\[ inputs.allow_failure \]\]/true/' >> $(BACKPORTS_BASE_FILE) + @sed '1,/^---$$/d' templates/validate.yml | sed -e 's/$$\[\[ inputs.as \]\]/.opentofu:validate/' | sed -e 's/$$\[\[ inputs.stage \]\]/validate/' >> $(BACKPORTS_BASE_FILE) + @sed '1,/^---$$/d' templates/plan.yml | sed -e 's/$$\[\[ inputs.as \]\]/.opentofu:plan/' | sed -e 's/$$\[\[ inputs.stage \]\]/build/' >> $(BACKPORTS_BASE_FILE) + @sed '1,/^---$$/d' templates/apply.yml | sed -e 's/$$\[\[ inputs.as \]\]/.opentofu:apply/' | sed -e 's/$$\[\[ inputs.stage \]\]/deploy/' | sed -e 's/$$\[\[ inputs.auto_apply \]\]/$$_TF_AUTO_APPLY/' >> $(BACKPORTS_BASE_FILE) + @sed '1,/^---$$/d' templates/destroy.yml | sed -e 's/$$\[\[ inputs.as \]\]/.opentofu:destroy/' | sed -e 's/$$\[\[ inputs.stage \]\]/cleanup/' | sed -e 's/$$\[\[ inputs.auto_destroy \]\]/$$_TF_AUTO_DESTROY/' | sed -e 's/$$\[\[ inputs.create_destroy_job \]\]/$$TF_CREATE_DESTROY_JOB/' >> $(BACKPORTS_BASE_FILE) + @sed '1,/^---$$/d' templates/delete-state.yml | sed -e 's/$$\[\[ inputs.as \]\]/.opentofu:delete-state/' | sed -e 's/$$\[\[ inputs.stage \]\]/cleanup/' | sed -e 's/$$\[\[ inputs.create_delete_state_job \]\]/$$TF_CREATE_DELETE_STATE_JOB/' | sed -e "/stage: cleanup/a \ \ needs: ['.opentofu:destroy']" >> $(BACKPORTS_BASE_FILE) + + @# Common inputs @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.image_registry_base \]\]/$$GITLAB_OPENTOFU_IMAGE_REGISTRY_BASE/' @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.version \]\]/$$GITLAB_OPENTOFU_VERSION/' @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.opentofu_version \]\]/$$OPENTOFU_VERSION/' @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.root_dir \]\]/$$TF_ROOT/' @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.state_name \]\]/$$TF_STATE_NAME/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.auto_apply \]\]/$$TF_AUTO_APPLY/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.auto_destroy \]\]/$$TF_AUTO_DESTROY/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.create_destroy_job \]\]/$$TF_CREATE_DESTROY_JOB/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/$$\[\[ inputs.create_delete_state_job \]\]/$$TF_CREATE_DELETE_STATE_JOB/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/\.default/.opentofu:default/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/^fmt:$$/.opentofu:fmt:/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/^validate:$$/.opentofu:validate:/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/^plan:$$/.opentofu:plan:/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/^apply:$$/.opentofu:apply:/' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/destroy:/.opentofu:destroy:/' - @sed -i $(BACKPORTS_BASE_FILE) -e '/needs: \[destroy\]/d' - @sed -i $(BACKPORTS_BASE_FILE) -e 's/^delete-state:$$/.opentofu:delete-state:/' @echo "Generated $(BACKPORTS_BASE_FILE)" diff --git a/README.md b/README.md index 99768d1440ce7f5a204854e34dd292fc80082c06..74e64f97bd609ec991e1c190ce6fa01247a215e4 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ include: - component: gitlab.com/components/opentofu/full-pipeline@<VERSION> inputs: # The version must currently be specified explicitly as an input, - # to find the correctly associated images. # This can be removed + # to find the correctly associated images. # This can be removed # once https://gitlab.com/gitlab-org/gitlab/-/issues/438275 is solved. version: <VERSION> opentofu_version: <OPENTOFU_VERSION> @@ -48,7 +48,7 @@ include: - component: gitlab.com/components/opentofu/full-pipeline@~latest inputs: # The version must currently be specified explicitly as an input, - # to find the correctly associated images. # This can be removed + # to find the correctly associated images. # This can be removed # once https://gitlab.com/gitlab-org/gitlab/-/issues/438275 is solved. version: latest opentofu_version: 1.6.0 @@ -62,7 +62,7 @@ include: - component: gitlab.com/components/opentofu/full-pipeline@0.0.0-alpha1 inputs: # The version must currently be specified explicitly as an input, - # to find the correctly associated images. # This can be removed + # to find the correctly associated images. # This can be removed # once https://gitlab.com/gitlab-org/gitlab/-/issues/438275 is solved. version: 0.0.0-alpha1 opentofu_version: 1.6.0 @@ -70,6 +70,34 @@ include: stages: [validate, test, build, deploy, cleanup] ``` +Instead of including the `full-pipeline`, it's also possible to include individual jobs +and compose your own pipeline, for example, to just run the `fmt` job you can do: + +```yaml +include: + - component: gitlab.com/components/opentofu/fmt@latest + inputs: + # The version must currently be specified explicitly as an input, + # to find the correctly associated images. # This can be removed + # once https://gitlab.com/gitlab-org/gitlab/-/issues/438275 is solved. + version: latest + opentofu_version: 1.6.0 + root_dir: tofu/ +``` + +Have a look at the [`full-pipeline`](templates/full-pipeline.yml) for how it's constructed. + +The following job components exist: + +- [`fmt`](templates/fmt.yml) +- [`validate`](templates/validate.yml) +- [`plan`](templates/plan.yml) +- [`apply`](templates/apply.yml) +- [`destroy`](templates/destroy.yml) +- [`delete-state`](templates/delete-state.yml) + +Have a look at the individual template spec to learn about the available inputs. + ### Inputs | Name | Default | Description | diff --git a/backports/.Base.gitlab-ci.yml b/backports/.Base.gitlab-ci.yml index 2484a6effbe989e3c245ef1298f455c235398c29..e601d06db2806e88f6290a3fa48f1d5ec84e8225 100644 --- a/backports/.Base.gitlab-ci.yml +++ b/backports/.Base.gitlab-ci.yml @@ -45,7 +45,7 @@ variables: echo " version: latest" echo " opentofu_version: 1.6.0" echo "" - echo "stages: [validate, test, build, deploy]" + echo "stages: [validate, build, deploy, cleanup]" echo " " echo "You can read about more about the OpenTofu CI/CD component here:" echo "https://gitlab.com/components/opentofu" diff --git a/backports/OpenTofu/Base.gitlab-ci.yml b/backports/OpenTofu/Base.gitlab-ci.yml index 2be22ab19bba082c610786b5669bd4563ffa28ba..5f035b9d5f25316f60d0b028976bf1b28ceba2e7 100644 --- a/backports/OpenTofu/Base.gitlab-ci.yml +++ b/backports/OpenTofu/Base.gitlab-ci.yml @@ -45,55 +45,54 @@ variables: echo " version: latest" echo " opentofu_version: 1.6.0" echo "" - echo "stages: [validate, test, build, deploy]" + echo "stages: [validate, build, deploy, cleanup]" echo " " echo "You can read about more about the OpenTofu CI/CD component here:" echo "https://gitlab.com/components/opentofu" - 'false' -.opentofu:default: - image: - name: '$GITLAB_OPENTOFU_IMAGE_REGISTRY_BASE/gitlab-opentofu:$GITLAB_OPENTOFU_VERSION-opentofu$OPENTOFU_VERSION' - - variables: - TF_ROOT: $TF_ROOT - TF_STATE_NAME: $TF_STATE_NAME - - cache: - key: "$TF_ROOT" - paths: - - $TF_ROOT/.terraform/ - -.opentofu:fmt: - extends: .opentofu:default +'.opentofu:fmt': stage: validate needs: [] - script: - - gitlab-tofu fmt - allow_failure: true rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline. when: never - if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead. + #allow_failure: true + allow_failure: true + cache: + key: "$TF_ROOT" + paths: + - $TF_ROOT/.terraform/ + variables: + TF_ROOT: $TF_ROOT + image: + name: '$GITLAB_OPENTOFU_IMAGE_REGISTRY_BASE/gitlab-opentofu:$GITLAB_OPENTOFU_VERSION-opentofu$OPENTOFU_VERSION' + script: + - gitlab-tofu fmt -.opentofu:validate: - extends: .opentofu:default +'.opentofu:validate': stage: validate - script: - - gitlab-tofu validate rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline. when: never - if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead. + cache: + key: "$TF_ROOT" + paths: + - $TF_ROOT/.terraform/ + variables: + TF_ROOT: $TF_ROOT + TF_STATE_NAME: $TF_STATE_NAME + image: + name: '$GITLAB_OPENTOFU_IMAGE_REGISTRY_BASE/gitlab-opentofu:$GITLAB_OPENTOFU_VERSION-opentofu$OPENTOFU_VERSION' + script: + - gitlab-tofu validate -.opentofu:plan: - extends: .opentofu:default +'.opentofu:plan': stage: build - script: - - gitlab-tofu plan - - gitlab-tofu plan-json environment: name: $TF_STATE_NAME action: prepare @@ -115,26 +114,43 @@ variables: - if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline. when: never - if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead. + cache: + key: "$TF_ROOT" + paths: + - $TF_ROOT/.terraform/ + variables: + TF_ROOT: $TF_ROOT + TF_STATE_NAME: $TF_STATE_NAME + image: + name: '$GITLAB_OPENTOFU_IMAGE_REGISTRY_BASE/gitlab-opentofu:$GITLAB_OPENTOFU_VERSION-opentofu$OPENTOFU_VERSION' + script: + - gitlab-tofu plan + - gitlab-tofu plan-json -.opentofu:apply: - extends: .opentofu:default +'.opentofu:apply': stage: deploy - script: - - gitlab-tofu apply environment: name: $TF_STATE_NAME action: start resource_group: $TF_STATE_NAME rules: - - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && "$TF_AUTO_APPLY" == "true"' + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && "$_TF_AUTO_APPLY" == "true"' - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH when: manual + cache: + key: "$TF_ROOT" + paths: + - $TF_ROOT/.terraform/ + variables: + TF_ROOT: $TF_ROOT + TF_STATE_NAME: $TF_STATE_NAME + image: + name: '$GITLAB_OPENTOFU_IMAGE_REGISTRY_BASE/gitlab-opentofu:$GITLAB_OPENTOFU_VERSION-opentofu$OPENTOFU_VERSION' + script: + - gitlab-tofu apply -.opentofu:destroy: - extends: .opentofu:default +'.opentofu:destroy': stage: cleanup - script: - - gitlab-tofu destroy environment: name: $TF_STATE_NAME action: stop @@ -142,13 +158,25 @@ variables: rules: - if: '"$TF_CREATE_DESTROY_JOB" != "true"' when: never - - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && "$TF_AUTO_DESTROY" == "true"' + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && "$_TF_AUTO_DESTROY" == "true"' - when: manual + cache: + key: "$TF_ROOT" + paths: + - $TF_ROOT/.terraform/ + variables: + TF_ROOT: $TF_ROOT + TF_STATE_NAME: $TF_STATE_NAME + image: + name: '$GITLAB_OPENTOFU_IMAGE_REGISTRY_BASE/gitlab-opentofu:$GITLAB_OPENTOFU_VERSION-opentofu$OPENTOFU_VERSION' + script: + - gitlab-tofu destroy -.opentofu:delete-state: - extends: .opentofu:default +'.opentofu:delete-state': stage: cleanup + needs: ['.opentofu:destroy'] resource_group: $TF_STATE_NAME + image: curlimages/curl:latest script: - curl --request DELETE -u "gitlab-ci-token:$CI_JOB_TOKEN" "$CI_API_V4_URL/projects/$CI_PROJECT_ID/terraform/state/$TF_STATE_NAME" rules: @@ -156,4 +184,3 @@ variables: when: never - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' - when: manual - diff --git a/templates/apply.yml b/templates/apply.yml new file mode 100644 index 0000000000000000000000000000000000000000..01316f382a32e4fd6ba6664acb54644fe54cf2e4 --- /dev/null +++ b/templates/apply.yml @@ -0,0 +1,70 @@ +spec: + inputs: + # Job and Stage name + as: + default: 'apply' + description: 'Defines the name of this job.' + stage: + default: 'deploy' + description: 'Defines the stage that this job will belong to.' + + # Versions + # This version is only required, because we cannot access the context of the component, + # see https://gitlab.com/gitlab-org/gitlab/-/issues/438275 + version: + default: 'latest' + description: 'Version of this component. Has to be the same as the one in the component include entry.' + + opentofu_version: + default: '1.6.0' + options: + - '$OPENTOFU_VERSION' + - '1.6.0' + - '1.6.0-rc1' + description: 'OpenTofu version that should be used.' + + # Images + image_registry_base: + default: '$CI_REGISTRY/components/opentofu' + # FIXME: not yet possible because of https://gitlab.com/gitlab-org/gitlab/-/issues/438722 + # gitlab_opentofu_image: + # # FIXME: This should reference the component tag that is used. + # # Currently, blocked by https://gitlab.com/gitlab-org/gitlab/-/issues/438275 + # # default: '$CI_REGISTRY/components/opentofu/gitlab-opentofu:$[[ inputs.opentofu_version ]]' + # default: '$CI_REGISTRY/components/opentofu/gitlab-opentofu:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]' + # description: 'Tag of the gitlab-opentofu image.' + + # Configuration + root_dir: + default: ${CI_PROJECT_DIR} + description: 'Root directory for the OpenTofu project.' + state_name: + default: default + description: 'Remote OpenTofu state name.' + auto_apply: + default: 'false' + description: 'Whether the apply job is manual or automatically run.' + +--- + +'$[[ inputs.as ]]': + stage: $[[ inputs.stage ]] + environment: + name: $[[ inputs.state_name ]] + action: start + resource_group: $[[ inputs.state_name ]] + rules: + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && "$[[ inputs.auto_apply ]]" == "true"' + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + when: manual + cache: + key: "$[[ inputs.root_dir ]]" + paths: + - $[[ inputs.root_dir ]]/.terraform/ + variables: + TF_ROOT: $[[ inputs.root_dir ]] + TF_STATE_NAME: $[[ inputs.state_name ]] + image: + name: '$[[ inputs.image_registry_base ]]/gitlab-opentofu:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]' + script: + - gitlab-tofu apply diff --git a/templates/delete-state.yml b/templates/delete-state.yml new file mode 100644 index 0000000000000000000000000000000000000000..300f299724f17e8f7ae56ef02e46dadcb26badbc --- /dev/null +++ b/templates/delete-state.yml @@ -0,0 +1,31 @@ +spec: + inputs: + # Job and Stage name + as: + default: 'delete-state' + description: 'Defines the name of this job.' + stage: + default: 'cleanup' + description: 'Defines the stage that this job will belong to.' + + # Configuration + state_name: + default: default + description: 'Remote OpenTofu state name.' + create_delete_state_job: + default: 'true' + description: 'Wheather the delete-state job should be created or not.' + +--- + +'$[[ inputs.as ]]': + stage: $[[ inputs.stage ]] + resource_group: $[[ inputs.state_name ]] + image: curlimages/curl:latest + script: + - curl --request DELETE -u "gitlab-ci-token:$CI_JOB_TOKEN" "$CI_API_V4_URL/projects/$CI_PROJECT_ID/terraform/state/$[[ inputs.state_name ]]" + rules: + - if: '"$[[ inputs.create_delete_state_job ]]" != "true"' + when: never + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' + - when: manual diff --git a/templates/destroy.yml b/templates/destroy.yml new file mode 100644 index 0000000000000000000000000000000000000000..8b343dc17ada44172249e3fc7b0d3ea4fe9f623b --- /dev/null +++ b/templates/destroy.yml @@ -0,0 +1,74 @@ +spec: + inputs: + # Job and Stage name + as: + default: 'destroy' + description: 'Defines the name of this job.' + stage: + default: 'cleanup' + description: 'Defines the stage that this job will belong to.' + + # Versions + # This version is only required, because we cannot access the context of the component, + # see https://gitlab.com/gitlab-org/gitlab/-/issues/438275 + version: + default: 'latest' + description: 'Version of this component. Has to be the same as the one in the component include entry.' + + opentofu_version: + default: '1.6.0' + options: + - '$OPENTOFU_VERSION' + - '1.6.0' + - '1.6.0-rc1' + description: 'OpenTofu version that should be used.' + + # Images + image_registry_base: + default: '$CI_REGISTRY/components/opentofu' + # FIXME: not yet possible because of https://gitlab.com/gitlab-org/gitlab/-/issues/438722 + # gitlab_opentofu_image: + # # FIXME: This should reference the component tag that is used. + # # Currently, blocked by https://gitlab.com/gitlab-org/gitlab/-/issues/438275 + # # default: '$CI_REGISTRY/components/opentofu/gitlab-opentofu:$[[ inputs.opentofu_version ]]' + # default: '$CI_REGISTRY/components/opentofu/gitlab-opentofu:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]' + # description: 'Tag of the gitlab-opentofu image.' + + # Configuration + root_dir: + default: ${CI_PROJECT_DIR} + description: 'Root directory for the OpenTofu project.' + state_name: + default: default + description: 'Remote OpenTofu state name.' + auto_destroy: + default: 'false' + description: 'Whether the destroy job is manual or automatically run.' + create_destroy_job: + default: 'true' + description: 'Wheather the destroy job should be created or not.' + +--- + +'$[[ inputs.as ]]': + stage: $[[ inputs.stage ]] + environment: + name: $[[ inputs.state_name ]] + action: stop + resource_group: $[[ inputs.state_name ]] + rules: + - if: '"$[[ inputs.create_destroy_job ]]" != "true"' + when: never + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && "$[[ inputs.auto_destroy ]]" == "true"' + - when: manual + cache: + key: "$[[ inputs.root_dir ]]" + paths: + - $[[ inputs.root_dir ]]/.terraform/ + variables: + TF_ROOT: $[[ inputs.root_dir ]] + TF_STATE_NAME: $[[ inputs.state_name ]] + image: + name: '$[[ inputs.image_registry_base ]]/gitlab-opentofu:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]' + script: + - gitlab-tofu destroy diff --git a/templates/fmt.yml b/templates/fmt.yml new file mode 100644 index 0000000000000000000000000000000000000000..aaea90d3211444d6711f210675bd731e6393034a --- /dev/null +++ b/templates/fmt.yml @@ -0,0 +1,69 @@ +spec: + inputs: + # Job and Stage name + as: + default: 'fmt' + description: 'Defines the name of this job.' + stage: + default: 'validate' + description: 'Defines the stage that this job will belong to.' + + # Versions + # This version is only required, because we cannot access the context of the component, + # see https://gitlab.com/gitlab-org/gitlab/-/issues/438275 + version: + default: 'latest' + description: 'Version of this component. Has to be the same as the one in the component include entry.' + + opentofu_version: + default: '1.6.0' + options: + - '$OPENTOFU_VERSION' + - '1.6.0' + - '1.6.0-rc1' + description: 'OpenTofu version that should be used.' + + # Images + image_registry_base: + default: '$CI_REGISTRY/components/opentofu' + # FIXME: not yet possible because of https://gitlab.com/gitlab-org/gitlab/-/issues/438722 + # gitlab_opentofu_image: + # # FIXME: This should reference the component tag that is used. + # # Currently, blocked by https://gitlab.com/gitlab-org/gitlab/-/issues/438275 + # # default: '$CI_REGISTRY/components/opentofu/gitlab-opentofu:$[[ inputs.opentofu_version ]]' + # default: '$CI_REGISTRY/components/opentofu/gitlab-opentofu:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]' + # description: 'Tag of the gitlab-opentofu image.' + + # Configuration + root_dir: + default: ${CI_PROJECT_DIR} + description: 'Root directory for the OpenTofu project.' + + # FIXME: wait for https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142009 + # allow_failure: + # default: true + # type: boolean + # description: 'If the job is allowed to fail or not.' + +--- + +'$[[ inputs.as ]]': + stage: $[[ inputs.stage ]] + needs: [] + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline. + when: never + - if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead. + #allow_failure: $[[ inputs.allow_failure ]] + allow_failure: true + cache: + key: "$[[ inputs.root_dir ]]" + paths: + - $[[ inputs.root_dir ]]/.terraform/ + variables: + TF_ROOT: $[[ inputs.root_dir ]] + image: + name: '$[[ inputs.image_registry_base ]]/gitlab-opentofu:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]' + script: + - gitlab-tofu fmt diff --git a/templates/full-pipeline.yml b/templates/full-pipeline.yml index 297ecada6d098f5834489cb2c2147c0a6f034be9..efe637a994254ef1959514d95ce5375aaa192849 100644 --- a/templates/full-pipeline.yml +++ b/templates/full-pipeline.yml @@ -62,110 +62,61 @@ spec: --- -.default: - image: - name: '$[[ inputs.image_registry_base ]]/gitlab-opentofu:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]' - - variables: - TF_ROOT: $[[ inputs.root_dir ]] - TF_STATE_NAME: $[[ inputs.state_name ]] - - cache: - key: "$[[ inputs.root_dir ]]" - paths: - - $[[ inputs.root_dir ]]/.terraform/ - -fmt: - extends: .default - stage: $[[ inputs.stage_validate ]] - needs: [] - script: - - gitlab-tofu fmt - allow_failure: true - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline. - when: never - - if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead. - -validate: - extends: .default - stage: $[[ inputs.stage_validate ]] - script: - - gitlab-tofu validate - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline. - when: never - - if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead. - -plan: - extends: .default - stage: $[[ inputs.stage_build ]] - script: - - gitlab-tofu plan - - gitlab-tofu plan-json - environment: - name: $[[ inputs.state_name ]] - action: prepare - resource_group: $[[ inputs.state_name ]] - artifacts: - # Terraform's cache files can include secrets which can be accidentally exposed. - # Please exercise caution when utilizing secrets in your Terraform infrastructure and - # consider limiting access to artifacts or take other security measures to protect sensitive information. - # - # The next line, which disables public access to pipeline artifacts, is not available on GitLab.com. - # See: https://docs.gitlab.com/ee/ci/yaml/#artifactspublic - public: false - paths: - - $[[ inputs.root_dir ]]/plan.cache - reports: - terraform: $[[ inputs.root_dir ]]/plan.json - rules: - - if: $CI_PIPELINE_SOURCE == "merge_request_event" - - if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline. - when: never - - if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead. - -apply: - extends: .default - stage: $[[ inputs.stage_deploy ]] - script: - - gitlab-tofu apply - environment: - name: $[[ inputs.state_name ]] - action: start - resource_group: $[[ inputs.state_name ]] - rules: - - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && "$[[ inputs.auto_apply ]]" == "true"' - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - when: manual - -destroy: - extends: .default - stage: $[[ inputs.stage_cleanup ]] - script: - - gitlab-tofu destroy - environment: - name: $[[ inputs.state_name ]] - action: stop - resource_group: $[[ inputs.state_name ]] - rules: - - if: '"$[[ inputs.create_destroy_job ]]" != "true"' - when: never - - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && "$[[ inputs.auto_destroy ]]" == "true"' - - when: manual +include: + - local: '/templates/fmt.yml' + inputs: + as: 'fmt' + stage: $[[ inputs.stage_validate ]] + version: $[[ inputs.version ]] + opentofu_version: $[[ inputs.opentofu_version ]] + image_registry_base: $[[ inputs.image_registry_base ]] + root_dir: $[[ inputs.root_dir ]] + - local: '/templates/validate.yml' + inputs: + as: 'validate' + stage: $[[ inputs.stage_validate ]] + version: $[[ inputs.version ]] + opentofu_version: $[[ inputs.opentofu_version ]] + image_registry_base: $[[ inputs.image_registry_base ]] + root_dir: $[[ inputs.root_dir ]] + state_name: $[[ inputs.state_name ]] + - local: '/templates/plan.yml' + inputs: + as: 'plan' + stage: $[[ inputs.stage_build ]] + version: $[[ inputs.version ]] + opentofu_version: $[[ inputs.opentofu_version ]] + image_registry_base: $[[ inputs.image_registry_base ]] + root_dir: $[[ inputs.root_dir ]] + state_name: $[[ inputs.state_name ]] + - local: '/templates/apply.yml' + inputs: + as: 'apply' + stage: $[[ inputs.stage_deploy ]] + version: $[[ inputs.version ]] + opentofu_version: $[[ inputs.opentofu_version ]] + image_registry_base: $[[ inputs.image_registry_base ]] + root_dir: $[[ inputs.root_dir ]] + state_name: $[[ inputs.state_name ]] + auto_apply: $[[ inputs.auto_apply ]] + - local: '/templates/destroy.yml' + inputs: + as: 'destroy' + stage: $[[ inputs.stage_cleanup ]] + version: $[[ inputs.version ]] + opentofu_version: $[[ inputs.opentofu_version ]] + image_registry_base: $[[ inputs.image_registry_base ]] + root_dir: $[[ inputs.root_dir ]] + state_name: $[[ inputs.state_name ]] + auto_destroy: $[[ inputs.auto_apply ]] + create_destroy_job: $[[ inputs.create_destroy_job ]] + - local: '/templates/delete-state.yml' + inputs: + as: 'delete-state' + stage: $[[ inputs.stage_cleanup ]] + state_name: $[[ inputs.state_name ]] + create_delete_state_job: $[[ inputs.create_delete_state_job ]] +# NOTE: we have to define this `needs` here, because inputs don't support arrays, yet. delete-state: - extends: .default - stage: $[[ inputs.stage_cleanup ]] needs: [destroy] - resource_group: $[[ inputs.state_name ]] - script: - - curl --request DELETE -u "gitlab-ci-token:$CI_JOB_TOKEN" "$CI_API_V4_URL/projects/$CI_PROJECT_ID/terraform/state/$[[ inputs.state_name ]]" - rules: - - if: '"$[[ inputs.create_delete_state_job ]]" != "true"' - when: never - - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' - - when: manual - diff --git a/templates/plan.yml b/templates/plan.yml new file mode 100644 index 0000000000000000000000000000000000000000..a2a618dbef5bb039c605a409a40edbdf54c5139b --- /dev/null +++ b/templates/plan.yml @@ -0,0 +1,81 @@ +spec: + inputs: + # Job and Stage name + as: + default: 'plan' + description: 'Defines the name of this job.' + stage: + default: 'build' + description: 'Defines the stage that this job will belong to.' + + # Versions + # This version is only required, because we cannot access the context of the component, + # see https://gitlab.com/gitlab-org/gitlab/-/issues/438275 + version: + default: 'latest' + description: 'Version of this component. Has to be the same as the one in the component include entry.' + + opentofu_version: + default: '1.6.0' + options: + - '$OPENTOFU_VERSION' + - '1.6.0' + - '1.6.0-rc1' + description: 'OpenTofu version that should be used.' + + # Images + image_registry_base: + default: '$CI_REGISTRY/components/opentofu' + # FIXME: not yet possible because of https://gitlab.com/gitlab-org/gitlab/-/issues/438722 + # gitlab_opentofu_image: + # # FIXME: This should reference the component tag that is used. + # # Currently, blocked by https://gitlab.com/gitlab-org/gitlab/-/issues/438275 + # # default: '$CI_REGISTRY/components/opentofu/gitlab-opentofu:$[[ inputs.opentofu_version ]]' + # default: '$CI_REGISTRY/components/opentofu/gitlab-opentofu:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]' + # description: 'Tag of the gitlab-opentofu image.' + + # Configuration + root_dir: + default: ${CI_PROJECT_DIR} + description: 'Root directory for the OpenTofu project.' + state_name: + default: default + description: 'Remote OpenTofu state name.' + +--- + +'$[[ inputs.as ]]': + stage: $[[ inputs.stage ]] + environment: + name: $[[ inputs.state_name ]] + action: prepare + resource_group: $[[ inputs.state_name ]] + artifacts: + # Terraform's cache files can include secrets which can be accidentally exposed. + # Please exercise caution when utilizing secrets in your Terraform infrastructure and + # consider limiting access to artifacts or take other security measures to protect sensitive information. + # + # The next line, which disables public access to pipeline artifacts, is not available on GitLab.com. + # See: https://docs.gitlab.com/ee/ci/yaml/#artifactspublic + public: false + paths: + - $[[ inputs.root_dir ]]/plan.cache + reports: + terraform: $[[ inputs.root_dir ]]/plan.json + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline. + when: never + - if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead. + cache: + key: "$[[ inputs.root_dir ]]" + paths: + - $[[ inputs.root_dir ]]/.terraform/ + variables: + TF_ROOT: $[[ inputs.root_dir ]] + TF_STATE_NAME: $[[ inputs.state_name ]] + image: + name: '$[[ inputs.image_registry_base ]]/gitlab-opentofu:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]' + script: + - gitlab-tofu plan + - gitlab-tofu plan-json diff --git a/templates/validate.yml b/templates/validate.yml new file mode 100644 index 0000000000000000000000000000000000000000..a37813bf00c2877e3180a10451c0bfdabcbd2b95 --- /dev/null +++ b/templates/validate.yml @@ -0,0 +1,64 @@ +spec: + inputs: + # Job and Stage name + as: + default: 'validate' + description: 'Defines the name of this job.' + stage: + default: 'validate' + description: 'Defines the stage that this job will belong to.' + + # Versions + # This version is only required, because we cannot access the context of the component, + # see https://gitlab.com/gitlab-org/gitlab/-/issues/438275 + version: + default: 'latest' + description: 'Version of this component. Has to be the same as the one in the component include entry.' + + opentofu_version: + default: '1.6.0' + options: + - '$OPENTOFU_VERSION' + - '1.6.0' + - '1.6.0-rc1' + description: 'OpenTofu version that should be used.' + + # Images + image_registry_base: + default: '$CI_REGISTRY/components/opentofu' + # FIXME: not yet possible because of https://gitlab.com/gitlab-org/gitlab/-/issues/438722 + # gitlab_opentofu_image: + # # FIXME: This should reference the component tag that is used. + # # Currently, blocked by https://gitlab.com/gitlab-org/gitlab/-/issues/438275 + # # default: '$CI_REGISTRY/components/opentofu/gitlab-opentofu:$[[ inputs.opentofu_version ]]' + # default: '$CI_REGISTRY/components/opentofu/gitlab-opentofu:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]' + # description: 'Tag of the gitlab-opentofu image.' + + # Configuration + root_dir: + default: ${CI_PROJECT_DIR} + description: 'Root directory for the OpenTofu project.' + state_name: + default: default + description: 'Remote OpenTofu state name.' + +--- + +'$[[ inputs.as ]]': + stage: $[[ inputs.stage ]] + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline. + when: never + - if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead. + cache: + key: "$[[ inputs.root_dir ]]" + paths: + - $[[ inputs.root_dir ]]/.terraform/ + variables: + TF_ROOT: $[[ inputs.root_dir ]] + TF_STATE_NAME: $[[ inputs.state_name ]] + image: + name: '$[[ inputs.image_registry_base ]]/gitlab-opentofu:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]' + script: + - gitlab-tofu validate