Я создал новый файл Pipeline.yml, который при запуске создает несколько ресурсов с помощью Terraform. Когда они уже созданы, конкретный этап следует пропустить и проверять только текущее состояние.
parameters:
- name: myConn
type: string
default: 'dev'
variables:
- group: dev-group
- name: workingDirectory
value: '$(Build.SourcesDirectory)/configs'
stages:
- stage: Just_printing
displayName: 'Printing some variables'
jobs:
- job: PrintJobs
displayName: 'Print Job'
steps:
- script: |
echo "printing directory: $(Build.SourcesDirectory)"
cd $(Build.SourcesDirectory)
ls -lha $(Build.SourcesDirectory)
- script: |
echo "printing directory: $(workingDirectory)"
cd $(workingDirectory)
ls -lha $(workingDirectory)
- stage: Deployment
displayName: 'Terraform deploy'
dependsOn:
- Just_printing
jobs:
- deployment: terraform
environment:
name: dev
pool: "server"
strategy:
runOnce:
deploy:
steps:
- task: ManualValidation@0
timeoutInMinutes: 1440
inputs:
notifyUsers: |
[email protected]
instructions: "approving..."
onTimeout: "reject"
- job: "TerraformApprove"
displayName: "Deployment ..."
dependsOn: terraform
steps:
- task: TerraformCLI@0
displayName: 'Terraform Init'
inputs:
command: init
backendType: gcs
backendGcsCredentials: ${{ parameters.myConn}}
backendGcsBucket: 'dev-state'
workingDirectory: $(workingDirectory)
- task: TerraformCLI@0
displayName: 'Terraform Plan'
name: plan
inputs:
command: plan
publishPlanResults: 'TerraformPlan'
workingDirectory: $(workingDirectory)
commandOptions: '-out=$(Build.SourcesDirectory)/configs/tf.tfplan'
providerGoogleCredentials: ${{ parameters.myConn}}
- task: PublishBuildArtifacts@1
displayName: 'Publish Terraform Plan'
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/configs/tf.tfplan'
artifactName: 'Plan'
- task: TerraformCLI@0
displayName: 'Terraform Apply'
inputs:
command: apply
workingDirectory: $(workingDirectory)
commandOptions: '$(Build.SourcesDirectory)/configs/tf.tfplan'
providerGoogleCredentials: ${{ parameters.myConn}}
- stage: Just_state
displayName: 'Just_state'
dependsOn: Deployment
jobs:
- job: Just_state
displayName: 'Just state Job'
steps:
- task: TerraformCLI@0
displayName: 'Terraform Init'
inputs:
command: init
backendType: gcs
backendGcsCredentials: ${{ parameters.myConn}}
backendGcsBucket: 'dev-state'
workingDirectory: $(workingDirectory)
commandOptions: '-reconfigure'
- task: TerraformCLI@0
displayName: 'terraform state list'
inputs:
command: state
workingDirectory: $(workingDirectory)
stateSubCommand: list
commandOptions: '-state=$(Build.SourcesDirectory)/configs/tf.tfstate'
Я хотел бы пропустить весь этап развертывания, когда terraform проверяет, не было ли изменений в ресурсе до последнего запуска конвейера. Я не уверен, как этого добиться.
Попробовал использовать скрипт bash на этапе Just_printing, который только проверяет, были ли внесены изменения, и, если нет, пропускает весь этап развертывания, однако на моей стороне возникло множество ошибок, и я застрял. Наконец, на этапе Just_state он проверяет только текущие развернутые ресурсы.
РЕДАКТИРОВАТЬ 1.
Добавлено в соответствии с ответом ниже, однако каждое мое изменение вызывает разные ошибки. Обычно это приводит к проблеме с учетными данными, но я не знаю, как передать их в предоставленном сценарии.
Текущая ошибка при запуске этого конвейера::
Инициализация серверной части... │ Ошибка: Google: не удалось найти значение по умолчанию. реквизиты для входа. Видеть https://cloud.google.com/docs/authentication/external/set-up-adc для Дополнительная информация
Фрагмент кода для Pipeline.yaml
- job: CheckChanges
displayName: 'Check Changes'
steps:
- task: Bash@3
displayName: 'Check resource changes'
name: setvar
inputs:
backendType: gcs
backendGcsCredentials: ${{ parameters.myConn}}
backendGcsBucket: 'dev-state'
workingDirectory: $(workingDirectory)
targetType: 'inline'
script: |
cd $(workingDirectory)
terraform init -reconfigure -backend-config = "bucket=dev-state" -backend-config = "[email protected]"
terraform plan -input=false -no-color -detailed-exitcode
retVal=$?
if [ $retVal -eq 2 ]; then
echo "##vso[task.setvar variable=deploy;isOutput=true]true"
else
echo "##vso[task.setvar variable=deploy;isOutput=true]false"
fi
- stage: Deployment
displayName: 'Terraform deploy'
dependsOn: Just_printing
condition: eq(dependencies.Just_printing.outputs['CheckChanges.setvar.deploy'], 'true')
jobs:
- deployment: terraform
К вашему сведению:
Я попробую, дайте мне несколько дней. В любом случае спасибо за очень быстрое обновление.
Привет @Kreg, ты пробовал yaml ниже? Это сработало для вас?
Спасибо @ZiyangLiu-MSFT за первый и быстрый ответ. Я ответил в EDIT 1, так как текста для комментариев слишком много.
В моем реальном тесте я использую сервисный принцип аутентификации в Azure и использую azurerm бэкэнд. Я обновил свой ответ ниже для вашей справки.





