如何解决Azure 管道 - terratest - 错误:请运行“az login”来设置帐户
我正面临 Azure Pipeline 中的(它接缝)重复性 pbm 来运行 terratest。
虽然资源很好地被破坏,但当我调用 azure.ResourceGroupExists 函数(或其他任何 azure.xxx 函数)时,我有以下错误:
--- FAIL: Testterraform_RM_resource_group (102.30s)
resourcegroup.go:15:
Error Trace: resourcegroup.go:15
RM_resource_group_test.go:108
Error: Received unexpected error:
Invoking Azure CLI Failed with the following error: ERROR: Please run 'az login' to setup account.
Test: Testterraform_RM_resource_group
FAIL
关于一些论坛,这似乎是一些配置问题,我遵循所有这些推荐的配置:
- 为 terraform 设置环境变量: -- ARM_CLIENT_ID -- ARM_CLIENT_SECRET -- ARM_SUBSCRIPTION_ID -- ARM_TENANT_ID
- 在 terratest 的 go 任务之外设置 AzureCli 任务中的 az 登录名,因为 terratest 似乎需要 2 种不同的身份验证:(此 az 登录名使用服务主体客户端 ID)
- 对于断言测试,需要 ARM_CLIENT 身份验证
- 对于 Exists 测试,需要服务连接身份验证
这里是我关注的链接:
- https://github.com/gruntwork-io/terratest/issues/454
- https://github.com/gruntwork-io/terratest/tree/master/examples/azure#review-environment-variables
- https://github.com/gruntwork-io/terratest/blob/master/modules/environment/envvar.go
- https://blog.jcorioland.io/archives/2019/09/25/terraform-microsoft-azure-ci-docker-azure-pipeline.html
下面是我的管道代码,其中 TF_VAR_ARM_CLIENT_SECRET 是管道的秘密变量
runOnce:
deploy:
steps:
- checkout: self
- task: ms-devlabs.custom-terraform-tasks.custom-terraform-installer-task.terraformInstaller@0
displayName: 'Install terraform $(terraform_VERSION)'
inputs:
terraformVersion: $(terraform_VERSION)
- task: GoTool@0
displayName: 'Use Go $(GOVERSION)'
inputs:
version: $(GOVERSION)
goPath: $(GOPATH)
goBin: $(GOBIN)
- task: Go@0
displayName: 'Install Go Terratest module'
inputs:
command: get
arguments: '$(TF_LOG) github.com/gruntwork-io/terratest/modules/terraform'
- task: Go@0
displayName: 'Install Go Assert module'
inputs:
command: get
arguments: '$(TF_LOG) github.com/stretchr/testify/assert'
- task: Go@0
displayName: 'Install Go Terratest Azure module'
inputs:
command: get
arguments: '$(TF_LOG) github.com/gruntwork-io/terratest/modules/azure'
- task: Go@0
displayName: 'Install Go hashicorp/terraform-json module'
inputs:
command: get
arguments: '$(TF_LOG) github.com/hashicorp/terraform-json'
- task: Go@0
displayName: 'Install Go azure-sdk-for-go module'
inputs:
command: get
arguments: '$(TF_LOG) github.com/Azure/azure-sdk-for-go'
- task: AzureCLI@2
displayName: Azure CLI
inputs:
azureSubscription: $(serviceConnection)
scriptType: ps
scriptLocation: inlinescript
inlinescript: |
az login --service-principal --username $(TF_VAR_ARM_CLIENT_ID) --password $(TF_VAR_ARM_CLIENT_SECRET) --tenant 'f5ff14e7-93c8-49f7-9706-7beea059bd32'
# Go test command
- task: Go@0
displayName: 'Run Go terratest for resource_Modules'
inputs:
command: test
arguments: '$(TF_LOG) $(pathToterraformRootModule)\resource_group\'
env:
ARM_CLIENT_SECRET: $(TF_VAR_ARM_CLIENT_SECRET) #pipeline secret variable
ARM_CLIENT_ID: $(TF_VAR_ARM_CLIENT_ID)
ARM_SUBSCRIPTION_ID: $(TF_VAR_ARM_SUBSCRIPTION_ID)
ARM_TENANT_ID: $(TF_VAR_ARM_TENANT_ID)
TF_VAR_SERVICE_PRINCIPAL_ID: $(TF_VAR_ARM_CLIENT_ID)
TF_VAR_SERVICE_PRINCIPAL_SECRET: $(TF_VAR_ARM_CLIENT_ID)
resource_group_name: $(storageAccountResourceGroup)
storage_account_name: $(storageAccount)
container_name: $(stateBlobContainer)
key: '$(MODULE)-$(TF_VAR_APPLICATION)-${{ parameters.Environment }}.tfstate'
请听我的 go terratest 代码:
package RM_resource_group_Test
import (
"testing"
"os"
"github.com/gruntwork-io/terratest/modules/azure"
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/assert"
)
var (
globalBackendConf = make(map[string]interface{})
globalEnvVars = make(map[string]string)
)
func Testterraform_RM_resource_group(t *testing.T) {
t.Parallel()
// terraform Directory
fixtureFolder := "./"
// input value
inputStage := "demo_we"
inputEnvironment := "DEMO"
inputApplication := "DEMO"
// expected value
expectedname := "z-adf-ftnd-shrd-dm-ew1-rgp42"
// getting enVars from environment variables
ARM_CLIENT_ID := os.Getenv("ARM_CLIENT_ID")
ARM_CLIENT_SECRET := os.Getenv("ARM_CLIENT_SECRET")
ARM_SUBSCRIPTION_ID := os.Getenv("ARM_SUBSCRIPTION_ID")
ARM_TENANT_ID := os.Getenv("ARM_TENANT_ID")
if ARM_CLIENT_ID != "" {
globalEnvVars["ARM_USE_MSI"] = "false"
globalEnvVars["ARM_CLIENT_ID"] = ARM_CLIENT_ID
globalEnvVars["ARM_CLIENT_SECRET"] = ARM_CLIENT_SECRET
globalEnvVars["ARM_SUBSCRIPTION_ID"] = ARM_SUBSCRIPTION_ID
globalEnvVars["ARM_TENANT_ID"] = ARM_TENANT_ID
}
// getting backend vars from environment variables
resource_group_name := os.Getenv("resource_group_name")
storage_account_name := os.Getenv("storage_account_name")
container_name := os.Getenv("container_name")
key := os.Getenv("key")
if resource_group_name != "" {
globalBackendConf["use_msi"] = false
globalBackendConf["resource_group_name"] = resource_group_name
globalBackendConf["storage_account_name"] = storage_account_name
globalBackendConf["container_name"] = container_name
globalBackendConf["key"] = key
}
// User Terratest to deploy the infrastructure
terraformOptions := terraform.WithDefaultRetryableErrors(t,&terraform.Options{
// The path to where our terraform code is located
terraformDir: fixtureFolder,// Variables to pass to our terraform code using -var options
Vars: map[string]interface{}{
"STAGE": inputStage,"ENVIRONMENT": inputEnvironment,"APPLICATION" : inputApplication,},EnvVars: globalEnvVars,// backend values to set when initialziing terraform
BackendConfig: globalBackendConf,// disable colors in terraform commands so its easier to parse stdout/stderr
NoColor: true,})
// website::tag::4::Clean up resources with "terraform destroy". Using "defer" runs the command at the end of the test,whether the test succeeds or fails.
// At the end of the test,run `terraform destroy` to clean up any resources that were created
defer terraform.Destroy(t,terraformOptions)
// website::tag::2::Run "terraform init" and "terraform apply".
// This will run `terraform init` and `terraform apply` and fail the test if there are any errors
terraform.InitAndApply(t,terraformOptions)
actualName := terraform.Output(t,terraformOptions,"tested_name")
actualReaderName := terraform.Output(t,"tested_readerName")
assert.Equal(t,expectedname,actualName)
assert.Equal(t,actualReaderName)
subscriptionID := terraform.Output(t,"current_subscription_id")
exists := azure.ResourceGroupExists(t,subscriptionID)
assert.True(t,exists,"Resource group does not exist")
}
我确定我在传递参数时遗漏了一些东西,在创建和销毁 Azure 中的资源后,一如既往地出现以下错误:
--- FAIL: Testterraform_RM_resource_group (90.75s)
resourcegroup.go:15:
Error Trace: resourcegroup.go:15
RM_resource_group_test.go:108
Error: Received unexpected error:
Invoking Azure CLI Failed with the following error: ERROR: Please run 'az login' to setup account.
Test: Testterraform_RM_resource_group
请帮忙。
解决方法
感谢您的回答..
正如我之前发现的,这是一个配置错误,在对 Go Terratest Azure 模块进行了一些深入挖掘之后,我发现这些行给出了所有解释:
- https://github.com/gruntwork-io/terratest/blob/master/modules/azure/authorizer.go#L11 导致
- https://docs.microsoft.com/en-us/azure/developer/go/azure-sdk-authorization#use-environment-based-authentication
所以我将管道更改为:
# Go test command
- task: Go@0
displayName: 'Run Go terratest for resource_Modules'
inputs:
command: test
arguments: '$(TF_LOG) $(pathToTerraformRootModule)\...'
env:
ARM_SUBSCRIPTION_ID: $(TF_VAR_ARM_SUBSCRIPTION_ID)
AZURE_CLIENT_ID: $(TF_VAR_ARM_CLIENT_ID)
AZURE_TENANT_ID: $(TF_VAR_ARM_TENANT_ID)
AZURE_CLIENT_SECRET: $(TF_VAR_ARM_CLIENT_SECRET)
resource_group_name: $(storageAccountResourceGroup)
storage_account_name: $(storageAccount)
container_name: $(stateBlobContainer)
key: '$(MODULE)-$(TF_VAR_APPLICATION)-${{ parameters.Environment }}.tfstate'
和我的 Go 代码(关于 envVariables 的使用):
// getting enVars from environment variables
ARM_CLIENT_ID := os.Getenv("AZURE_CLIENT_ID")
ARM_CLIENT_SECRET := os.Getenv("AZURE_CLIENT_SECRET")
ARM_TENANT_ID := os.Getenv("AZURE_TENANT_ID")
ARM_SUBSCRIPTION_ID := os.Getenv("ARM_SUBSCRIPTION_ID")
// creating globalEnVars for terraform call through Terratest
if ARM_CLIENT_ID != "" {
//globalEnvVars["ARM_USE_MSI"] = "true"
globalEnvVars["ARM_CLIENT_ID"] = ARM_CLIENT_ID
globalEnvVars["ARM_CLIENT_SECRET"] = ARM_CLIENT_SECRET
globalEnvVars["ARM_SUBSCRIPTION_ID"] = ARM_SUBSCRIPTION_ID
globalEnvVars["ARM_TENANT_ID"] = ARM_TENANT_ID
}
// getting backend vars from environment variables
resource_group_name := os.Getenv("resource_group_name")
storage_account_name := os.Getenv("storage_account_name")
container_name := os.Getenv("container_name")
key := os.Getenv("key")
// creating globalBackendConf for terraform call through Terratest
if resource_group_name != "" {
//globalBackendConf["use_msi"] = true
globalBackendConf["resource_group_name"] = resource_group_name
globalBackendConf["storage_account_name"] = storage_account_name
globalBackendConf["container_name"] = container_name
globalBackendConf["key"] = key
}
// User Terratest to deploy the infrastructure
terraformOptions := terraform.WithDefaultRetryableErrors(t,&terraform.Options{
// website::tag::1::Set the path to the Terraform code that will be tested.
// The path to where our Terraform code is located
TerraformDir: fixtureFolder,// Variables to pass to our Terraform code using -var options
Vars: map[string]interface{}{
"STAGE": inputStage,"ENVIRONMENT": inputEnvironment,"APPLICATION" : inputApplication,//"configuration" : inputConfiguration,},// globalvariables for user account
EnvVars: globalEnvVars,// backend values to set when initialziing Terraform
BackendConfig: globalBackendConf,// Disable colors in Terraform commands so its easier to parse stdout/stderr
NoColor: true,})
一切顺利! 希望这可以帮助其他人。
再次感谢。
[编辑] 更明确:
Go 和 Terraform 使用两种不同的 Azure 身份验证方法。
** Terraform 身份验证解释如下:
** Go 认证解释如下:
** Terratest 正在使用两种认证方法来处理它必须完成的工作:
- azure 存在性测试使用 Go azure 身份验证:
- terraform 命令使用 terraform 身份验证:
所以两种认证方法都必须实现
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。