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'"
}
}
]
}
}
}
}