Terraform Cloud Project Bootcamp with Andrew Brown —
2.6.0 Terraform Cloud and Multi Homes
This article is part of my Terraform journey with Terraform Bootcamp by Andrew Brown and Andrew Bayko with Chris Williams and Shala.
My wild career adventure into Cloud Computing continues with Andrews, and I highly, highly recommend you to come join us if you are interested. Check out Andrews’ free youtube learning contents. You can also buy some paid courses here to support their good cause.
Agenda
Video here: 2 6 0 Terraform Cloud and Multi Homes
Issue #51 Goals
- ✅ 1) Move our state back to Terraform Cloud with local execution
- ✅ 2) Provision more than one terra home
Workflow
- ✅ 1) Switch back to Terraform Cloud
- ✅ 2) Configure multi
homes
- ✅ 3) Nested variables
1. Switch back to Terraform Cloud
We have been developing and executing locally in Gitpod workspace. In this last episode, Andrew and Andrew walk us through the migration process to move back from the local environment to ‘Terraform Cloud while executing locally’.
First, we go to Terraform Cloud and set our Default Execution Mode
as Local
. At the project level (our terra-house
), set the Execution Mode as Custom > Local.
We have to be able to connect to the remote Terraform Cloud from local Gitpod workspace. So let’s bring back the configuration. Uncomment the cloud
block inside terraform{}
in main.tf
.
terraform {
...
cloud {
organization = "mariachiinajar"
workspaces {
name = "terra-house"
}
}
}
Andrew updates gitpod.yml
.
tasks:
- name: terraform
env:
TF_LOG=DEBUG
before: |
cd $PROJECT_ROOT
source ./bin/install_terraform_cli
source ./bin/generate_tfrc_credentials
source ./bin/set_tf_alias
+ source ./bin/build_provider
Andrew runs terraform init
and terraform apply
and it works.
2. Configure multi homes
Andrew creates another terratowns_home
using the same module (terrahome_aws
). The configuration is the same as before. Now that we are deploying homes for real, you can change the town to the one you like amongst cooker-cove
, gamers-grotto
, the-nomad-pad
, video-valley
, and melomaniac-mansion
. Interesting things to note are:
module
name can be anything. What matters is the path to thesource
.- As every
resource
has to have a unique name, the first home (home
) and second home (home_voices
)have different names. - There are better was to create multiple instances of the same resource. This could be a micro project to further our Terraform skills.
module "home_nomadiachi_hosting" {
source = "./modules/terrahome_aws"
user_uuid = var.teacherseat_user_uuid
public_path = var.nomadiachi.public_path
content_version = var.nomadiachi.content_version
}
resource "terratowns_home" "home" {
name = "Nomadiachi's nomadic life"
description = <<DESCRIPTION
Mariachi works nomadically so popping in and checking out here and there.
Pictures of some memorable moments, quick snapshots of days in and days out.
Come join my nomadinary journey? :D
DESCRIPTION
domain_name = module.home_nomadiachi_hosting.domain_name
town = "the-nomad-pad"
content_version = var.nomadiachi.content_version
}
module "home_voices_hosting" {
source = "./modules/terrahome_aws"
user_uuid = var.teacherseat_user_uuid
public_path = var.voices.public_path
content_version = var.voices.content_version
}
resource "terratowns_home" "home_voices" {
name = "Voices that keep me going"
description = <<DESCRIPTION
Reading is a mental nomadism. Reading quotes is traveling through million different minds and angles.
There were many moments and days I entertained quitting.
But there were voices that give me nudges and pushes (and punches and smashes... and slaps and !@#$@$).
I'm still here and keep moving forward.
Come have a look who are those with the badass voices. lol
DESCRIPTION
domain_name = module.home_voices_hosting.domain_name
town = "the-nomad-pad"
content_version = var.voices.content_version
}
Now Andrew reorganises the assets for homes
. The folder structure is:
public
├── home1
│ ├── assets
│ │ ├── ...
│ │ └── image.jpg
│ ├── index.html
│ └── error.html
├── home2
│ ├── assets
│ │ ├── ...
│ │ └── image.jpg
│ ├── index.html
└── └── error.html
In modules/terrahome_aws/variables.tf
, change the variable name as below.
- variable "index_html_filepath" {
- description = "File path for index.html"
+ variable "public_path" {
+ description = "The file path for the public directory"
In modules/terrahome_aws/resource-storage.tf
, modify the paths using the public_path
variable both aws_s3_object.index_html
and error_html
.
# resource-storage.tf
resource "aws_s3_object" "index_html" {
bucket = aws_s3_bucket.website_bucket.bucket
key = "error.html"
- source = "${path.root}/public/index.html"
+ source = "${var.public_path}/index.html"
content_type = "text/html"
- etag = filemd5("${path.root}/public/index.html")
+ etag = filemd5("${var.public_path}/index.html")
}
3. Nested variables
Andrew decides to reorganise the variables using the nested variable structure. In Terraform, we can achieve this using object
or map
.
// variables.tf at root
variable "nomadiachi" {
type = object({
public_path = string
content_version = number
})
}
variable "voices" {
type = object({
public_path = string
content_version = number
})
}
Now we can use the nested variables as below.
// main.tf at root
module "home_nomadiachi_hosting" {
source = "./modules/terrahome_aws"
user_uuid = var.teacherseat_user_uuid
public_path = var.nomadiachi.public_path
content_version = var.nomadiachi.content_version
}
Andrew changes the module name to terrahome_aws
so we make the changes accordingly across the files where the module
is referenced.
// outputs.tf
module "home_nomadiachi_hosting" {
- source = "./modules/terrahouse_aws"
+ source = "./modules/terrahome_aws"
user_uuid = var.teacherseat_user_uuid
public_path = var.nomadiachi.public_path
content_version = var.nomadiachi.content_version
}
Andrew updates resourceHouseUpdate
function in main.go
. (45:32)
- Add
// parse response JSON
var responseData map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&responseData); err != nil {
return diag.FromErr(err)
}
- Replace
// StatusOK = 200 HTTP Response Code
if resp.StatusCode != http.StatusOK {
- return diag.FromErr(fmt.Errorf("failed to update home resource, status_code: %d, status: %s", resp.StatusCode, resp.Status))
+ return diag.FromErr(fmt.Errorf("failed to create home resource, status_code: %d, status: %s, body: %s", resp.StatusCode, resp.Status, responseData))
}
Then run:
./bin/build_provider
terraform init
Andrew runs terraform init
and terraform apply
and the resources are running on TerraTowns. In case you run into error, compare your code against Andrew’s source code here.
📑 Notes
- With nested variables, we can organise the structure of variables more neatly.
- The term “interpolation” means embedding variables within other strings.
- If you are looking to further your terraform skills, you can try refactoring the multihomes using, for example,
for_each
ormap
function.
Resources
Bootcamp
- Video: 2 6 0 Terraform Cloud and Multi Homes
- My feature branch:
- My complete Learning Journal