Skip to content

taichi-dev/meshy-infra

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

meshy-infra

Terraform infrastructure managed with Terramate for stack orchestration.


Prerequisites

Tool Purpose
Terraform ≥ 1.0 Apply infrastructure
Terramate Stack orchestration and code generation
pre-commit Git hooks
terraform-docs Module README generation (used by the terraform_docs hook)

First-time setup

Install Terramate:

brew install terramate

Install pre-commit if you haven't already:

pip install pre-commit
# After cloning
pre-commit install

That's it. The hooks run automatically on every commit.


Repo layout

envs/
  <env>/                  # dev | staging | prod | logs
    terramate.tm.hcl      # env globals: environment, aws_account_id, regions, etc.
    <service>/            # leaf stack — gets terraform apply'd directly
      stack.tm.hcl        # stack name, description, watch list
      providers.tf        # generated by Terramate — do not edit
      terraform.tf
      main.tf
      variables.tf
      outputs.tf
      README.md

modules/
  <name>/                 # reusable module called via source = "../../../modules/<name>"
    _generated_tags.tf    # generated — tagging vars with null defaults
    main.tf
    variables.tf
    outputs.tf
    terraform.tf
    README.md

scripts/
  update-watches.sh       # rewrites watch = [...] blocks; see scripts/README.md

envs/ contains root Terraform configurations — one per service per environment. Each is an independent state. Run terraform apply (or terramate run) from here.

modules/ contains reusable modules. They are never applied directly; they are called from stacks via source = "../../../modules/<name>".


How Terramate is used here

Globals and generated tags

Shared variables are defined as Terramate globals and code-generated into every stack as providers.tf (envs stacks) or _generated_tags.tf (modules). You never write these by hand.

Global Defined in Value
environment envs/<env>/terramate.tm.hcl "dev", "prod", etc.
aws_account_id envs/<env>/terramate.tm.hcl AWS account number for the env
aws_primary_region envs/<env>/terramate.tm.hcl Default region (e.g. "us-west-2")
aws_regions envs/<env>/terramate.tm.hcl List of regions to create aliased providers for
repo envs/terramate.tm.hcl "meshy-infra"
managed_by envs/terramate.tm.hcl "terraform"
service derived at generation time stack directory name

Each envs/ leaf stack gets four Terraform variables (var.env, var.service, var.repo, var.managed_by) with their defaults pre-populated, plus a local.default_tags map:

# Use in any resource inside an envs/ stack:
resource "aws_instance" "example" {
  # ...
  tags = local.default_tags
}

# Pass through when calling a module:
module "vpc" {
  source     = "../../../modules/vpc"
  env        = var.env
  service    = var.service
  repo       = var.repo
  managed_by = var.managed_by
}

Adding a new shared tag

  1. Add the global to the appropriate level:

    • Repo-wide default → envs/terramate.tm.hcl
    • Per-env override → envs/<env>/terramate.tm.hcl

    Example adding cost_center repo-wide:

    globals {
      repo       = "meshy-infra"
      managed_by = "terraform"
      cost_center = "platform"   # ← new
    }
  2. Add the corresponding variable block and update the default_tags local inside the generate_file "providers.tf" block in envs/<env>/terramate.tm.hcl (repeat for each env, or extract the pattern to a root-level generate block if all envs share it).

  3. Regenerate:

    terramate generate

    This rewrites every providers.tf in envs/ and _generated_tags.tf in modules/. Commit the result.

If Terramate is not installed locally, edit the providers.tf files manually to match what terramate generate would produce, following the pattern of the existing variables.

Watch blocks and --changed detection

The watch = [...] field in stack.tm.hcl tells Terramate which paths outside a stack's own directory affect it. Without this, terramate run --changed won't detect that envs/dev/meshy is affected by a change to modules/vpc.

scripts/update-watches.sh keeps these in sync automatically (the update-terramate-watches pre-commit hook runs it on every .tf commit). After manually adding or removing a module block, you can also run it directly:

./scripts/update-watches.sh

Common workflows

Plan / apply a single stack

cd envs/dev/meshy
terraform init
terraform plan
terraform apply

Plan all stacks with Terramate

terramate run -- terraform init
terramate run -- terraform plan

Plan only stacks affected by your current changes (fast path)

terramate run --changed -- terraform plan

Terramate computes the changed set using git diff against the default branch, plus the watch entries.

Add a module dependency to a stack

  1. Add a module block in the stack's main.tf:

    module "vpc" {
      source = "../../../modules/vpc"
    }
  2. The update-terramate-watches pre-commit hook will update watch in stack.tm.hcl automatically on commit. To update it immediately:

    ./scripts/update-watches.sh

Add a new service or infrastructure component to an environment

Each directory under envs/<env>/ is an independently applied unit of infrastructure — its own Terraform state, its own plan, its own apply. Adding a new one means adding a new directory. Here is the full sequence:

  1. Create the directory and write stack.tm.hcl. This two-line file is what registers the directory with Terramate. Without it, terramate generate will not produce any files here and terramate run will not include it:

    mkdir -p envs/<env>/<name>
    # envs/<env>/<name>/stack.tm.hcl
    stack {
      name        = "<name>"   # should match the folder name
      description = "<one-line description>"
    }
  2. Run terramate generate. This produces providers.tf and state.tf in the new directory — you do not write these by hand:

    terramate generate
  3. Write your .tf files (main.tf, variables.tf, outputs.tf, etc.).

  4. If your .tf files call any shared modules, run the watch script so Terramate knows to re-plan this directory when those modules change:

    ./scripts/update-watches.sh
  5. Initialize and plan:

    cd envs/<env>/<name>
    terraform init
    terraform plan

Adding a brand-new environment (not dev, staging, prod, or logs): you will also need to create envs/<env>/terramate.tm.hcl with the AWS account ID and region list before running terramate generate. Copy envs/dev/terramate.tm.hcl as a starting point.


Pre-commit hooks

Hook What it does
terraform_fmt Formats all .tf files
terraform_docs Injects input/output tables into README.md for any changed module
update-terramate-watches Rewrites watch = [...] in stack.tm.hcl for any stack whose .tf files changed

Run all hooks manually against every file:

pre-commit run --all-files

Files you should not edit by hand

File Owner How to update
providers.tf (in envs/) Terramate Edit globals in envs/<env>/terramate.tm.hcl or envs/terramate.tm.hcl, then run terramate generate
_generated_tags.tf (in modules/) Terramate Edit globals in modules/terramate.tm.hcl, then run terramate generate
watch = [...] in stack.tm.hcl update-watches.sh Add/remove module blocks in .tf files and commit (hook runs automatically)
README.md in modules/ (between the <!-- BEGIN/END_TF_DOCS --> markers) terraform_docs hook Update variables.tf / outputs.tf and commit

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors