#!/bin/bash set -e OUTPUT_FILE=".gitlab-ci.generated.yml" cat > "$OUTPUT_FILE" << 'HEADER' workflow: rules: - when: always variables: AWS_EC2_METADATA_DISABLED: "true" TF_CLI_ARGS: "-no-color" TG_LOG_LEVEL: "error" TG_DEPENDENCY_FETCH_OUTPUT_FROM_STATE: "true" stages: - validate - plan - apply HEADER find live -name "terragrunt.hcl" -not -path "*/.terragrunt-cache/*" | sort | while read -r config_file; do component_dir=$(dirname "$config_file") relative_path=$(echo "$component_dir" | sed 's|^live/||') env=$(echo "$relative_path" | cut -d'/' -f1) component=$(echo "$relative_path" | cut -d'/' -f2) if [ -z "$component" ] || [ "$component" = "$env" ]; then continue fi job_prefix="${env}-${component}" full_component_dir="${component_dir}" needs_section="" if [ "$component" = "secrets" ]; then needs_section=" needs: - validate-${env}-namespace - validate-${env}-s3 - validate-${env}-database dependencies: - validate-${env}-namespace - validate-${env}-s3 - validate-${env}-database" fi case "$env" in stage) folder_var="YC_STAGE_FOLDER_ID" ;; prod) folder_var="YC_PROD_FOLDER_ID" ;; preprod) folder_var="YC_PREPROD_FOLDER_ID" ;; *) folder_var="YC_FOLDER_ID" ;; esac # Определяем тег runner'а и правила в зависимости от окружения if [ "$env" = "prod" ]; then runner_tags=" tags: - prod" branch_rules=" - if: '\$CI_PIPELINE_SOURCE == \"parent_pipeline\"' - if: '\$CI_COMMIT_BRANCH == \"master\"' - if: '\$CI_PIPELINE_SOURCE == \"pipeline\" && \$TARGET_ENV == \"prod\"'" else runner_tags="" branch_rules=" - if: '\$CI_PIPELINE_SOURCE == \"parent_pipeline\"' - if: '\$CI_PIPELINE_SOURCE == \"pipeline\"' - if: '\$CI_PIPELINE_SOURCE == \"merge_request_event\"' - if: '\$CI_COMMIT_BRANCH == \"stage\"' - if: '\$CI_COMMIT_BRANCH =~ /^feature\\\\/.*/' - if: '\$CI_PIPELINE_SOURCE == \"pipeline\" && \$TARGET_ENV == \"stage\"'" fi cat >> "$OUTPUT_FILE" << VALIDATE_JOB validate-${job_prefix}: stage: validate image: \$TERRAFORM_IMAGE_NAME ${runner_tags} variables: TG_ROOT: "${full_component_dir}" ENVIRONMENT: "${env}" YC_FOLDER_ID: "\$${folder_var}" TG_SKIP_DEPENDENCY_OUTPUTS: "true" before_script: - cd \$TG_ROOT - echo "Working directory:" && pwd - ls -la script: - terragrunt init -upgrade -reconfigure - terragrunt validate rules: ${branch_rules} interruptible: true artifacts: paths: - ${full_component_dir}/.terragrunt-cache/ expire_in: 1 hour when: always ${needs_section} VALIDATE_JOB # Plan needs и before_script для secrets plan_needs="validate-${job_prefix}" plan_before_script="cd \$TG_ROOT && ls -la" if [ "$component" = "secrets" ]; then plan_needs="validate-${job_prefix} - plan-${env}-namespace - plan-${env}-s3 - plan-${env}-database" # Для secrets инициализируем зависимости чтобы получить их outputs plan_before_script="cd live/${env}/namespace && terragrunt init -upgrade -reconfigure && cd ../s3 && terragrunt init -upgrade -reconfigure && cd ../database && terragrunt init -upgrade -reconfigure && cd ../secrets && ls -la" fi cat >> "$OUTPUT_FILE" << PLAN_JOB plan-${job_prefix}: stage: plan image: \$TERRAFORM_IMAGE_NAME ${runner_tags} variables: TG_ROOT: "${full_component_dir}" ENVIRONMENT: "${env}" YC_FOLDER_ID: "\$${folder_var}" needs: - ${plan_needs} before_script: - ${plan_before_script} script: - terragrunt init -upgrade -reconfigure - terragrunt plan -out=tfplan rules: ${branch_rules} interruptible: true artifacts: paths: - ${full_component_dir}/tfplan - ${full_component_dir}/.terragrunt-cache/ expire_in: 1 week when: always PLAN_JOB # Apply всегда manual when_clause="manual" apply_needs="plan-${job_prefix}" apply_before_script="cd \$TG_ROOT && ls -la" if [ "$component" = "secrets" ]; then apply_needs="plan-${job_prefix} - apply-${env}-namespace - apply-${env}-s3 - apply-${env}-database" # Для secrets инициализируем зависимости чтобы получить их outputs apply_before_script="cd live/${env}/namespace && terragrunt init -upgrade -reconfigure && cd ../s3 && terragrunt init -upgrade -reconfigure && cd ../database && terragrunt init -upgrade -reconfigure && cd ../secrets && ls -la" fi # Apply rules в зависимости от окружения if [ "$env" = "prod" ]; then apply_rules=" - if: '\$CI_COMMIT_BRANCH == \"master\"' when: ${when_clause} - if: '\$CI_PIPELINE_SOURCE == \"pipeline\" && \$TARGET_ENV == \"prod\"' when: ${when_clause}" else apply_rules=" - if: '\$CI_COMMIT_BRANCH == \"stage\"' when: ${when_clause} - if: '\$CI_PIPELINE_SOURCE == \"pipeline\" && \$TARGET_ENV == \"stage\"' when: ${when_clause}" fi cat >> "$OUTPUT_FILE" << APPLY_JOB apply-${job_prefix}: stage: apply image: \$TERRAFORM_IMAGE_NAME ${runner_tags} variables: TG_ROOT: "${full_component_dir}" ENVIRONMENT: "${env}" YC_FOLDER_ID: "\$${folder_var}" needs: - ${apply_needs} before_script: - ${apply_before_script} script: - terragrunt init -upgrade -reconfigure - terragrunt apply -auto-approve rules: ${apply_rules} interruptible: true APPLY_JOB done echo "Pipeline generated successfully: $OUTPUT_FILE" echo "Found components:" find live -name "terragrunt.hcl" -not -path "*/.terragrunt-cache/*" | sed 's|live/||; s|/terragrunt.hcl||' | grep '/' | sort