-
Timo Furrer authored
feat: add graph subcommand See merge request components/opentofu!93
Timo Furrer authoredfeat: add graph subcommand See merge request components/opentofu!93
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
gitlab-tofu.sh 8.23 KiB
#!/bin/sh -e
# ATTENTION: this script is yet JUST A COPY of https://gitlab.com/gitlab-org/terraform-images/-/blob/master/src/bin/gitlab-terraform.sh
# with some VERY MINIMAL MODIFICATIONS.
# It definitely needs cleanup in the future.
if [ "${DEBUG_OUTPUT}" = "true" ]; then
set -x
fi
# Feature Flags
# =============
# Below are a bunch of variables that we use as "feature flags".
if [ -z "$TF_FF_AUTO_URLENCODE_STATE_NAME" ]; then
TF_FF_AUTO_URLENCODE_STATE_NAME=true
fi
if [ -z "$TF_FF_AUTO_APPROVE_APPLY" ]; then
TF_FF_AUTO_APPROVE_APPLY=true
fi
# Helpers
# Evaluate if this script is being sourced or executed directly.
# See https://stackoverflow.com/a/28776166
sourced=0
if [ -n "$ZSH_VERSION" ]; then
case $ZSH_EVAL_CONTEXT in *:file) sourced=1;; esac
elif [ -n "$KSH_VERSION" ]; then
# shellcheck disable=SC2296
[ "$(cd -- "$(dirname -- "$0")" && pwd -P)/$(basename -- "$0")" != "$(cd -- "$(dirname -- "${.sh.file}")" && pwd -P)/$(basename -- "${.sh.file}")" ] && sourced=1
elif [ -n "$BASH_VERSION" ]; then
(return 0 2>/dev/null) && sourced=1
else # All other shells: examine $0 for known shell binary filenames.
# Detects `sh` and `dash`; add additional shell filenames as needed.
case ${0##*/} in sh|-sh|dash|-dash) sourced=1;; esac
fi
JQ_PLAN='
(
[.resource_changes[]?.change.actions?] | flatten
) | {
"create":(map(select(.=="create")) | length),
"update":(map(select(.=="update")) | length),
"delete":(map(select(.=="delete")) | length)
}
'
# If TF_USERNAME is unset then default to GITLAB_USER_LOGIN
TF_USERNAME="${TF_USERNAME:-${GITLAB_USER_LOGIN}}"
# If TF_PASSWORD is unset then default to gitlab-ci-token/CI_JOB_TOKEN
if [ -z "${TF_PASSWORD}" ]; then
TF_USERNAME="gitlab-ci-token"
TF_PASSWORD="${CI_JOB_TOKEN}"
fi
# If TF_ADDRESS is unset but TF_STATE_NAME is provided, then default to GitLab backend in current project
if [ -n "${TF_STATE_NAME}" ] && [ -z "${TF_ADDRESS}" ]; then
# auto url-encode TF_STATE_NAME when FF is enabled
if $TF_FF_AUTO_URLENCODE_STATE_NAME; then
TF_STATE_NAME="$(jq -rn --arg x "${TF_STATE_NAME}" '$x|@uri')"
fi
TF_ADDRESS="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${TF_STATE_NAME}"
fi
if [ -z "${TF_PLAN_NAME}" ]; then
TF_PLAN_NAME=plan
fi
if [ -z "${TF_APPLY_NO_PLAN}" ]; then
TF_APPLY_NO_PLAN=false
fi
# If TF_ROOT is set then use the -chdir option
if [ -n "${TF_ROOT}" ]; then
abs_tf_root=$(cd "${CI_PROJECT_DIR}"; realpath "${TF_ROOT}")
TF_CHDIR_OPT="-chdir=${abs_tf_root}"
default_tf_plan_cache="${abs_tf_root}/${TF_PLAN_NAME}.cache"
default_tf_plan_json="${abs_tf_root}/${TF_PLAN_NAME}.json"
fi
# If TF_PLAN_CACHE is not set then use either the plan.cache file within TF_ROOT if set, or plan.cache in CWD
if [ -z "${TF_PLAN_CACHE}" ]; then
TF_PLAN_CACHE="${default_tf_plan_cache:-${TF_PLAN_NAME}.cache}"
fi
# If TF_PLAN_JSON is not set then use either the plan.json file within TF_ROOT if set, or plan.json in CWD
if [ -z "${TF_PLAN_JSON}" ]; then
TF_PLAN_JSON="${default_tf_plan_json:-${TF_PLAN_NAME}.json}"
fi
# Set variables for the HTTP backend to default to TF_* values
export TF_HTTP_ADDRESS="${TF_HTTP_ADDRESS:-${TF_ADDRESS}}"
export TF_HTTP_LOCK_ADDRESS="${TF_HTTP_LOCK_ADDRESS:-${TF_ADDRESS}/lock}"
export TF_HTTP_LOCK_METHOD="${TF_HTTP_LOCK_METHOD:-POST}"
export TF_HTTP_UNLOCK_ADDRESS="${TF_HTTP_UNLOCK_ADDRESS:-${TF_ADDRESS}/lock}"
export TF_HTTP_UNLOCK_METHOD="${TF_HTTP_UNLOCK_METHOD:-DELETE}"
export TF_HTTP_USERNAME="${TF_HTTP_USERNAME:-${TF_USERNAME}}"
export TF_HTTP_PASSWORD="${TF_HTTP_PASSWORD:-${TF_PASSWORD}}"
export TF_HTTP_RETRY_WAIT_MIN="${TF_HTTP_RETRY_WAIT_MIN:-5}"
# Expose Gitlab specific variables to terraform since no -tf-var is available
# Usable in the .tf file as variable "CI_JOB_ID" { type = string } etc
export TF_VAR_CI_JOB_ID="${TF_VAR_CI_JOB_ID:-${CI_JOB_ID}}"
export TF_VAR_CI_COMMIT_SHA="${TF_VAR_CI_COMMIT_SHA:-${CI_COMMIT_SHA}}"
export TF_VAR_CI_JOB_STAGE="${TF_VAR_CI_JOB_STAGE:-${CI_JOB_STAGE}}"
export TF_VAR_CI_PROJECT_ID="${TF_VAR_CI_PROJECT_ID:-${CI_PROJECT_ID}}"
export TF_VAR_CI_PROJECT_NAME="${TF_VAR_CI_PROJECT_NAME:-${CI_PROJECT_NAME}}"
export TF_VAR_CI_PROJECT_NAMESPACE="${TF_VAR_CI_PROJECT_NAMESPACE:-${CI_PROJECT_NAMESPACE}}"
export TF_VAR_CI_PROJECT_PATH="${TF_VAR_CI_PROJECT_PATH:-${CI_PROJECT_PATH}}"
export TF_VAR_CI_PROJECT_URL="${TF_VAR_CI_PROJECT_URL:-${CI_PROJECT_URL}}"
# Use terraform automation mode (will remove some verbose unneeded messages)
export TF_IN_AUTOMATION=true
DEFAULT_TF_CONFIG_PATH="$HOME/.terraformrc"
# Set a Terraform CLI Configuration File
if [ -z "${TF_CLI_CONFIG_FILE}" ] && [ -f "${DEFAULT_TF_CONFIG_PATH}" ]; then
export TF_CLI_CONFIG_FILE="${DEFAULT_TF_CONFIG_PATH}"
fi
terraform_authenticate_private_registry() {
# From Terraform 1.2.0 and later (or all versions of OpenTofu), we can use TF_TOKEN_your_domain_name to authenticate to registry.
# The credential environment variable has the following requirements:
# - Domain names containing non-ASCII characters are converted to their punycode equivalent with an ACE prefix
# - Periods are encoded as underscores
# - Hyphens are encoded as double underscores
# For more info, see https://www.terraform.io/cli/config/config-file#environment-variable-credentials
if [ "${CI_SERVER_PROTOCOL}" = "https" ] && [ -n "${CI_SERVER_HOST}" ]; then
tf_token_var_name=TF_TOKEN_$(idn2 "${CI_SERVER_HOST}" | sed 's/\./_/g' | sed 's/-/__/g')
# If TF_TOKEN_ for the Gitlab domain is not set then use the CI_JOB_TOKEN
if [ -z "$(eval "echo \${${tf_token_var_name}:-}")" ]; then
export "${tf_token_var_name}"="${CI_JOB_TOKEN}"
fi
fi
}
# If TF_IMPLICIT_INIT is not set, we set it to `true`.
# If set to `true` it will call `terraform init` prior
# to calling the wrapper `terraform` commands.
TF_IMPLICIT_INIT=${TF_IMPLICIT_INIT:-true}
# Allows users to continue the actual command in case init failed
TF_IGNORE_INIT_ERRORS=${TF_IGNORE_INIT_ERRORS:-false}
terraform_init() {
# If TF_INIT_NO_RECONFIGURE is not set to 'true',
# a `-reconfigure` flag is added to the `terraform init` command.
if [ "$TF_INIT_NO_RECONFIGURE" != 'true' ]; then
tf_init_reconfigure_flag='-reconfigure'
fi
# We want to allow word splitting here for TF_INIT_FLAGS
# shellcheck disable=SC2086
tofu "${TF_CHDIR_OPT}" init "${@}" -input=false ${tf_init_reconfigure_flag} ${TF_INIT_FLAGS} \
1>&2 || $TF_IGNORE_INIT_ERRORS
}
# If this script is executed and not sourced, a terraform command is ran.
# Otherwise, nothing happens and the sourced shell can use the defined variables
# and helper functions exposed by this script.
if [ $sourced -eq 0 ]; then
# Authenticate to private registry
terraform_authenticate_private_registry
case "${1}" in
"apply")
auto_approve_args=""
if [ "${TF_FF_AUTO_APPROVE_APPLY}" = true ]; then
auto_approve_args="-auto-approve"
fi
$TF_IMPLICIT_INIT && terraform_init
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}"
fi
;;
"destroy")
$TF_IMPLICIT_INIT && terraform_init
tofu "${TF_CHDIR_OPT}" "${@}" -auto-approve
;;
"fmt")
tofu "${TF_CHDIR_OPT}" "${@}" -check -diff -recursive
;;
"init")
# shift argument list „one to the left“ to not call 'terraform init init'
shift
terraform_init "${@}"
;;
"plan")
$TF_IMPLICIT_INIT && terraform_init
tofu "${TF_CHDIR_OPT}" "${@}" -input=false -out="${TF_PLAN_CACHE}"
;;
"plan-json")
tofu "${TF_CHDIR_OPT}" show -json "${TF_PLAN_CACHE}" | \
jq -r "${JQ_PLAN}" \
> "${TF_PLAN_JSON}"
;;
"validate")
$TF_IMPLICIT_INIT && terraform_init -backend=false
tofu "${TF_CHDIR_OPT}" "${@}"
;;
"test")
$TF_IMPLICIT_INIT && terraform_init -backend=false
tofu "${TF_CHDIR_OPT}" "${@}"
;;
"graph")
$TF_IMPLICIT_INIT && terraform_init
tofu "${TF_CHDIR_OPT}" "${@}"
;;
--)
shift
tofu "${TF_CHDIR_OPT}" "${@}"
;;
*)
tofu "${TF_CHDIR_OPT}" "${@}"
;;
esac
else
# This variable can be used if the script is sourced
# shellcheck disable=SC2034
TF_GITLAB_SOURCED=true
fi