Using Terraform output values in Azure DevOps pipeline

Standard

Terraform logoWhen working with Terraform to deploy an infrastructure in an Azure DevOps pipeline, it is useful to use the output values in the following steps of your pipeline. Let’s see how we can achieve this easily.

Planning

For deploying Terraform templates to an infrastructure, I use the Terraform tasks library made by Microsoft.
Thanks to the output variables of the Terraform task, we are able to get a reference to a file containing the output values after a successful apply.
Now, all the work is to read this file to convert it to variables for Azure DevOps. For this we are going to use a YAML pipeline. However it should be possible to do it with a classic pipeline.

Execution

First of all, we need to give a name to the apply task of our pipeline, here we name it ‘terraformApply’.

- task: ms-devlabs.custom-terraform-tasks.custom-terraform-release-task.TerraformTaskV1@0
  name: terraformApply
  displayName: 'Terraform : validate and apply'
  inputs:
      command: apply
      workingDirectory: '$(Pipeline.Workspace)/terraform'
      commandOptions: 'tfplan'
      environmentServiceNameAzureRM: ${{variables.EnvironmentServiceArm}}
      backendServiceArm: ${{variables.BackendServiceArm}}
      backendAzureRmResourceGroupName: ${{variables.BackendResourceGroup}}
      backendAzureRmStorageAccountName: ${{variables.BackendStorageAccount}}
      backendAzureRmContainerName: ${{variables.BackendContainer}}
      backendAzureRmKey: ${{variables.BackendKey}}

Next step is parsing the file produced by the task above and convert it to variables. For this, we are going to use Powershell and the ability to define variables at runtime with the ##vso commands.
The produced file looks like this :

{
  "myapp_hostname": {
    "sensitive": false,
    "type": "string",
    "value": "myapp.azurewebsites.net"
  },
  "myapp_name": {
    "sensitive": false,
    "type": "string",
    "value": "myapp-dev"
  }
}

We need to iterate on each property, take in account if the variable is sensitive (if so we have to specify that it is a secret) and use the ##vso commands.
The corresponding task looks like this :

- powershell: |
    $terraformOutput = Get-Content "$(terraformApply.jsonOutputVariablesPath)" | ConvertFrom-Json
    $terraformOutput | Get-Member -MemberType NoteProperty | % { $o = $terraformOutput.($_.Name); Write-Host "##vso[task.setvariable variable=$($_.Name);isoutput=true;issecret=$($o.sensitive)]$($o.value)" }
  name: terraformOutput
  displayName: Read terraform outputs

We read the file (note that the jsonOutputVariablesPath variable is an output of the apply task, thus we need to prefix with the task name terraformApply), parse the json and then on each property we output the ##vso command with the parameter issecret if needed.

We are now ready to use it in the next tasks. Such as the following App Service deployment task:

- task: AzureRmWebAppDeployment@4
  displayName: 'Deploy MyApp'
  inputs:
    ConnectionType: 'AzureRM'
    azureSubscription: ${{variables.EnvironmentServiceArm}}
    appType: 'webApp'
    WebAppName: '$(terraformOutput.myapp_name)'
    packageForLinux: '$(Pipeline.Workspace)/MyApp.zip'

Please note, as the variables are defined as output, it’s needed to also prefix with terraformOutput (which is the name of the powershell task we created).

Conclusion

Here we are ! We now are using the terraform outputs in the next tasks of our pipeline. Luckily, with the sensitive parameter we are also able to keep our secrets safe !

5 thoughts on “Using Terraform output values in Azure DevOps pipeline

  1. Arie Heinrich

    Dont you need to run the ‘plan’ step first to create the plan file, and then supply it to the apply command ?

    • Sure ! This is just an abstract of the whole pipeline.
      In fact you should do this: install the terraform tool, run terraform init, run terraform plan, run terraform apply and then you’ll be able to get the output variables.

    • C’est vrai Michel, mais pour plusieurs raisons j’ai décidé de faire par moi même:
      – ca m’a intéressé de faire ca pour l’exercice
      – c’est plutôt trivial à faire
      – installer une extension peut se révéler compliqué dans certains environnement type on premise
      – une extension d’un tiers dont on ne connait pas la politique de support peut poser problème également
      – enfin, l’extension sur le store execute Terraform à nouveau pour produire le fichier, ce qui est peu utile vu qu’il a déjà été généré

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.