Cloud Documentation

Setting Up Terraform

Introduction

Terraform manages Lightspeed Cloud resources through the CloudStack provider, maintained by the Apache CloudStack project. You describe the infrastructure you want in configuration files, Terraform compares that description with what exists, and it shows a plan of the changes before applying them. The Terraform sections of the reference architectures assume the setup described on this page.

Terraform downloads the provider automatically the first time a project is initialised, so the only software you install yourself is the Terraform CLI.

Before you start

You need an API key and secret key for your Lightspeed Cloud account. These are generated from your account settings in the portal - see API access.

Installing Terraform

HashiCorp publishes packages and binaries for Linux, macOS, Windows and the BSDs. Follow the instructions for your platform on the official Install Terraform page:

  • Linux - add the HashiCorp package repository for your distribution (dnf/yum for AlmaLinux, Rocky Linux, RHEL and Fedora; apt for Debian and Ubuntu) and install the terraform package. Installing from the repository means routine system updates also keep Terraform current.
  • macOS - install with Homebrew from the HashiCorp tap: brew tap hashicorp/tap followed by brew install hashicorp/tap/terraform.
  • Windows - download the zip archive, extract terraform.exe, and move it to a directory on your PATH.

Confirm the installation#

terraform version

Creating a project and installing the provider

A Terraform project is a directory of .tf files. Create one, and declare the CloudStack provider in a versions.tf file:

# versions.tf
terraform {
  required_providers {
    cloudstack = {
      source  = "cloudstack/cloudstack"
      version = "~> 0.6.0"
    }
  }
}

Then initialise the project from inside the directory:

terraform init

terraform init downloads the provider from the Terraform Registry into a .terraform directory and records the exact version and checksums in .terraform.lock.hcl.

Choosing a provider version#

The ~> 0.6.0 constraint accepts any 0.6.x release and nothing newer. The reference architectures are written and tested against the 0.6 series, so this is the constraint to use with them. Newer releases are listed on the provider's registry page; read the release notes before raising the constraint, as minor versions of the provider can deprecate resources and arguments.

Pin the provider version. Version 0.6.0 replaced the ports list on firewall and ACL rules with a single port string, and configurations using the old argument still pass terraform validate and terraform plan, then fail at apply. A version constraint ensures changes of this kind arrive only when you choose to take them.

To move to a newer release within your constraint, run terraform init -upgrade.

Providing credentials

Keep API keys out of your .tf files. The provider can read them from any of three places.

Environment variables#

With these variables set, the provider block needs no arguments:

export CLOUDSTACK_API_URL=https://cloud.lightspeedhosting.com.au/client/api
export CLOUDSTACK_API_KEY=<api key>
export CLOUDSTACK_SECRET_KEY=<secret key>
# provider.tf
provider "cloudstack" {}

This is the most convenient method for CI pipelines, where the values can be injected from the pipeline's secret store.

A CloudMonkey profile#

If you have set up CloudMonkey, the provider can read the URL and keys from the same profile, so they are stored in one place:

# provider.tf
provider "cloudstack" {
  config  = pathexpand("~/.cmk/config")
  profile = "lightspeed"
}

Input variables#

The reference architectures declare the keys as sensitive input variables, which Terraform redacts from plan and apply output:

# provider.tf
variable "api_url"    { default = "https://cloud.lightspeedhosting.com.au/client/api" }
variable "api_key"    { sensitive = true }
variable "secret_key" { sensitive = true }

provider "cloudstack" {
  api_url    = var.api_url
  api_key    = var.api_key
  secret_key = var.secret_key
}

Supply the values on the command line with -var, through TF_VAR_api_key and TF_VAR_secret_key environment variables, or from a .tfvars file that is excluded from version control.

The provider also accepts a timeout argument (or the CLOUDSTACK_TIMEOUT environment variable), which sets how many seconds each asynchronous operation is allowed to run. The default of 300 seconds can be too short for large volumes or Kubernetes clusters.

Running a first configuration

This configuration reads the au-mel01 zone using a data source. Data sources only read, so it creates nothing and is a safe test of the provider and your credentials. Add it to the project alongside versions.tf and provider.tf:

# main.tf
data "cloudstack_zone" "mel" {
  filter {
    name  = "name"
    value = "au-mel01"
  }
}

output "zone_id" {
  value = data.cloudstack_zone.mel.id
}
terraform init
terraform plan

A working setup shows a plan with no resource changes and a value for zone_id. Run terraform apply to record the output in state; with real resources, review the plan it shows and confirm with yes.

State and version control

Terraform records the resources it manages in a state file, terraform.tfstate, in the project directory. Terraform relies on that file to know what it created, so losing it means Terraform can no longer manage those resources. State can also contain sensitive values, such as generated passwords.

  • Commit your .tf files and .terraform.lock.hcl, so everyone working on the project uses the same provider version.
  • Exclude state, the provider download directory and any file holding credentials:
# .gitignore
.terraform/
*.tfstate
*.tfstate.*
*.tfvars

For a project shared by a team or run from a pipeline, store state in a remote backend, which keeps one authoritative copy of the state. Most backends also lock the state while a change is applied, so two people cannot apply changes at once. An S3-compatible object storage bucket can serve as the backend.

Troubleshooting

  • Failed to query available provider packages during terraform init - Terraform cannot reach registry.terraform.io. Check outbound HTTPS access and any proxy settings (HTTPS_PROXY).
  • unable to verify user credentials and/or request signature - the API key or secret key is incorrect, or the two keys belong to different pairs.
  • An argument passes plan and fails at apply - most often a field the provider has deprecated, such as ports on firewall rules. Check the argument against the provider documentation for the version recorded in .terraform.lock.hcl.
  • Operations time out on large resources - raise the provider timeout, described under Providing credentials.

Next steps

Each reference architecture includes a complete Terraform configuration, starting with RA-01. The provider documentation lists every resource and data source.

For quick queries and one-off changes from the command line, see Setting Up CloudMonkey.