将 Azure Devops 管道变量传递给模板,而不将其设置为文字值

问题描述 投票:0回答:3

我有一个带有模板的管道,该模板使用 TerraformTestV1@0 来规划 terraform

我当前正在根据分支设置一个变量,并希望它设置它使用的变量组,但它正在设置文字值并尝试查找具有该值的变量组。 E.G 它正在搜索 $(variable group) 而不是进行转换。

我尝试使用 $[variables.countryCode] 和 $(countryCode) 但得到相同的结果。我还以同样的方式使用另一个变量,但这个变量正在被转换。

我知道countryCode变量也被设置,因为我事先测试了一个powershell任务,显示了我期望的输出。

这是我当前设置的管道

部署.yml

name: $(BuildDefinitionName)_1.0$(Rev:.r)

trigger:
  tags:
    include:
    - 'refs/tags/uk-*'
    - 'refs/tags/us-*'
    - 'refs/tags/es-*'

pool: Default

variables:
- name: countryCode
  ${{ if startsWith(variables['Build.SourceBranch'], 'refs/tags/es-') }}:
    value: es
  ${{ if startsWith(variables['Build.SourceBranch'], 'refs/tags/us-') }}:
    value: us
  ${{ if startsWith(variables['Build.SourceBranch'], 'refs/tags/uk-') }}:
    value: uk
- name: statefilename
  value: pipelinetest 

resources:
  repositories:
    - repository: templates
      type: git
      name: MyTemplateRepo

stages :
  - stage:
    jobs:
      - job: test
        steps:
              - task: PowerShell@2
                displayName: Split_Tag
                continueOnError: false
                inputs:
                  targetType: inline
                  script: | 
                    Write-host $(countryCode)

  - stage: Plan_Dev
    jobs:
    - template: terraform-plan2.yml@templates
      parameters:
        servicePrincipal: Development $[variables.countryCode]
        stateFileName: "$(statefilename).tfstate"
        variableGroup: Terraform $[variables.countryCode] Development Environment
        terraformVersion: '0.14.6'
        condition: ""

模板:

parameters:
- name: 'servicePrincipal'
  default: 'CI Subscription'
  type: string
- name: 'stateFileName'
  type: string
- name: 'variableGroup'
  type: string
- name: 'condition'
  type: string
- name: 'terraformVersion'
  type: string
  default: "0.14.6"

jobs:
  - job: TerraformPlan
    condition: ${{ parameters.condition }}
    variables:
      - group: ${{ parameters.variableGroup }}
    steps:
          - task: TerraformInstaller@0
            displayName: Terraform Install
            inputs:
                terraformVersion: ${{ parameters.terraformVersion }}
          - task: replacetokens@3
            inputs:
                targetFiles: '**/*.tfvars'
                encoding: 'auto'
                writeBOM: true
                actionOnMissing: 'warn'
                keepToken: false
                tokenPrefix: '#{'
                tokenSuffix: '}'
                useLegacyPattern: false
                enableTransforms: false
                enableTelemetry: true
          - task: TerraformTaskV1@0
            displayName: Terraform init
            inputs:
                provider: 'azurerm'
                command: 'init'
                commandOptions: '-upgrade'
                backendServiceArm: ${{ parameters.servicePrincipal }}
                backendAzureRmResourceGroupName: $(backendResourceGroup)
                backendAzureRmStorageAccountName: $(backendStorageAccount)
                backendAzureRmContainerName: $(backendContainer)
                backendAzureRmKey: "$(short_location).$(tenant).$(short_environment).${{ parameters.stateFileName }}"
          - task: TerraformTaskV1@0
            displayName: Terraform Validate
            inputs:
                provider: 'azurerm'
                command: 'validate'
                backendAzureRmKey: ${{ parameters.servicePrincipal }}
          - task: TerraformTaskV1@0
            displayName: Terraform Plan
            inputs:
                provider: 'azurerm'
                command: 'plan'
                commandOptions: '-var-file="devops.tfvars"'
                environmentServiceNameAzureRM: ${{ parameters.servicePrincipal }}

这是我收到的错误: 管道无效。作业 TerraformPlan:找不到变量组 Terraform $(countryCode) 开发环境。变量组不存在或未被授权使用。

