One of the big challenges is how to organize your cloud account setup.

In one account, you can have a couple of application stacks. The challenge is to able fast to apply/plan/destroy them without any burden.

What works for me is to use one application-terraform-bulk.sh script which will know which modules to which stacks belong. And if I have a couple of modules to apply in the application stack I use terraform-bulk.sh script which just applies all modules in the current folder.

Here is an example.

Those are the ECR modules which must be presented in this account. I do not care about which stack will own them, so I will use the general terraform_bulk.sh script

The commands which I can do are:

./terraform_bulk.sh init
# ...It will go in each folder and do terraform init
./terraform_bulk.sh plan
# ...It will go in each folder and do terraform plan
./terraform_bulk.sh apply
./terraform_bulk.sh destroy

Here is how it looks the script

#!/bin/bash
trap "exit" INT

modules=(
  anaconda
  essential
  essential-anaconda-environment
)


terraform_plan() {
  local project="$1"
  pushd .
  cd $project
  terraform plan
  popd
}



terraform_init() {
  local project="$1"
  pushd .
  cd $project
  terraform init
  popd
}


terraform_apply() {
  local project="$1"
  pushd .
  cd $project
  terraform apply -auto-approve
  popd
}


terraform_destroy() {
  local project="$1"
  pushd .
  cd $project
  terraform destroy -auto-approve
  popd
}


terraform_show() {
  local project="$1"
  pushd .
  cd $project
  terraform show
  popd
}


# array=(1 2 3 4)
# reverse array foo
# echo "${foo[@]}"
reverse() {
    # first argument is the array to reverse
    # second is the output array
    declare -n arr="$1" rev="$2"
    for project in "${arr[@]}"
    do
        rev=("$project" "${rev[@]}")
    done
}





case "$1" in
  init)
      for project in "${modules[@]}"
      do
        echo ""
        echo ""
        echo $project
        terraform_init $project
      done

      ;;

  show)
      for project in "${modules[@]}"
      do
        echo ""
        echo ""
        echo $project
        terraform_show $project
      done
      ;;


  apply)
      for project in "${modules[@]}"
      do
        echo ""
        echo ""
        echo $project
        terraform_apply $project
      done
      ;;

  destroy)
      reverse modules reversed_modules
      for project in "${reversed_modules[@]}"
      do
        echo ""
        echo ""
        echo $project
        terraform_destroy $project
      done
      ;;

  plan)
      reverse modules reversed_modules
      for project in "${reversed_modules[@]}"
      do
        echo ""
        echo ""
        echo $project
        terraform_plan $project
      done
      ;;

  *)
      echo $"Usage: $0 {init|apply|destroy}"
      exit 1

esac


In my case in the development cloud account, I have to host two applications. Then I just create two versions of the script like this.

wxr-xr-x 13 guda guda 4096 Nov 15 13:20 .
drwxr-xr-x  6 guda guda 4096 Nov  5 11:20 ..
drwxr-xr-x  3 guda guda 4096 Oct 28 18:14 athena
drwxr-xr-x  3 guda guda 4096 Jul 10 15:17 cm
drwxr-xr-x  5 guda guda 4096 Dec  5 22:42 ecr
drwxr-xr-x 11 guda guda 4096 Oct 28 18:39 endpoints
-rwxr-xr-x  1 guda guda 2345 Oct 28 18:38 essential-terraform_bulk.sh <<<<<
-rwxr-xr-x  1 guda guda 2190 Oct 28 18:14 etl_monitoring-terraform_bulk.sh <<<<<
drwxr-xr-x  3 guda guda 4096 Nov  5 11:24 fargate_essential
drwxr-xr-x  3 guda guda 4096 Oct 28 18:47 rds
drwxrwxr-x  3 guda guda 4096 Sep  3 19:48 s3
drwxr-xr-x  5 guda guda 4096 Oct 28 18:47 secret_manager
drwxr-xr-x  3 guda guda 4096 Aug 15 17:02 vpc
drwxr-xr-x  4 guda guda 4096 Nov 15 13:20 vpc_peering
drwxr-xr-x  3 guda guda 4096 Aug 19 14:51 zone_security_groups

So when I want to provision:

  • essential app – use essential-terraform_bulk.sh
  • etl monitoring app – use etl_monitoring-terraform_bulk.sh

Be aware when you have to share the resources – for example vpc, you do not want the first terraform-bulk.sh to drop a resource which is needed by the second application terraform bulk.