Azure DevOps 使用变量作为部署阶段之间的条件

时间:2021-06-18 01:22:02

标签: azure yaml terraform azure-pipelines

我目前通过 Azure DevOps Pipelines 使用 Terraform 构建我们所有的 Azure 基础设施。这一直运行良好,我们有一个标准的管道,它调用两个模板

  • 计划阶段
    • 部署工作
    • 规划模板
    • 每次运行
  • 应用阶段
    • 部署工作
    • 应用模板
    • 通过手动审批检查运行

现在这工作正常,但我想要做的是只有在需要进行更改时才运行应用步骤。我找到了其他关于如何在计划阶段获取变量集的文章,我可以这样做并且效果很好。

我可以在下一步中调用这个相同的变量

  variables:
    varFromPlanStage: $[stageDependencies.Plan.planning_stage.outputs['planning_stage.terraformPlanResult.terraformChanges']]
  steps:
    - script: echo $(varFromPlanStage)

但是当我尝试在条件中使用相同的变量时,问题就出现了。 我发现你们的方式不同,需要依赖而不是 stagedependancy,但无论我怎么努力,我都无法让它工作。

管道看起来像这样。

stages:
- stage: 'Plan'
  displayName: 'Planning'
  jobs:
  - deployment: planning_stage
    displayName: 'Planning Changes'
    pool:
      vmImage: 'Ubuntu-20.04'
    environment: 'planning'
    strategy:
      runOnce:
        deploy:
          steps:
          - template: /Pipelines/10-TEST-terraform-planning-template.yml  # Run the Planning Template
            parameters:
                terraform_version: ${{ parameters.terraform_version }}
                terraform_backend_service_arm: ${{ parameters.terraform_backend_service_arm }}
                terraform_backend_resource_group: ${{ parameters.terraform_backend_resource_group }}
                terraform_backend_storage_account: ${{ parameters.terraform_backend_storage_account }}
                terraform_backend_storage_container: ${{ parameters.terraform_backend_storage_container }}
                terraform_state_key: ${{ parameters.terraform_state_key }}
                git_working_directory: ${{ parameters.git_working_directory }}

# This is the Build Stage - Only do this when on the master branch (which is via a PR)

- stage: 'Apply'
  condition: and(succeeded(), eq(dependencies.Plan.planning_stage.outputs['planning_stage.terraformPlanResult.terraformChanges'], 'true'))
  variables:
    varFromPlanStage: $[stageDependencies.Plan.planning_stage.outputs['planning_stage.terraformPlanResult.terraformChanges']]
  displayName: 'Applying Changes'
  jobs:
  - deployment: applying_stage
    displayName: 'Lets Build'
    pool:
      vmImage: 'Ubuntu-20.04'
    environment: 'building'
    strategy:
      runOnce:
        deploy:
          steps:
            - script: echo $(varFromPlanStage) # Just a test
            - template: /Pipelines/20-TEST-terraform-apply-template.yml  # Run the Apply Template
              parameters:
                  terraform_version: ${{ parameters.terraform_version }}
                  terraform_backend_service_arm: ${{ parameters.terraform_backend_service_arm }}
                  terraform_backend_resource_group: ${{ parameters.terraform_backend_resource_group }}
                  terraform_backend_storage_account: ${{ parameters.terraform_backend_storage_account }}
                  terraform_backend_storage_container: ${{ parameters.terraform_backend_storage_container }}
                  terraform_state_key: ${{ parameters.terraform_state_key }}
                  git_working_directory: ${{ parameters.git_working_directory }}

导出变量的规划模板部分称为 terraformPlanResult,其中 var 为 terraformChanges

知道我在这里做错了什么,为什么我不能将变量称为条件,但我可以作为步骤的一部分?

谢谢!

3 个答案:

答案 0 :(得分:0)

对我有用的(通过许多试验和错误)是格式:

dependencies.stage_name.outputs['job_name.step_name.variable_name']

在您的情况下,这将是:

dependencies.Plan.outputs['planning_stage.terraformPlanResult.terraformChanges']

如果这不起作用,唯一不寻常的是您的 planning_stage 是一个部署。您可以尝试将其更改为常规工作。

这是一个 pipeline that tests various ways of referencing outputs in conditions

答案 1 :(得分:0)

对我来说,这看起来像是 Azure Devops 上的一个问题(稍后 O 将准备最小的工作示例并为此创建一个错误)。因为相同的语法适用于常规作业,但不适用于部署。您也可以使用 condition: in(dependencies.A.result, 'Succeeded', 'SucceededWithIssues', 'Skipped') 之类的条件,但不能使用输出。而根据这个

