为啥我的多阶段完整 yaml azure devops 管道在移动到模板时会中断?

Posted

技术标签:

【中文标题】为啥我的多阶段完整 yaml azure devops 管道在移动到模板时会中断?【英文标题】:Why my multi stage full yaml azure devops pipeline breaks when moved to template?为什么我的多阶段完整 yaml azure devops 管道在移动到模板时会中断? 【发布时间】:2020-07-03 16:03:38 【问题描述】:

我在 azure devops 服务中有一个多阶段的完整 yaml 管道。不同的阶段包括构建阶段、开发阶段(将 azure 资源部署到 azure 资源组)和 UAT 阶段(将 azure 资源部署到不同的资源组)。一切都很好。但是我需要使用模板,因为我想重用这些步骤。将步骤移至模板后,开发阶段继续工作,但 UAT 阶段给出授权错误。值得一提的是,dev 和 uat 阶段针对不同的订阅使用不同的服务连接。但是,为什么当我不使用模板并且只是将步骤突然移动到模板文件时它不起作用时它会起作用。这是一个已知的错误吗?

这是我在使用模板方法时遇到的错误:

 | The client '9e5cc21a-bb38-46b9-a16a-289fbbf9c8b9' with object
     | id '9e5cc21a-bb38-46b9-a16a-289fbbf9c8b9' does not have
     | authorization to perform action
     | 'Microsoft.Resources/subscriptions/resourceGroups/resources/read' over scope '/subscriptions/7041f5ba-1040-4989-8e48-497b3b826d01/resourceGroups/Resource-Group-Test-A' or the scope is invalid. If access was recently granted, please refresh your credentials. StatusCode: 403 ReasonPhrase: Forbidden OperationID : 464f577e-6617-4bed-9a14-1f7487b5f209 

这是不使用模板的管道(完美!)。

# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml

trigger:
- master

variables:
- group: 'Dev ARMT SFTP Connection'

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

stages: 
- stage: Build
  jobs:
    - job: Build
      pool:
        vmImage: 'ubuntu-latest'
      steps:
      - task: printAllVariables@1
      - task: CopyFiles@2
        inputs:
          SourceFolder: '$(System.DefaultWorkingDirectory)'
          Contents: 'ARM-Templates/**'
          TargetFolder: '$(Build.ArtifactStagingDirectory)'
      - task: PublishBuildArtifacts@1
        inputs:
          PathtoPublish: '$(Build.ArtifactStagingDirectory)'
          ArtifactName: 'drop'
          publishLocation: 'Container'
      - task: PowerShell@2
        inputs:
          targetType: 'inline'
          script: |
            # Write your PowerShell commands here.
            
            Write-Host "Build Completed..."
            $workingdir = "$(Build.ArtifactStagingDirectory)"
            Write-Host $workingdir
            $fcontent = Get-ChildItem -Path $workingdir
            Write-Host $fcontent

    
- stage: Dev
  jobs:
  - job: Dev
    pool:
        vmImage: 'ubuntu-latest'
    steps:
    - task: DownloadBuildArtifacts@0
      inputs:
        buildType: 'specific'
        project: '530cfd4b-51b8-4237-b2fa-f296a4cba29d'
        pipeline: '30'
        buildVersionToDownload: 'latest'
        downloadType: 'single'
        artifactName: 'drop'
        downloadPath: '$(System.ArtifactsDirectory)/CommonTasks'
    - task: DownloadBuildArtifacts@0
      inputs:
        buildType: 'current'
        downloadType: 'single'
        artifactName: 'drop'
        downloadPath: '$(System.ArtifactsDirectory)/SftpConnection'
    - task: FileTransform@1
      displayName: 'ARMT SFTP Connection - Parameters File Transform '
      inputs:
        folderPath: '$(System.ArtifactsDirectory)/SftpConnection/drop'
        fileType: json
        targetFiles: 'ARM-Templates/parameters.json'
    - task: AzurePowerShell@4
      displayName: 'ARMT SFTP Connection - Check Resource Existance'
      inputs:
        azureSubscription: 'Starwood-DT-DEV-ServiceConnection'
        ScriptPath: '$(System.ArtifactsDirectory)/CommonTasks/drop/AzurePowerShell/ResourceExistance.ps1'
        ScriptArguments: '-resourceGroupName Starwood-DT-DEV -resourceName $(parameters.sftp_name.value)'
        azurePowerShellVersion: LatestVersion
    - task: AzureResourceGroupDeployment@2
      displayName: 'ARMT SFTP Connection - Deploy'
      inputs:
        azureSubscription: 'Starwood-DT-DEV-ServiceConnection'
        resourceGroupName: 'Starwood-DT-DEV'
        location: 'East US'
        csmFile: '$(System.ArtifactsDirectory)/SftpConnection/drop/ARM-Templates/template.json'
        csmParametersFile: '$(System.ArtifactsDirectory)/SftpConnection/drop/ARM-Templates/parameters.json'
      condition: eq(variables['deployresource'],'true')

