Python-Terrascript

Introduction

https://img.shields.io/github/license/mjuenema/python-terrascript https://img.shields.io/travis/mjuenema/python-terrascript https://img.shields.io/pypi/v/terrascript https://img.shields.io/pypi/pyversions/terrascript https://img.shields.io/pypi/dm/terrascript https://img.shields.io/github/issues/mjuenema/python-terrascript https://img.shields.io/github/stars/mjuenema/python-terrascript

About

Python-Terrascript is a Python package for generating Terraform configurations in JSON format.

Creating Terraform through a Python script offers a degree of flexibility superior to writing Terraform configurations by hand.

  • Control structures like if/else, for/continue/break or try/except/finally.
  • More string methods.
  • Python functions may be used as an alternative to Terraform Modules.
  • Access to the Python Standard Library and third-party packages.

The file PROVIDERS.md lists all currently supported Terraform providers.

Installing Terrascript

Terrascript is available from the Python Package Repository PyPi or alternatively from its Github repository.

Installing Terrascript from PyPi

It is easiest to install Terrascript directly from the Python Package Index.

$ python3 -m pip install terrascript

Installing Terrascript from Github

Terrascript can also be installed from its Github repository.

$ git clone https://github.com/mjuenema/python-terrascript.git
$ cd python-terrascript/
$ git fetch
$ git fetch --tags

The master branch should be identical to the version on PyPi.

$ git checkout master
$ python3 setup.py install

The develop branch includes the latest changes but may not always be in a stable state. Do not use the develop branch unless you want to submit a merge request on github.

$ git checkout develop
$ python3 setup.py install

Compatibility

Terraform releases

`Terraform 0.13`_ added the `required providers`_ block together with tighter integration with the Terraform Provider Registry. Terrascript 0.10.x reflects this change and is not backwards compatible with earlier Terraform releases.

Terraform 0.12 introduced some changes to how it deals with configuration files in JSON format. This is reflected in Terrascript by currently having separate releases for Terraform 0.12 and Terraform 0.11. Earlier releases of Terraform are not supported.

Terraform Terrascript Notes
0.13.x 0.10.x Introduced namespaces, many more providers, suppports Terraform 0.13 only
0.13.x 0.9.x Cleanup efforts and bug fixes, dropping support for Python <3.6, supporting Terraform 0.13.x
0.12.x 0.8.x Terrascript 0.8 are a (almost) complete rewrite
0.12.x 0.7.x Never released
0.11.x 0.6.x Last releases to support Terraform 0.11 and earlier

Terrascript supports Python 3.6 and later.

Module layout

Python-Terrascript’s top-level directory layout is structured into providers, resources and data sources.

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

This is then further structured into namespaces to reflect the changes in Terraform 0.13. Below are examples for importing the modules for the

Amazon Web Services Provider which is maintained by Hashicorp.
import terrascript.provider.hashicorp.aws
import terrascript.resource.hashicorp.aws
import terrascript.data.hashicorp.aws

A first example

The following example has been taken from the official Terraform documentation for the AWS Provider and then converted into a Python script that generates the equivalent configuration in JSON syntax.

First the original Terraform HCL format, which since Terraform 0.13 must include a required_providers block inside the terraform block.

terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
      version = "3.36.0"
    }
  }
}

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

resource "aws_vpc" "example" {
  cidr_block = "10.0.0.0/16"
}

The Terrascript code would look like this. The required_providers argument is supplied as a nested dictionary. In this example only the

Amazon Web Services Provider is used, which is maintained by Hashicorp.
import terrascript
import terrascript.provider.hashicorp.aws
import terrascript.resource.hashicorp.aws

config = terrascript.Terrascript()

# The ``required_providers`` argument is supplied as a nested dictionary.
config += terrascript.Terraform(required_providers={'aws': {'source': 'hashicorp/aws',
                                                            'version': '3.36.0' }
                                                   })

# The provider is a module and a class:  ***.***
config += terrascript.provider.hashicorp.aws.aws(region='us-east-1')
config += terrascript.resource.hashicorp.aws.aws_vpc('example', cidr_block='10.0.0.0/16')