"dependencies": {
  "<STAGE_NAME>" : {
    "result": "Succeeded|SucceededWithIssues|Skipped|Failed|Canceled",
    "outputs": {
        "jobName.stepName.variableName": "value"
    }
  },
  "...": {
    // another stage
  }
}

这是正确的语法。

我还检查了 this,但使用生命周期钩子而不是作业名称对我没有帮助。

如果它们处于同一阶段,您可以在作业条件中使用输出变量有什么奇怪的。

Here 是问题的链接。

答案 2 :(得分:0)

这似乎会有所不同,具体取决于您是在“部署”作业还是“作业”作业中设置变量。经过一些试验、错误和谷歌搜索,我设法为两者工作。下面的例子:-)

  • 从“部署”作业传递变量的示例。
# Example passing variables from a 'deployment' job.
stages:

  # Create some variables to pass to next stage.
 - stage: 'A'
    jobs:
    - deployment: 'A1'
      pool:
        vmImage: 'windows-2019'
      environment: 'test'
      strategy:
        runOnce:
          deploy:
            steps:
            # Create a variable.
            - task: PowerShell@2
              name: foo
              displayName: 'Create a variable.'
              inputs:
                targetType: 'inline'
                script: |
                    echo "##vso[task.setvariable variable=bar;isOutput=true]apple"
            # Check variable.
            - task: PowerShell@2
              displayName: 'Check a variable.'
              inputs:
                targetType: 'inline'
                script: |
                  Write-Host "$env:MY_MAPPED_ENV_VAR"
              env:
                MY_MAPPED_ENV_VAR: $(foo.bar)

  # Confirm condition works & variables are available for use.
 - stage: 'B'
    dependsOn:
    - 'A'
    variables:
      - name: varFromStageA
        # stageDependencies.stageName.deploymentName.outputs['deploymentName.stepName.variableName']
        value: $[ stageDependencies.A.A1.outputs['A1.foo.bar'] ]
    # dependencies.stageName.outputs['deploymentName.deploymentName.stepName.variableName']
    condition: and(succeeded(), eq(dependencies.A.outputs['A1.A1.foo.bar'], 'apple'))
    jobs:
    - job: 'B1'
      pool:
        vmImage: 'windows-2019'
      steps:
      # Confirm variable has been passed between stages.
      - task: PowerShell@2
        displayName: 'Confirm var passed between stages'
        inputs:
          targetType: 'inline'
          script: |
            Write-Host "$env:MY_MAPPED_ENV_VAR"
        env:
          MY_MAPPED_ENV_VAR: $(varFromStageA)
  • 从“作业”作业传递变量的示例。
# Example passing variables from a 'job' job.
stages:

  # Create some variables to pass to next stage.
  - stage: 'A'
    jobs:
    - job: 'A1'
      pool:
        vmImage: 'windows-2019'
      steps:
      # Create a variable.
      - task: PowerShell@2
        name: foo
        displayName: 'Create a variable.'
        inputs:
          targetType: 'inline'
          script: |
              echo "##vso[task.setvariable variable=bar;isOutput=true]apple"
      # Check variable.
      - task: PowerShell@2
        displayName: 'Check a variable.'
        inputs:
          targetType: 'inline'
          script: |
            Write-Host "$env:MY_MAPPED_ENV_VAR"
        env:
          MY_MAPPED_ENV_VAR: $(foo.bar)

  # Confirm condition works & variables are available for use.
  - stage: 'B'
    dependsOn:
    - 'A'
    variables:
      - name: varFromStageA
        # stageDependencies.stageName.jobName.outputs['stepName.variableName']
        value: $[ stageDependencies.A.A1.outputs['foo.bar'] ]
    # dependencies.stageName.outputs['jobName.stepName.variableName']
    condition: and(succeeded(), eq(dependencies.A.outputs['A1.foo.bar'], 'apple'))
    jobs:
    - job: 'B1'
      pool:
        vmImage: 'windows-2019'
      steps:
      # Confirm variable has been passed between stages.
      - task: PowerShell@2
        displayName: 'Confirm var passed between stages'
        inputs:
          targetType: 'inline'
          script: |
            Write-Host "$env:MY_MAPPED_ENV_VAR"
        env:
          MY_MAPPED_ENV_VAR: $(varFromStageA)