AWS CodeBuild buildspec bash 语法错误:错误替换 if 语句

Mar*_*llm 7 bash amazon-web-services aws-codebuild

背景:

我正在使用 AWS CodeBuild buildspec.yml 迭代 GitHub 存储库中的目录。在循环目录路径之前$TF_ROOT_DIR,我使用 bash if 语句来检查 GitHub 分支名称是否$BRANCH_NAME在环境变量内$LIVE_BRANCHES。正如您在下面的错误屏幕截图中看到的,bash if 语句输出错误:syntax error: bad substitution。当我在本地 bash 脚本中重现 if 语句时,if 语句按预期工作。

以下是 CodeBuild 项目中定义的环境变量:

环境 以下是 buildspec.yml 中的相关片段:

version: 0.2
env:
  shell: bash
phases:
  build:
    commands:
      - |
        if [[ " ${LIVE_BRANCHES[*]} " == *"$BRANCH_NAME"* ]]; then
          # Iterate only through BRANCH_NAME directory
          TF_ROOT_DIR=${TF_ROOT_DIR}/*/${BRANCH_NAME}/
        else
          # Iterate through both dev and prod directories
          TF_ROOT_DIR=${TF_ROOT_DIR}/*/
        fi
      - echo $TF_ROOT_DIR
Run Code Online (Sandbox Code Playgroud)

这是显示语法错误的构建日志:

在此输入图像描述

以下是用于重现 CodeBuild 项目的 AWS CodeBuild 项目 JSON:

{
    "projects": [
        {
            "name": "terraform_validate_plan",
            "arn": "arn:aws:codebuild:us-west-2:xxxxx:project/terraform_validate_plan",
            "description": "Perform terraform plan and terraform validator",
            "source": {
                "type": "GITHUB",
                "location": "https://github.com/marshall7m/sparkify_end_to_end.git",
                "gitCloneDepth": 1,
                "gitSubmodulesConfig": {
                    "fetchSubmodules": false
                },
                "buildspec": "deployment/CI/dev/cfg/buildspec_terraform_validate_plan.yml",
                "reportBuildStatus": false,
                "insecureSsl": false
            },
            "secondarySources": [],
            "secondarySourceVersions": [],
            "artifacts": {
                "type": "NO_ARTIFACTS",
                "overrideArtifactName": false
            },
            "cache": {
                "type": "NO_CACHE"
            },
            "environment": {
                "type": "LINUX_CONTAINER",
                "image": "hashicorp/terraform:0.12.28",
                "computeType": "BUILD_GENERAL1_SMALL",
                "environmentVariables": [
                    {
                        "name": "TF_ROOT_DIR",
                        "value": "deployment",
                        "type": "PLAINTEXT"
                    },
                    {
                        "name": "LIVE_BRANCHES",
                        "value": "(dev, prod)",
                        "type": "PLAINTEXT"
                    }

Run Code Online (Sandbox Code Playgroud)

这是关联的构建规范文件内容:( buildspec_terraform_validate_plan.yml)

version: 0.2
env:
  shell: bash
  parameter-store:
      AWS_ACCESS_KEY_ID_PARAM: TF_AWS_ACCESS_KEY_ID
      AWS_SECRET_ACCESS_KEY_PARAM: TF_AWS_SECRET_ACCESS_KEY_ID
phases:
  install:
    commands:
      # install/incorporate terraform validator? 
  pre_build:
    commands:
      # CodeBuild environment variables
      #   BRANCH_NAME -- GitHub branch that triggered the CodeBuild project
      #   TF_ROOT_DIR -- Directory within branch ($BRANCH_NAME) that will be iterated through for terraform planning and testing
      #   LIVE_BRANCHES -- Branches that represent a live cloud environment
      - export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID_PARAM
      - export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY_PARAM
      - bash -version || echo "${BASH_VERSION}" || bash --version
      - |
        if [[ -z "${BRANCH_NAME}" ]]; then
          # extract branch from github webhook
          BRANCH_NAME=$(echo $CODEBUILD_WEBHOOK_HEAD_REF | cut -d'/' -f 3)
        fi
      - "echo Triggered Branch: $BRANCH_NAME"
      - |
        if [[ " ${LIVE_BRANCHES[*]} " == *"$BRANCH_NAME"* ]]; then
          # Iterate only through BRANCH_NAME directory
          TF_ROOT_DIR=${TF_ROOT_DIR}/*/${BRANCH_NAME}/
        else
          # Iterate through both dev and prod directories
          TF_ROOT_DIR=${TF_ROOT_DIR}/*/
        fi
      - "echo Terraform root directory: $TF_ROOT_DIR"
  build:
    commands:
      - |
        for dir in $TF_ROOT_DIR; do
          #get list of non-hidden directories within $dir/
          service_dir_list=$(find "${dir}" -type d | grep -v '/\.')
          for sub_dir in $service_dir_list; do
            #if $sub_dir contains .tf or .tfvars files
            if (ls ${sub_dir}/*.tf) > /dev/null 2>&1 || (ls ${sub_dir}/*.tfvars) > /dev/null 2>&1; then
              cd $sub_dir 
              echo ""
              echo "*************** terraform init ******************"
              echo "******* At directory: ${sub_dir} ********"
              echo "*************************************************"
              terraform init
              echo ""
              echo "*************** terraform plan ******************"
              echo "******* At directory: ${sub_dir} ********"
              echo "*************************************************"
              terraform plan
              cd - > /dev/null 
            fi
          done 
        done
Run Code Online (Sandbox Code Playgroud)

鉴于这只是一个副项目,所有可能与此问题相关的文件都位于此处的公共存储库中。

更新

尝试添加#!/bin/bashshebang 行但导致 CodeBuild 错误:

Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: #!/bin/bash
Run Code Online (Sandbox Code Playgroud)
version: 0.2
env:
  shell: bash
phases:
  build:
    commands:
      - |
        #!/bin/bash
        if [[ " ${LIVE_BRANCHES[*]} " == *"$BRANCH_NAME"* ]]; then
          # Iterate only through BRANCH_NAME directory
          TF_ROOT_DIR=${TF_ROOT_DIR}/*/${BRANCH_NAME}/
        else
          # Iterate through both dev and prod directories
          TF_ROOT_DIR=${TF_ROOT_DIR}/*/
        fi
      - echo $TF_ROOT_DIR
Run Code Online (Sandbox Code Playgroud)

解决方案

正如 @Marcin 所提到的,我在 Codebuild (aws/codebuild/standard:4.0) 中使用了 AWS 托管映像,并在该install阶段下载了 Terraform。

phases:
  install:
    commands:
      - wget https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip -q
      - unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip && mv terraform /usr/local/bin/
Run Code Online (Sandbox Code Playgroud)

Mar*_*cin 1

我尝试重现您的问题,但对我来说一切正常。

我唯一注意到的是您正在使用$BRANCH_NAME但它没有在任何地方定义。但即使缺少您发布的$BRANCH_NAME内容也可以正常运行。buildspec.yml

hashicorp/terraform:0.12.28使用图像更新

Hashicorp/terraform:0.12.28

  • 啊,这就是为什么,我盲目地假设 hashicorp/terraform:0.12.28 会内置 bash。我猜“语法错误:错误替换”错误让我感到困惑,我认为该错误与 bash 严格相关。我听取了您关于使用 AWS 托管映像的建议,并在我的帖子中反映了这一变化。感谢@Marcin 的所有帮助! (2认同)