Azure Pipeline向模板传递变量组参数时SSH服务连接报错
- Azure DevOps Pipeline 中,使用
${{ }}包裹的模板参数、变量属于编译期求值范围,这个阶段发生在流水线启动后的模板展开步骤,此时系统尚未拉取变量组内存储的变量值,只会将传入的$(Dev-mnode1)识别为普通字符串字面量,不会做变量替换。 - SSH任务的
sshEndpoint字段对应的服务连接,会在编译阶段做存在性、权限校验,系统拿到的校验值是字面量$(Dev-mnode1),和项目中实际存在的Dev11 Connection服务连接名称不匹配,因此直接抛出找不到服务连接的错误。 - 你在脚本中打印
${{ parameters.connection }}能得到正确值,是因为脚本执行属于运行时阶段,此时变量组的变量已经完成加载替换,$(Dev-mnode1)被解析为实际值Dev11 Connection,但这个替换时机晚于服务连接的编译期校验,无法解决校验失败的问题。

涉及的配置文件内容参考:vars.yml变量模板配置:
variables: - group: Agile-Connections - name: extensions_dir value: /apps/agile/product/agile936/integration/sdk/extensions - name: properties_dir value: /apps/agile/product/Properties - name: build_name value: RestrictPreliminaryBOMPX.jar - name: resource_name value: RestrictPreliminaryBOMPX.properties
顶层流水线azure-pipeline.yml配置:
trigger: - None pool: name: AgentBuildAgile stages: - template: templates/build.yml - stage: DEV_Deployment variables: - template: templates/vars.yml jobs: - job: steps: - script: echo $(Dev-mnode1) - template: templates/deploy.yml parameters: connection: $(Dev-mnode1) environment: 'DEV'
部署模板deploy.yml配置:
parameters: - name: connection - name: environment jobs: - deployment: variables: - template: vars.yml environment: ${{ parameters.environment }} displayName: Deploy to ${{ parameters.environment }} strategy: runOnce: deploy: steps: - script: echo Initiating Deployment ${{ parameters.connection }} - template: copy-artifact.yml parameters: connection: ${{ parameters.connection }}
文件拷贝模板copy-artifact.yml配置:
parameters: - name: connection jobs: - job: variables: - template: vars.yml displayName: 'Copy jar' steps: - task: SSH@0 displayName: 'Task - Backup Existing jar file' inputs: sshEndpoint: ${{ parameters.connection }} runOptions: inline inline: if [[ -f ${{ variables.extensions_dir }}/${{ variables.build_name }} ]]; then mv ${{ variables.extensions_dir }}/${{ variables.build_name }} ${{ variables.extensions_dir }}/${{ variables.build_name }}_"`date +"%d%m%Y%H%M%S"`"; echo "Successfully Backed up the existing jar"; fi
运行时抛出的错误:
The pipeline is not valid. Job Job3: Step SSH input sshEndpoint references service connection $(Dev-mnode1) which could not be found. The service connection does not exist or has not been authorized for use.
可根据实际使用场景选择以下两种方案修复:
方案1:直接使用运行时变量语法引用服务连接
不需要跨模板逐层传递connection参数,由于所有需要用到该变量的Job都已经通过vars.yml引入了Agile-Connections变量组,直接在SSH任务中用运行时变量语法引用即可,绕开编译期的服务连接值校验:
修改copy-artifact.yml中的SSH任务配置:
- task: SSH@0 displayName: 'Task - Backup Existing jar file' inputs: sshEndpoint: $(Dev-mnode1) runOptions: inline inline: | if [[ -f ${{ variables.extensions_dir }}/${{ variables.build_name }} ]]; then mv ${{ variables.extensions_dir }}/${{ variables.build_name }} ${{ variables.extensions_dir }}/${{ variables.build_name }}_"`date +"%d%m%Y%H%M%S"`" echo "Successfully Backed up the existing jar" fi
说明:运行时变量$(xxx)不会在编译期被解析为具体值,系统会跳过对该字段的编译期强校验,等到任务实际执行时再替换为真实的服务连接名,完成连接调用。
方案2:编译期传入固定服务连接名称
如果要保留模板参数传递的逻辑,需要保证传给sshEndpoint的参数值在编译期就是真实的服务连接名称,不要传入需要运行时解析的变量:
- 直接在顶层Pipeline调用模板时传入真实服务连接名,修改
azure-pipeline.yml的传参部分:
- template: templates/deploy.yml parameters: connection: 'Dev11 Connection' environment: 'DEV'
- 如果需要适配多环境部署,可以在模板中通过编译期条件判断映射不同环境对应的服务连接名,不需要从变量组取值,示例配置(写在
deploy.yml中):
parameters: - name: environment type: string variables: - name: target_connection ${{ if eq(parameters.environment, 'DEV') }}: value: 'Dev11 Connection' ${{ if eq(parameters.environment, 'TEST') }}: value: 'Test11 Connection' ${{ if eq(parameters.environment, 'PROD') }}: value: 'Prod11 Connection' jobs: - deployment: variables: - template: vars.yml environment: ${{ parameters.environment }} displayName: Deploy to ${{ parameters.environment }} strategy: runOnce: deploy: steps: - script: echo Initiating Deployment $(target_connection) - template: copy-artifact.yml parameters: connection: ${{ variables.target_connection }}
这种方式下传给sshEndpoint的值在编译期就是确定的真实服务连接名,可以正常通过校验。
内容的提问来源于stack exchange,提问作者Tapan

