diff --git a/src/gitlab-tofu.sh b/src/gitlab-tofu.sh index 8a27947e7023c712df87748c98c9fea91cf0d719..b552713ca1c12670fc5095061fe138533dd86eef 100644 --- a/src/gitlab-tofu.sh +++ b/src/gitlab-tofu.sh @@ -204,6 +204,11 @@ if [ $sourced -eq 0 ]; then # Authenticate to private registry terraform_authenticate_private_registry + var_file_args="" + if [ -n "${OPENTOFU_COMPONENT_VAR_FILE}" ]; then + var_file_args="--var-file=${OPENTOFU_COMPONENT_VAR_FILE}" + fi + case "${1}" in "apply") auto_approve_args="" @@ -215,7 +220,8 @@ if [ $sourced -eq 0 ]; then if [ "$TF_APPLY_NO_PLAN" = false ]; then tofu "${TF_CHDIR_OPT}" "${@}" -input=false "${auto_approve_args}" "${TF_PLAN_CACHE}" else - tofu "${TF_CHDIR_OPT}" "${@}" -input=false "${auto_approve_args}" + # shellcheck disable=SC2086 + tofu "${TF_CHDIR_OPT}" "${@}" -input=false "${auto_approve_args}" ${var_file_args} fi ;; "destroy") @@ -232,7 +238,8 @@ if [ $sourced -eq 0 ]; then ;; "plan") $TF_IMPLICIT_INIT && terraform_init - tofu "${TF_CHDIR_OPT}" "${@}" -input=false -out="${TF_PLAN_CACHE}" + # shellcheck disable=SC2086 + tofu "${TF_CHDIR_OPT}" "${@}" -input=false -out="${TF_PLAN_CACHE}" ${var_file_args} ;; "plan-json") tofu "${TF_CHDIR_OPT}" show -json "${TF_PLAN_CACHE}" | \ @@ -241,15 +248,18 @@ if [ $sourced -eq 0 ]; then ;; "validate") $TF_IMPLICIT_INIT && terraform_init -backend=false - tofu "${TF_CHDIR_OPT}" "${@}" + # shellcheck disable=SC2086 + tofu "${TF_CHDIR_OPT}" "${@}" ${var_file_args} ;; "test") $TF_IMPLICIT_INIT && terraform_init -backend=false - tofu "${TF_CHDIR_OPT}" "${@}" + # shellcheck disable=SC2086 + tofu "${TF_CHDIR_OPT}" "${@}" ${var_file_args} ;; "graph") $TF_IMPLICIT_INIT && terraform_init - tofu "${TF_CHDIR_OPT}" "${@}" + # shellcheck disable=SC2086 + tofu "${TF_CHDIR_OPT}" "${@}" ${var_file_args} ;; --) shift diff --git a/templates/apply.yml b/templates/apply.yml index 90adf3961d02cb5c52f4f129422dbe3d34455aeb..3836302c773311e28cf9696710a0c6cb2bdc2421 100644 --- a/templates/apply.yml +++ b/templates/apply.yml @@ -84,6 +84,10 @@ spec: default: false type: boolean description: 'Whether the apply job is manual or automatically run.' + var_file: + default: '' + type: string + description: 'Path to a variables files relative to root_dir. Only used if no_plan is true otherwise the variables are coming from the plan.' --- @@ -108,6 +112,7 @@ spec: TF_STATE_NAME: $[[ inputs.state_name ]] TF_APPLY_NO_PLAN: $[[ inputs.no_plan ]] TF_PLAN_NAME: $[[ inputs.plan_name ]] + OPENTOFU_COMPONENT_VAR_FILE: '$[[ inputs.var_file ]]' image: name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]$[[ inputs.image_digest ]]$[[ inputs.image_digest ]]' script: diff --git a/templates/destroy.yml b/templates/destroy.yml index 9975044db5f8bd2d18efc5561f86fa7b41948308..07914954e875154e21d20741bb051efae8d2d838 100644 --- a/templates/destroy.yml +++ b/templates/destroy.yml @@ -84,6 +84,10 @@ spec: default: false type: boolean description: 'Whether the destroy job is manual or automatically run.' + var_file: + default: '' + type: string + description: 'Path to a variables files relative to root_dir. Only used if no_plan is true otherwise the variables are coming from the plan.' --- @@ -107,6 +111,7 @@ spec: TF_STATE_NAME: $[[ inputs.state_name ]] TF_APPLY_NO_PLAN: $[[ inputs.no_plan ]] TF_PLAN_NAME: $[[ inputs.plan_name ]] + OPENTOFU_COMPONENT_VAR_FILE: '$[[ inputs.var_file ]]' image: name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]$[[ inputs.image_digest ]]' script: diff --git a/templates/full-pipeline.yml b/templates/full-pipeline.yml index 12e01c46890460f9cea6de56f9641f33372e17ec..922debb56a28f7a7a49198578504225137ad4f64 100644 --- a/templates/full-pipeline.yml +++ b/templates/full-pipeline.yml @@ -96,6 +96,10 @@ spec: plan_artifacts_access: default: 'none' description: 'Access level for the plan artifact. See https://docs.gitlab.com/ee/ci/yaml/#artifactsaccess for possible values.' + var_file: + default: '' + type: string + description: 'Path to a variables files relative to root_dir.' --- @@ -123,6 +127,7 @@ include: image_digest: $[[ inputs.image_digest ]] root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/test.yml' inputs: as: '$[[ inputs.job_name_prefix ]]test' @@ -135,6 +140,7 @@ include: image_digest: $[[ inputs.image_digest ]] root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] + var_file: $[[ inputs.var_file ]] rules: - exists: - $[[ inputs.root_dir ]]/**/*.tftest.hcl @@ -151,6 +157,7 @@ include: root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] artifacts_access: $[[ inputs.plan_artifacts_access ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/apply.yml' inputs: as: '$[[ inputs.job_name_prefix ]]apply' @@ -164,6 +171,7 @@ include: root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] auto_apply: $[[ inputs.auto_apply ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/destroy.yml' inputs: as: '$[[ inputs.job_name_prefix ]]destroy' @@ -177,6 +185,7 @@ include: root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] auto_destroy: $[[ inputs.auto_destroy ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/delete-state.yml' inputs: as: '$[[ inputs.job_name_prefix ]]delete-state' diff --git a/templates/graph.yml b/templates/graph.yml index 7a0a0d0796b80469e3b693c9ab3edcfe08f2f8ec..18cc1bf450e18f22b89b9e4cc74fb231fb4d4294 100644 --- a/templates/graph.yml +++ b/templates/graph.yml @@ -78,6 +78,10 @@ spec: description: | Name of the graph file that should be generated. It will be uploaded as an artifact. + var_file: + default: '' + type: string + description: 'Path to a variables files relative to root_dir.' --- @@ -93,6 +97,7 @@ spec: __CACHE_KEY_HACK: "$[[ inputs.root_dir ]]" TF_ROOT: $[[ inputs.root_dir ]] TF_STATE_NAME: $[[ inputs.state_name ]] + OPENTOFU_COMPONENT_VAR_FILE: '$[[ inputs.var_file ]]' image: name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]$[[ inputs.image_digest ]]' script: diff --git a/templates/job-templates.yml b/templates/job-templates.yml index 448d0ad68ac9f3fe699f2e2988892125f4dd4b2c..6fd140b7e4d94d46ede041c6c15c9d7bfa177e1a 100644 --- a/templates/job-templates.yml +++ b/templates/job-templates.yml @@ -93,6 +93,10 @@ spec: default: false type: boolean description: 'Whether the destroy job is manual or automatically run.' + var_file: + default: '' + type: string + description: 'Path to a variables files relative to root_dir.' --- @@ -120,6 +124,7 @@ include: image_digest: $[[ inputs.image_digest ]] root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/graph.yml' inputs: as: '$[[ inputs.job_name_prefix ]]graph' @@ -130,6 +135,7 @@ include: image_registry_base: $[[ inputs.image_registry_base ]] image_name: $[[ inputs.image_name ]] root_dir: $[[ inputs.root_dir ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/test.yml' inputs: as: '$[[ inputs.job_name_prefix ]]test' @@ -142,6 +148,7 @@ include: image_digest: $[[ inputs.image_digest ]] root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/plan.yml' inputs: as: '$[[ inputs.job_name_prefix ]]plan' @@ -154,6 +161,7 @@ include: image_digest: $[[ inputs.image_digest ]] root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/apply.yml' inputs: as: '$[[ inputs.job_name_prefix ]]apply' @@ -167,6 +175,7 @@ include: root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] auto_apply: $[[ inputs.auto_apply ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/destroy.yml' inputs: as: '$[[ inputs.job_name_prefix ]]destroy' @@ -180,6 +189,7 @@ include: root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] auto_destroy: $[[ inputs.auto_destroy ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/delete-state.yml' inputs: as: '$[[ inputs.job_name_prefix ]]delete-state' diff --git a/templates/plan.yml b/templates/plan.yml index cf6e7892bea2aaf054975582c78bfcae871c30aa..d6af1e8d863660e9c71a648e416572e7570b6f1e 100644 --- a/templates/plan.yml +++ b/templates/plan.yml @@ -83,6 +83,10 @@ spec: artifacts_access: default: 'none' description: 'Access level for the plan artifact. See https://docs.gitlab.com/ee/ci/yaml/#artifactsaccess for possible values.' + var_file: + default: '' + type: string + description: 'Path to a variables files relative to root_dir.' --- @@ -117,6 +121,7 @@ spec: TF_ROOT: $[[ inputs.root_dir ]] TF_STATE_NAME: $[[ inputs.state_name ]] TF_PLAN_NAME: $[[ inputs.plan_name ]] + OPENTOFU_COMPONENT_VAR_FILE: '$[[ inputs.var_file ]]' image: name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]$[[ inputs.image_digest ]]' script: diff --git a/templates/test.yml b/templates/test.yml index 2f4894b54965c782149b60d32adacbcd22de5dc0..376f2c4e73c395ff2b3d6669fe6f0da40b12d07c 100644 --- a/templates/test.yml +++ b/templates/test.yml @@ -73,6 +73,10 @@ spec: state_name: default: default description: 'Remote OpenTofu state name.' + var_file: + default: '' + type: string + description: 'Path to a variables files relative to root_dir.' --- @@ -93,6 +97,7 @@ spec: __CACHE_KEY_HACK: "$[[ inputs.root_dir ]]" TF_ROOT: $[[ inputs.root_dir ]] TF_STATE_NAME: $[[ inputs.state_name ]] + OPENTOFU_COMPONENT_VAR_FILE: '$[[ inputs.var_file ]]' image: name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]$[[ inputs.image_digest ]]' script: diff --git a/templates/validate-plan-apply.yml b/templates/validate-plan-apply.yml index abf6c4f7bebc99168814fbd0daf8d4785ab08489..9b3e65f4fa8658515ab6f9fca7561a2cf3e952c2 100644 --- a/templates/validate-plan-apply.yml +++ b/templates/validate-plan-apply.yml @@ -86,6 +86,10 @@ spec: plan_artifacts_access: default: 'none' description: 'Access level for the plan artifact. See https://docs.gitlab.com/ee/ci/yaml/#artifactsaccess for possible values.' + var_file: + default: '' + type: string + description: 'Path to a variables files relative to root_dir.' --- @@ -113,6 +117,7 @@ include: image_digest: $[[ inputs.image_digest ]] root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/plan.yml' inputs: as: '$[[ inputs.job_name_prefix ]]plan' @@ -126,6 +131,7 @@ include: root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] artifacts_access: $[[ inputs.plan_artifacts_access ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/apply.yml' inputs: as: '$[[ inputs.job_name_prefix ]]apply' @@ -139,3 +145,4 @@ include: root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] auto_apply: $[[ inputs.auto_apply ]] + var_file: $[[ inputs.var_file ]] diff --git a/templates/validate-plan-destroy.yml b/templates/validate-plan-destroy.yml index c68b05c29cc49a8e8eb2c57060a45662b6d71757..fe136c66ce7e4288c2c342dafc223d21998625d9 100644 --- a/templates/validate-plan-destroy.yml +++ b/templates/validate-plan-destroy.yml @@ -89,6 +89,10 @@ spec: default: false type: boolean description: 'Whether the destroy job is manual or automatically run.' + var_file: + default: '' + type: string + description: 'Path to a variables files relative to root_dir.' --- @@ -116,6 +120,7 @@ include: image_digest: $[[ inputs.image_digest ]] root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/plan.yml' inputs: as: '$[[ inputs.job_name_prefix ]]plan' @@ -131,6 +136,7 @@ include: plan_name: $[[ inputs.plan_name ]] artifacts_access: $[[ inputs.plan_artifacts_access ]] destroy: true + var_file: $[[ inputs.var_file ]] - local: '/templates/destroy.yml' inputs: as: '$[[ inputs.job_name_prefix ]]destroy' @@ -146,6 +152,7 @@ include: no_plan: false plan_name: $[[ inputs.plan_name ]] auto_destroy: $[[ inputs.auto_destroy ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/delete-state.yml' inputs: as: '$[[ inputs.job_name_prefix ]]delete-state' diff --git a/templates/validate-plan.yml b/templates/validate-plan.yml index e3c30856239a14822323e862b675bfe911b55893..39b61dd9bc63923ef6450c9da374277cd4f00b33 100644 --- a/templates/validate-plan.yml +++ b/templates/validate-plan.yml @@ -79,6 +79,10 @@ spec: artifacts_access: default: 'none' description: 'Access level for the plan artifact. See https://docs.gitlab.com/ee/ci/yaml/#artifactsaccess for possible values.' + var_file: + default: '' + type: string + description: 'Path to a variables files relative to root_dir.' --- @@ -106,6 +110,7 @@ include: image_digest: $[[ inputs.image_digest ]] root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] + var_file: $[[ inputs.var_file ]] - local: '/templates/plan.yml' inputs: as: '$[[ inputs.job_name_prefix ]]plan' @@ -119,3 +124,4 @@ include: root_dir: $[[ inputs.root_dir ]] state_name: $[[ inputs.state_name ]] artifacts_access: $[[ inputs.artifacts_access ]] + var_file: $[[ inputs.var_file ]] diff --git a/templates/validate.yml b/templates/validate.yml index f88189c05e927392a067146736c4b128e1e9a055..9b474e24897ac175bfea616f05f2fb5e599a6ad5 100644 --- a/templates/validate.yml +++ b/templates/validate.yml @@ -73,6 +73,10 @@ spec: state_name: default: default description: 'Remote OpenTofu state name.' + var_file: + default: '' + type: string + description: 'Path to a variables files relative to root_dir.' --- @@ -93,6 +97,7 @@ spec: TF_ROOT: $[[ inputs.root_dir ]] TF_STATE_NAME: $[[ inputs.state_name ]] TF_IGNORE_INIT_ERRORS: 'true' # Tofu can report errors which might be the reason init failed. + OPENTOFU_COMPONENT_VAR_FILE: '$[[ inputs.var_file ]]' image: name: '$[[ inputs.image_registry_base ]]/$[[ inputs.image_name ]]:$[[ inputs.version ]]-opentofu$[[ inputs.opentofu_version ]]-$[[ inputs.base_os ]]$[[ inputs.image_digest ]]' script: diff --git a/tests/iac/main.tf b/tests/iac/main.tf index 9efc7bc0082e7e3ae1d28a61cc0018a793fa114d..f65a2b5a7a0681119c15026fd645f1ab8a7f8501 100644 --- a/tests/iac/main.tf +++ b/tests/iac/main.tf @@ -7,11 +7,20 @@ resource "local_file" "foo" { filename = "${path.module}/foo.bar" } -variable "CI_PROJECT_NAME" { +variable "ci_project_name" { type = string default = "default" } +variable "test_variable" { + type = string + default = "default value" +} + output "project_name" { - value = var.CI_PROJECT_NAME + value = var.ci_project_name +} + +output "test_variable" { + value = var.test_variable } diff --git a/tests/iac/varfile.integration-test.tfvars b/tests/iac/varfile.integration-test.tfvars new file mode 100644 index 0000000000000000000000000000000000000000..a9e6ed522698bc6187641fb135c39346cd4223e2 --- /dev/null +++ b/tests/iac/varfile.integration-test.tfvars @@ -0,0 +1 @@ +test_variable = "varfile integration test" diff --git a/tests/integration-tests/VarFile.gitlab-ci.yml b/tests/integration-tests/VarFile.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..0c035dae6f4d7ab226aa7453dbba4a6340da3927 --- /dev/null +++ b/tests/integration-tests/VarFile.gitlab-ci.yml @@ -0,0 +1,36 @@ +include: + - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/full-pipeline@$CI_COMMIT_SHA + inputs: + image_registry_base: $GITLAB_OPENTOFU_IMAGE_BASE + version: $CI_COMMIT_SHA + base_os: $GITLAB_OPENTOFU_BASE_IMAGE_OS + opentofu_version: $OPENTOFU_VERSION + root_dir: $TEST_TF_ROOT + state_name: $TEST_TF_STATE_NAME + var_file: varfile.integration-test.tfvars + +stages: [validate, test, build, deploy, cleanup] + +# Required to run everything immediately, instead of manually. + +fmt: + rules: [{when: always}] + +validate: + rules: [{when: always}] + +test: + rules: [{when: always}] + +plan: + rules: [{when: always}] + +apply: + rules: [{when: always}] + +destroy: + rules: [{when: always}] + +delete-state: + rules: [{when: always}] + diff --git a/tests/integration.gitlab-ci.yml b/tests/integration.gitlab-ci.yml index 7b1f5fbae32a5eb2edaa3bb68a773a14884624d2..af76bcbdec8f316bea3f05fc6bac6a34f7fd49d7 100644 --- a/tests/integration.gitlab-ci.yml +++ b/tests/integration.gitlab-ci.yml @@ -15,6 +15,7 @@ component: - TestJob - ModuleRelease - Destroy + - VarFile GITLAB_OPENTOFU_BASE_IMAGE_OS: - alpine - debian