# Все корни Terraform в environments/dev/<имя>/ (файл main.tf). # State на диске раннера: /var/lib/terraform-state/grafana-dev/<имя>/terraform.tfstate # (без S3; один persistent path на хосте act_runner). name: terraform-dev on: pull_request: paths: - "environments/dev/**" - "environments/modules/**" - ".gitea/workflows/terraform-dev.yml" push: branches: - main paths: - "environments/dev/**" - "environments/modules/**" - ".gitea/workflows/terraform-dev.yml" workflow_dispatch: inputs: run_apply: description: "Run terraform apply (true/false)" required: true default: "false" env: TF_IN_AUTOMATION: "true" TF_INPUT: "false" TF_CLI_ARGS_init: "-backend=false -plugin-dir=/root/.terraform.d/plugins" STATE_ROOT: "/var/lib/terraform-state/grafana-dev" jobs: validate: runs-on: [terraform-host] steps: - name: Checkout uses: actions/checkout@v4 - name: Terraform version run: terraform version - name: Terraform fmt check run: terraform fmt -check -recursive - name: Terraform init + validate (all dev environments) env: VAULT_ADDR: ${{ secrets.VAULT_ADDR }} VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }} run: | set -euo pipefail restore_state() { local dir="$1" local name="${dir%/}" name="${name##*/}" local sdir="${STATE_ROOT}/${name}" mkdir -p "$sdir" if [ -f "${sdir}/terraform.tfstate" ]; then cp -f "${sdir}/terraform.tfstate" "${dir}/terraform.tfstate" echo "Restored state: ${sdir} -> ${dir}" else echo "No saved state yet: ${sdir}" fi } found=0 for d in environments/dev/*/; do [ -f "${d}main.tf" ] || continue found=1 echo "========== ${d} ==========" restore_state "$d" (cd "$d" && terraform init && terraform validate) done if [ "$found" -eq 0 ]; then echo "No environments found under environments/dev/*/ with main.tf" exit 1 fi plan: needs: validate runs-on: [terraform-host] steps: - name: Checkout uses: actions/checkout@v4 - name: Terraform plan (all dev environments) env: VAULT_ADDR: ${{ secrets.VAULT_ADDR }} VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }} run: | set -euo pipefail restore_state() { local dir="$1" local name="${dir%/}" name="${name##*/}" local sdir="${STATE_ROOT}/${name}" mkdir -p "$sdir" if [ -f "${sdir}/terraform.tfstate" ]; then cp -f "${sdir}/terraform.tfstate" "${dir}/terraform.tfstate" echo "Restored state: ${sdir} -> ${dir}" else echo "No saved state yet: ${sdir}" fi } found=0 for d in environments/dev/*/; do [ -f "${d}main.tf" ] || continue found=1 echo "========== ${d} ==========" restore_state "$d" (cd "$d" && terraform init && terraform plan -refresh=false -lock=false -out=tfplan) done if [ "$found" -eq 0 ]; then echo "No environments found under environments/dev/*/ with main.tf" exit 1 fi apply: if: github.event_name == 'workflow_dispatch' && github.event.inputs.run_apply == 'true' needs: plan runs-on: [terraform-host] steps: - name: Checkout uses: actions/checkout@v4 - name: Terraform apply (all dev environments) env: VAULT_ADDR: ${{ secrets.VAULT_ADDR }} VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }} run: | set -euo pipefail restore_state() { local dir="$1" local name="${dir%/}" name="${name##*/}" local sdir="${STATE_ROOT}/${name}" mkdir -p "$sdir" if [ -f "${sdir}/terraform.tfstate" ]; then cp -f "${sdir}/terraform.tfstate" "${dir}/terraform.tfstate" echo "Restored state: ${sdir} -> ${dir}" else echo "No saved state yet: ${sdir}" fi } save_state() { local dir="$1" local name="${dir%/}" name="${name##*/}" local sdir="${STATE_ROOT}/${name}" mkdir -p "$sdir" if [ -f "${dir}/terraform.tfstate" ]; then cp -f "${dir}/terraform.tfstate" "${sdir}/terraform.tfstate" chmod 600 "${sdir}/terraform.tfstate" 2>/dev/null || true echo "Saved state: ${dir} -> ${sdir}" fi } found=0 for d in environments/dev/*/; do [ -f "${d}main.tf" ] || continue found=1 echo "========== ${d} ==========" restore_state "$d" rc=0 (cd "$d" && terraform init && terraform apply -refresh=false -lock=false -auto-approve) || rc=$? save_state "$d" [ "$rc" -eq 0 ] || exit "$rc" done if [ "$found" -eq 0 ]; then echo "No environments found under environments/dev/*/ with main.tf" exit 1 fi