Как упоминалось в этом вопросе , вы можете использовать опцию -detailed-exitcode в terraform plan, чтобы проверить, есть ли какие-либо изменения. Согласно Команде: план,
-detailed-exitcode— Возвращает подробный код выхода при завершении команды. Если этот аргумент предоставлен, он изменяет коды выхода и их значения, чтобы предоставить более подробную информацию о том, что содержит результирующий план:
- 0 = успешно с пустым диффом (без изменений)
- 1 = Ошибка
- 2 = успешно с непустым diff (присутствуют изменения)
Затем создайте выходную переменную , в моем примере ниже это deploy, чтобы контролировать, запускать ли Deployment этап. Когда значение retVal равно 2, установите значение deploy на true. В противном случае установите значение false.
На этапе Deployment используйте condition, чтобы контролировать, что этап будет запускаться только тогда, когда значение deploy равно true.
stages:
- stage: Just_printing
displayName: 'Printing some variables'
jobs:
- job: CheckChanges
displayName: 'Check Changes'
steps:
- task: Bash@3
displayName: 'Check resource changes'
name: setvar
env:
ARM_CLIENT_ID: ${{ parameters.clientId }}
ARM_CLIENT_SECRET: $(clientSecret)
ARM_TENANT_ID: ${{ parameters.tenantId }}
ARM_SUBSCRIPTION_ID: ${{ parameters.deploymentSubscriptionId }}
inputs:
targetType: 'inline'
script: |
terraform init -backend-config = "resource_group_name = {resource group which holds my storage account}" -backend-config = "storage_account_name = {storage account name}" -backend-config = "container_name = {container name}" -backend-config = "key=terraform.tfstate" -backend-config = "subscription_id = {Sub id}"
terraform plan -input=false -no-color -detailed-exitcode
retVal=$?
if [ $retVal -eq 2 ]; then
echo "##vso[task.setvariable variable=deploy;isOutput=true]true"
else
echo "##vso[task.setvariable variable=deploy;isOutput=true]false"
fi
- stage: Deployment
displayName: 'Terraform deploy'
dependsOn: Just_printing
condition: eq(dependencies.Just_printing.outputs['CheckChanges.setvar.deploy'], 'true')
jobs:
- deployment: terraform
...
В приведенном выше примере я использую принцип службы для аутентификации в Azure и сохраняю учетные данные как переменные среды. (По соображениям безопасности ARM_CLIENT_SECRET предоставляется через секретную переменную clientSecret) Вы также можете предоставить учетные данные в блоке вашего провайдера. Подробности см. в разделе Аутентификация с использованием принципала службы с секретом клиента. Убедитесь, что у вашего принципала службы достаточно разрешений для развертывания целевого ресурса. Вы можете назначить ему роль участника вашего подписчика.
Я использую бэкэнд azurerm и настраиваю его с помощью команды. Вы также можете настроить бэкэнд в блоке backend "azurerm". См. пример здесь Примеры конфигураций серверной части.