- stage: GroupATest
  jobs:
  - job: GroupATest
    pool:
        vmImage: 'ubuntu-latest'
    steps:
    - task: DownloadBuildArtifacts@0
      inputs:
        buildType: 'specific'
        project: '530cfd4b-51b8-4237-b2fa-f296a4cba29d'
        pipeline: '30'
        buildVersionToDownload: 'latest'
        downloadType: 'single'
        artifactName: 'drop'
        downloadPath: '$(System.ArtifactsDirectory)/CommonTasks'
    - task: DownloadBuildArtifacts@0
      inputs:
        buildType: 'current'
        downloadType: 'single'
        artifactName: 'drop'
        downloadPath: '$(System.ArtifactsDirectory)/SftpConnection'
    - task: FileTransform@1
      displayName: 'ARMT SFTP Connection - Parameters File Transform '
      inputs:
        folderPath: '$(System.ArtifactsDirectory)/SftpConnection/drop'
        fileType: json
        targetFiles: 'ARM-Templates/parameters.json'
    - task: AzurePowerShell@4
      displayName: 'ARMT SFTP Connection - Check Resource Existance'
      inputs:
        azureSubscription: 'Resource-Group-Test-A'
        ScriptPath: '$(System.ArtifactsDirectory)/CommonTasks/drop/AzurePowerShell/ResourceExistance.ps1'
        ScriptArguments: '-resourceGroupName Resouce-Group-Test-A -resourceName $(parameters.sftp_name.value)'
        azurePowerShellVersion: LatestVersion

    - task: AzureResourceGroupDeployment@2
      displayName: 'ARMT SFTP Connection - Deploy'
      inputs:
        azureSubscription: 'Resource-Group-Test-A'
        resourceGroupName: 'Resouce-Group-Test-A'
        location: 'East US'
        csmFile: '$(System.ArtifactsDirectory)/SftpConnection/drop/ARM-Templates/template.json'
        csmParametersFile: '$(System.ArtifactsDirectory)/SftpConnection/drop/ARM-Templates/parameters.json'
      condition: eq(variables['deployresource'],'true')

当移动到步骤模板时(然后我得到错误):

 # Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml

trigger:
- master


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

stages: 
- stage: Build
  jobs:
    - job: Build
      pool:
        vmImage: 'ubuntu-latest'
      steps:
      - task: printAllVariables@1
      - task: CopyFiles@2
        inputs:
          SourceFolder: '$(System.DefaultWorkingDirectory)'
          Contents: 'ARM-Templates/**'
          TargetFolder: '$(Build.ArtifactStagingDirectory)'
      - task: PublishBuildArtifacts@1
        inputs:
          PathtoPublish: '$(Build.ArtifactStagingDirectory)'
          ArtifactName: 'drop'
          publishLocation: 'Container'
      - task: PowerShell@2
        inputs:
          targetType: 'inline'
          script: |
            # Write your PowerShell commands here.
            
            Write-Host "Build Completed..."
            $workingdir = "$(Build.ArtifactStagingDirectory)"
            Write-Host $workingdir
            $fcontent = Get-ChildItem -Path $workingdir
            Write-Host $fcontent

    
