Greetings my fellow Technology Advocates and Specialists!!!
This Blog post is a follow-up to my previous post - Publish Terraform Plan in Azure DevOps GUI
In this Session, I will demonstrate how to Publish Terraform Plan in Azure DevOps GUI Using PIPELINE TEMPLATES.
THIS IS HOW IT LOOKS AT THE END!!!
Azure Subscription.
Azure DevOps Organisation and Project.
Service Principal with Delegated Graph API Rights and Required RBAC (Typically Contributor on Subscription or Resource Group)
Azure Resource Manager Service Connection in Azure DevOps.
Azure Pipelines Terraform Tasks Extension by Charles Zipp Installed in Azure DevOps.
CODE REPOSITORY:-
TERRAFORM PLAN IN DEVOPS GUI USING TEMPLATES
TERRAFORM PLAN IN DEVOPS GUI USING TEMPLATES
Greetings my fellow Technology Advocates and Specialists!!!
This Blog post is a follow-up to my previous post - [Publish Terraform Plan in Azure DevOps GUI] (https://dev.to/arindam0310018/terraform-plan-in-devops-gui-52fp )
In this Session, I will demonstrate how to Publish Terraform Plan in Azure DevOps GUI Using PIPELINE TEMPLATES.
THIS IS HOW IT LOOKS AT THE END!!!
Azure Subscription.
Azure DevOps Organisation and Project.
Service Principal with Delegated Graph API Rights and Required RBAC (Typically Contributor on Subscription or Resource Group)
Azure Resource Manager Service Connection in Azure DevOps.
Azure Pipelines Terraform Tasks Extension by Charles Zipp Installed in Azure DevOps.
OBJECTIVE:-
Deploy a Resource Group and Log Analytics Workspace.
Publish the Terraform Plan in Azure DevOps GUI using Pipeline Templates.
HOW DOES MY CODE PLACEHOLDER LOOKS LIKE:-
…
OBJECTIVE:-
Deploy a Resource Group and Log Analytics Workspace.
Publish the Terraform Plan in Azure DevOps GUI using Pipeline Templates.
HOW DOES MY CODE PLACEHOLDER LOOKS LIKE:-
ORDER OF THE PIPELINES:-
Below is the order, the Pipelines are called -
azure-pipelines-v1.0.yml
azure-pipelines-v1.0-Main.yml
azure-pipelines-v1.0-PublishPlan.yml
azure-pipelines-v1.0-Validate.yml
azure-pipelines-v1.0-Deploy.yml
ADVANTAGES WITH PIPELINE TEMPLATES:-
1. Scalable
2. Advocates DRY (Don't repeat yourself) Principle
3. Each YAML Pipeline file (Template) can be a Task or a Stage
AZURE DEVOPS YAML PIPELINE TEMPLATE (azure-pipelines-v1.0.yml):-
trigger:
none
stages:
- template: ./azure-pipelines-v1.0-Main.yml
parameters:
container_name: "terraform"
container_key: "PUBLISH-TF-PLAN/LogaPublishTFPlan.tfstate"
environment_name: "NonProd"
planfilename: "tfplan"
tfvarfilename: "loga.tfvars"
root_directory: "/Publish-TF-Plan-In-GUI-DevOps-Templates"
service_connection_name: "amcloud-cicd-service-connection"
backend_resource_group: "tfpipeline-rg"
backend_storage_accountname: "tfpipelinesa"
storageAccountSku: "Standard_LRS"
pool:
vmImage: "ubuntu-latest"
terraformVersion: "latest"
environment_name_Job: "ARINDAM_DEPLOYMENT"
Enter fullscreen mode
Exit fullscreen mode
NOTE:-
No User Input Required.
Any Parameters Value can be changed.
All YAML pipelines templates are build using Parameters. No Values are Hardcoded.
AZURE DEVOPS YAML PIPELINE TEMPLATE (azure-pipelines-v1.0-Main.yml):-
parameters:
container_name:
container_key:
environment_name:
planfilename:
tfvarfilename:
root_directory:
service_connection_name:
backend_resource_group:
backend_storage_accountname:
storageAccountSku:
environment_name_Job:
terraformVersion:
pool:
vmImage:
stages:
- stage: Publish_Plan
jobs:
- template: azure-pipelines-v1.0-PublishPlan.yml
parameters:
container_name: ${{ parameters.container_name }}
container_key: ${{ parameters.container_key }}
environment_name: ${{ parameters.environment_name }}
planfilename: ${{ parameters.planfilename }}
tfvarfilename: ${{ parameters.tfvarfilename }}
root_directory: ${{ parameters.root_directory }}
service_connection_name: ${{ parameters.service_connection_name }}
backend_resource_group: ${{ parameters.backend_resource_group }}
backend_storage_accountname: ${{ parameters.backend_storage_accountname }}
backendAzureRmStorageAccountSku: ${{ parameters.backend_storageAccountSku }}
terraformVersion: ${{ parameters.terraformVersion }}
pool: ${{ parameters.pool }}
- stage: Validate
jobs:
- template: azure-pipelines-v1.0-Validate.yml
parameters:
container_name: ${{ parameters.container_name }}
container_key: ${{ parameters.container_key }}
environment_name: ${{ parameters.environment_name }}
planfilename: ${{ parameters.planfilename }}
tfvarfilename: ${{ parameters.tfvarfilename }}
root_directory: ${{ parameters.root_directory }}
service_connection_name: ${{ parameters.service_connection_name }}
backend_resource_group: ${{ parameters.backend_resource_group }}
backend_storage_accountname: ${{ parameters.backend_storage_accountname }}
backendAzureRmStorageAccountSku: ${{ parameters.backend_storageAccountSku }}
terraformVersion: ${{ parameters.terraformVersion }}
pool: ${{ parameters.pool }}
- stage: Deploy
condition: |
and(succeeded(),
eq(variables['build.sourceBranch'], 'refs/heads/main')
)
dependsOn: "Validate"
jobs:
- deployment: ${{ parameters.environment_name_job }}
pool:
vmImage: ${{ parameters.vmImage }}
displayName: Deploy
environment: ${{ parameters.environment_name }}
strategy:
runOnce:
deploy:
steps:
- template: azure-pipelines-v1.0-Deploy.yml
parameters:
container_name: ${{ parameters.container_name }}
container_key: ${{ parameters.container_key }}
environment_name: ${{ parameters.environment_name }}
tfvarfilename: ${{ parameters.tfvarfilename }}
root_directory: ${{ parameters.root_directory }}
service_connection_name: ${{ parameters.service_connection_name }}
backend_resource_group: ${{ parameters.backend_resource_group }}
backend_storage_accountname: ${{ parameters.backend_storage_accountname }}
backendAzureRmStorageAccountSku: ${{ parameters.backend_storageAccountSku }}
terraformVersion: ${{ parameters.terraformVersion }}
Enter fullscreen mode
Exit fullscreen mode
This is a 3 Stage Pipeline Template.
The Names of the Stages are - a) PUBLISH_PLAN b) VALIDATE, and c) DEPLOY
All Parameters defined in "azure-pipelines-v1.0.yml" are referenced in the above Pipeline "azure-pipelines-v1.0-Main.yml".
PUBLISH_PLAN Stage References to "azure-pipelines-v1.0-PublishPlan.yml".
VALIDATE Stage References to "azure-pipelines-v1.0-Validate.yml".
DEPLOY Stage References to "azure-pipelines-v1.0-Deploy.yml".
DEPLOY Stage will Execute only if the following conditions are met - a) VALIDATE Stage gets completed successfully. b) Source Branch = Main. If not, DEPLOY Stage will get Skipped Automatically.
DEPLOY Stage will Execute only after Approval. The Approval is integrated with Environment defined in the Pipeline Parameters Section.
AZURE DEVOPS YAML PIPELINE TEMPLATE (azure-pipelines-v1.0-PublishPlan.yml):-
parameters:
container_name:
container_key:
environment_name:
planfilename:
tfvarfilename:
root_directory:
service_connection_name:
backend_resource_group:
backend_storage_accountname:
storageAccountSku:
environment_name_Job:
terraformVersion:
pool:
vmImage:
jobs:
- job: Publish_Plan
pool: ${{ parameters.pool }}
steps:
# Install Terraform Installer in the Build Agent:-
- task: ms-devlabs.custom-terraform-tasks.custom-terraform-installer-task.TerraformInstaller@0
displayName: INSTALL TERRAFORM VERSION
inputs:
terraformVersion: ${{ parameters.terraformVersion }}
# Terraform Init:-
- task: TerraformCLI@0
displayName: TERRAFORM INIT
inputs:
backendType: 'azurerm'
command: 'init'
workingDirectory: '$(System.DefaultWorkingDirectory)/${{ parameters.root_directory }}'
backendServiceArm: ${{ parameters.service_connection_name }}
backendAzureRmResourceGroupName: ${{ parameters.backend_resource_group }}
backendAzureRmStorageAccountName: ${{ parameters.backend_storage_accountname }}
backendAzureRmStorageAccountSku: ${{ parameters.backend_storageAccountSku }}
backendAzureRmContainerName: ${{ parameters.container_name }}
backendAzureRmKey: ${{ parameters.container_key }}
# Terraform Validate:-
- task: TerraformCLI@0
displayName: TERRAFORM VALIDATE
inputs:
backendType: 'azurerm'
command: 'validate'
workingDirectory: '$(System.DefaultWorkingDirectory)/${{ parameters.root_directory }}'
environmentServiceName: ${{ parameters.service_connection_name }}
# Terraform Plan:-
- task: TerraformCLI@0
displayName: TERRAFORM PLAN
inputs:
backendType: 'azurerm'
command: 'plan'
workingDirectory: '$(System.DefaultWorkingDirectory)/${{ parameters.root_directory }}'
commandOptions: "--var-file=${{ parameters.tfvarfilename }} --out=${{ parameters.planfilename }}"
environmentServiceName: ${{ parameters.service_connection_name }}
publishPlanResults: 'tfplan'
Enter fullscreen mode
Exit fullscreen mode
PUBLISH_PLAN STAGE PERFORMS BELOW:-
##
TASKS
1.
Terraform Installer installed in Azure DevOps Build Agent.
2.
Terraform Init
3.
Terraform Validate
4.
Terraform Plan
5.
Publish Terraform Plan in Azure DevOps GUI.
- task: ms-devlabs.custom-terraform-tasks.custom-terraform-installer-task.TerraformInstaller@0
Enter fullscreen mode
Exit fullscreen mode
EXPLANATION:-
Instead of using TerraformInstaller@0 YAML Task, I have specified the Full Name. This is because I have two Terraform Extensions in my DevOps Organisation and with each of the Terraform Extension, exists the Terraform Install Task
The Names of the Extensions are listed below:-
1. Terraform by Microsoft DevLabs
2. Azure Pipelines Terraform Tasks by Charles Zipp
If Full Name is not provided , then below Error is Encountered :-
Alternatively , below can also be used as Full Name:-
- task: charleszipp.azure-pipelines-tasks-terraform.azure-pipelines-tasks-terraform-installer.TerraformInstaller@0
Enter fullscreen mode
Exit fullscreen mode
AZURE DEVOPS YAML PIPELINE TEMPLATE (azure-pipelines-v1.0-Validate.yml):-
parameters:
container_name:
container_key:
environment_name:
planfilename:
tfvarfilename:
root_directory:
service_connection_name:
backend_resource_group:
backend_storage_accountname:
storageAccountSku:
environment_name_Job:
terraformVersion:
pool:
vmimage:
jobs:
- job: Validate
pool: ${{ parameters.pool }}
steps:
# Install Terraform Installer in the Build Agent:-
- task: ms-devlabs.custom-terraform-tasks.custom-terraform-installer-task.TerraformInstaller@0
displayName: INSTALL TERRAFORM VERSION
inputs:
terraformVersion: ${{ parameters.terraformVersion }}
# Terraform Init:-
- task: TerraformCLI@0
displayName: TERRAFORM INIT
inputs:
backendType: 'azurerm'
command: 'init'
workingDirectory: '$(System.DefaultWorkingDirectory)/${{ parameters.root_directory }}'
backendServiceArm: ${{ parameters.service_connection_name }}
backendAzureRmResourceGroupName: ${{ parameters.backend_resource_group }}
backendAzureRmStorageAccountName: ${{ parameters.backend_storage_accountname }}
backendAzureRmStorageAccountSku: ${{ parameters.backend_storageAccountSku }}
backendAzureRmContainerName: ${{ parameters.container_name }}
backendAzureRmKey: ${{ parameters.container_key }}
# Terraform Validate:-
- task: TerraformCLI@0
displayName: TERRAFORM VALIDATE
inputs:
backendType: 'azurerm'
command: 'validate'
workingDirectory: '$(System.DefaultWorkingDirectory)/${{ parameters.root_directory }}'
environmentServiceName: ${{ parameters.service_connection_name }}
# Terraform Plan:-
- task: TerraformCLI@0
displayName: TERRAFORM PLAN
inputs:
backendType: 'azurerm'
command: 'plan'
workingDirectory: '$(System.DefaultWorkingDirectory)/${{ parameters.root_directory }}'
commandOptions: "--var-file=${{ parameters.tfvarfilename }} --out=${{ parameters.planfilename }}"
environmentServiceName: '${{ parameters.service_connection_name }}'
# Copy Files to Artifacts Staging Directory:-
- task: CopyFiles@2
displayName: COPY FILES ARTIFACTS STAGING DIRECTORY
inputs:
SourceFolder: '$(System.DefaultWorkingDirectory)/${{ parameters.root_directory }}'
Contents: |
**/*.tf
**/*.tfvars
**/*tfplan*
TargetFolder: $(build.artifactstagingdirectory)/AMTF
# Publish Artifacts:-
- task: PublishBuildArtifacts@1
displayName: PUBLISH ARTIFACTS
inputs:
targetPath: $(build.artifactstagingdirectory)/AMTF
artifactName: 'drop'
Enter fullscreen mode
Exit fullscreen mode
VALIDATE STAGE PERFORMS BELOW:-
##
TASKS
1.
Terraform Installer installed in Azure DevOps Build Agent.
2.
Terraform Init
3.
Terraform Validate
4.
Terraform Plan
5.
Copy the Terraform files (Most Importantly Terraform Plan Output ) to Artifacts Staging Directory.
6.
Publish Artifacts
AZURE DEVOPS YAML PIPELINE TEMPLATE (azure-pipelines-v1.0-Deploy.yml):-
parameters:
container_name:
container_key:
environment_name:
planfilename:
tfvarfilename:
root_directory:
service_connection_name:
backend_resource_group:
backend_storage_accountname:
storageAccountSku:
environment_name_Job:
terraformVersion:
steps:
- download: none
- task: DownloadBuildArtifacts@0
displayName: 'Downloading ${{ parameters.environment_name }} Artifacts'
inputs:
buildType: 'current'
downloadType: 'single'
artifactName: 'drop'
downloadPath: '$(System.ArtifactsDirectory)'
# Install Terraform Installer in the Build Agent:-
- task: ms-devlabs.custom-terraform-tasks.custom-terraform-installer-task.TerraformInstaller@0
displayName: INSTALL TERRAFORM VERSION
inputs:
terraformVersion: ${{ parameters.terraformVersion }}
# Terraform Init:-
- task: TerraformCLI@0
displayName: TERRAFORM INIT
inputs:
backendType: 'azurerm'
command: 'init'
workingDirectory: '$(System.ArtifactsDirectory)/drop/AMTF'
backendServiceArm: ${{ parameters.service_connection_name }}
backendAzureRmResourceGroupName: ${{ parameters.backend_resource_group }}
backendAzureRmStorageAccountName: ${{ parameters.backend_storage_accountname }}
backendAzureRmStorageAccountSku: ${{ parameters.backend_storageAccountSku }}
backendAzureRmContainerName: ${{ parameters.container_name }}
backendAzureRmKey: ${{ parameters.container_key }}
# Terraform Apply:-
- task: TerraformCLI@0
displayName: TERRAFORM APPLY
inputs:
backendType: 'azurerm'
command: 'apply'
workingDirectory: '$(System.ArtifactsDirectory)/drop/AMTF'
commandOptions: "--var-file=${{ parameters.tfvarfilename }}"
environmentServiceName: ${{ parameters.service_connection_name }}
Enter fullscreen mode
Exit fullscreen mode
DEPLOY STAGE PERFORMS BELOW:-
##
TASKS
1.
Download the Published Artifacts.
2.
Terraform Installer installed in Azure DevOps Build Agent.
3.
Terraform Init
4.
Terraform Apply
DETAILS AND ALL TERRAFORM CODE SNIPPETS FOLLOWS BELOW:-
terraform {
required_version = ">= 1.2.0"
backend "azurerm" {
resource_group_name = "tfpipeline-rg"
storage_account_name = "tfpipelinesa"
container_name = "terraform"
key = "PUBLISH-TF-PLAN/LogaPublishTFPlan.tfstate"
}
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.2"
}
}
}
provider "azurerm" {
features {}
skip_provider_registration = true
}
Enter fullscreen mode
Exit fullscreen mode
# Azure Resource Group:-
resource "azurerm_resource_group" "rg" {
name = var.rg-name
location = var.rg-location
}
## Azure log Analytics Workspace:-
resource "azurerm_log_analytics_workspace" "loga" {
name = var.loga-name
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
sku = var.loga-sku
retention_in_days = var.loga-retention
depends_on = [azurerm_resource_group.rg]
}
Enter fullscreen mode
Exit fullscreen mode
TERRAFORM (variables.tf):-
variable "rg-name" {
type = string
description = "Name of the Resource Group"
}
variable "rg-location" {
type = string
description = "Resource Group Location"
}
variable "loga-name" {
type = string
description = "Name of the Log Analytics Workspace"
}
variable "loga-sku" {
type = string
description = "SKU the Log Analytics Workspace"
}
variable "loga-retention" {
type = string
description = "Retention Period of the Log Analytics Workspace"
}
Enter fullscreen mode
Exit fullscreen mode
TERRAFORM (loga.tfvars):-
rg-name = "AMTESTRG100"
rg-location = "West Europe"
loga-name = "AMLOGA100"
loga-sku = "PerGB2018"
loga-retention = "30"
Enter fullscreen mode
Exit fullscreen mode
ITS TIME TO TEST:-
DESIRED RESULT : Stages - PUBLISH_PLAN , VALIDATE and DEPLOY should Complete Successfully. Terraform Plan Gets Published Successfully in Azure DevOps GUI. Resource Group and Log Analytics Workspace Resources gets deployed.
PIPELINE STAGE PUBLISH_PLAN EXECUTED SUCCESSFULLY:-
TERRAFORM PLAN GETS PUBLISHED IN AZURE DEVOPS GUI:-
PIPELINE STAGE VALIDATE EXECUTED SUCCESSFULLY:-
PIPELINE STAGE DEPLOY WAITING APPROVAL:-
PIPELINE STAGE DEPLOY EXECUTED SUCCESSFULLY:-
PIPELINE OVERALL EXECUTION STATUS:-
VALIDATE RESOURCES DEPLOYED IN PORTAL:-
IMPORTANT TO NOTE:-
Terraform Plan are NOT PUBLISHED in Azure DevOps GUI unless there is a change in Infrastructure - ADD , DESTROY or CHANGE
In order to demonstrate, the same pipeline was re-run.
Hope You Enjoyed the Session!!!
Stay Safe | Keep Learning | Spread Knowledge
Top comments (0)