terroir
goût de terroir - the taste of the place
terroir is a wrapper around terraform, providing users with the ability to
treat .tf files as templates (in particular, jinja2 templates). It accepts
(simply passes through) all commands, but before running terraform, it
processes the files as jinja2 templates. The only injected template value
(currently) is python's os module, which will give you access to environment
variables. Future releases will give the user more control over what sources of
information are added.
The primary motivation behind this tool is to allow terraform's backend
configuration to be "dynamic", i.e. to allow setting information such as the
state bucket, state key, etc. based on some other information. When these
values change, terraform will also require terraform init to be run, which is
handled automatically by terroir.
Usage:
$ TERRAFORM_STATE_BUCKET=your-state-bucket terroir plan
Acquiring state lock. This may take a few moments...
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
data.terraform_remote_state.vpc: Refreshing state...
aws_s3_bucket.files: Refreshing state...
------------------------------------------------------------------------
No changes. Infrastructure is up-to-date.
This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
Releasing state lock. This may take a few moments...
Just like a regular plan run.
Apply is supported as well, including interactive yes/no:
$ TERRAFORM_STATE_BUCKET=your-state-bucket terroir apply
data.terraform_remote_state.vpc: Refreshing state...
aws_s3_bucket.files: Refreshing state...
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
...
Plan: 0 to add, 1 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_s3_bucket.files: Modifying...
aws_s3_bucket.files: Still modifying...
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
Outputs:
files_bucket = the-filez-bucket
Here is what a templated file might look like:
terraform {
backend "s3" {
bucket = "{{ os.environ["TERRAFORM_STATE_BUCKET"] -}}"
key = "state.tfstate"
region = "us-east-1"
dynamodb_table = "pop-and-lock"
}
}
Configuration:
terroir also has a configuration file, which should generally be placed in
the root of the repo at .terroir/config.toml. This configuration file allows
you set environment variables that will be loaded automatically when terroir
is run with either terroir --env=staging or TERROIR_ENV=staging terroir
(if the named env is staging).
[env]
DEFAULT_REGION = "us-east-1"
[env.staging]
AWS_ACCOUNT_ID = "000000000000000"
[env.prod]
AWS_ACCOUNT_ID = "111111111111111"
This example config will always apply DEFAULT_REGION to the environ, and when
the env is staging, will supply AWS_ACCOUNT_ID with the value
000000000000000.
terroir also supports plugins. The plugin system allows you to import python
code, which can then be invoked to update/apply template variables before
render, or to take actions on a terraform file post rendering. In this way you
can make further programmatic updates, if necessary. An example config is:
[[plugins]]
plugin = "terroir_plugin.py"
This will load a file at .terroir/terroir_plugin.py as a plugin, an example
of which is as follows:
import datetime
import os
import re
class Plugin:
def update_template_variables(self, template_variables, tf_file=None):
template_variables["get_current_time"] = lambda: datetime.datetime.now()
def post_render_callback(self, rendered, tf_file=None):
if os.environ["TERROIR_ENV"] == "staging" and re.search("prod", rendered):
raise ValueError("unexpected prod reference in staging env render!")
Plugins can also be written as an arbitrary import of available python code, for example:
[[plugins]]
plugin = "myterroir.plugins.env::EnvPlugin"
This will perform the equivalent of:
from myterroir.plugins.env import EnvPlugin
plugin = EnvPlugin()
Such a plugin might be written as:
import sys
class EnvPlugin:
def update_template_variables(self, template_variables, tf_file=None):
template_variables["sys"] = sys
If the call to update_template_variables returns a value, the template_variables will be replaced with that value. For example:
class Plugin:
def update_template_variables(self, template_variables, tf_file=None):
return {}
Will result in template_variables being set to an empty dictionary.
If the call to post_render_callback returns a value, the rendered text will be replace with that value. For example:
import re
class Plugin:
def post_render_callback(self, rendered, tf_file=None):
return re.sub("production-", "prod-", rendered)
Will result in all instances of production- being replaced with prod- in the output.
Metadata
Release files for terroir 0.11
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| terroir-0.11-py3-none-any.whl | Python 3 | none | any | Details for terroir-0.11-py3-none-any.whl |
Release files / terroir-0.11-py3-none-any.whl
| Download URL | terroir-0.11-py3-none-any.whl |
|---|---|
| Size | 8.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
308f0a96227abef46e76751a0199024bbc1e07989328bf901f239a2c26fa56bd
|
|
BLAKE2b-256 checksum How to use checksums |
1de087bec46418694b3a43fd81ae3c58f58504f4cfdbf4ab4707ef8468b8121c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.5
|
Security for terroir 0.11
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.