with open('config.tf.json', 'wt') as fp:
    fp.write(str(config))

The content of config.tf.json is shown below. It is equivalent to the original HCL format.

{
  "terraform": {
    "required_providers": {
      "aws": {
        "source": "hashicorp/aws",
        "version": "3.36.0"
      }
    }
  },
  "provider": {
    "aws": [
      {
        "region": "us-east-1"
      }
    ]
  },
  "resource": {
    "aws_vpc": {
      "example": {
        "cidr_block": "10.0.0.0/16"
      }
    }
  }
}

Terrascript does not verify that the generated JSON code is a valid Terraform configuration. This is a deliberate design decision and is explained in the Frequently Asked Questions (FAQ)

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

List of providers

This document lists the Terraform providers that are currently supported by Terrascript.

Official providers

Official providers can be imported with or without namespace.

# With namespace
import provider.hashicorp.aws
import resource.hashicorp.aws
import data.hashicorp.aws

# Without namespace
import provider.aws
import resource.aws
import data.aws

Terrascript currently supports the following official Terraform providers.

  • ad (hashicorp/ad/0.4.3)
  • alicloud (hashicorp/alicloud/1.136.0)
  • archive (hashicorp/archive/2.2.0)
  • aws (hashicorp/aws/3.60.0)
  • azuread (hashicorp/azuread/2.4.0)
  • azurerm (hashicorp/azurerm/2.78.0)
  • azurestack (hashicorp/azurestack/0.10.0)
  • boundary (hashicorp/boundary/1.0.5)
  • ciscoasa (hashicorp/ciscoasa/1.2.0)
  • cloudinit (hashicorp/cloudinit/2.2.0)
  • consul (hashicorp/consul/2.13.0)
  • dns (hashicorp/dns/3.2.1)
  • external (hashicorp/external/2.1.0)
  • fakewebservices (hashicorp/fakewebservices/0.2.1)
  • github (hashicorp/github/4.15.1)
  • google (hashicorp/google/3.85.0)
  • google-beta (hashicorp/google-beta/3.85.0)
  • googleworkspace (hashicorp/googleworkspace/0.4.1)
  • hcp (hashicorp/hcp/0.17.0)
  • hcs (hashicorp/hcs/0.5.0)
  • helm (hashicorp/helm/2.3.0)
  • http (hashicorp/http/2.1.0)
  • kubernetes (hashicorp/kubernetes/2.5.0)
  • kubernetes-alpha (hashicorp/kubernetes-alpha/0.6.0)
  • local (hashicorp/local/2.1.0)
  • nomad (hashicorp/nomad/1.4.15)
  • null (hashicorp/null/3.1.0)
  • oci (hashicorp/oci/4.45.0)
  • opc (hashicorp/opc/1.4.1)
  • oraclepaas (hashicorp/oraclepaas/1.5.3)
  • random (hashicorp/random/3.1.0)
  • template (hashicorp/template/2.2.0)
  • terraform (hashicorp/terraform/1.0.2)
  • tfe (hashicorp/tfe/0.26.1)
  • time (hashicorp/time/0.7.2)
  • tls (hashicorp/tls/3.1.0)
  • vault (hashicorp/vault/2.24.0)
  • vsphere (hashicorp/vsphere/2.0.2)

Partner providers

Partner providers can be imported with or without namespace.

# With namespace
import provider.akamai.akamai
import resource.akamai.akamai
import data.akamai.akamai

# Without namespace
import provider.akamai
import resource.akamai
import data.akamai

Terrascript currently supports the following partner Terraform providers.

Community providers

Community providers must be imported with namespace.

# With namespace
import provider.innovationnorway.git

Terrascript currently supports the following community Terraform providers.

Unsupported providers

The following providers are not supported.

  • aiven (juniorz/aiven/0.1.0) - Failed to initialise provider
  • appd (maskerade/appd/0.0.5) - Failed to initialise provider
  • flexkube (invidian/flexkube/0.3.3) - Failed to initialise provider
  • googlecalendar (sethvargo/googlecalendar/0.3.1) - Failed to initialise provider
  • grafana (58231/grafana/0.0.2) - 58231 is not a valid Python identifier
  • ipam (beauknowssoftware/ipam/0.2.6) - Failed to initialise provider
  • k8s (mingfang/k8s/1.0.2) - Failed to process provider
  • kind1 (unicell/kind1/0.0.2-u2) - Failed to initialise provider
  • lxd (arren-ru/lxd/1.4.0) - Failed to initialise provider
  • null (paultyng/null/0.1.1) - Failed to initialise provider
  • null (ptyng/null/0.1.1) - Failed to initialise provider
  • okta (gavinbunney/okta/3.12.7) - Failed to initialise provider
  • okta (oktadeveloper/okta/3.13.13) - Failed to initialise provider
  • pass (camptocamp/pass/2.0.0) - pass is a Python keyword
  • safedns (ukfast/safedns/1.1.2) - Failed to process provider
  • shakenfist (shakenfist/shakenfist/0.2.5) - Failed to initialise provider
  • unofficial-travis (kamatama41/unofficial-travis/0.5.0) - Failed to initialise provider
  • vmworkstation (elsudano/vmworkstation/0.2.3) - Failed to process provider
  • zerotier (someara/zerotier/0.1.47) - Failed to initialise provider

Terraform JSON format

The following sections show the JSON output Python-Terrascript generates for the different Terraform elements.

Resource

Resources are coded as nested dictionaries. The top-level key is the type of the resource. The second-level key is the name of a resource instance.

Example:

  • Two aws_instance resources named instance1 and instance2
  • One aws_subnet resource named subnet1.
{
  "resource": {
    "aws_instance": {
      "instance1": {
        "instance_type": "t2.micro"
      },
      "instance2": {
        "instance_type": "t2.micro"
      }
    },
    "aws_subnet": {
      "subnet1" {
        "availability_zone": "usa-west-2a"
      }
    }
  }
}

Provider

A Terraform configuration contains one or more provider sections. Unlike resources and data sources providers don’t have a name and are distinguised by their alias attribute instead. Therefore multiple instances of the same provider type are encoded as a list.

Example:

  • Two aws providers with aliases aws1 and aws2.
  • One google provider with alias google1.
{
  "provider": {
    "aws": [
      {
        "region": "us-east-1",
        "alias": "aws1"
      },
      {
        "region": "us-east-2",
        "alias": "aws2"
      }
    ],
    "google": [
      {
        "region": "us-central-1",
        "alias": "google1"
      }
    ]
  }
}

Variable

Variables are encoded as a dictionary whose keys are the names of the variables.

Example:

  • Two variables names image_id and availability_zone_names.
{
  "variable": {
    "image_id": {
      "type": "string"
    },
    "availability_zone_names": {
      "type": "list(string)",
      "default": [
        "us-west-1a",
        "us-west-1b"
      ]
    }
  }
}

Variable references

When using a variable as a attribute value for a object, a reference are used.

Example: * Variable image_id are used as name for instance.

{
  "variable": {
    "image_id": {
      "type": "string"
    }
  },
  "resource": {
    "aws_instance": {
      "instance1": {
        "instance_type": "${var.image_id}"
      }
    }
  }
}

Output Values

Output values are encoded as a dictionary whose keys are the names of the value.

Example:

  • Output values for two resources.
{
  "output": {
    "instance1_ip_addr": {
      "value": "instance1.server.private_ip"
    },
    "instance2_ip_addr": {
      "value": "instance2.server.private_ip"
    },
  }
}

Local Values

Local values are encoded as a dictionary whose keys are the names of the value.

Example:

{
  "locals": {
    "service_name": "forum",
    "owner": "Community Team",
    "Service": "local.service_name",
    "Owner": "local.owner"
  }
}

Modules

Module calls are dictionaries keyed by the name of the module and module arguments as values.

Note

In contrast to calling existing modules, creating modules is not supported by Python-Terrascript as Python functions could be used as an alternative.

Example:

  • Calling module vpc.
{
  "module": {
    "vpc": {
      "source": "terraform-aws-modules/vpc/aws",
      "version": "2.9.0"
    }
  }
}

