TrademarkTrademark
Features
Documentation
  1. Learning Center
  2. What is OpenTofu?

Article · part of a guide

API Driven Workflows for Terraform and OpenTofu

Learn how to take an API driven approach with examples

API Driven Workflows for Terraform and OpenTofu

Key takeaways

  1. API-driven runs in Scalr use a push-based model, giving you full control over when a Terraform or OpenTofu run is triggered.
  2. API-driven runs suit real-time or event-driven provisioning, integration with external systems like Slack or New Relic, and complex custom automation.
  3. The example Python workflow uploads a configuration version to an existing workspace, then triggers a run via the Scalr API, with an is-dry flag to choose a speculative plan or a full apply.
  4. Combining VCS-driven and API-driven runs is often most effective: VCS handles versioning while API runs add agility for dynamic changes.

Most people run Terraform or OpenTofu in Scalr through the CLI or a connected version control system (VCS). This post covers a less common path: triggering a run through the API. The difference is control. With a VCS-driven run, something in your repository sets the run off. With an API-driven run, you make the call yourself, so you decide exactly when it happens. Here are a few reasons you might want that.

When Do You Need Real-Time or Event-Driven Provisioning?

Sometimes a run has to fire the moment something happens, not on a schedule or a git push. An API-driven run can be triggered programmatically in response to an event, so infrastructure changes follow events as they happen. That matters most when waiting for someone to click a button isn't an option.

How Do You Integrate Runs with External Systems?

If you need tight integration with external systems, calling the API directly is often the better option. This comes up when Terraform has to talk to custom scripts, external APIs, or other tools that aren't connected to your VCS provider. Going through the API gives you room to handle those integrations however you want. For example, if an alert goes off in New Relic, you might have a specific workspace and configuration update that needs to be made in response to that alert. A few customers also integrate with Slack so they can kick off runs from Slack in certain scenarios.

Can the API Handle Custom Workflows and Complex Automation?

Some automation goes past what a VCS-driven run can do on its own. When you need to chain several steps together, or wire a run into systems that have nothing to do with your repository, the API gives you room to do it. It's not unusual to see the API approach used with tools such as GitHub Actions, Harness, Bamboo, or Jenkins.

What Does an API-Driven Workflow Look Like in Practice?

In this example, we'll upload a new configuration version (can be Terraform or OpenTofu) to an existing workspace, and then execute a new run.

Prerequisites

You'll need values for the following objects in Scalr:

  • API token
  • URL for your Scalr account
  • Workspace ID
  • Environment ID
  • Terraform configuration files that are in a tar.gz file

Script

The sample script below covers the basic steps, and you can modify it to suit your setup. Make sure to update the token, base_url, env_id, ws_id, and upload_archive_path with values specific to your Scalr account. You can also update the is_dry_run flag based on the type of run you want to execute, a dry (speculative plan) run or a full Terraform apply.

import requests
 
token = ""
base_url = 'https://example.scalr.io'
headers = {
    'Prefer': 'profile=preview',
    'accept': 'application/vnd.api+json',
    'content-type': 'application/vnd.api+json',
    'Authorization': f'Bearer {token}'
}
env_id = ""
ws_id = ""
is_dry_run = True
upload_archive_path = ''
 
## Create CV
url = f'{base_url}/api/iacp/v3/configuration-versions'
data = {
    'data': {
        'attributes': {
            "auto-queue-runs": False,
        },
        'relationships': {
            'workspace': {
                'data': {
                    'type': 'workspaces',
                    'id': ws_id
                }
            }
        },
        'type': 'configuration-versions'
    }
}
 
response = requests.post(url, headers=headers, json=data)
 
cv_id = None
if response.status_code == 201:
    # Successful request
    result = response.json()
    # Process the response data
    print(result)
    cv_id = result['data']['id']
else:
    # Request failed
    raise Exception(f"Error: {response.status_code} - {response.text}")
 
upload_url = result['data']['links']['upload']
print(upload_url)
 
upload = requests.put(upload_url, headers={'Content-Type': 'application/octet-stream'}, data=open(upload_archive_path, 'rb'))
print(upload.status_code)
 
## create run
url = f'{base_url}/api/iacp/v3/runs'
data = {
    'data': {
        'attributes': {
            "is-dry": is_dry_run,
        },
        'relationships': {
            'configuration-version': {
                'data': {
                    'type': 'configuration-versions',
                    'id': cv_id
                }
            },
            'workspace': {
                'data': {
                    'type': 'workspaces',
                    'id': ws_id
                }
            }
        },
        'type': 'runs'
    }
}
 
response = requests.post(url, headers=headers, json=data)
if response.status_code == 201:
    # Successful request
    result = response.json()
    # Process the response data
    print(result)
else:
    # Request failed
    raise Exception(f"Error: {response.status_code} - {response.text}")

The script targets an existing workspace. To start from scratch, create the workspace first (in the UI, with the Scalr Terraform provider, or through the API) and pass its ID as ws_id. Workspace settings offer many more options, including whether runs execute immediately or wait until someone makes a separate request. The full Scalr API documentation is here.

Should You Use VCS-Driven or API-Driven Runs?

For a lot of teams, the best setup uses both. VCS keeps your infrastructure as code versioned and reviewable, and API-driven runs cover the dynamic, real-time changes that don't fit a git workflow. Which one you reach for depends on what a given workspace needs.

About the author

Ryan Fee

director of platform engineering at Scalr

Ryan Fee is the director of platform engineering at Scalr, with over 15 years of experience improving infrastructure experiences at companies large and small.

Part of this guide

15 sheets

What is OpenTofu?

14 articles