#!/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}" secrets_dependency_components=() needs_section="" # Для secrets: расшифровать sops-файл с live-значениями во временный файл вне артефактов # и передать путь в terragrunt через INFRA_SECRET_VALUES_FILE (требуется SOPS_AGE_KEY в CI). secrets_decrypt_before="" if [ "$component" = "secrets" ]; then secrets_decrypt_before=" - sops --decrypt infrastructure-secrets.yaml > /tmp/infra-secret-values.yaml - export INFRA_SECRET_VALUES_FILE=/tmp/infra-secret-values.yaml" fi if [ "$component" = "secrets" ]; then for dep_component in namespace s3 database rabbitmq kafka-topics; do if [ -f "live/${env}/${dep_component}/terragrunt.hcl" ]; then secrets_dependency_components+=("$dep_component") fi done needs_section=" needs:" dependencies_section=" dependencies:" for dep_component in "${secrets_dependency_components[@]}"; do needs_section="${needs_section} - validate-${env}-${dep_component}" dependencies_section="${dependencies_section} - validate-${env}-${dep_component}" done needs_section="${needs_section} ${dependencies_section}" fi validate_before_script=" - cd \$TG_ROOT - echo \"Working directory:\" && pwd - ls -la" if [ "$component" = "secrets" ]; then validate_before_script="${secrets_decrypt_before} ${validate_before_script}" 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 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 if [ "$component" = "kafka-topics" ]; then validate_before_script=" - cd \$TG_ROOT - echo \"Working directory:\" && pwd - ls -la" 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: ${validate_before_script} 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="validate-${job_prefix}" plan_before_script=" - cd \$TG_ROOT && ls -la" if [ "$component" = "secrets" ]; then for dep_component in "${secrets_dependency_components[@]}"; do plan_needs="${plan_needs} - plan-${env}-${dep_component}" done dependency_init_chain="" for dep_component in "${secrets_dependency_components[@]}"; do if [ -z "$dependency_init_chain" ]; then dependency_init_chain="cd live/${env}/${dep_component} && terragrunt init -upgrade -reconfigure" else dependency_init_chain="${dependency_init_chain} && cd ../${dep_component} && terragrunt init -upgrade -reconfigure" fi done plan_before_script="${secrets_decrypt_before} - ${dependency_init_chain} && cd ../secrets && ls -la" fi if [ "$component" = "kafka-topics" ]; then plan_before_script=" - cd \$TG_ROOT && ls -la" fi plan_allow_failure="" if [ "$env" = "stage" ] && [ "$component" = "secrets" ]; then plan_allow_failure=" allow_failure: true" fi cat >> "$OUTPUT_FILE" << PLAN_JOB plan-${job_prefix}: stage: plan image: \$TERRAFORM_IMAGE_NAME ${runner_tags} ${plan_allow_failure} 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 when_clause="manual" apply_needs="plan-${job_prefix}" apply_before_script=" - cd \$TG_ROOT && ls -la" if [ "$component" = "secrets" ]; then for dep_component in "${secrets_dependency_components[@]}"; do apply_needs="${apply_needs} - apply-${env}-${dep_component}" done dependency_init_chain="" for dep_component in "${secrets_dependency_components[@]}"; do if [ -z "$dependency_init_chain" ]; then dependency_init_chain="cd live/${env}/${dep_component} && terragrunt init -upgrade -reconfigure" else dependency_init_chain="${dependency_init_chain} && cd ../${dep_component} && terragrunt init -upgrade -reconfigure" fi done apply_before_script="${secrets_decrypt_before} - ${dependency_init_chain} && cd ../secrets && ls -la" fi if [ "$component" = "kafka-topics" ]; then apply_before_script=" - cd \$TG_ROOT && ls -la" fi 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