Tutorial

This section explains the different Terrascript Python classes that can be used to generate a Terraform configuration.

Since release 0.8.0 all Terrascript classes are available by importing just four modules.

import terrascript
import terrascript.provider
import terrascript.resource
import terrascript.data

Note

The old layout, e.g. import terarscript.aws.r is still available for backward compatibility but its use is discouraged.

Provider

Providers can be found in the terrascript.provider module, with one class for each provider. Terrascript supports most Terraform providers. The full list can be found in List of Providers.

HCL

provider "aws" {
  alias   = "east"
  region  = "us-east-1"
}

provider "aws" {
  alias   = "west"
  region  = "us-west-1"
}

Python

import terrascript
import terrascript.provider

config = terrascript.Terrascript()

# Amazon Web Service with aliases
config += terrascript.provider.aws(alias="east", region="us-east-1")
config += terrascript.provider.aws(alias="west", region="us-west-1")

JSON

{
  "provider": {
    "aws": [
      {
        "alias": "east",
        "region": "us-east-1"
      },
      {
        "alias": "west",
        "region": "us-west-1"
      }
    ]
  }
}

Resource

Resources can be found in the terrascript.resource module. The example below shows the original HCL syntax for creating an AWS S3 bucket and the equivalent Python code.

HCL

provider "aws" {
    region     = "us-east-1"
}

resource "aws_s3_bucket" "mybucket" {
    bucket = "mybucket"
    acl    = "private"
    tags = {
        Name        = "My bucket"
        Environment = "Dev"
    }
}

Python

And here is the same as a Python script. The first argument to terrascript.resource.aws_s3_bucket() is the Terraform label under which it can be referenced later. Note how the tags is a dictionary as in the HCL syntax.

import terrascript
import terrascript.provider.hashicorp.aws
import terrascript.resource.hashicorp.aws

config = terrascript.Terrascript()

# AWS provider
config += terrascript.provider.hashicorp.aws.aws(region="us-east-1")

# Add an AWS S3 bucket resource
config += terrascript.resource.hashicorp.aws.aws_s3_bucket(
    "mybucket",
    bucket="mybucket",
    acl="private",
    tags={"Name": "My bucket", "Environment": "Dev"},
)

JSON

{
  "provider": {
    "aws": [
      {
        "region": "us-east-1",
        "version": "3.60.0",
        "source": "https://github.com/hashicorp/terraform-provider-aws"
      }
    ]
  },
  "resource": {
    "aws_s3_bucket": {
      "mybucket": {
        "bucket": "mybucket",
        "acl": "private",
        "tags": {
          "Name": "My bucket",
          "Environment": "Dev"
        }
      }
    }
  }
}

Data Source

Data Sources are located in the terrascript.data module. The example creates a Google Compute Instance based on the Debian-9 image. First the Terrascript HCL syntax.

provider "google" {
    credentials = "${file("account.json")}"
    project     = "myproject"
    region      = "us-central1"
}

data "google_compute_image" "debian9" {
    family  = "debian-9"
    project = "debian-cloud"
}

resource "google_compute_instance" "myinstance" {
    name         = "test"
    machine_type = "n1-standard-1"
    zone         = "us-central1-a"
    boot_disk {
        initialize_params {
            image = data.google_compute_image.debian9.self_link
        }
    }
    network_interface {
        network = "default"
        access_config {
            // Ephemeral IP
        }
    }
}

And the same as Python code.

import terrascript
import terrascript.provider
import terrascript.resource
import terrascript.data

config = terrascript.Terrascript()

# Google Cloud Compute provider
config += terrascript.provider.google(
    credentials='${file("account.json")}', project="myproject", region="us-central1"
)

# Google Compute Image (Debian 9) data source
config += terrascript.data.google_compute_image("image", family="debian-9")

# Add Google Compute Instance resource
config += terrascript.resource.google_compute_instance(
    "myinstance",
    name="myinstance",
    machine_type="n1-standard-1",
    zone="us-central1-a",
    boot_disk={
        "initialize_params": {"image": "data.google_compute_image.image.self_link"}
    },
    network_interface={"network": "default", "access_config": {}},
)

