docs-terraform-guidelines

Context pattern

A design pattern is a general, reusable solution to a commonly occurring problem within a given context in software design

.
β”œβ”€β”€ environment 
β”‚Β Β  β”œβ”€β”€ module.hcl
β”‚Β Β  β”œβ”€β”€ dev  
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ inputs.hcl 
β”‚Β Β  β”‚Β Β  └── terragrunt.hcl 
β”‚Β Β  β”œβ”€β”€ preproduction
β”‚Β Β  β”‚Β Β  β”œβ”€β”€ inputs.hcl 
β”‚Β Β  β”‚Β Β  └── terragrunt.hcl
β”‚Β Β  └── production
β”‚Β Β  Β  Β  β”œβ”€β”€ inputs.hcl 
β”‚Β Β  Β Β   β”œβ”€β”€ organisation.tf
β”‚Β Β  Β Β   └── terragrunt.hcl 
β”œβ”€β”€ application 
β”‚Β Β  β”œβ”€β”€ app_1  
β”‚Β Β  β”‚   β”œβ”€β”€ module.hcl
|   β”‚Β Β  β”œβ”€β”€ dev  
|   β”‚Β Β  β”‚Β Β  β”œβ”€β”€ inputs.hcl 
|   β”‚Β Β  β”‚Β Β  └── terragrunt.hcl
|   β”‚   β”œβ”€β”€ preproduction  
|   β”‚Β Β  β”‚Β Β  β”œβ”€β”€ inputs.hcl 
|   β”‚Β Β  β”‚Β Β  └── terragrunt.hcl
|   β”‚   └── production  
|   β”‚Β Β  Β Β  β”œβ”€β”€ inputs.hcl 
|   β”‚Β Β  Β Β  └── terragrunt.hcl
β”‚Β Β  β”œβ”€β”€ app_2
β”‚Β Β  └── app_3
β”œβ”€β”€ common.hcl
└── _settings.hcl

πŸ—¨οΈ Context pattern

You implemented the WYSIWYG pattern and have instantiated your module multiple times in your layers and are tired of copying them or/and made some mistakes while doing so.

The context pattern for WYSIWYG aims to keep your code DRY (Don’t repeat yourself)! 🌞

Thus all concepts from the WYSIWYG pattern apply to this pattern.

πŸ— Terragrunt context proposal

Don’t repeat yourself is the motto of terragrunt. Terragrunt allows you:

πŸ‘Ό Input heaven

Each terragrunt layer defines one and only one module, but input for this module can be defined throughout the tree structure. Example:

.
β”œβ”€β”€ environment 
β”‚Β Β  β”œβ”€β”€ module.hcl # Defines the module used by every subsequent layer
β”‚Β Β  └─── dev  
β”‚Β Β   Β Β  β”œβ”€β”€ inputs.hcl # Defines **unique** input for this layer (Ex: the database should be a bit smaller in dev)
β”‚Β Β  Β  Β  └── terragrunt.hcl # Defines terragrunt configuration
β”œβ”€β”€ common.hcl # Defines default value to every layer (Ex: tenant id, size of the database)
└── _settings.hcl # Defines required_version of terraform, terraform provider used but not the version and unique identifier for the backend **for every layer**

πŸ—¨οΈ Context

The context of a layer is all the inputs required for it to be created. Your tree structure, with inputs throughout it, is thus your context.

If your context is DRY, then your tree structure is OK. If you have to repeat an input you might want to refactor your tree structure. Check the refactoring section for details.

πŸ’Ž Uniqueness

Each terragrunt layer defines one and only one module, you can not create a new resource independently without adding it to the module. This will force you to ask the question

Should this new resource really be added to this layer ? Isn’t this resource a new project need ?

Consequently, you can either:

⛩️ Ease of refactoring

The biggest advantage of terragrunt is that since every layer is a single module thus a single state. When identifying a new projectneed,d you can rearrange you tree structure to match the new view of your project need.

πŸͺ“ Splitting of layers

While terragrunt allows you to have a DRY configuration. It also allows you to easily split layer to match project needs This will enforce you to rethink your splitting every time you add a resource / module to a layer.

In Example 1 the use case is that we want to add resources for a new frontend. At this point you have 2 choices :

βœ’οΈ Example 1 : Add a one frontend

.
β”œβ”€β”€ application 
β”‚Β Β  β”œβ”€β”€ module.hcl # Calls the backend module
β”‚Β Β  └─── app_1
|    Β Β    β”œβ”€β”€ dev
β”‚Β Β  Β Β     β”‚    β”œβ”€β”€ inputs.hcl 
β”‚Β Β  Β Β     β”‚    └── terragrunt.hcl 
β”‚         └── production
β”‚   Β Β  Β Β       β”œβ”€β”€ inputs.hcl 
β”‚   Β Β  Β Β       └── terragrunt.hcl
└── _settings.hcl

My application needs a frontend, but only for this one app

.
β”œβ”€β”€ application 
β”‚Β Β  β”œβ”€β”€ backend
β”‚Β Β  β”‚   β”œβ”€β”€ module.hcl
β”‚   β”‚Β Β  └─── app_1  
β”‚   β”‚         β”œβ”€β”€ dev
β”‚   β”‚Β Β  Β Β     β”‚   β”œβ”€β”€ inputs.hcl 
β”‚   β”‚Β Β  Β Β     β”‚   └── terragrunt.hcl 
β”‚   β”‚         └── production
β”‚   β”‚   Β Β  Β Β      β”œβ”€β”€ inputs.hcl 
β”‚   β”‚   Β Β  Β Β      └── terragrunt.hcl
β”‚Β Β  └── frontend
β”‚Β Β      β”œβ”€β”€ module.hcl
β”‚   Β  Β  └─── app_1  
β”‚             β”œβ”€β”€ dev
β”‚      Β Β  Β Β   β”‚   β”œβ”€β”€ inputs.hcl 
β”‚      Β Β  Β Β   β”‚   └── terragrunt.hcl 
β”‚             └── production
β”‚         Β Β  Β Β    β”œβ”€β”€ inputs.hcl 
β”‚         Β Β  Β Β    └── terragrunt.hcl
└── _settings.hcl

βœ’οΈ Example 2 : Add Redis to all backends

.
β”œβ”€β”€ application 
β”‚Β Β  β”œβ”€β”€ module.hcl # Calls the backend module
β”‚Β Β  └─── app_1
|    Β Β    β”œβ”€β”€ dev
β”‚Β Β  Β Β     β”‚    β”œβ”€β”€ inputs.hcl 
β”‚Β Β  Β Β     β”‚    └── terragrunt.hcl 
β”‚         └── production
β”‚   Β Β  Β Β       β”œβ”€β”€ inputs.hcl 
β”‚   Β Β  Β Β       └── terragrunt.hcl
└── _settings.hcl

I’m going to need a Redis for my backend I’ll juste update my module backend and test it by overwriting the call to the module within the layer terragrunt.hcl

πŸ—ƒοΈ Files and folder naming

πŸ“ Folders

πŸ“„ Files

πŸ—οΈ Files organisation

There are a lot of ways to organize your files and include function. Here is a proposition :

βš–οΈ Pros and cons

Pros:

Cons: