# a DRY terraform demo

The idea here was to show how we _could_ move away from a "set of terraform per environment" model to a "single set of terraform with parameterised builds" model.

It's not to try and convince anyone one way or another, but to have a go and see if it sparks joy ✨

## How it works

You have all your terraform as usual, and you set your variables as usual too, but you only set a default if you want default behaviour (don't do it unless you require the build to fail when vars are not supplied).

The magic is in the `env` folder. In there, you declare set of config per environment you wish to target. 
The set of per-environment config is two files, each has a different purpose

1. Backend config. This is stuff you need to init terraform with (such as where to find the state = where to deploy to) - this is stored in `env/*.tfbackend`.
2. Build-time config. This is stuff you want to inject into the components at build time (such as how big of an rds instance to deploy, or how much memory you want to give your lambdas, in each environment)- this is stored in `env/*.tfvars`.

That's it, you just initialise terraform with the `tfbackend`, and plan and apply with the `tfvars`, and it will plan and deploy your stuff wherever you've told it to, in the configuration you want for that env.

## To run this locally

(these commands should point at the terraform entry point, ie where your provider is defined)

```zsh
cd cbeesley/split/terraform

# Assume the role for the environment you're targeting
awsume qa

# Initialise terraform for the QA environment - pass in the tfbackend for QA
tf init -backend-config=env/qa.tfbackend

# Run the plan - pass in the tfvars for QA
tf plan -var-file=env/qa.tfvars

# Apply if you are happy

# If you want to run a plan for another environment, you need to re-init terraform with that backend config:
tf init -reconfigure -backend-config=env/prod.tfbackend

# etc
```

## To run this in a CI environment such as Atlantis

TODO

### Pros and cons

Some of the advantages of this model are:

- No drift between environments (_provided you revert from `main` anything you decide not to progress to production!_)
- Fewer mistakes caused by copypasting, and by fixing stuff in the QA code and forgetting to update the Prod code
- The confidence to deploy to Prod knowing that whatever happens, has already happened in QA (which is reassuring..if you have good monitoring in QA)
- Less "stuff" to deal with (more code = more mental load)
- We could bundle tf templates in with our cookie cutters. Instead of copypaste-propagating errors, instead propagate best practice (as long as we update our templates and that's a whole thing).
- Keeping infra code and app code together empowers developers and maybe takes the burden of responsibility for the whole estate's infra code off of devops

Some of the disadvantages are:

- Our current tooling isn't really up to it, we'd probably need to change some of it (atlantis.yml)
- It lends itself better to a pattern where application code and infra code are maintained side by side (that's a marrive paradigm shift for us)
- It would be hard to migrate it all so would only really be feasible for new projects
- We'd be in a messy pace with two ways of working, maybe for a long time