The example above is mostly a one-to-one adaptation of the HCL syntax. Let’s make some changes to show how generating Terraform configurations through Python-Terrascript may help.

  • Define the Google Compute Image family and Google Compute Instance machine type at the beginning of the script so they are easier to change.
  • Reference an instance of the Python-Terrascript class terrascript.data.google_compute_image() as the boot disk image.
IMAGE_FAMILY = "debian-9"
MACHINE_TYPE = "n1-standard-1"

import terrascript
import terrascript.provider
import terrascript.resource
import terrascript.data

config = terrascript.Terrascript()

# Google Cloud Compute provider
config += terrascript.provider.google(
    credentials='${file("account.json")}', project="myproject", region="us-central1"
)

# Google Compute Image (Debian 9) data source
image = terrascript.data.google_compute_image("image", family=IMAGE_FAMILY)
config += image

# Add Google Compute Instance resource
config += terrascript.resource.google_compute_instance(
    "myinstance",
    name="myinstance",
    machine_type=MACHINE_TYPE,
    zone="us-central1-a",
    boot_disk={"initialize_params": {"image": image.self_link}},
    network_interface={"network": "default", "access_config": {}},
)

Variable

The terrascript.Variable class can be used to define variables that can be referenced later. Python-Terrascript automatically takes care of converting a reference to a Python variable into the correct Terraform JSON syntax.

HCL

provider "aws" {
  region     = "us-east-1"
}

variable "image_id" {
  type = string
}

resource "aws_instance" "example" {
  instance_type = "t2.micro"
  ami           = var.image_id
}

Python

import terrascript
import terrascript.provider
import terrascript.resource

config = terrascript.Terrascript()

# AWS provider
config += terrascript.provider.aws(region="us-east-1")

# Define Variable and add to config
v = terrascript.Variable("image_id", type="string")
config += v

# AWS EC2 instance referencing the variable.
config += terrascript.resource.aws_instance(
    "example",
    instance_type="t2.micro",
    ami=v,
)

JSON

In the output the reference to the image_id has been converted from a reference to a Python variable ami=v to the correct Terraform JSON syntax of ${var.image_id}.

{
  "provider": {
    "aws": [
      {
        "region": "us-east-1"
      }
    ]
  },
  "variable": {
    "image_id": {
      "type": "string"
    }
  },
  "resource": {
    "aws_instance": {
      "example": {
        "instance_type": "t2.micro",
        "ami": "${var.image_id}"
      }
    }
  }
}

Output

Output is implemented as the terrascript.Output class.

HCL

provider "aws" {
  region     = "us-east-1"
}

variable "image_id" {
  type = string
}

resource "aws_instance" "example" {
  instance_type = "t2.micro"
  ami           = var.image_id
}

output "instance_ip_addr" {
  value         = aws_instance.server.private_ip
  description   = "The private IP address of the instance."
}

Python

import terrascript
import terrascript.provider
import terrascript.resource

config = terrascript.Terrascript()

# AWS provider
config += terrascript.provider.aws(region="us-east-1")

# Define Variable and add to config
v = terrascript.Variable("image_id", type="string")
config += v

# Define AWS EC2 instance and add to config
i = terrascript.resource.aws_instance("example", instance_type="t2.micro", ami=v)
config += i

# Output the instance's private IP
config += terrascript.Output(
    "instance_ip_addr",
    value=i.private_ip,
    description="The private IP address of the instance.",
)

JSON

{
  "provider": {
    "aws": [
      {
        "region": "us-east-1"
      }
    ]
  },
  "variable": {
    "image_id": {
      "type": "string"
    }
  },
  "resource": {
    "aws_instance": {
      "example": {
        "instance_type": "t2.micro",
        "ami": "${var.image_id}"
      }
    }
  },
  "output": {
    "instance_ip_addr": {
      "value": "aws_instance.example.private_ip",
      "description": "The private IP address of the instance."
    }
  }
}

Module

Calls to other Terraform modules are implemented through the terrascript.Module class.

HCL

module "ec2_cluster" {
  source                 = "terraform-aws-modules/ec2-instance/aws"
  version                = "~> 2.0"

  name                   = "my-cluster"
  instance_count         = 5

  ami                    = "ami-ebd02392"
  instance_type          = "t2.micro"
  key_name               = "user1"
  monitoring             = true
  vpc_security_group_ids = ["sg-12345678"]
  subnet_id              = "subnet-eddcdzz4"
}

Python

"""Terrascript module example based on https://registry.terraform.io/modules/terraform-aws-modules/ec2-instance/aws/"""

import terrascript
import terrascript.provider

config = terrascript.Terrascript()

# AWS provider
config += terrascript.provider.aws(region="us-east-1")

# AWS EC2 module
config += terrascript.Module(
    "ec2_cluster",
    source="terraform-aws-modules/ec2-instance/aws",
    version="~> 2.0",
    name="my-cluster",
    instance_count=5,
    ami="ami-ebd02392",
    instance_type="t2.micro",
    key_name="user1",
    monitoring=True,
    vpc_security_group_ids=["sg-12345678"],
    subnet_id="subnet-eddcdzz4",
)

JSON

{
  "provider": {
    "aws": [
      {
        "region": "us-east-1"
      }
    ]
  },
  "module": {
    "ec2_cluster": {
      "source": "terraform-aws-modules/ec2-instance/aws",
      "version": "~> 2.0",
      "name": "my-cluster",
      "instance_count": 5,
      "ami": "ami-ebd02392",
      "instance_type": "t2.micro",
      "key_name": "user1",
      "monitoring": true,
      "vpc_security_group_ids": [
        "sg-12345678"
      ],
      "subnet_id": "subnet-eddcdzz4"
    }
  }
}

Backend

HCL

terraform {
  backend "local" {
    path    = "example_app/terraform_state"
  }
}

Python

import terrascript

config = terrascript.Terrascript()

backend = terrascript.Backend(
    "local",
    path="example_app/terraform_state",
)

config += terrascript.Terraform(backend=backend)

JSON

{
  "terraform": {
    "backend": {
      "local": {
        "path": "example_app/terraform_state"
      }
    }
  }
}

Connection

Locals

Terraform local values are not supported. Use Python variables instead.

Python

import terrascript
import terrascript.provider
import terrascript.resource

config = terrascript.Terrascript()

# AWS provider
config += terrascript.provider.aws(region="us-east-1")

# Local values as Python variables
tags = {"service_name": "forum", "owner": "Community Team"}

# Resource with two provisioners
config += terrascript.resource.aws_instance(
    "instance1",
    instance_type="t2.micro",
    ami="ami-4bf3d731",
    tags=tags,
)

JSON

{
  "provider": {
    "aws": [
      {
        "region": "us-east-1"
      }
    ]
  },
  "resource": {
    "aws_instance": {
      "instance1": {
        "instance_type": "t2.micro",
        "ami": "ami-4bf3d731",
        "tags": {
          "service_name": "forum",
          "owner": "Community Team"
        }
      }
    }
  }
}

Provisioner

One or multiple provisioners can be added to a Terraform resource. Multiple provisioners must be added as a Python list, a single provisioner can be either on its own or inside a list.

The example adds one “create” and one “destroy” provisioner.

Python

import terrascript
import terrascript.provider
import terrascript.resource

config = terrascript.Terrascript()

# AWS provider
config += terrascript.provider.aws(region="us-east-1")

# Provisioners
create = terrascript.Provisioner("local-exec", command="echo 'Create'")
destroy = terrascript.Provisioner(
    "local-exec",
    when="destroy",
    command="echo 'Destroy'",
)

# Resource with two provisioners
config += terrascript.resource.aws_instance(
    "instance1",
    instance_type="t2.micro",
    ami="ami-4bf3d731",
    provisioner=[
        create,
        destroy,
    ],
)

JSON

{
  "provider": {
    "aws": [
      {
        "region": "us-east-1"
      }
    ]
  },
  "resource": {
    "aws_instance": {
      "instance1": {
        "instance_type": "t2.micro",
        "ami": "ami-4bf3d731",
        "provisioner": [
          {
            "local-exec": {
              "command": "echo 'Create'"
            }
          },
          {
            "local-exec": {
              "when": "destroy",
              "command": "echo 'Destroy'"
            }
          }
        ]
      }
    }
  }
}