Terraform

Overview

Generating terraform with pyterranetes is, as with kubernetes, just a question of writing a p10s script which creates a terraform.Context object and adds terraform blocks to it:

from p10s import tf

c = tf.Context()

# Fully explicit style
c += tf.Variable("foo", dict(
    default=0
))

c += tf.Resource("type", "name", dict(
    var = 'value'
))

# Helper function
c += tf.variables(key="${data.terraform_remote_state.key}"})
c += tf.outputs(key="${module.m.key}"})

# HCL syntax if a large amount of code needs to be converted to
# pyterranetes quickly
c += tf.from_hcl("""
    module "m" {
      source = "../m/"
    }
""")

# property/attribute syntax for a more pythonic feeling
c.resource.type.name = {
    'key': 'value',
}

c.module.name = {
    'source': './modules/my-module/',
}

For each terraform configuration block there is a corresponding python class. Depending on the block type and how it’s used some of the classes provid convenience methods and constructors. All of the classes have a .body property representing the data inside the block.

There are 3 different categories of terraform blocks:

Blocks that don’t have any properties other than .body:

terraform, and locals.

Blocks that also have a name property:

provider, variable, and output

Blocks that also have a type and a name property:

resource, and data

Sometimes it’s more convenient to start with hcl code, we can use the from_hcl function:

c += tf.from_hcl("""
    resource "type" "name" {
      var = "value"
      ...
    }
""")

Note the hcl has two, equivalent, ways to assign a nested map (dict in python):

key {
   v = k
}

and

key = {
   v = k
}

When parsing hcl pyterranetes will convert both of these to a single entry with key key and value a dict with the values of the corresponsding block. As pyterranetes only actually generates .tf.json and not .tf (hcl) files, there is also no ambiguity in the output.

Alternatively there’s another way to add blocks to a context using the properties resource, module and variable (there is currently no equivalent auto syntax for provider, local or output blocks).

from p10s import tf

c = tf.Context()

c.resource.random_id.project_name = {
    'byte_length': 8
}

c.module.mod = {
    'source': './modules/module'
}

c.variable.name = 'default-value'

Blocks

class p10s.terraform.Resource(type, name, body=None)[source]

resource block. Exposes .name and .type as properties.

class p10s.terraform.Module(name, body=None)[source]

module block. Exposes .name as a property.

class p10s.terraform.Variable(name, body=None)[source]

variable block. Exposes .name as a property.

If you’re defining a variable without a type or a description (90% of the cases in practice), it is probably easier to use variables.

class p10s.terraform.Data(type, name, body=None)[source]

data block. Exposes .name and .type as properties.

class p10s.terraform.Output(name=None, body=None, **kwargs)[source]

output block. Exposes .name as a property.

The constructor is designed to be convenient to use in p10s scripts. Any (single) keyword argument passed to the constructor, other than name and body, is assumed to be the name of an output with the given value.

So this call:

o = Output(ip="${aws_eip.ip.public_ip})

is equivalent to this:

o = Output(name="ip", body={
    'var_name': "${aws_eip.ip.public_ip}
})

The convenience constructor can be used to define exactly one output, for similar syntax for multiple outputs see outputs

class p10s.terraform.Provider(name, body=None)[source]

provider block. Exposes .name as a property.

class p10s.terraform.Locals(body)[source]

locals block. Doesn’t expose any properties beyond body.

class p10s.terraform.Terraform(body)[source]

terraform block. Doesn’t expose any properties beyond body.

Helpers

p10s.terraform.variables(**kwargs)[source]

Helper function for defining multiple variable <p10s.terraform.Variable blocks which only specify their default value.

Example:

c += tf.variables(
    name='value,
    other='other value')

is short hand for:

c += tf.Variable("name", {'default': 'value'})
c += tf.Variable("other", {'default': 'other value'})
p10s.terraform.outputs(**kwargs)[source]

Helper function for defining multiple output blocks.

Example:

c += tf.outputs(
    name='${module.foo.id},
    other='${module.foo.key}')

is short hand for:

c += tf.Output("name", {'value': '${module.foo.id}'})
c += tf.Output("other", {'value': '${module.foo.key}'})
p10s.terraform.from_hcl(hcl_string)[source]

Build a TerraformBlock from hcl text.

Parameters:

hcl_string (a string, a pathlib.Path, or an io.Base object) – hcl text to parse

c += tf.from_hcl("""
  foo { }
""")

Note that the return value is an instance of tf.TerraformBlock, and has all the corresponding methods:

resource = tf.from_hcl('''
  resource "type" "name" {
    key = 'value'
  }
''')

resource.body['key'] = 'other value'

It can be convenient to keep most of the terraform code in a seperate file and only use pyterranetes for certain operations. In this case it’s often best to leave the terraform code seperate and just read it into the p10s script:

for name in (name1, name2, ...):
    resource = tf.from_hcl(Path('./base.tf'))
    resource.name = name
    c += resource

See p10s.loads.hcl() for details on the unerlying hcl parser.

p10s.terraform.many_from_hcl(hcl_string)[source]

Build TerraformBlock objects from hcl text. Always returns a list of blocks.

See p10s.terraform.from_hcl() for examples and p10s.loads.hcl() for details on the unerlying hcl parser.

Base Classes

class p10s.terraform.Context(*args, data=None, strict=False, **kwargs)[source]

Context for terraform files.

As with the k8s.Context this instances of this class represent a single terraform file. Block of terraform can be added using the += operator.

By default adding the same terraform block multiple times to a context does not cause any errors, the values will be merged in as normal. If needed more strict verification can be added by passing strict=True to the Context constructor.

__add__(block)[source]

Returns a new context containg all the data in self and block

Parameters:

block (TerraformBlock) –

__iadd__(block)[source]

Add block to the context’s data, destructively modifies self

Parameters:

block (TerraformBlock) –

class p10s.terraform.TerraformBlock(data=None)[source]

Abstract base class for all terrform blocks.

Exposes the .body property for direct manipulation of the block’s data.

property body

Returns the data contained in thie block. name, type, provider or other non-body values are exposed as properties on the corresponding object.

update(new_body_values)[source]

Merges in new_body_values with this block’s body. Does not change name or type or any of the block’s properties.