我有一个带有模板的管道,该模板使用 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) 开发环境。变量组不存在或未被授权使用。
有什么想法为什么这没有得到转变吗?
您使用了错误的语法来引用变量。
$[]
用于 runtime 变量,这意味着在编译 YAML 模板之后的过程中绝对最后设置的变量。除非您专门处理运行时变量,否则安全的假设是该语法不正确。
您要查找的语法是
${{ variables.countryCode }}
或 ${{ variables['countryCode'] }}
。其中任何一项都应该有效。编译时变量引用可能有点棘手......其中一些在某些情况下有效,但在其他情况下则无效。
我发现最一致可靠的语法是
${{ variable.whatever }}
。
共有三种语法:
宏语法:$(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 }}'
只有非常具体的变量在编译时可用!请参阅预定义变量文章,因为它有一个表格列出了编译时可以使用哪些变量。 也来自
同一篇文章运行时和编译时表达式语法之间的区别主要在于可用的上下文。在编译时表达式 (countryCode${{ <expression> }}
) 中,您可以访问参数和
静态定义的变量。在运行时表达式 ($[ <expression> ]
) 中,您可以访问更多变量,但没有参数。 强调“静态定义的变量”指的是编译时上下文中的变量。您的
可能看起来是“静态”的,因为它是在管道中预先声明的,但实际情况是变量的实际值直到编译发生后才会解析。
从您提供的示例中,它不起作用的原因是您尝试将运行时值传递给模板参数,这会导致变量组的编译时扩展。在编译时,$(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 }}
。
问题:这个变量可以作为库(变量组)中的值而不是静态值吗?