Skip to content

Commit 15e2852

Browse files
committed
Released Stacks v2
1 parent 8e0491f commit 15e2852

File tree

73 files changed

+2169
-811
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+2169
-811
lines changed

.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Python
2+
__pycache__
3+
4+
# uv
5+
.python-version
6+
.venv
7+
build

README.md

+54-99
Original file line numberDiff line numberDiff line change
@@ -5,102 +5,57 @@
55
</div>
66

77

8-
## What is Stacks for Terraform?
9-
10-
**Stacks** is a code pre-processor for Terraform. It implements a **sustainable scaling pattern**, **prevents drift** and **boilerplate**, all while **plugging into your already existing Terraform pipeline**.
11-
12-
Stacks was initially presented at [SREcon23 Americas](https://www.usenix.org/conference/srecon23americas/presentation/bejarano).
13-
14-
***Warning:** Stacks is under heavy development, many things may change.*
15-
16-
17-
## What is a "stack"?
18-
19-
- A **stack** is a set of Terraform resources you want to deploy one or more times.
20-
- Each instance of a stack is a **layer**. A stack has one or more layers, hence, the name "stacks".
21-
22-
### Example
23-
24-
```
25-
vpc/
26-
27-
├── base/
28-
│ ├── vpc.tf
29-
│ └── subnets.tf
30-
31-
├── layers/
32-
│ ├── production/
33-
│ │ └── layer.tfvars
34-
│ └── staging/
35-
│ ├── layer.tfvars
36-
│ └── vpn.tf
37-
38-
└── stack.tfvars
39-
```
40-
41-
- This is an example stack called `vpc`.
42-
- It contains a `base` folder, containing the common Terraform configuration scoped for all layers in this stack.
43-
- It contains a `layers` folder with two layers, one called `production` and one called `staging`. Layer directories contain layer-specific Terraform configuration.
44-
- Finally, it contains an optional `stack.tfvars` file, which defines variables global to all layers in the stack. These variables can be overriden at the layer level through a layer-specific `layer.tfvars`.
45-
46-
47-
## How does Stacks work?
48-
49-
Stacks sits between you (the Terraform user) and Terraform. It's a **code pre-processor**.
50-
Here's an overview of Stacks inner workings:
51-
52-
1. It takes your stack definitions (as shown above)
53-
1. For each layer:
54-
1. Joins the `base` code with the layer-specific code
55-
1. Applies a number of transformations
56-
1. Injects some extra configuration
57-
1. Bundles it up for Terraform to plan/apply on it
58-
59-
60-
## How to use Stacks?
61-
62-
First, you need to put the Stacks code somewhere close to your stack definitions.
63-
Here's an example (not necessarily what we recommend):
64-
65-
```
66-
your-terraform-repository/
67-
68-
├── src/ # the contents of the `src` directory
69-
│ ├── helpers.py
70-
│ ├── postinit.py
71-
│ └── preinit.py
72-
73-
├── environments/ # see the `example` directory on how to set this up
74-
│ ├── production/
75-
│ │ ├── backend.tfvars
76-
│ │ └── environment.tfvars
77-
│ └── staging/
78-
79-
└── stacks/ # put your stack definitions here
80-
└── vpc/ # the `vpc` stack shown above
81-
├── base/
82-
│ ├── vpc.tf
83-
│ └── subnets.tf
84-
├── layers/
85-
│ ├── production/
86-
│ │ └── layer.tfvars
87-
│ └── staging/
88-
│ ├── layer.tfvars
89-
│ └── vpn.tf
90-
└── stack.tfvars
91-
```
92-
93-
You can find [another example here](example/stacks/example) with all the appropriate file contents.
94-
95-
Then you need to run Stacks in the layer you want to apply:
96-
```bash
97-
cd stacks/vpc/layers/production
98-
python3 ../../../../src/preinit.py
99-
cd stacks.out # where the preinit output goes
100-
terraform init
101-
python3 ../../../../../src/postinit.py
102-
```
103-
104-
Now you're ready to run any further `terraform` commands in the `stacks.out` directory.
105-
106-
***Note:** we recommend putting `stacks.out` in `.gitignore` to prevent it from being tracked by git.*
8+
## What is Stacks?
9+
10+
**Stacks** is a [Terraform](https://www.terraform.io/) code pre-processor.
11+
Its primary goal is to minimize your total Terraform codebase without giving up on coverage. To do more with less.
12+
13+
As a code pre-processor, Stacks receives your "input code" and returns "output code" for Terraform to consume.
14+
15+
Stacks was originally developed and continues to be maintained by the Infrastructure SRE team at [Cisco ThousandEyes](https://www.thousandeyes.com/).
16+
It was initially presented and open-sourced at [SREcon23 Americas](https://www.usenix.org/conference/srecon23americas/presentation/bejarano).
17+
18+
You can read "Terraform" and "OpenTofu" interchangeably, Stacks works with both but we've chosen to go with "Terraform" for readability.
19+
20+
The ["I am starting from scratch" quick-start guide](<2.2. I am starting from scratch.md>) is a good introduction to Stacks and what it does.
21+
22+
23+
## Documentation
24+
25+
1. About
26+
1. [Considerations before using](<docs/1.1. Considerations before using.md>)
27+
2. [Stacks vs. its alternatives](<docs/1.2. Stacks vs its alternatives.md>)
28+
29+
2. Quick-start guide
30+
1. [Installation instructions](<docs/2.1. Installation instructions.md>)
31+
2. [I am starting from scratch](<docs/2.2. I am starting from scratch.md>)
32+
3. [I am collaborating to an existing stack](<docs/2.3. I am collaborating to an existing stack.md>)
33+
4. [I am collaborating to Stacks itself](<docs/2.4. I am collaborating to Stacks itself.md>)
34+
35+
3. Reference
36+
1. Native features
37+
1. [Global Terraform code](<docs/3.1.1. Global Terraform code.md>)
38+
2. [Reusable root modules](<docs/3.1.2. Reusable root modules.md>)
39+
3. [Jinja templating for Terraform](<docs/3.1.3. Jinja templating for Terraform.md>)
40+
4. [Jinja templating for variables](<docs/3.1.4. Jinja templating for variables.md>)
41+
5. [Remote lookup functions](<docs/3.1.5. Remote lookup functions.md>)
42+
6. [Inline secret encryption](<docs/3.1.6. Inline secret encryption.md>)
43+
7. [Automatic variable initialization](<docs/3.1.7. Automatic variable initialization.md>)
44+
2. Features you can build with Stacks
45+
1. [Terraform state backend configuration](<docs/3.2.1. Terraform state backend configuration.md>)
46+
2. [Terraform provider generation](<docs/3.2.2. Terraform provider generation.md>)
47+
3. [Input validation](<docs/3.2.3. Input validation.md>)
48+
3. Command-line interface
49+
1. [`stacks render`](<docs/3.3.1. stacks render.md>)
50+
2. [`stacks terraform`](<docs/3.3.2. stacks terraform.md>)
51+
3. [`stacks diff`](<docs/3.3.3. stacks diff.md>)
52+
4. [`stacks encrypt`](<docs/3.3.4. stacks encrypt.md>)
53+
5. [`stacks decrypt`](<docs/3.3.5. stacks decrypt.md>)
54+
6. [`stacks surgery list`](<docs/3.3.6. stacks surgery list.md>)
55+
7. [`stacks surgery import`](<docs/3.3.7. stacks surgery import.md>)
56+
8. [`stacks surgery remove`](<docs/3.3.8. stacks surgery remove.md>)
57+
9. [`stacks surgery rename`](<docs/3.3.9. stacks surgery rename.md>)
58+
10. [`stacks surgery move`](<docs/3.3.10. stacks surgery move.md>)
59+
11. [`stacks surgery edit`](<docs/3.3.11. stacks surgery edit.md>)
60+
4. [Directory structure](<docs/3.4. Directory structure.md>)
61+
5. [Special variables](<docs/3.5. Special variables.md>)
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Considerations before using
2+
3+
## Stacks is designed for monorepos
4+
5+
Stacks is primarily designed to be used in Terraform monorepos.
6+
7+
We define a Terraform monorepo as a single version control repository whose code maps to two or more Terraform states.
8+
You can have multiple Terraform monorepos as long as they all map to more than one state each.
9+
10+
While perfectly possible to use in "1 repository = 1 state" setups, Stacks shines brightest when "1 repository = N states".
11+
12+
If your setup is not monorepo-like, we do not recommend you use Stacks.
13+
14+
## Not all Terraform automation tools support pre-processors like Stacks
15+
16+
Stacks was originally developed to run on top of [Atlantis](https://www.runatlantis.io/).
17+
Atlantis does support code pre-processors in the form of [pre-workflow hooks](https://www.runatlantis.io/docs/pre-workflow-hooks.html#pre-workflow-hooks).
18+
19+
Unfortunately, not all Terraform automation tools are flexible enough for you to run a thing that will modify your checked-out code before Terraform consumes it.
20+
21+
Same restrictions apply to any code scanning tools you may be using. You'll have to put Stacks before them, which may not be possible depending on what continuous integration platform they're running on.
22+
23+
If your Terraform automation pipeline does not support such code pre-processors, you cannot use Stacks.
24+
25+
## You will not be able to use code formatters like `terraform fmt`
26+
27+
Since not all Stacks' input code is valid HCL, formatters like `terraform fmt` will not work.
28+
29+
You can still use code formatters in output code, but since its not meant to be persisted anywhere there's little to no reason to do that either.
30+
31+
If format enforcing through code formatters is something you're not willing to give up, you cannot use Stacks.
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Stacks vs. its alternatives
2+
3+
## Stacks vs. Terraform workspaces
4+
5+
A Stacks stack is a Terraform root module which you can deploy as many times as you have layers.
6+
7+
Terraform CLI [workspaces](https://developer.hashicorp.com/terraform/language/state/workspaces) let you deploy the same root module as many times as you have workspaces.
8+
9+
Both allow you to inject different input variable values on different layers or workspaces, respectively.
10+
11+
So it would seem like both are similar, however, the primary goal of Terraform workspaces is to [enable testing changes](https://developer.hashicorp.com/terraform/cli/workspaces#use-cases) on a separate state before modifying production infrastructure, and HashiCorp [explicitly recommends against](https://developer.hashicorp.com/terraform/cli/workspaces#when-not-to-use-multiple-workspaces) using workspaces for long-lived parallel deployments of the same root module.
12+
13+
_HCP Terraform workspaces are a different feature to Terraform CLI workspaces, and do not compare with Stacks._
14+
15+
## Stacks vs. Terragrunt
16+
17+
[Terragrunt](https://terragrunt.gruntwork.io/) and Stacks achieve very similar results with very different strategies.
18+
19+
Both enforce a specific directory structure on your repository.
20+
Both generate output code for Terraform to consume.
21+
22+
Terragrunt adds an [extra layer of configuration](https://terragrunt.gruntwork.io/docs/getting-started/overview/#example) on top of Terraform which lets you define what code it generates.
23+
Terragrunt is heavily influenced by Terraform's [specifics](https://terragrunt.gruntwork.io/docs/features/state-backend/).
24+
It even has special features for [AWS](https://terragrunt.gruntwork.io/docs/features/aws-authentication/).
25+
26+
Stacks is radically simpler in that it's mainly a thin layer of [Jinja](https://jinja.palletsprojects.com/en/stable/) on top of your Terraform code.
27+
So much so that you can probably use Stacks for other declarative purposes like generating [Kubernetes](https://kubernetes.io/) manifests for [`kubectl`](https://kubernetes.io/docs/reference/kubectl/) to consume, for example.
28+
29+
_Terragrunt Stacks is a Terragrunt feature that does not compare with Stacks, and while the word "stacks" is overloaded, Stacks existence precedes that of Terragrunt Stacks._
30+
31+
## Stacks vs. CDK for Terraform
32+
33+
Both Stacks and [CDKTF](https://developer.hashicorp.com/terraform/cdktf) can be used to achieve the same results, but again with very different approaches.
34+
35+
Where Stacks adds a thin layer of Jinja templating on top of the HCL you already know, CDKTF replaces HCL with one of the imperative programming language it supports.
36+
While that can be a good thing if what you want is limitless customizability of your infrastructure set based on imperative logic, we've found that very similar results can be achieved without the complexities CDK for Terraform comes with.
37+
38+
## Stacks vs. Pulumi
39+
40+
Everything we said above about CDK for Terraform can be said about Pulumi, as they're basically interchangable.
41+
42+
## Terraform Cloud Stacks
43+
44+
Terraform Cloud Stacks is a HCP Terraform feature that enables orchestrating the deployment of multiple interdependent root modules together.
45+
So while the names are the same, HCP Terraform Stacks does not compare with Stacks.
46+
47+
_And about the word "stacks" being overloaded again: Stacks was initially released on March 2023, Terraform Cloud Stacks was announced later on October that year._
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Installation instructions
2+
3+
## 1. Install Python
4+
5+
Stacks is written in Python, so it'll need a working [Python](https://www.python.org/downloads/) interpreter on your machine.
6+
7+
We recommend the version specified in [pyproject.toml](../pyproject.toml).
8+
9+
## 2. Install `pip` or `uv`
10+
11+
Stacks is installable with both [`pip`](https://pypi.org/project/pip/) and [`uv`](https://docs.astral.sh/uv/).
12+
13+
Choose one and install it. If you already have `pip` installed you can skip `uv`, otherwise we recommend the latter.
14+
15+
## 3. Install Terraform
16+
17+
Stacks requires [Terraform](https://developer.hashicorp.com/terraform/install) (or [OpenTofu](https://opentofu.org/docs/intro/install/)) to be installed on your machine.
18+
19+
Stacks will use the binary in the `STACKS_TERRAFORM_PATH` environment variable, which defaults to `terraform` (so it'll look up `terraform` in `$PATH` and use that).
20+
21+
If you use OpenTofu make sure to set `STACKS_TERRAFORM_PATH` to `tofu`.
22+
23+
If `STACKS_TERRAFORM_PATH` is not in `$PATH`, you can also set `STACKS_TERRAFORM_PATH` to the absolute path of the binary you want to use (e.g.: `STACKS_TERRAFORM_PATH=/usr/bin/terraform`).
24+
25+
## 4. Install Stacks
26+
27+
To install Stacks using `pip`:
28+
```shell
29+
pip3 install --break-system-packages git+https://github.com/cisco-open/stacks.git
30+
```
31+
32+
To install Stacks using `uv`:
33+
```shell
34+
uv tool install git+https://github.com/cisco-open/stacks.git
35+
```
36+
37+
For development, we recommend you install Stacks from source:
38+
```shell
39+
git clone [email protected]:cisco-open/stacks.git
40+
cd stacks/
41+
uv tool install --editable .
42+
```
43+
The `--editable` flag allows you to try your changes right away without reinstalling `stacks`.

0 commit comments

Comments
 (0)