TrademarkTrademark
Features
Documentation
  1. Learning Center
  2. CI/CD and GitOps for Terraform & OpenTofu

Article · part of a guide

Setting up Scalr & Azure DevOps Part 3 - Execute Your Terraform Code and Create a Workspace

Execute your TF code and create a workspace, both using PR automation, and by plugging the CLI into Azure DevOps.

Setting up Scalr & Azure DevOps Part 3 - Execute Your Terraform Code and Create a Workspace

Key takeaways

  1. This third post in a Scalr and Azure DevOps series walks through creating a workspace and executing Terraform code, both via VCS-driven PR automation and by plugging the Terraform CLI into Azure DevOps.
  2. When creating a VCS-integrated workspace, Scalr auto-detects required variables, supports custom hooks like terraform fmt --check before or after plan and apply, and can trigger dry runs on pull requests.
  3. A Scalr run progresses through Plan, Cost Estimate, Policy Check (against OPA policies), and Apply stages, skipping stages when no resources have cost or no policies are defined.
  4. For a CLI-driven workspace using Scalr as a remote backend, the Azure DevOps pipeline generates a terraformrc file with an API token, which must be a user or team token, not an organization token.
  5. The remote backend does not accept -var or -var-file CLI options; Scalr run-scope variables are defined in the workspace or via the API and provider instead.

This was written by Jack Roper, a guest blogger.

Getting started with Scalr and Azure DevOps takes three stages. This series walks through each one step by step.

This is the third and final post, and it covers how to execute your Terraform code and create a workspace, both using PR automation and by plugging the CLI into Azure DevOps. There's also a third way to create a workspace, through the module registry, but that one still relies on the VCS connection.

If you missed the first post in the series, check it out here: picking a workflow.

And the second post here: how to add Azure credentials and link them to an environment.

How Do You Execute Your Terraform Code and Create a Workspace?

What Does the Existing Scalr Environment Look Like?

In the first 2 posts, we linked our Azure DevOps instance and our Azure subscription to our Scalr environment. Here's the current environment setup.

Selecting provider credentials shows our linked Azure account.

Scalr environment provider credentials showing linked Azure account

Selecting 'VCS' we see that our Azure DevOps project is linked.

Scalr VCS tab showing linked Azure DevOps project

Selecting variables shows the variables inherited from cloud credentials that were set up earlier.

Scalr variables view showing variables inherited from cloud credentials

Where Can You Find the Sample Terraform Code?

The Terraform code on my GitHub page has configuration files that add some groups to Azure Active Directory. Download it if you want to follow along.

https://github.com/jackwesleyroper

How Do You Create a VCS-Integrated Workspace?

Next up is creating a workspace. A workspace is where all the objects tied to your Terraform-managed resources live.

  1. Within the environment, select the 'create workspace' button.

Scalr environment screen with create workspace button

  1. We're creating a workspace linked to our Azure DevOps VCS provider. Select it from the drop-down list, then choose the repo that holds the code and the branch. Here you can specify the Terraform version, and auto-apply changes when a terraform plan run is successful if desired.

With VCS-driven dry runs enabled, Scalr automatically kicks off a dry run when it detects a pull request opened against a branch.

The Terraform directory sets where Terraform runs and executes commands. It's a relative path and must be a subdirectory of the top level of the repository or of the subdirectory if specified.

Runs can also be triggered on certain subdirectories only. To enable this option, set the working directory.

The custom hooks option calls custom actions at various stages in the Terraform workflow. These can be set before or after the plan stage, or before or after the apply stage.

For example, a custom script or API call can be executed after the apply phase, or the terraform validate command could be executed before the plan phase. I'm going to add the terraform fmt --check command into my workflow here to validate that the formatting of my code is consistent. You can even download scripts here with wget or run tests with curl.

Scalr workspace creation form with Azure DevOps VCS provider settings

Scalr workspace custom hooks configuration with terraform fmt check

  1. Press create once all the options are filled out.