Data Sources

Data sources are coded as nested dictionaries. The top-level key is the type of the resource. The second-level key is the name of the data source.

Example:

  • Two aws_ami data sources named ami1 and ami2.
{
  "data": {
    "aws_ami": {
      "ami1": {
        "most_recent": true
      },
      "ami2": {
        "most_recent": true
      },
    }
  }
}

Expressions

Functions

Functions are encoded as text. Example: "content": "file('hello_world.txt')".

Terraform Settings

Terraform settings are a simple dictionary although the values of settings may contain nested data structures.

Example:

  • Terraform backend configuration.
{
  "terraform": {
    "backend": {
      "s3": {
        "bucket": "mybucket"
      }
    }
  }
}

Frequently Asked Questions

Questions I frequently asked myself ;-)

Why no error checking?

Python-Terrascript does not perform any error checking whatsoever! This was a deliberate design decision to keep the code simple. Therefore it is perfectly possible to generate JSON output that Terraform will later reject.

import terrascript
import terrascript.provider
import terrascript.resource

config = terrascript.Terrascript()

config += terrascript.provider.aws(region='us-east-1')

i = terrascript.resource.aws_instance('myinstance', foo='bar')
config += i

# AWS Instance resource does not have a `foo` argument but accepts it anyway.
assert i.foo == 'bar'
 {
 "provider": {
     "aws": [
     {
         "region": "us-east-1"
     }
     ]
 },
 "resource": {
     "aws_instance": {
       "myinstance": {
           "foo": "bar"
       }
     }
 }

Terraform will reject the generated JSON as the aws_instance resource does not accept the foo argument.

At an early stage I contemplated parsing the Terraform Go source code and auto-create Python code that does indeed verify whether the generated JSON configuration is valid Terraform input. This attempt proved much too difficult so I abandonded that approach.

Why is provider XYZ not supported?

All provider specific code is auto-generated through the tools/makecode.py script based on the list of providers in tools/providers.yml. So if a provider is missing it simply has not yet been added to tools/providers.yml.

If you believe a provider is missing simply open a new issue or submit a pull request with the missing provider added to tools/providers.yml.

Why is there sometimes so little progress in this project?

Python-Terrascript is a hobby project which I can only work on in my very limited spare time.

Professionally I am a Systems and Network Engineer working on an Intelligent Transport Systems project. None of its infrastructure is in the Cloud, it’s all very physcially located on the freeways around Melbourne, Australia. Until someone writes Terraform modules for traffic cameras or vehicle sensors my manager simply wouldn’t appreciate if I spent time on Python-Terrascript during work hours.

Is Python-Terrascript better than writing configurations by hand?

I regard Python-Terrascript as an alternative to writing Terraform configurations by hand. Whether it is better or not is for everyone to decide for themselves.

How can I contribute to the project?

There a various ways you can contribute to the development of Python-Terrascript.

  • Issues: Do not hestiate to raise an issue if you believe you found a bug or simply have a question. As the maintainer of a small Github project it is amazingly satisfying to see that there are other people out there who find Python-Terrascript useful. Do not get discouraged if I don’t respond immediately. As mentioned earlier I can only spend limited time on Python-Terrascript. You will hear from me eventually.
  • Pull Requests: Yes, Pull Requests are welcome but please bear in my that this is a personal project and not a community project. I promise to provide an explanation if should I reject a Pull Request.
  • Documentation: Documentation can always be improved so any support (Issues, Pull Requests) is very welcome. The biggest problem with documentation is always what may be obvious to me may not be obvious to the reader at all. I also tend to be rather terse when writing documentation which is not a good thing.
  • Examples: I would like to include a collection of real-world examples of how Python-Terrascript is used. So if you are willing to share your code please come forward.
  • Drinks: Anyone willing to catch-up for a chat over coffee (hot chocolate in my case) or beer when they are in Melbourne?

Are there any alternatives to Python-Terrascript?

I know that there are comparable projects to Python-Terrascript. I just haven’t managed to compile a list yet. Please stand-by for updates…

Indices and tables