有什么想法为什么这没有得到转变吗?

azure-devops continuous-integration terraform pipeline
3个回答
1
投票

您使用了错误的语法来引用变量。

$[]
用于 runtime 变量,这意味着在编译 YAML 模板之后的过程中绝对最后设置的变量。除非您专门处理运行时变量,否则安全的假设是该语法不正确。

您要查找的语法是

${{ variables.countryCode }}
${{ variables['countryCode'] }}
。其中任何一项都应该有效。编译时变量引用可能有点棘手......其中一些在某些情况下有效,但在其他情况下则无效。

我发现最一致可靠的语法是

${{ variable.whatever }}


1
投票

共有三种语法:

  • 宏语法:$(variableName)

    宏语法在运行时评估。因此,如果您定义变量,然后在管道过程中动态更改它,$(variableName) 将始终具有最新值。

  • 运行时表达式:$[表达式]

    运行时表达式很棘手。它们在运行时评估一次。本文前几段的重要说明:

    运行时表达式旨在作为计算变量和状态内容的一种方式

    根据我的解释和过去的经验,运行时表达式必须是“等式的整个右侧”。举几个例子: variables: myLiteral: 'hello' myVariable: $[ format('{0} world!', variables.myLiteral) ] steps: - powershell: write-host '$(myVariable)' condition: $[ contains( variables.myVariable, 'hello') ]

    有趣的观察,当用作条件时,不需要 
    $[ ]

    - powershell: write-host '$(myVariable)' condition: contains(variables.myVariable, 'hello')

  • 编译时表达式

    :${{表达式}} 编译时表达式在管道编译/扩展时计算。与运行时表达式不同,编译时表达式的使用位置限制较少,因此它们可以出现在文字的中间。例如)

    parameters: - name: firstName type: string steps: - powershell: Write-Host 'Hello ${{ parameters.firstName }}'

    非常重要:

    只有非常具体的变量在编译时可用!请参阅预定义变量文章,因为它有一个表格列出了编译时可以使用哪些变量。 也来自

    同一篇文章

    ,重点是我的:

    运行时和编译时表达式语法之间的区别主要在于可用的上下文。在编译时表达式 (
    ${{ <expression> }}

    ) 中,您可以访问参数和

    静态定义的变量
    。在运行时表达式 ($[ <expression> ]) 中,您可以访问更多变量,但没有参数。
    
    

    强调“静态定义的变量”指的是编译时上下文中的变量。您的
    countryCode

    可能看起来是“静态”的,因为它是在管道中预先声明的,但实际情况是变量的实际值直到编译发生后才会解析。

    从您提供的示例中,它不起作用的原因是您尝试将运行时值传递给模板参数,这会导致变量组的编译时扩展。在编译时,$(countryCode) 的值为
  • "$(countryCode)"
这就是找不到变量组的原因。

您需要对要传递的参数进行编译时评估: - stage: Plan_Dev jobs: - template: terraform-plan2.yml@templates parameters: servicePrincipal: Development $[variables.countryCode] stateFileName: "$(statefilename).tfstate" terraformVersion: '0.14.6' condition: "" ${{ if startsWith(variables['Build.SourceBranch'], 'refs/tags/es-') }}: variableGroup: Terraform es Development Environment ${{ if startsWith(variables['Build.SourceBranch'], 'refs/tags/us-') }}: variableGroup: Terraform us Development Environment ${{ if startsWith(variables['Build.SourceBranch'], 'refs/tags/uk-') }}: variableGroup: Terraform uk Development Environment

在类似的主题中,我认为您可能也会发现

servicePrincipal
 存在同样的问题,因为服务连接和变量组被视为
受保护资源

,它们使用 Approvals+Checks API 进行保护,该 API 在管道运行之前进行评估。您可能希望在模板内移动主体和变量组,并将国家代码作为编译值传递。 更新:


经过更多的实验,我能够在 pipeline.yml 中的编译时解析 ${{ variables['whatever'] }}

${{ variables.whatever }}

    
问题:这个变量可以作为库(变量组)中的值而不是静态值吗?


-1
投票

© www.soinside.com 2019 - 2024. All rights reserved.