- stage: Dev
  variables:
  - group: 'Dev ARMT SFTP Connection'
  jobs:
  - job: Dev
    pool:
        vmImage: 'ubuntu-latest'
    steps:
    - task: DownloadBuildArtifacts@0
      inputs:
        buildType: 'specific'
        project: '530cfd4b-51b8-4237-b2fa-f296a4cba29d'
        pipeline: '30'
        buildVersionToDownload: 'latest'
        downloadType: 'single'
        artifactName: 'drop'
        downloadPath: '$(System.ArtifactsDirectory)/CommonTasks'
    - task: DownloadBuildArtifacts@0
      inputs:
        buildType: 'current'
        downloadType: 'single'
        artifactName: 'drop'
        downloadPath: '$(System.ArtifactsDirectory)/SftpConnection'
    - template: YamlTemplate/azure-resource-deploy.yml@templates
      parameters:
        dropLocation: '$(System.ArtifactsDirectory)/SftpConnection/drop'
        transformTargetPath: 'ARM-Templates/parameters.json'
        resourceName: $(parameters.sftp_name.value)
        resourceGroupName: 'Starwood-DT-DEV'
        azureServiceConnectionName: 'Starwood-DT-DEV-ServiceConnection'
        resourceLocation: 'East US'
        armtTemplateFilePath: '$(System.ArtifactsDirectory)/SftpConnection/drop/ARM-Templates/template.json'
        armtParemeterFilePath: '$(System.ArtifactsDirectory)/SftpConnection/drop/ARM-Templates/parameters.json'

- stage: GroupATest
  variables:
  - group: 'GroupA ARMT SFTP Connection'
  jobs:
  - job: GroupATest
    pool:
        vmImage: 'ubuntu-latest'
    steps: 
    - task: DownloadBuildArtifacts@0
      inputs:
        buildType: 'specific'
        project: '530cfd4b-51b8-4237-b2fa-f296a4cba29d'
        pipeline: '30'
        buildVersionToDownload: 'latest'
        downloadType: 'single'
        artifactName: 'drop'
        downloadPath: '$(System.ArtifactsDirectory)/CommonTasks'
    - task: DownloadBuildArtifacts@0
      inputs:
        buildType: 'current'
        downloadType: 'single'
        artifactName: 'drop'
        downloadPath: '$(System.ArtifactsDirectory)/SftpConnection'
    - template: YamlTemplate/azure-resource-deploy.yml@templates
      parameters:
        dropLocation: '$(System.ArtifactsDirectory)/SftpConnection/drop'
        transformTargetPath: 'ARM-Templates/parameters.json'
        resourceName: $(parameters.sftp_name.value)
        resourceGroupName: 'Resource-Group-Test-A'
        azureServiceConnectionName: 'Resource-Group-Test-A'
        resourceLocation: 'East US'
        armtTemplateFilePath: '$(System.ArtifactsDirectory)/SftpConnection/drop/ARM-Templates/template.json'
        armtParemeterFilePath: '$(System.ArtifactsDirectory)/SftpConnection/drop/ARM-Templates/parameters.json'

这是模板结构 父模板 - (azure-resource-deploy.yml):

parameters:
- name: dropLocation
  type: string
  displayName: 'Artifact path to drop location'
  default: ''
- name: transformTargetPath
  type: string
  default: ''
- name: resourceName
  type: string
  default: ''
- name: resourceGroupName
  type: string
  default: ''
- name: azureServiceConnectionName
  type: string
  default: ''
- name: resourceLocation
  type: string
  default: ''
- name: armtTemplateFilePath
  type: string
  default: ''
- name: armtParemeterFilePath
  type: string
  default: ''


steps:
- template: armt-parameter-file-transform.yml
  parameters:
   transformStepDisplayName: ''
   folderPath: $parameters.dropLocation
   targetFile: $parameters.transformTargetPath

- template: azure-resource-check.yml
  parameters:
   resourceName: $parameters.resourceName
   resourceGroupName: $parameters.resourceGroupName
   azureServiceConnectionName: $parameters.azureServiceConnectionName