Scalr workspace create button after filling out options

Now we need to set some variables. Scalr detects which variables in the Terraform code need values (those that don't have one) and creates them automatically. Variables can be set in the Terraform code or the Scalr UI. For my example, I need to fill out the ad_group_names variable.

If the local workspace contains any *.auto.tfvars files these will provide default variable values that Terraform will automatically use. If variables in the *.auto.tfvars files have the same names as variables specified in the workspace, the predefined workspace values will be used. For map variables the values in *.auto.tfvars are merged with values in the same named variable in the workspace.

Scalr workspace variables view prompting to set the ad_group_names variable

If your Terraform configuration needs shell variables, you can add them here too. The variables we used earlier to set up the cloud credentials for our Azure subscription are automatically inherited.

If the Terraform configuration utilizes shell variables (export var=value), e.g. for credentials or to set values for Terraform input variables with TF_VAR_{variable_name}={value} (-parallelism, -var-file, etc). Shell variables can be set at all levels in Scalr and are inherited by lower levels. Use environment or account level for shell variables that are needed in multiple workspaces or environments. Use workspace level for shell variables that are specific to individual Terraform configurations. You can also use the Scalr provider to pull output from one workspace and post it as an environment or account shell variable to make it easily available to all other workspaces.

How Do You Queue a Run and Fix a Failed terraform fmt --check?

With everything in place, we can run our code.

Navigate to Runs -> Queue Run, enter a reason for the run, and hit Queue run.

Scalr Runs menu with Queue Run option

Scalr Queue Run dialog with reason field

Scalr run output showing Terraform execution in progress

My first run errored! The custom hook I set up earlier detected that my code wasn't formatted correctly and exited with error code 3. The check option I used exits with code 0 if the configuration is formatted.

-check Check if the input is formatted. Exit status will be 0 if all input is properly formatted and non-zero otherwise.

Scalr run failed with error from terraform fmt check custom hook

Over in Azure DevOps, I also noticed an error message on my repo:

Azure DevOps repo displaying an error message on the commit

Azure DevOps commit details showing failed Scalr status check

I ran terraform fmt on my code and executed the run.

Terminal output of terraform fmt formatting the code

Scalr run output confirming creation of 3 Azure AD groups

The run confirmed that my 3 groups would be created in AzureAD and that the configuration was formatted correctly. Over in Azure DevOps, I could see the plan in progress:

Azure DevOps commit view showing Terraform plan in progress

The 'needs confirmation' warning appeared, so I hit 'approve' at the bottom of the run screen.

Scalr run screen with needs confirmation warning and approve button

Scalr run progressing through plan and apply stages

Scalr run completed showing repository and commit links to Azure DevOps

The repository link and commit link take you to the matching location in Azure DevOps.

The workspace runs through the following stages:

Plan, which allows users to view the planned creation, update, or destruction of resource through the standard console output or detailed plan view. The detailed plan will alert users of destructive changes and makes it easier to search the plan when there are many resources affected. It is also the section to check who approved an apply and comments associated with the approval.

Cost Estimate, which will show you the estimated cost for the resources that are being created. This information can be used for writing a policy to check cost

Policy Check, which is used to check the Terraform plan JSON output against Open Policy Agent policies. This step can be used to enforce your company standards.

Apply, which will actually create, update, or destroy the resources based on the Terraform configuration file.

Note that in my example, I was creating Azure AD Groups that don't incur any cost, so Scalr reported that it had detected no resources. I also hadn't defined any policies, so that stage was skipped.

How Do You Create a CLI-Driven Workspace and Set TF_CLI_CONFIG_FILE in Azure DevOps?

Say you already have a workflow set up in Azure DevOps that uses the Terraform CLI, and you want to point it at Scalr. Scalr executes the runs in a container on its backend, and the logs and output come back to your console.

In post 1, we showed how to get an API token so the local Terraform CLI could use Scalr as a remote backend. That login was interactive. An Azure DevOps Pipeline runs unattended, so the login stage has to be automated.

  1. Generate an API token. If you didn't save the one from the first article, generate a new one from the Scalr UI.

Scalr UI option to generate a new API token

Scalr API token generated dialog displaying the token value

  1. Create a new workspace. Click on New workspace, then choose CLI. Configure the required options and press create.

Scalr new workspace dialog with CLI option selected

Scalr CLI workspace creation form with required options

  1. Click on 'base backend configuration'.

Scalr CLI workspace with base backend configuration button highlighted

This shows the configuration needed for the Terraform configuration to use Scalr as the remote backend. Update the configuration file to set Scalr as the remote backend.

Scalr base backend configuration snippet for use as Terraform remote backend

  1. To connect to Scalr, we need to provide the API token. It must be a user token or a team token, and can't be an organization token according to the Terraform docs.

In Azure DevOps, under Pipelines -> Library -> Add a new variable group.

Azure DevOps Pipelines Library page with option to add a new variable group

Add the token as a secret value, with scalr-api-token as the name.

Azure DevOps variable group adding scalr-api-token as a secret

  1. Add a step at the beginning of your pipeline YAML file for generating your CLI configuration file. The location of the file can be specified using the TF_CLI_CONFIG_FILE environment variable. This creates a file called terraformrc that contains the API token. It's the same thing that happens when you authenticate interactively with Scalr using the CLI, just automated.
variables:
- group: Scalr
 
steps:
- task: charleszipp.azure-pipelines-tasks-terraform.azure-pipelines-tasks-terraform-installer.TerraformInstaller@0
  displayName: 'Use Terraform latest'
 
- script: |
        RC_FILE=".terraformrc"
        cat > ${RC_FILE} << EOF
        credentials "jackwesleyroper.scalr.io" {
          token = "$(scalr-api-token)"
        }
        EOF
        mv .terraformrc ~/.terraformrc
        export TF_CLI_CONFIG_FILE="~/.terraformrc"
  name: scalr_credentials
  displayName: 'Scalr Credentials'
 
- task: TerraformCLI@0
  inputs:
    command: 'init'
    backendType: 'selfConfigured'
    allowTelemetryCollection: true
 
- task: TerraformCLI@0
  inputs:
    command: 'plan'
    allowTelemetryCollection: true
 
- task: TerraformCLI@0
  inputs:
    command: 'apply'
    allowTelemetryCollection: true

Once authenticated the pipeline proceeds to run terraform init, terraform plan and terraform apply.

The remote backend itself doesn't accept the CLI -var=<variable> or -var-file=<file> options. This is a property of the remote backend protocol. (Scalr does support run-scope variables; you just define them in the workspace or via the API/provider rather than passing them as CLI flags.) That's why the plan and apply steps above pass no -var-file option; put values in a *.auto.tfvars file or in workspace variables instead. If you specify the CLI flags, you'll get this error:

The "remote" backend does not support setting run variables at this time. Currently the only to way to pass variables to the remote backend is by creating a '.auto.tfvars' variables file. This file will automatically be loaded by the "remote" backend when the workspace is configured to use Terraform v0.10.0 or later.*

On execution, the pipeline runs through each stage and shows the cost estimation at the end of the apply stage.

Azure DevOps pipeline run output showing Terraform init plan and apply stages

Azure DevOps pipeline apply stage showing cost estimation output

What Did This Series Cover?

This final article showed how to create a workspace, both VCS-integrated and CLI-driven, and execute our Terraform code. We used an Azure DevOps pipeline to automate the workflow on the CLI-driven workspace, using Scalr as the remote backend.

Workspaces and variables can also be created with the Scalr Terraform provider.

Cheers! 🍻

About the author

Jack Roper

DevOps engineer

Jack Roper is a DevOps engineer and technical writer specializing in Terraform and cloud infrastructure.

Part of this guide

25 sheets

CI/CD and GitOps for Terraform & OpenTofu

24 articles