Skip to content

Commit 193c430

Browse files
authored
Updated Terraform: Missing answer, clarified some questions, removed duplicate, fixed typos (bregman-arie#10323)
1 parent 4863152 commit 193c430

File tree

3 files changed

+74
-44
lines changed

3 files changed

+74
-44
lines changed

topics/terraform/README.md

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Terraform
1+
# Terraform
22

33
- [Terraform](#terraform)
44
- [Exercises](#exercises)
@@ -71,7 +71,7 @@
7171
- Full automation: In the past, resource creation, modification and removal were handled manually or by using a set of tooling. With Terraform or other IaC technologies, you manage the full lifecycle in an automated fashion.<br>
7272
- Modular and Reusable: Code that you write for certain purposes can be used and assembled in different ways. You can write code to create resources on a public cloud and it can be shared with other teams who can also use it in their account on the same (or different) cloud><br>
7373
- Improved testing: Concepts like CI can be easily applied on IaC based projects and code snippets. This allow you to test and verify operations beforehand
74-
-
74+
-
7575
</b></details>
7676

7777
<details>
@@ -80,7 +80,7 @@
8080
- Declarative: Terraform uses the declarative approach (rather than the procedural one) in order to define end-status of the resources
8181
- No agents: as opposed to other technologies (e.g. Puppet) where you use a model of agent and server, with Terraform you use the different APIs (of clouds, services, etc.) to perform the operations
8282
- Community: Terraform has strong community who constantly publishes modules and fixes when needed. This ensures there is good modules maintenance and users can get support quite quickly at any point
83-
-
83+
-
8484
</b></details>
8585

8686
<details>
@@ -186,7 +186,7 @@ Run `terraform apply`. That will apply the changes described in your .tf files.
186186
A user should be careful with this command because there is no way to revert it. Sure, you can always run again "apply" but that can take time, generates completely new resources, etc.
187187
</b></details>
188188

189-
### Dependencies
189+
### Dependencies
190190

191191
<details>
192192
<summary>Sometimes you need to reference some resources in the same or separate .tf file. Why and how it's done?</summary><br><b>
@@ -201,7 +201,7 @@ In your AWS instance it would like that:
201201

202202
```
203203
resource "aws_instance" "some-instance" {
204-
204+
205205
ami = "some-ami"
206206
instance_type = "t2.micro"
207207
vpc_security_group_ids = [aws_security_group.instance.id]
@@ -215,7 +215,7 @@ resource "aws_instance" "some-instance" {
215215

216216
Yes, when there is a dependency between different Terraform resources, you want the resources to be created in the right order and this is exactly what Terraform does.
217217

218-
To make it ever more clear, if you have a resource X that references the ID of resource Y, it doesn't makes sense to create first resource X because it won't have any ID to get from a resource that wasn't created yet.
218+
To make it ever more clear, if you have a resource X that references the ID of resource Y, it doesn't makes sense to create first resource X because it won't have any ID to get from a resource that wasn't created yet.
219219
</b></details>
220220

221221
<details>
@@ -237,7 +237,7 @@ The output is in DOT - A graph description language.
237237
<details>
238238
<summary>Where can you find publicly available providers?</summary><br><b>
239239

240-
In the [Terraform Registry](https://registry.terraform.io/browse/providers)
240+
In the [Terraform Registry](https://registry.terraform.io/browse/providers)
241241
</b></details>
242242

243243
<details>
@@ -419,10 +419,10 @@ True
419419
- The file `terraform.tfvars`
420420
- Environment variable
421421
- Using `-var` or `-var-file`
422-
422+
423423
According to variable precedence, which source will be used first?</summary><br><b>
424424

425-
The order is:
425+
Terraform loads variables in the following order, with later sources taking precedence over earlier ones:
426426

427427
- Environment variable
428428
- The file `terraform.tfvars`
@@ -487,9 +487,9 @@ You have multiple hardcoded values that repeat themselves in different sections,
487487

488488
```
489489
variable "app_id" {
490-
type = string
490+
type = string
491491
description = "The id of application"
492-
default = "some_value"
492+
default = "some_value"
493493
}
494494
```
495495

@@ -638,7 +638,7 @@ data "aws_vpc" "default {
638638
}
639639
```
640640

641-
You can retrieve the ID attribute this way: `data.aws_vpc.default.id`
641+
You can retrieve the ID attribute this way: `data.aws_vpc.default.id`
642642
</b></details>
643643

644644
<details>
@@ -716,6 +716,9 @@ Since a provisioner can run a variety of actions, it's not always feasible to pl
716716

717717
<details>
718718
<summary>What is <code>local-exec</code> and <code>remote-exec</code> in the context of provisioners?</summary><br><b>
719+
720+
<code>local-exec</code> provisioners run commands on the machine where Terraform is executed, while <code>remote-exec</code> provisioners run commands on the remote resource.
721+
719722
</b></details>
720723

721724
<details>
@@ -747,11 +750,6 @@ There are quite a few cases you might need to use them:
747750
Output variables are named values that are sourced from the attributes of a module. They are stored in terraform state, and can be used by other modules through <code>remote_state</code>
748751
</b></details>
749752

750-
<details>
751-
<summary>Explain <code>remote-exec</code> and <code>local-exec</code></summary><br><b>
752-
</b></details>
753-
754-
755753
<details>
756754
<summary>Explain "Remote State". When would you use it and how?</summary><br><b>
757755
Terraform generates a `terraform.tfstate` json file that describes components/service provisioned on the specified provider. Remote
@@ -833,7 +831,7 @@ There is more than one answer to this question. It's very much depends on whethe
833831
- tfstate contains credentials in plain text. You don't want to put it in publicly shared location
834832
- tfstate shouldn't be modified concurrently so putting it in a shared location available for everyone with "write" permissions might lead to issues. (Terraform remote state doesn't has this problem).
835833
- tfstate is an important file. As such, it might be better to put it in a location that has regular backups and good security.
836-
834+
837835
As such, tfstate shouldn't be stored in git repositories. secured storage such as secured buckets, is a better option.
838836

839837
</b></details>
@@ -855,7 +853,7 @@ In general, storing state file on your computer isn't a problem. It starts to be
855853

856854
- Don't edit it manually. tfstate was designed to be manipulated by terraform and not by users directly.
857855
- Store it in secured location (since it can include credentials and sensitive data in general)
858-
- Backup it regularly so you can roll-back easily when needed
856+
- Backup it regularly so you can roll-back easily when needed
859857
- Store it in remote shared storage. This is especially needed when working in a team and the state can be updated by any of the team members
860858
- Enabled versioning if the storage where you store the state file, supports it. Versioning is great for backups and roll-backs in case of an issue.
861859

@@ -902,7 +900,7 @@ Let's say we chose use Amazon s3 as a remote Terraform backend where we can stor
902900
4. Block public access
903901
5. Handle locking. One way is to add DB for it
904902
6. Add the point you'll want to run init and apply commands to avoid an issue where you at the same time create the resources for remote backend and also switch to a remote backend
905-
7. Once resources were created, add Terraform backend code
903+
7. Once resources were created, add Terraform backend code
906904

907905
```
908906
terraform {
@@ -911,7 +909,7 @@ terraform {
911909
}
912910
}
913911
```
914-
7. Run `teraform init` as it will configure the backend
912+
7. Run `terraform init` as it will configure the backend
915913

916914
</b></details>
917915

@@ -1044,14 +1042,25 @@ resource "some_resource" "some_name" {
10441042
</b></details>
10451043

10461044
<details>
1047-
<summary>You have a list variable called "users". How to access the second item in that list and attribute called "name"?</summary><br><b>
1045+
<summary>You have a list variable called "users" with an object containing a name attribute like this:<br>
1046+
1047+
```
1048+
variable "users" {
1049+
type = list(object({
1050+
name = string
1051+
age = number
1052+
}))
1053+
}
1054+
```
1055+
1056+
How to access the name attribute of the second item in that list?</summary><br><b>
10481057

10491058
`users[1].name`
10501059

10511060
</b></details>
10521061

10531062
<details>
1054-
<summary>You have a list variable called "users". How to access attribute "name" of all items?</summary><br><b>
1063+
<summary>Given the same list, how to access attribute "name" of all items?</summary><br><b>
10551064

10561065
`users[*].name`
10571066

@@ -1139,19 +1148,19 @@ resource "aws_iam_user" "user" {
11391148

11401149
```
11411150
resource “google_compute_instance” “instances” {
1142-
1151+
11431152
for_each = var.names_map
11441153
name = each.value
11451154
}
11461155
```
11471156
</b></details>
11481157

11491158
<details>
1150-
<summary>The following resource tries to use for_each loop on a list of string but it fails, why?
1159+
<summary>The following resource tries to use for_each loop on a list of strings but it fails, why?
11511160

11521161
```
11531162
resource “google_compute_instance” “instances” {
1154-
1163+
11551164
for_each = var.names
11561165
name = each.value
11571166
}
@@ -1261,11 +1270,11 @@ output "name_and_age" {
12611270
</b></details>
12621271

12631272
<details>
1264-
<summary>You have a map variable, called "users", with the keys "name" (string) and "age" (float). Define an output map variable with the key being name in uppercase and value being age in the closest whole number </summary><br><b>
1273+
<summary>You have a map variable, called "users", with the keys "name" (string) and "age" (number). Define an output map variable with the key being name in uppercase and value being age in the closest whole number </summary><br><b>
12651274

12661275
```
12671276
output "name_and_age" {
1268-
value = {for name, age in var.users : upper(name) => floor(age)
1277+
value = {for name, age in var.users : upper(name) => floor(age)
12691278
}
12701279
```
12711280

@@ -1357,7 +1366,7 @@ Renders a template file and returns the result as string.
13571366
<details>
13581367
<summary>You are trying to use templatefile as part of a module and you use a relative path to load a file but sometimes it fails, especially when others try to reuse the module. How can you deal with that?</summary><br><b>
13591368

1360-
Switch relative paths with what is known as path references. These are fixes paths like module root path, module expression file path, etc.
1369+
Switch relative paths with what is known as path references. These are fixes: paths like module root path, module expression file path, etc.
13611370

13621371
</b></details>
13631372

@@ -1387,7 +1396,7 @@ False. terraform console is ready-only.
13871396
<details>
13881397
<summary>Explain what <code>depends_on</code> used for and given an example</summary><br><b>
13891398

1390-
`depends_on` used to create a dependency between resources in Terraform. For example, there is an application you would like to deploy in a cluster. If the cluster isn't ready (and also managed by Terraform of course) then you can't deploy the app. In this case, you will define "depends_on" in the app configuration and its value will be the cluster resource.
1399+
`depends_on` used to create an explicit dependency between resources in Terraform. For example, there is an application you would like to deploy in a cluster. If the cluster isn't ready (and also managed by Terraform of course) then you can't deploy the app. In this case, you will define "depends_on" in the app configuration and its value will be the cluster resource.
13911400

13921401
</b></details>
13931402

@@ -1490,7 +1499,7 @@ module "amazing_module" {
14901499
<details>
14911500
<summary>What should be done every time you modify the source parameter of a module?</summary><br><b>
14921501

1493-
`terraform init` should be executed as it takes care of downloading and installing the module from the new path.
1502+
`terraform get -update` should be executed as it takes care of downloading and installing the module from the new path.
14941503
</b></details>
14951504

14961505
<details>
@@ -1550,9 +1559,11 @@ It's does NOT create the definitions/configuration for creating such infrastruct
15501559
<summary>You have a Git repository with Terraform files but no .gitignore. What would you add to a .gitignore file in Terraform repository?</summary><br><b>
15511560

15521561
```
1553-
.terraform
1562+
**/.terraform/*
15541563
*.tfstate
1555-
*.tfstate.backup
1564+
*.tfstate.*
1565+
*.tfvars
1566+
*.tfvars.json
15561567
```
15571568

15581569
You don't want to store state file nor any downloaded providers in .terraform directory. It also doesn't makes sense to share/store the state backup files.
@@ -1562,17 +1573,18 @@ You don't want to store state file nor any downloaded providers in .terraform di
15621573
### AWS
15631574

15641575
<details>
1565-
<summary>What happens if you update user_data in the following case apply the changes?
1576+
<summary>What happens if you update user_data in the following case and apply the changes?
15661577

15671578
```
15681579
resource "aws_instance" "example" {
15691580
ami = "..."
15701581
instance_type = "t2.micro"
15711582
1572-
user_data = <<-EOF
1573-
#!/bin/bash
1574-
echo "Hello, World" > index.xhtml
1575-
EOF
1583+
user_data = <<-EOF
1584+
#!/bin/bash
1585+
echo "Hello, World" > index.xhtml
1586+
EOF
1587+
}
15761588
```
15771589
</summary><br><b>
15781590

@@ -1703,7 +1715,7 @@ provider "aws" {
17031715
```
17041716
</summary><br><b>
17051717

1706-
It's not secure! you should never store credentials in plain text this way.
1718+
It's not secure! you should never store credentials in plain text this way.
17071719

17081720
</b></details>
17091721

@@ -1787,7 +1799,7 @@ terraform_project/
17871799

17881800
Each environment has its own backend (as you don't want to use the same authentication and access controls for all environments)
17891801

1790-
Going further, under each environment you'll separate between comoponents, applications and services
1802+
Going further, under each environment you'll separate between components, applications and services
17911803

17921804

17931805
```

topics/terraform/exercises/s3_bucket_rename/exercise.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ resource "aws_s3_bucket" "some_bucket" {
1111
}
1212
```
1313

14+
Attention: Since S3 buckets are globally unique, you will likely have to rename the bucket as someone else might have named it that way already.
15+
1416
## Objectives
1517

1618
1. Rename an existing S3 bucket and make sure it's still tracked by Terraform
1719

1820
## Solution
1921

20-
Click [here to view the solution](solution.md)
22+
Click [here to view the solution](solution.md)

topics/terraform/exercises/s3_bucket_rename/solution.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ resource "aws_s3_bucket" "some_bucket" {
1111
}
1212
```
1313

14+
Attention: Since S3 buckets are globally unique, you will likely have to rename the bucket as someone else might have named it that way already.
15+
1416
## Objectives
1517

1618
1. Rename an existing S3 bucket and make sure it's still tracked by Terraform
@@ -24,10 +26,12 @@ aws s3 mb s3://some-new-bucket-123
2426
# Sync old bucket to new bucket
2527
aws s3 sync s3://some-old-bucket s3://some-new-bucket-123
2628

27-
# Remove the old bucket from Terraform's state
29+
# Option 1 (remove and import)
30+
31+
## Remove the old bucket from Terraform's state
2832
terraform state rm aws_s3_bucket.some_bucket
2933

30-
# Import new bucket to Terraform's state
34+
## Import new bucket to Terraform's state
3135
terraform import aws_s3_bucket.some_bucket some-new-bucket-123
3236

3337
: '
@@ -38,6 +42,18 @@ The resources that were imported are shown above. These resources are now in
3842
your Terraform state and will henceforth be managed by Terraform.
3943
'
4044

45+
# Option 2 (move)
46+
47+
## Move the old bucket from Terraform's state to the new one
48+
terraform state mv aws_s3_bucket.some_bucket some-new-bucket-123
49+
50+
: '
51+
Move "aws_s3_bucket.some_bucket" to "aws_s3_bucket.some-new-bucket-123"
52+
Successfully moved 1 object(s).
53+
'
54+
55+
# Modify Terraform file
56+
4157
# Modify the Terraform definition to include the new name
4258
# resource "aws_s3_bucket" "some_bucket" {
4359
# bucket = "some-new-bucket-123"
@@ -46,4 +62,4 @@ your Terraform state and will henceforth be managed by Terraform.
4662
# Remove old bucket
4763
aws s3 rm s3://some-old-bucket --recursive
4864
aws s3 rb s3://some-old-bucket
49-
```
65+
```

0 commit comments

Comments
 (0)