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
: - Blocks that also have a name property:
- Blocks that also have a type and a name property:
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.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
andbody
, 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
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 andp10s.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
andblock
- Parameters:
block (TerraformBlock) –
- __iadd__(block)[source]¶
Add
block
to the context’s data, destructively modifiesself
- 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.