You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: first pass at reworking to more holistic example (#5)
## what
- Reworking the `client-tf-templates` repo into `example-tf`
## why
- I want to have something more holistic that shows + describes how we
do things. The way things are now is great, but I want to setup this
project so that we can use it for more. This is a first attempt at doing
so. cc @gberenice I want to collab on this, so we'll discuss soon 👍
## references
- N/A
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Documentation**
- Revised repository overview and module guides for clearer usage
instructions.
- **New Features**
- Introduced a new configuration for streamlined CLI tool version
management.
- **Chores**
- Removed obsolete pre-commit settings.
- Updated tool versions and added a new linting action to enhance
overall quality.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Veronika Gnilitska <[email protected]>
Copy file name to clipboardExpand all lines: README.md
+74-13Lines changed: 74 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,14 +1,25 @@
1
-
# client-tf-templates
1
+
# example-tf
2
2
3
-
This repository serves as a template for creating Terraform [child](https://opentofu.org/docs/language/modules/#child-modules) and [root](https://opentofu.org/docs/language/modules/#the-root-module) modules, providing a standardized structure and essential files for efficient module development. It's designed to ensure consistency and best practices across Terraform projects.
3
+
This repository serves as an example and template for how Masterpoint thinks about organizing a vanilla Terraform or OpenTofu (from now on referred to as "TF") monorepo with root modules, child modules, and accompanying tooling.
4
4
5
-
Child module example is provided in [terraform-random-pet](./terraform-random-pet/) directory.
5
+
This includes example configurations and recommendations around the following topics:
6
6
7
-
Root module example is provided in [root-module](./root-module/) directory.
7
+
<!-- TODO: Link to what Multi-instance root modules are once https://github.com/masterpointio/masterpoint.io/pull/49 ships -->
8
8
9
-
This README.md serves as the module's primary documentation and entry point.
9
+
1. Example organizational structure for an IaC Monorepo (Multi-instance Root Modules + Child Modules)
10
+
1. Root module example is provided in the [root-modules/template-root-module](./root-modules/template-root-module/) directory.
11
+
2. Child module example is provided in the [child-modules/random-pet](./child-modules/random-pet/) directory
12
+
2.[Recommendations for module file structure](#structure) with [file-by-file guidance](#file-by-file-guidance)
13
+
3.[Recommendations for version pinning TF + Providers](#versioning-tf-and-providers)
14
+
4.[Managing which TF binary is used per project](#managing-which-tf-binary-is-used-per-project)
15
+
5.[Guidance on linting + CI for TF](#tf-linting--ci)
1. Example Native TF Tests with accompanying GitHub Action workflow for running tests
20
+
-->
21
+
22
+
## Recommendations (TODO: Discuss)
12
23
13
24
We recommend to include:
14
25
@@ -123,14 +134,16 @@ We’re particular about how we version providers and Terraform/OpenTofu in chil
123
134
124
135
### Child Modules
125
136
126
-
Since child-modules are intended to be used many times throughout your code, it’s important to make it so that they create as little restrictions on the consuming consuming root module as possible.
137
+
<!-- TODO: Update to link Child Modules to Terms blog post once live -->
138
+
139
+
Since child-modules are intended to be used many times throughout your or others code, it’s important to make it so that they create as little restrictions on the consuming root module as possible.
127
140
128
141
This means you should:
129
142
130
143
- Identify the earliest Terraform/OpenTofu and provider versions your child module supports.
131
144
- Use the `>=` operator to ensure that consumers run at least these versions.
132
145
133
-
By setting a lower bound (e.g., `>= 1.3`) rather than pinning exact versions, you allow root modules to choose their own Terraform and provider versions. This means a root module can upgrade Terraform or providers without requiring updates to all child modules.
146
+
By setting a lower bound (e.g., `>= 1.3`) rather than pinning exact versions, you allow root modules to choose their own Terraform/OpenTofu and provider versions. This means a root module can upgrade their TF or providers versions without requiring updates to the child modules that they consume.
134
147
135
148
Example:
136
149
@@ -147,15 +160,17 @@ terraform {
147
160
}
148
161
```
149
162
150
-
In this example, the child module only demands a minimum version (Terraform 1.3, Random provider 3.0), letting the root module run newer versions as they become available.
163
+
In this example, the child module only demands a minimum version (Terraform or OpenTofu 1.3, Random provider 3.0), letting the root module run newer versions as they become available.
151
164
152
165
### Root Modules
153
166
154
-
Root modules are intended to be planned and applied and therefore they should be more prescriptive so that they’re called consistently in each case that you instantiate a new root module instance (i.e. a state file).
167
+
<!-- TODO: Update to link Root Modules to Terms blog post once live -->
168
+
169
+
Root modules are intended to be planned and applied and therefore they should be more prescriptive so that they’re called consistently in each case that you instantiate a new root module instance (i.e. create a new state file).
155
170
156
171
To accomplish that, you should do the following:
157
172
158
-
- Explicitly pin the latest version of Terraform/OpenTofu that your root module supports. You’ll need to upgrade this version each time you want to use a new TF version across your code base.
173
+
- Explicitly pin the latest version of TF that your root module supports. You’ll need to upgrade this version each time you want to use a new TF version across your code base.
159
174
- Identify the highest stable provider versions your root module supports, then use the [pessimistic operator](https://developer.hashicorp.com/terraform/language/expressions/version-constraints#operators)`~>` to allow only patch-level updates. This gives you automatic bug fixes and minor improvements without risking major breaking changes.
160
175
161
176
Example:
@@ -173,9 +188,55 @@ terraform {
173
188
}
174
189
```
175
190
176
-
In this example Terraform is pinned exactly at 1.3.7, the AWS provider is pinned with `~> 5.81.0`, which means it can update to 5.81.1, 5.81.2, etc., but not jump to 5.82.0.
191
+
In this example two things are happening:
192
+
193
+
1. TF is pinned exactly at `1.3.7`, which ensures your entire team will use the correct version with this root module.
194
+
2. The AWS provider is pinned with `~> 5.81.0`, which means it can update to `5.81.1`, `5.81.2`, etc., but not jump to `5.82.0`.
195
+
196
+
If you're more willing to use the bleeding edge of providers, you can always use the `~>` operator on the minor version like so `version = "~> 5.81"`. This will enable any new minor version updates and is essentially a shorthand for `>= 5.81.0 && < 6.0`. Be aware that providers do break and this has the possibility to frustrating bugs from providers to affect your project.
177
197
198
+
## Managing which TF binary is used per project
199
+
200
+
At Masterpoint, we're big fans of [Aqua](https://aquasecurity.github.io/aqua/) for managing which TF binary is used per project. This allows us to have a single TF binary that is used across our entire project, but still enables us to use root module specific TF versions if needed.
201
+
202
+
Check out the [aqua.yaml](.aqua/aqua.yaml) file to see how simple it is to use aqua for this project and check out [the Aqua docs](https://aquasecurity.github.io/aqua/getting-started/installation/) on how you can use this tool for your own project.
203
+
204
+
<!--
205
+
TODO: Work these into other sections.
178
206
## Additional Tips
179
207
180
208
- Testing and Examples: Consider adding an examples/ directory with sample configurations and a test/ directory (if using tools like terratest or native Terraform testing) to ensure the module works as intended
181
-
- Continuous Improvement: Update documentation and constraints (versions.tf) as Terraform and providers evolve, and as you refine the module’s functionality.
209
+
- Continuous Improvement: Update documentation and constraints (versions.tf) as Terraform and providers evolve, and as you refine the module’s functionality. -->
210
+
211
+
## TF Linting + CI
212
+
213
+
There are many tools to format, lint, and ensure consistency of TF code. The tool that we recommend is [trunk Code Quality](https://docs.trunk.io/code-quality). This single tool allows us to do the following:
214
+
215
+
1. Format our TF code with `terraform fmt` or `tofu fmt` within our IDE and ensure this is run on each commit.
216
+
1.[This is handled by the trunk `terraform` or `tofu` linter](https://docs.trunk.io/code-quality/linters/supported/tofu).
217
+
2. Validate our TF code with `terraform validate` or `tofu validate` within our IDE and ensure this is run on each commit.
218
+
1.[This is handled by the trunk `terraform` or `tofu` linter](https://docs.trunk.io/code-quality/linters/supported/tofu).
219
+
3. Generate documentation for our TF code with `terraform-docs` and ensure it is kept up-to-date on each commit.
220
+
1.[This is handled by the trunk `terraform-docs` action](https://github.com/trunk-io/plugins/tree/main/actions/terraform-docs), which [Masterpoint originally developed](https://github.com/trunk-io/plugins/pull/966).
221
+
4. Run TFLint against our code to ensure it is written against the best practices.
222
+
1.[This is handled by the trunk `tflint` linter](https://docs.trunk.io/code-quality/linters/supported/tflint).
223
+
5. Run a TF security scan against our code to ensure we're not introducing any security vulnerabilities.
224
+
1.[This is handled by the trunk `trivy` linter](https://docs.trunk.io/code-quality/linters/supported/trivy).
225
+
6. Run these checks in a CI pipeline to ensure they're enforced on each PR.
226
+
1.[This is handled by the trunk-action workflow](https://docs.trunk.io/code-quality/setup-and-installation/github-integration) in the [.github/workflows/lint.yaml](.github/workflows/lint.yaml) file.
227
+
228
+
As you can see, this is a LOT of checks that trunk is supporting for us and this consolidation on one tool to support this (and much more) is a huge win.
229
+
230
+
Check out our [.trunk/trunk.yaml](.trunk/trunk.yaml) file to see how we configure this and [check the trunk Code Quality getting started documentation](https://docs.trunk.io/code-quality) on how you can use this tool for your own project.
231
+
232
+
## Frequently Asked Questions
233
+
234
+
### Why do you prefer DRY (Don't Repeat Yourself) Root Modules vs WET (Write Every Time) Root Modules?
235
+
236
+
We advocate IaC should be treated like code and traditional software. You encode some level of business logic into it, and consistently copying+pasting that logic as part of your day-to-day processes creates a maintenance burden that we believe should be avoided. This particularly shows up when IaC is managed at scale and we have seen these types of setups lead to a lot of toil and a lot of technical debt.
237
+
238
+
We will write up more on this soon and link to it here.
239
+
240
+
### Why don't you use a TF Framework like [Terragrunt](https://terragrunt.gruntwork.io/), [Terramate](https://terramate.io/), or [Atmos](https://atmos.tools/)?
241
+
242
+
We're big fans of the frameworks (particularly Atmos + Terramate, which we have a good deal of experience with), and we believe they're fantastic options for sophisticated teams that are starting from scratch. But for projects that aren't starting from scratch or have a desire to keep things simple, we believe Vanilla TF combined with a strong automation platform is a great option.
0 commit comments