- template: armt-deploy.yml
  parameters:
   resourceName: $parameters.resourceName
   resourceGroupName: $parameters.resourceGroupName
   resourceLocation: $parameters.resourceLocation
   azureServiceConnectionName: $parameters.azureServiceConnectionName
   templateFilePath: $parameters.armtTemplateFilePath
   parametersFilePath: $parameters.armtParemeterFilePath
   

从父级引用的模板:

(armt-parameter-file-transform.yml)

parameters:
- name: transformStepDisplayName
  type: string
  displayName: 'Display name for this step'
  default: ''
- name: folderPath
  type: string
  displayName: 'Path to drop location'
  default: ''
- name: targetFile
  type: string
  displayName: 'Path to paremeter file relative to drop location.'
  default: ''

steps:
- task: FileTransform@1
  displayName: $parameters.transformStepDisplayName
  inputs:
    folderPath: $parameters.folderPath
    fileType: json
    targetFiles: $parameters.targetFile

(天蓝色资源检查.yml)

parameters:
- name: resourceName
  type: string
- name: resourceGroupName
  type: string
- name: azureServiceConnectionName
  type: string

steps:
- script: echo Echo -resourceGroupName $ parameters.resourceGroupName  -resourceName $ parameters.resourceName 
- task: AzurePowerShell@4
  displayName: '$ parameters.resourceName  - Checking Resource Existance'
  inputs:
    azureSubscription: '$ parameters.azureServiceConnectionName '
    ScriptPath: '$(System.ArtifactsDirectory)/CommonTasks/drop/AzurePowerShell/ResourceExistance.ps1'
    ScriptArguments: '-resourceGroupName $ parameters.resourceGroupName  -resourceName $ parameters.resourceName '
    azurePowerShellVersion: LatestVersion

(armt-deploy.yml)

parameters:
- name: resourceName
  type: string
- name: resourceGroupName
  type: string
- name: resourceLocation
  type: string
- name: azureServiceConnectionName
  type: string
- name: templateFilePath
  type: string
- name: parametersFilePath
  type: string

steps:
- task: AzureResourceGroupDeployment@2
  displayName: 'ARMT Deploy - $parameters.resourceName'
  inputs:
    azureSubscription: $parameters.azureServiceConnectionName
    resourceGroupName: $parameters.resourceGroupName
    location: $parameters.resourceLocation
    csmFile: $parameters.templateFilePath
    csmParametersFile: $parameters.parametersFilePath
  condition: eq(variables['deployresource'],'true')

【问题讨论】:

该错误与管道无关,与 Azure 中服务主体的权限有关。确保您在管道中使用正确的服务连接,并且服务主体已获得充分授权。 是的,服务主体在订阅中具有贡献者角色。当我不使用 yaml 模板文件时,这再次完美运行。为什么将步骤移动到模板文件会有什么不同? 不会。您确定它显示的客户端 ID 属于您期望的服务主体吗?你的 YAML 是什么样的? 我更新了帖子以显示带有和不带有模板的 yaml 代码。我不确定如何找到它在错误中显示的客户端 ID。我怎样才能找到它? 包括所有 YAML,包括你创建的模板。 【参考方案1】:

这只是一个错字造成的。资源组的实际名称是Resouce-Group-Test-A,我在命名这个资源组时漏掉了r。在非模板版本中不会发生该错误,因为当您从下拉列表中选择资源组时,您会使用正确的预填充名称进行操作,因此不会出错。然而,在一个完整的 yaml 管道中,您必须输入它,这就是发生错字的地方。如果这里有什么可以学习的。输入资源名称时要密切注意,错误可能描述性不够。对不起,如果浪费了任何人的宝贵时间。

【讨论】:

以上是关于为啥我的多阶段完整 yaml azure devops 管道在移动到模板时会中断?的主要内容,如果未能解决你的问题,请参考以下文章

Azure Pipelines Stages (YAML) 上的手动触发器

Azure Pipelines 将 YAML 用于具有不同变量值但没有 YAML 重复的多个环境(阶段)

Azure 管道 yaml 权限被拒绝

为啥 SonarQube 不从 yaml 构建更新 Azure DevOps 质量门状态?

Azure管道构建阶段验证

如何在 azure devops YAML 管道中将单个代理用于多个作业/阶段