问题描述
在构建一个Packer流水线时,我遇到了一个问题:无法在Powershell provisioner步骤的测试失败时使Packer作业本身失败。这一点很重要,因为如果不使Packer作业失败,AMI将被发布,尽管测试失败。
我的操作步骤如下:
1. 运行设置步骤进行配置。
2. 将Pester脚本复制到远程机器。
3. 使用内联PowerShell语句调用Invoke-Pester
进行测试。
4. 从远程运行的Pester测试中下载测试结果。
5. 接下来的配置步骤解析文件以计算错误数量,并在问题数大于0时抛出错误。
然而,即使错误数大于0,它也没有导致流水线中止。此外,其他配置步骤中抛出的一些错误也未能导致Packer作业停止。我在其中一个步骤上设置了$ErrorActionPreference = 'Stop'
,但似乎没有任何改变。
以下是Packer的一部分配置流程:
...
{
"type": "file",
"source": "{{ template_dir }}/tests/windows-server.tests.ps1",
"destination": "{{ user `TEMP_DIRECTORY` }}"
},
{
"type": "powershell",
"environment_vars": [
"TEMP_DIRECTORY={{ user `TEMP_DIRECTORY` }}/"
],
"inline": [
"if(-not (Get-InstalledModule Pester -MinimumVersion 4.10.1)){ Install-Module Pester -Scope AllUsers -AllowClobber -Force -verbose}",
"Import-Module Pester -MinimumVersion 4.10.1 -Force -DisableNameChecking",
"$null = New-Item -Path $ENV:TEMP_DIRECTORY -ItemType Directory -Force -ErrorAction SilentlyContinue",
"$testresult = Invoke-Pester -Script (Join-Path $ENV:TEMP_DIRECTORY 'windows-server.tests.ps1') -OutputFile (Join-Path $ENV:TEMP_DIRECTORY 'TEST-pester-results.xml') -OutputFormat 'NUnitXML' -PassThru"
]
},
{
"type": "file",
"direction": "download",
"source": "{{ user `TEMP_DIRECTORY` }}/TEST-pester-results.xml",
"destination": "{{ template_dir }}/artifacts/TEST-pester-results.xml"
},
...
完成上述部分后,会执行下面的步骤,其中包含一些来自此博客文章的逻辑:
{
"environment_vars": [
"TEMP_DIRECTORY={{ user `TEMP_DIRECTORY` }}/"
],
"script": "./scripts/Get-TestResults.ps1",
"type": "powershell"
}
Get-TestResults.ps1
脚本如下,感谢这篇文章提供的帮助:
[cmdletbinding()]
param()
$TestFile = Join-Path $ENV:TEMP_DIRECTORY 'TEST-pester-results.xml'
if (Test-Path -Path $TestFile -PathType Leaf) {
[xml]$testResults = Get-Content -Path $TestFile -Raw
$totalIssues = [int]$($testResults.'test-results'.errors) + [int]$($testResults.'test-results'.failures) + [int]$($testResults.'test-results'.invalid)
exit $totalIssues
} else {
Write-Error " Failed to find `$TestFile: $TestFile"
Write-Warning "$(Get-ChildItem $ENV:TEMP_DIRECTORY -Recurse | Format-Table -autosize -wrap | Out-String)"
Write-Error " Failed to find `$TestFile: $TestFile"
exit 1
}
解决方案
请注意以下操作可能存在版本差异,修改前请备份。
解决方案1
在处理上述问题时,你需要确保在PowerShell provisioner的步骤中,错误的发生能够正确中止Packer作业。为此,你需要在出现错误时抛出一个非零的退出代码。
下面是一个解决方案示例,使用$ErrorActionPreference = 'Stop'
来确保错误能够中止脚本,然后在出现错误时抛出一个非零的退出代码:
$ErrorActionPreference = 'Stop'
try {
# 在此处执行操作
} catch {
Write-Error "发生了重要错误: $_"
exit 1 # Packer将会在此时识别到失败
}
解决方案2
要使Packer作业在Powershell provisioner步骤失败时中止,你需要设置Azure DevOps Pipeline以便无论是否失败都能发布测试结果。你可以按如下方式配置:
- task: PowerShell@2
displayName: 运行Packer配置
inputs:
filePath: build/build.ps1
arguments: '-Task PackerBuild -Configuration $(Configuration)'
errorActionPreference: 'Continue'
pwsh: true
continueOnError: true # 我希望无论如何都能发布测试结果
- task: PublishTestResults@2
displayName: 发布Pester测试结果
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: '**/TEST-*.xml'
condition: succeededOrFailed()
总结
通过在PowerShell provisioner的步骤中正确设置$ErrorActionPreference
以及抛出适当的退出代码,你可以使Packer作业在Pester测试失败时中止,并确保测试结果的发布。
希望这些解决方案能够帮助你解决Packer流水线中的问题。如果你在实施解决方案时遇到任何问题,欢迎随时提问。