dojo.md 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/courses/GENERATION_LOG.md +20 -0
- package/courses/api-documentation-writing/course.yaml +12 -0
- package/courses/api-documentation-writing/scenarios/level-1/authentication-basics.yaml +46 -0
- package/courses/api-documentation-writing/scenarios/level-1/data-types-formats.yaml +45 -0
- package/courses/api-documentation-writing/scenarios/level-1/endpoint-description.yaml +45 -0
- package/courses/api-documentation-writing/scenarios/level-1/error-documentation.yaml +45 -0
- package/courses/api-documentation-writing/scenarios/level-1/first-documentation-shift.yaml +47 -0
- package/courses/api-documentation-writing/scenarios/level-1/getting-started-guide.yaml +42 -0
- package/courses/api-documentation-writing/scenarios/level-1/pagination-docs.yaml +51 -0
- package/courses/api-documentation-writing/scenarios/level-1/request-parameters.yaml +46 -0
- package/courses/api-documentation-writing/scenarios/level-1/request-response-examples.yaml +48 -0
- package/courses/api-documentation-writing/scenarios/level-1/status-codes.yaml +45 -0
- package/courses/api-documentation-writing/scenarios/level-2/error-patterns.yaml +48 -0
- package/courses/api-documentation-writing/scenarios/level-2/intermediate-documentation-shift.yaml +48 -0
- package/courses/api-documentation-writing/scenarios/level-2/oauth-documentation.yaml +47 -0
- package/courses/api-documentation-writing/scenarios/level-2/openapi-specification.yaml +46 -0
- package/courses/api-documentation-writing/scenarios/level-2/rate-limiting-docs.yaml +45 -0
- package/courses/api-documentation-writing/scenarios/level-2/request-body-schemas.yaml +46 -0
- package/courses/api-documentation-writing/scenarios/level-2/schema-definitions.yaml +41 -0
- package/courses/api-documentation-writing/scenarios/level-2/swagger-redoc-rendering.yaml +43 -0
- package/courses/api-documentation-writing/scenarios/level-2/validation-documentation.yaml +47 -0
- package/courses/api-documentation-writing/scenarios/level-2/versioning-changelog.yaml +42 -0
- package/courses/api-documentation-writing/scenarios/level-3/advanced-documentation-shift.yaml +43 -0
- package/courses/api-documentation-writing/scenarios/level-3/api-style-guide.yaml +40 -0
- package/courses/api-documentation-writing/scenarios/level-3/code-samples-multilang.yaml +40 -0
- package/courses/api-documentation-writing/scenarios/level-3/content-architecture.yaml +47 -0
- package/courses/api-documentation-writing/scenarios/level-3/deprecation-communication.yaml +44 -0
- package/courses/api-documentation-writing/scenarios/level-3/interactive-api-explorer.yaml +42 -0
- package/courses/api-documentation-writing/scenarios/level-3/migration-guides.yaml +42 -0
- package/courses/api-documentation-writing/scenarios/level-3/sdk-documentation.yaml +40 -0
- package/courses/api-documentation-writing/scenarios/level-3/webhook-documentation.yaml +48 -0
- package/courses/api-documentation-writing/scenarios/level-3/websocket-sse-docs.yaml +47 -0
- package/courses/api-documentation-writing/scenarios/level-4/api-changelog-management.yaml +44 -0
- package/courses/api-documentation-writing/scenarios/level-4/api-governance-standards.yaml +41 -0
- package/courses/api-documentation-writing/scenarios/level-4/api-product-strategy.yaml +41 -0
- package/courses/api-documentation-writing/scenarios/level-4/developer-portal-design.yaml +48 -0
- package/courses/api-documentation-writing/scenarios/level-4/docs-as-code.yaml +41 -0
- package/courses/api-documentation-writing/scenarios/level-4/documentation-localization.yaml +46 -0
- package/courses/api-documentation-writing/scenarios/level-4/documentation-metrics.yaml +45 -0
- package/courses/api-documentation-writing/scenarios/level-4/documentation-testing.yaml +41 -0
- package/courses/api-documentation-writing/scenarios/level-4/expert-documentation-shift.yaml +45 -0
- package/courses/api-documentation-writing/scenarios/level-4/multi-audience-docs.yaml +46 -0
- package/courses/api-documentation-writing/scenarios/level-5/ai-powered-documentation.yaml +44 -0
- package/courses/api-documentation-writing/scenarios/level-5/api-first-documentation.yaml +45 -0
- package/courses/api-documentation-writing/scenarios/level-5/api-marketplace-docs.yaml +42 -0
- package/courses/api-documentation-writing/scenarios/level-5/board-api-strategy.yaml +48 -0
- package/courses/api-documentation-writing/scenarios/level-5/documentation-program-strategy.yaml +42 -0
- package/courses/api-documentation-writing/scenarios/level-5/documentation-team-structure.yaml +47 -0
- package/courses/api-documentation-writing/scenarios/level-5/dx-competitive-advantage.yaml +46 -0
- package/courses/api-documentation-writing/scenarios/level-5/ecosystem-documentation.yaml +45 -0
- package/courses/api-documentation-writing/scenarios/level-5/industry-documentation-patterns.yaml +46 -0
- package/courses/api-documentation-writing/scenarios/level-5/master-documentation-shift.yaml +46 -0
- package/courses/code-review-feedback-writing/course.yaml +12 -0
- package/courses/code-review-feedback-writing/scenarios/level-1/approve-vs-request-changes.yaml +48 -0
- package/courses/code-review-feedback-writing/scenarios/level-1/asking-questions.yaml +50 -0
- package/courses/code-review-feedback-writing/scenarios/level-1/clear-comment-writing.yaml +45 -0
- package/courses/code-review-feedback-writing/scenarios/level-1/constructive-tone.yaml +43 -0
- package/courses/code-review-feedback-writing/scenarios/level-1/first-review-shift.yaml +46 -0
- package/courses/code-review-feedback-writing/scenarios/level-1/giving-praise.yaml +44 -0
- package/courses/code-review-feedback-writing/scenarios/level-1/nitpick-etiquette.yaml +44 -0
- package/courses/code-review-feedback-writing/scenarios/level-1/providing-context.yaml +46 -0
- package/courses/code-review-feedback-writing/scenarios/level-1/reviewing-small-prs.yaml +43 -0
- package/courses/code-review-feedback-writing/scenarios/level-1/style-vs-logic.yaml +48 -0
- package/courses/code-review-feedback-writing/scenarios/level-2/architectural-feedback.yaml +52 -0
- package/courses/code-review-feedback-writing/scenarios/level-2/intermediate-review-shift.yaml +46 -0
- package/courses/code-review-feedback-writing/scenarios/level-2/performance-feedback.yaml +50 -0
- package/courses/code-review-feedback-writing/scenarios/level-2/reviewing-breaking-changes.yaml +44 -0
- package/courses/code-review-feedback-writing/scenarios/level-2/reviewing-complex-prs.yaml +43 -0
- package/courses/code-review-feedback-writing/scenarios/level-2/reviewing-documentation.yaml +47 -0
- package/courses/code-review-feedback-writing/scenarios/level-2/reviewing-error-handling.yaml +50 -0
- package/courses/code-review-feedback-writing/scenarios/level-2/reviewing-tests.yaml +53 -0
- package/courses/code-review-feedback-writing/scenarios/level-2/security-review-comments.yaml +50 -0
- package/courses/code-review-feedback-writing/scenarios/level-2/suggesting-alternatives.yaml +42 -0
- package/courses/code-review-feedback-writing/scenarios/level-3/cross-team-review.yaml +45 -0
- package/courses/code-review-feedback-writing/scenarios/level-3/mentoring-through-review.yaml +46 -0
- package/courses/code-review-feedback-writing/scenarios/level-3/reviewing-unfamiliar-code.yaml +43 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-1/first-debugging-shift.yaml +66 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-1/hcl-syntax-errors.yaml +65 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-1/plan-output-reading.yaml +71 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-1/provider-configuration.yaml +62 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-1/resource-creation-failures.yaml +54 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-1/resource-references.yaml +70 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-1/state-file-basics.yaml +73 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-1/terraform-fmt-validate.yaml +58 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-1/variable-and-output-errors.yaml +78 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-2/count-vs-for-each.yaml +58 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-2/dependency-management.yaml +80 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-2/intermediate-debugging-shift.yaml +66 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-2/lifecycle-rules.yaml +51 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-2/locals-and-expressions.yaml +58 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-2/module-structure.yaml +75 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-2/provisioner-pitfalls.yaml +64 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-2/remote-state-backend.yaml +55 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-2/terraform-import.yaml +55 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-2/workspace-management.yaml +51 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-3/advanced-debugging-shift.yaml +63 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-3/api-rate-limiting.yaml +50 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-3/conditional-resources.yaml +66 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-3/drift-detection.yaml +66 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-3/dynamic-blocks.yaml +71 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-3/large-scale-refactoring.yaml +59 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-3/multi-provider-config.yaml +69 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-3/state-surgery.yaml +57 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-3/terraform-cloud-enterprise.yaml +59 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-3/terraform-debugging.yaml +51 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-4/blast-radius-management.yaml +51 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-4/cicd-pipeline-design.yaml +50 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-4/compliance-as-code.yaml +46 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-4/cost-estimation-governance.yaml +42 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-4/expert-debugging-shift.yaml +51 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-4/iac-organization-strategy.yaml +45 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-4/incident-response-iac.yaml +47 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-4/infrastructure-testing.yaml +41 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-4/module-registry-design.yaml +45 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-4/multi-account-strategy.yaml +57 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-5/board-infrastructure-investment.yaml +53 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-5/disaster-recovery-iac.yaml +47 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-5/enterprise-iac-transformation.yaml +48 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-5/iac-technology-evolution.yaml +49 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-5/ma-infrastructure-consolidation.yaml +54 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-5/master-debugging-shift.yaml +53 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-5/multi-cloud-strategy.yaml +49 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-5/platform-engineering.yaml +47 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-5/regulatory-compliance-automation.yaml +47 -0
- package/courses/terraform-infrastructure-setup/scenarios/level-5/terraform-vs-alternatives.yaml +46 -0
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +2 -1
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/train.d.ts.map +1 -1
- package/dist/cli/commands/train.js +6 -3
- package/dist/cli/commands/train.js.map +1 -1
- package/dist/cli/index.js +9 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/run-demo.js +3 -2
- package/dist/cli/run-demo.js.map +1 -1
- package/dist/engine/model-utils.d.ts +6 -0
- package/dist/engine/model-utils.d.ts.map +1 -1
- package/dist/engine/model-utils.js +28 -1
- package/dist/engine/model-utils.js.map +1 -1
- package/dist/engine/training.d.ts.map +1 -1
- package/dist/engine/training.js +4 -3
- package/dist/engine/training.js.map +1 -1
- package/dist/generator/course-generator.d.ts.map +1 -1
- package/dist/generator/course-generator.js +4 -3
- package/dist/generator/course-generator.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +7 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/session-manager.d.ts.map +1 -1
- package/dist/mcp/session-manager.js +3 -2
- package/dist/mcp/session-manager.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: hcl-syntax-errors
|
|
3
|
+
level: 1
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Fix HCL syntax errors — diagnose missing braces, incorrect attribute assignments, string interpolation issues, and block structure problems"
|
|
7
|
+
tags: [Terraform, HCL, syntax, validation, formatting, beginner]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
You run `terraform validate` and get multiple errors:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Error: Missing closing brace
|
|
16
|
+
|
|
17
|
+
on main.tf line 12:
|
|
18
|
+
12: tags = {
|
|
19
|
+
13: Name = "web-server"
|
|
20
|
+
14:
|
|
21
|
+
|
|
22
|
+
Error: Unsupported argument
|
|
23
|
+
|
|
24
|
+
on main.tf line 8, in resource "aws_instance" "web":
|
|
25
|
+
8: ami := "ami-0c55b159cbfafe1f0"
|
|
26
|
+
|
|
27
|
+
Error: Invalid reference
|
|
28
|
+
|
|
29
|
+
on main.tf line 15, in resource "aws_instance" "web":
|
|
30
|
+
15: subnet_id = "${var.subnet_id}"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Your main.tf:
|
|
34
|
+
|
|
35
|
+
```hcl
|
|
36
|
+
resource "aws_instance" "web" {
|
|
37
|
+
ami := "ami-0c55b159cbfafe1f0"
|
|
38
|
+
instance_type = var.instance_type
|
|
39
|
+
|
|
40
|
+
tags = {
|
|
41
|
+
Name = "web-server"
|
|
42
|
+
|
|
43
|
+
vpc_security_group_ids = [aws_security_group.web.id]
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Task: Explain HCL syntax fundamentals, common syntax errors and
|
|
48
|
+
how to fix them, the difference between = and := (Terraform only
|
|
49
|
+
uses =), string interpolation rules, terraform fmt for auto-formatting,
|
|
50
|
+
terraform validate for catching errors before plan, and block structure
|
|
51
|
+
(resource, data, variable, output, locals).
|
|
52
|
+
|
|
53
|
+
assertions:
|
|
54
|
+
- type: llm_judge
|
|
55
|
+
criteria: "HCL syntax fundamentals are explained — blocks: resource, data, variable, output, locals, terraform, provider. Attribute assignment uses = (not :=, that's Go syntax). String interpolation: use ${} inside quoted strings, but for simple references just use var.name directly (no interpolation needed since Terraform 0.12). Heredoc syntax: <<-EOT for multi-line strings. Comments: # for single line, /* */ for multi-line. Lists: [], maps: {}. The specific errors: (1) := should be =, (2) missing closing brace for tags block, (3) bare ${var.subnet_id} should be just var.subnet_id (interpolation-only expressions are deprecated)"
|
|
56
|
+
weight: 0.35
|
|
57
|
+
description: "HCL fundamentals"
|
|
58
|
+
- type: llm_judge
|
|
59
|
+
criteria: "terraform fmt and validate workflow is covered — terraform fmt: auto-formats HCL files to canonical style (consistent indentation, alignment). Run before committing. terraform fmt -check in CI to enforce formatting. terraform validate: checks configuration for internal consistency (syntax, attribute names, required arguments). Does NOT check against cloud APIs. Workflow order: fmt → validate → plan → apply. validate catches: missing required arguments, unknown attributes, type mismatches, invalid references"
|
|
60
|
+
weight: 0.35
|
|
61
|
+
description: "Formatting and validation"
|
|
62
|
+
- type: llm_judge
|
|
63
|
+
criteria: "Block structure is explained — resource 'type' 'name' {}: creates infrastructure. data 'type' 'name' {}: reads existing infrastructure. variable 'name' {}: input parameters (type, default, description, validation). output 'name' {}: export values. locals {}: computed local values (like constants). terraform {}: settings (required_version, required_providers, backend). provider 'name' {}: provider configuration. Each block type has specific allowed arguments. Meta-arguments available on resources: depends_on, count, for_each, provider, lifecycle"
|
|
64
|
+
weight: 0.30
|
|
65
|
+
description: "Block structure"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: plan-output-reading
|
|
3
|
+
level: 1
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Read terraform plan output — interpret change symbols, understand resource actions, identify destructive changes before apply"
|
|
7
|
+
tags: [Terraform, plan, output, changes, destroy, beginner]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Your terraform plan shows this output and you need to understand
|
|
13
|
+
what will happen before approving:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Terraform will perform the following actions:
|
|
17
|
+
|
|
18
|
+
# aws_instance.web will be destroyed and re-created
|
|
19
|
+
# (because ami has changed)
|
|
20
|
+
-/+ resource "aws_instance" "web" {
|
|
21
|
+
~ ami = "ami-old123" -> "ami-new456" # forces replacement
|
|
22
|
+
~ arn = "arn:aws:ec2:..." -> (known after apply)
|
|
23
|
+
~ id = "i-abc123" -> (known after apply)
|
|
24
|
+
instance_type = "t3.micro"
|
|
25
|
+
~ public_ip = "54.1.2.3" -> (known after apply)
|
|
26
|
+
+ secondary_private_ips = (known after apply)
|
|
27
|
+
- tags = {} -> null
|
|
28
|
+
# (15 unchanged attributes hidden)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# aws_s3_bucket.data will be updated in-place
|
|
32
|
+
~ resource "aws_s3_bucket" "data" {
|
|
33
|
+
id = "my-data-bucket"
|
|
34
|
+
~ tags = {
|
|
35
|
+
+ "Environment" = "prod"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# aws_security_group.old will be destroyed
|
|
40
|
+
- resource "aws_security_group" "old" {
|
|
41
|
+
- id = "sg-old789" -> null
|
|
42
|
+
- name = "old-sg" -> null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# aws_security_group.new will be created
|
|
46
|
+
+ resource "aws_security_group" "new" {
|
|
47
|
+
+ id = (known after apply)
|
|
48
|
+
+ name = "new-sg"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
Plan: 2 to add, 1 to change, 2 to destroy.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Task: Explain how to read terraform plan output, what each symbol
|
|
55
|
+
means (+, -, ~, -/+), what "forces replacement" means and why it's
|
|
56
|
+
dangerous, "known after apply" values, and best practices for
|
|
57
|
+
reviewing plans before apply.
|
|
58
|
+
|
|
59
|
+
assertions:
|
|
60
|
+
- type: llm_judge
|
|
61
|
+
criteria: "Plan symbols are explained — + (create): new resource will be created. - (destroy): existing resource will be deleted. ~ (update in-place): resource will be modified without recreation. -/+ (destroy and recreate): resource must be destroyed and recreated (replacement). +/- (create before destroy): new resource created first, then old destroyed (lifecycle create_before_destroy). Within attributes: + (added), - (removed), ~ (changed). 'forces replacement' means changing that attribute requires destroying and recreating the resource (e.g., changing AMI on EC2 instance). '(known after apply)' means the value will be determined by the cloud provider during creation"
|
|
62
|
+
weight: 0.35
|
|
63
|
+
description: "Plan symbols"
|
|
64
|
+
- type: llm_judge
|
|
65
|
+
criteria: "Dangerous changes are identified — destroy and recreate (-/+) is dangerous: causes downtime, new IP address, new resource ID. The example: changing AMI forces EC2 instance replacement — means the server goes down, gets a new public IP, loses ephemeral storage. Review all -/+ changes carefully. Mitigation: lifecycle { create_before_destroy = true } creates the new resource before destroying the old one (reduces downtime). Pure destroy (-) is also dangerous: verify you actually want to remove the resource. Summary line 'Plan: 2 to add, 1 to change, 2 to destroy' is the quick check"
|
|
66
|
+
weight: 0.35
|
|
67
|
+
description: "Dangerous changes"
|
|
68
|
+
- type: llm_judge
|
|
69
|
+
criteria: "Plan review best practices are practical — always run plan before apply. Save plan: terraform plan -out=plan.tfplan, then terraform apply plan.tfplan (prevents drift between plan and apply). In CI/CD: plan on PR, apply on merge. Review checklist: (1) any destroys? expected? (2) any replacements? understand why? (3) count of changes matches expectations? (4) no sensitive data exposed in plan output? Use terraform plan -target=resource to plan specific resources. terraform plan -detailed-exitcode: exit 0 (no changes), exit 1 (error), exit 2 (changes present) — useful in scripts"
|
|
70
|
+
weight: 0.30
|
|
71
|
+
description: "Review practices"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: provider-configuration
|
|
3
|
+
level: 1
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Configure Terraform providers — set up AWS credentials, handle authentication errors, manage provider aliases for multi-region deployments"
|
|
7
|
+
tags: [Terraform, providers, AWS, authentication, credentials, beginner]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
You run `terraform plan` and get this error:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Error: No valid credential sources found
|
|
16
|
+
|
|
17
|
+
with provider["registry.terraform.io/hashicorp/aws"],
|
|
18
|
+
on main.tf line 5, in provider "aws":
|
|
19
|
+
5: provider "aws" {
|
|
20
|
+
|
|
21
|
+
Please see https://registry.terraform.io/providers/hashicorp/aws
|
|
22
|
+
for more information about providing credentials.
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Your configuration:
|
|
26
|
+
|
|
27
|
+
```hcl
|
|
28
|
+
provider "aws" {
|
|
29
|
+
region = "us-east-1"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
resource "aws_s3_bucket" "data" {
|
|
33
|
+
bucket = "my-data-bucket-12345"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
resource "aws_s3_bucket" "logs" {
|
|
37
|
+
provider = aws.west
|
|
38
|
+
bucket = "my-logs-bucket-12345"
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
You have AWS CLI installed with a profile named "dev" but haven't
|
|
43
|
+
configured any credentials for Terraform.
|
|
44
|
+
|
|
45
|
+
Task: Explain Terraform provider configuration, AWS credential
|
|
46
|
+
chain (how Terraform finds credentials), provider aliases for
|
|
47
|
+
multi-region, common authentication errors and fixes, and best
|
|
48
|
+
practices for credential management (never hardcode keys).
|
|
49
|
+
|
|
50
|
+
assertions:
|
|
51
|
+
- type: llm_judge
|
|
52
|
+
criteria: "AWS credential chain is explained — Terraform AWS provider checks credentials in order: (1) provider block (access_key/secret_key — NEVER do this), (2) environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN), (3) shared credentials file (~/.aws/credentials), (4) shared config file (~/.aws/config with profile), (5) EC2 instance metadata / ECS task role / Lambda execution role. Fix: export AWS_PROFILE=dev or set profile in provider block. For CI/CD: use environment variables or OIDC federation (GitHub Actions → AWS IAM role)"
|
|
53
|
+
weight: 0.35
|
|
54
|
+
description: "Credential chain"
|
|
55
|
+
- type: llm_judge
|
|
56
|
+
criteria: "Provider aliases are explained — to use multiple regions, define provider aliases: provider 'aws' { region = 'us-east-1' } and provider 'aws' { alias = 'west', region = 'us-west-2' }. Reference alias: provider = aws.west in resource block. Without the alias provider block defined, the aws.west reference will fail. Default provider (no alias) is used when provider isn't specified. Each alias can have different credentials, regions, or assume_role configurations"
|
|
57
|
+
weight: 0.35
|
|
58
|
+
description: "Provider aliases"
|
|
59
|
+
- type: llm_judge
|
|
60
|
+
criteria: "Security best practices are covered — NEVER hardcode credentials in .tf files (they end up in version control and state files). Use: environment variables, AWS profiles, IAM roles (instance profiles, task roles), or OIDC federation. For assume_role: provider block supports assume_role {} for cross-account access. State files contain provider config — ensure state is encrypted and access-controlled. Use terraform plan output to verify no credentials are exposed. Add *.tfvars with secrets to .gitignore"
|
|
61
|
+
weight: 0.30
|
|
62
|
+
description: "Security practices"
|
package/courses/terraform-infrastructure-setup/scenarios/level-1/resource-creation-failures.yaml
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: resource-creation-failures
|
|
3
|
+
level: 1
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Debug resource creation failures — diagnose API errors, dependency issues, naming conflicts, and partial apply states"
|
|
7
|
+
tags: [Terraform, resources, apply, errors, dependencies, beginner]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
You run `terraform apply` and it partially succeeds:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
aws_vpc.main: Creating...
|
|
16
|
+
aws_vpc.main: Creation complete after 3s [id=vpc-0abc123def456]
|
|
17
|
+
aws_subnet.public: Creating...
|
|
18
|
+
aws_subnet.public: Creation complete after 1s [id=subnet-0abc789]
|
|
19
|
+
aws_security_group.web: Creating...
|
|
20
|
+
|
|
21
|
+
Error: creating Security Group (web-sg): InvalidGroup.Duplicate:
|
|
22
|
+
The security group 'web-sg' already exists for VPC 'vpc-0abc123def456'
|
|
23
|
+
|
|
24
|
+
aws_instance.web: Creating...
|
|
25
|
+
|
|
26
|
+
Error: creating EC2 Instance: UnauthorizedOperation: You are not
|
|
27
|
+
authorized to perform this operation. Encoded authorization failure
|
|
28
|
+
message: ...
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
State after partial apply:
|
|
32
|
+
- VPC: created ✓
|
|
33
|
+
- Subnet: created ✓
|
|
34
|
+
- Security Group: FAILED ✗
|
|
35
|
+
- EC2 Instance: FAILED ✗
|
|
36
|
+
|
|
37
|
+
Task: Explain how terraform apply works (dependency graph, parallel
|
|
38
|
+
creation, partial state), what happens when apply partially fails,
|
|
39
|
+
how to recover from partial failures, common resource creation errors
|
|
40
|
+
(duplicates, permissions, quotas), and terraform plan vs apply workflow.
|
|
41
|
+
|
|
42
|
+
assertions:
|
|
43
|
+
- type: llm_judge
|
|
44
|
+
criteria: "Apply process is explained — terraform builds a dependency graph (DAG) and creates resources in parallel where possible. Resources with dependencies wait for their dependencies. Partial failure: successfully created resources are saved to state. Failed resources are not in state. On next apply, Terraform will try to create the failed resources again (it won't recreate already-created ones). The state file tracks what exists. Recovery: fix the errors and run apply again. terraform plan shows what will happen without making changes"
|
|
45
|
+
weight: 0.35
|
|
46
|
+
description: "Apply process"
|
|
47
|
+
- type: llm_judge
|
|
48
|
+
criteria: "Common creation errors are diagnosed — (1) Duplicate resource: security group already exists outside Terraform. Fix: import it (terraform import) or use a unique name. (2) UnauthorizedOperation: IAM permissions missing. Decode the message: aws sts decode-authorization-message. Fix: add required IAM permissions. (3) Quota exceeded: AWS service limits. Fix: request limit increase. (4) Invalid parameter: wrong AMI for region, invalid CIDR block. (5) Timeout: resource takes too long to create (increase timeouts in resource block)"
|
|
49
|
+
weight: 0.35
|
|
50
|
+
description: "Common errors"
|
|
51
|
+
- type: llm_judge
|
|
52
|
+
criteria: "Plan vs apply workflow is practical — terraform plan: preview changes without modifying infrastructure. Shows: resources to add (+), change (~), destroy (-). Save plan: terraform plan -out=tfplan, then terraform apply tfplan (ensures exactly the planned changes are applied). Always review plan before apply in production. terraform apply -auto-approve: skips confirmation (only for CI/CD, not manual runs). terraform destroy: removes all managed resources. Partial state: use terraform state list to see what's managed, terraform show for current state"
|
|
53
|
+
weight: 0.30
|
|
54
|
+
description: "Plan vs apply"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: resource-references
|
|
3
|
+
level: 1
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Fix resource reference errors — debug circular dependencies, missing attributes, implicit vs explicit dependencies, and data source lookups"
|
|
7
|
+
tags: [Terraform, references, dependencies, data-sources, expressions, beginner]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Your Terraform configuration has reference errors:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Error: Cycle: aws_security_group.web, aws_security_group.db
|
|
16
|
+
|
|
17
|
+
Error: Unsupported attribute
|
|
18
|
+
|
|
19
|
+
on main.tf line 25:
|
|
20
|
+
25: vpc_id = aws_vpc.main.vpc_id
|
|
21
|
+
|
|
22
|
+
A managed resource "aws_vpc" "main" has not been declared in the
|
|
23
|
+
root module.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Your configuration:
|
|
27
|
+
|
|
28
|
+
```hcl
|
|
29
|
+
resource "aws_security_group" "web" {
|
|
30
|
+
ingress {
|
|
31
|
+
from_port = 443
|
|
32
|
+
to_port = 443
|
|
33
|
+
security_groups = [aws_security_group.db.id]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
resource "aws_security_group" "db" {
|
|
38
|
+
ingress {
|
|
39
|
+
from_port = 5432
|
|
40
|
+
to_port = 5432
|
|
41
|
+
security_groups = [aws_security_group.web.id]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
resource "aws_subnet" "public" {
|
|
46
|
+
vpc_id = aws_vpc.main.vpc_id
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The VPC already exists in AWS (created by another team) — you need
|
|
51
|
+
to reference it, not create it.
|
|
52
|
+
|
|
53
|
+
Task: Explain Terraform resource references, implicit vs explicit
|
|
54
|
+
dependencies, circular dependency detection and resolution, data
|
|
55
|
+
sources for reading existing infrastructure, and expression syntax
|
|
56
|
+
for accessing resource attributes.
|
|
57
|
+
|
|
58
|
+
assertions:
|
|
59
|
+
- type: llm_judge
|
|
60
|
+
criteria: "Resource references and dependencies are explained — implicit dependency: when resource A references resource B's attribute (aws_security_group.web.id), Terraform automatically creates A after B. Explicit dependency: depends_on = [aws_security_group.web] when there's no attribute reference but order matters. Circular dependency: A references B and B references A — Terraform can't determine creation order. Fix: break the cycle by using aws_security_group_rule as separate resources instead of inline ingress blocks, or use depends_on with one direction only"
|
|
61
|
+
weight: 0.35
|
|
62
|
+
description: "Dependencies"
|
|
63
|
+
- type: llm_judge
|
|
64
|
+
criteria: "Data sources are explained — data sources read existing infrastructure without managing it. data 'aws_vpc' 'main' { filter { name = 'tag:Name', values = ['production'] } } reads the VPC. Reference: data.aws_vpc.main.id. Use data sources when: resource exists outside your Terraform config, managed by another team/state, or pre-existing infrastructure. Common data sources: aws_ami (find latest AMI), aws_vpc, aws_subnet, aws_caller_identity (current AWS account), aws_region. Data sources are refreshed on every plan"
|
|
65
|
+
weight: 0.35
|
|
66
|
+
description: "Data sources"
|
|
67
|
+
- type: llm_judge
|
|
68
|
+
criteria: "Expression syntax is covered — resource attributes: aws_instance.web.id, aws_instance.web.public_ip. With count: aws_instance.web[0].id or aws_instance.web[*].id (splat). With for_each: aws_instance.web['key'].id. Module outputs: module.vpc.vpc_id. Data sources: data.aws_vpc.main.id. Local values: local.common_tags. Built-in functions: lookup(), element(), concat(), join(). Conditional: condition ? true_val : false_val. For expressions: [for s in var.list : upper(s)]"
|
|
69
|
+
weight: 0.30
|
|
70
|
+
description: "Expression syntax"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: state-file-basics
|
|
3
|
+
level: 1
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Understand Terraform state — diagnose state file corruption, lock conflicts, state drift, and local vs remote state tradeoffs"
|
|
7
|
+
tags: [Terraform, state, tfstate, locking, drift, beginner]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Your colleague runs `terraform plan` and gets unexpected results:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
$ terraform plan
|
|
16
|
+
|
|
17
|
+
Note: Objects have changed outside of Terraform
|
|
18
|
+
|
|
19
|
+
Terraform detected the following changes made outside of Terraform
|
|
20
|
+
since the last "terraform apply":
|
|
21
|
+
|
|
22
|
+
# aws_instance.web has been changed
|
|
23
|
+
~ resource "aws_instance" "web" {
|
|
24
|
+
~ instance_type = "t3.micro" -> "t3.large"
|
|
25
|
+
# (10 unchanged attributes hidden)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
Terraform will perform the following actions:
|
|
29
|
+
|
|
30
|
+
# aws_instance.web will be updated in-place
|
|
31
|
+
~ resource "aws_instance" "web" {
|
|
32
|
+
~ instance_type = "t3.large" -> "t3.micro"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
Plan: 0 to add, 1 to change, 0 to destroy.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Someone changed the instance type in the AWS console from t3.micro
|
|
39
|
+
to t3.large. Terraform wants to revert it back to match the code.
|
|
40
|
+
|
|
41
|
+
Also, when two people run terraform at the same time:
|
|
42
|
+
```
|
|
43
|
+
Error: Error acquiring the state lock
|
|
44
|
+
|
|
45
|
+
Error message: ConditionalCheckFailedException: The conditional
|
|
46
|
+
request failed
|
|
47
|
+
Lock Info:
|
|
48
|
+
ID: 12345-abcde
|
|
49
|
+
Path: my-bucket/prod/terraform.tfstate
|
|
50
|
+
Operation: OperationTypeApply
|
|
51
|
+
Who: colleague@laptop
|
|
52
|
+
Version: 1.7.0
|
|
53
|
+
Created: 2024-01-15 10:30:00 UTC
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Task: Explain Terraform state fundamentals, what the state file
|
|
57
|
+
contains and why it exists, state drift detection and resolution,
|
|
58
|
+
state locking (why it matters, how it works with DynamoDB), and
|
|
59
|
+
local vs remote state.
|
|
60
|
+
|
|
61
|
+
assertions:
|
|
62
|
+
- type: llm_judge
|
|
63
|
+
criteria: "State fundamentals are explained — terraform.tfstate is a JSON file mapping configuration to real infrastructure IDs. It tracks: resource IDs, attribute values, dependencies, metadata. Why state exists: (1) map config to real resources (Terraform needs to know which aws_instance.web is vpc-abc123), (2) track metadata (dependencies), (3) performance (cache attribute values instead of querying APIs every time). State is the source of truth for what Terraform manages. Drift: when real infrastructure differs from state, detected during plan/apply refresh"
|
|
64
|
+
weight: 0.35
|
|
65
|
+
description: "State fundamentals"
|
|
66
|
+
- type: llm_judge
|
|
67
|
+
criteria: "Drift detection and resolution are covered — Terraform refreshes state before plan (compares real infrastructure to state). Drift detected: plan shows changes to revert. Options: (1) apply to revert to code (desired state wins), (2) update code to match reality (if the manual change was intentional), (3) terraform apply -refresh-only to update state without changing infrastructure. Best practice: all changes through Terraform, never manual. If manual changes are needed: update the .tf files to match, then plan to confirm no changes"
|
|
68
|
+
weight: 0.35
|
|
69
|
+
description: "Drift resolution"
|
|
70
|
+
- type: llm_judge
|
|
71
|
+
criteria: "Locking and remote state are practical — local state: terraform.tfstate in working directory. Problem: not shared, no locking, easy to lose. Remote state: store in S3, GCS, Azure Blob, Terraform Cloud. S3 backend with DynamoDB: S3 stores state file, DynamoDB provides locking (prevents concurrent modifications). Lock error: someone else is running terraform. Fix: wait for them to finish, or terraform force-unlock <ID> (dangerous, only if lock is stale). Never commit terraform.tfstate to git (contains secrets). Add to .gitignore"
|
|
72
|
+
weight: 0.30
|
|
73
|
+
description: "Locking and remote"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: terraform-fmt-validate
|
|
3
|
+
level: 1
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Use terraform fmt and validate — enforce consistent formatting, catch configuration errors before plan, and set up pre-commit hooks"
|
|
7
|
+
tags: [Terraform, fmt, validate, formatting, pre-commit, beginner]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Your team's Terraform codebase is a formatting mess. Every developer
|
|
13
|
+
uses different indentation, alignment, and spacing. Code reviews are
|
|
14
|
+
full of style nitpicks instead of substance:
|
|
15
|
+
|
|
16
|
+
```hcl
|
|
17
|
+
resource "aws_instance" "web" {
|
|
18
|
+
ami = "ami-0c55b159cbfafe1f0"
|
|
19
|
+
instance_type="t3.micro"
|
|
20
|
+
tags={
|
|
21
|
+
Name ="web-server"
|
|
22
|
+
Environment= "prod"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
variable "region" {
|
|
27
|
+
type=string
|
|
28
|
+
default ="us-east-1"
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Additionally, a developer pushed this broken config that wasn't caught
|
|
33
|
+
until CI ran terraform plan (wasting 10 minutes):
|
|
34
|
+
|
|
35
|
+
```hcl
|
|
36
|
+
resource "aws_s3_bucket" "data" {
|
|
37
|
+
bucket = var.bucket_name
|
|
38
|
+
acl = "private" # acl argument removed in AWS provider v4+
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Task: Explain terraform fmt (auto-formatting), terraform validate
|
|
43
|
+
(configuration checking), how to enforce both in CI/CD and pre-commit
|
|
44
|
+
hooks, and the difference between validate and plan for error catching.
|
|
45
|
+
|
|
46
|
+
assertions:
|
|
47
|
+
- type: llm_judge
|
|
48
|
+
criteria: "terraform fmt is explained — terraform fmt rewrites .tf files to canonical format (2-space indent, aligned equals signs, consistent spacing). terraform fmt -check: returns non-zero exit code if files need formatting (for CI). terraform fmt -recursive: formats all .tf files in subdirectories. terraform fmt -diff: shows the formatting changes. The example code would be auto-fixed to consistent 2-space indentation with aligned = signs. Best practice: run fmt before every commit"
|
|
49
|
+
weight: 0.35
|
|
50
|
+
description: "Formatting"
|
|
51
|
+
- type: llm_judge
|
|
52
|
+
criteria: "terraform validate is explained with its limitations — validate checks: syntax errors, invalid argument names, type mismatches, missing required arguments, invalid resource references. validate does NOT check: cloud API validity (wrong AMI ID), permissions, resource existence, provider-specific logic. The acl argument error: validate might not catch this because it depends on provider version schema. Plan catches more because it initializes providers and checks against their schemas. Workflow: fmt → validate → plan → apply. validate is fast (no API calls), plan is thorough (makes API calls)"
|
|
53
|
+
weight: 0.35
|
|
54
|
+
description: "Validation"
|
|
55
|
+
- type: llm_judge
|
|
56
|
+
criteria: "CI/CD and pre-commit integration are practical — pre-commit hook: use pre-commit framework with terraform_fmt and terraform_validate hooks. CI pipeline: (1) terraform fmt -check -recursive (fail if unformatted), (2) terraform init -backend=false (for validate only), (3) terraform validate, (4) terraform plan. This catches formatting issues before PR, validation errors without cloud access, and full errors with plan. Tools: pre-commit-terraform hooks, GitHub Actions, GitLab CI. TFLint for additional linting beyond validate (naming conventions, deprecated syntax, best practices)"
|
|
57
|
+
weight: 0.30
|
|
58
|
+
description: "CI integration"
|
package/courses/terraform-infrastructure-setup/scenarios/level-1/variable-and-output-errors.yaml
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: variable-and-output-errors
|
|
3
|
+
level: 1
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Debug variable and output errors — fix type mismatches, missing required variables, default values, and output reference issues"
|
|
7
|
+
tags: [Terraform, variables, outputs, types, validation, beginner]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
You run `terraform plan` and hit these errors:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Error: No value for required variable
|
|
16
|
+
|
|
17
|
+
on variables.tf line 1:
|
|
18
|
+
1: variable "environment" {
|
|
19
|
+
|
|
20
|
+
The root module input variable "environment" is not set, and has
|
|
21
|
+
no default value.
|
|
22
|
+
|
|
23
|
+
Error: Invalid value for variable
|
|
24
|
+
|
|
25
|
+
on variables.tf line 7:
|
|
26
|
+
7: variable "instance_count" {
|
|
27
|
+
|
|
28
|
+
This variable does not accept the value "three". Expected type number.
|
|
29
|
+
|
|
30
|
+
Error: Unsupported attribute
|
|
31
|
+
|
|
32
|
+
on outputs.tf line 3:
|
|
33
|
+
3: value = aws_instance.web.public_dns
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Your files:
|
|
37
|
+
|
|
38
|
+
variables.tf:
|
|
39
|
+
```hcl
|
|
40
|
+
variable "environment" {
|
|
41
|
+
type = string
|
|
42
|
+
description = "Deployment environment"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
variable "instance_count" {
|
|
46
|
+
type = number
|
|
47
|
+
default = 1
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
variable "allowed_cidrs" {
|
|
51
|
+
type = list(string)
|
|
52
|
+
default = ["0.0.0.0/0"]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
terraform.tfvars:
|
|
57
|
+
```hcl
|
|
58
|
+
instance_count = "three"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Task: Explain Terraform variables (types, defaults, validation),
|
|
62
|
+
how to pass values (tfvars, CLI, env vars, auto.tfvars), output
|
|
63
|
+
values and their uses, type system (string, number, bool, list,
|
|
64
|
+
map, object, tuple), and common variable/output errors.
|
|
65
|
+
|
|
66
|
+
assertions:
|
|
67
|
+
- type: llm_judge
|
|
68
|
+
criteria: "Variable system is explained — types: string, number, bool (primitives), list(type), set(type), map(type), object({key=type}), tuple([types]) (complex). Required vs optional: variables without default are required. Validation blocks: variable 'env' { validation { condition = contains(['dev','prod'], var.env), error_message = '...' } }. Sensitive = true: hides value in plan output. Nullable = false: disallows null values. The errors: (1) environment has no default and no value provided, (2) instance_count expects number but got string 'three', (3) public_dns might not exist if count = 0 or resource uses for_each"
|
|
69
|
+
weight: 0.35
|
|
70
|
+
description: "Variable system"
|
|
71
|
+
- type: llm_judge
|
|
72
|
+
criteria: "Value passing methods are covered in precedence order — (1) -var flag on CLI: terraform plan -var='environment=prod'. (2) -var-file flag: terraform plan -var-file=prod.tfvars. (3) terraform.tfvars or terraform.tfvars.json (auto-loaded). (4) *.auto.tfvars files (auto-loaded, alphabetical order). (5) TF_VAR_name environment variables: TF_VAR_environment=prod. Later sources override earlier ones. Best practice: use terraform.tfvars for defaults, environment-specific .tfvars files for overrides, never commit secrets in tfvars"
|
|
73
|
+
weight: 0.35
|
|
74
|
+
description: "Value passing"
|
|
75
|
+
- type: llm_judge
|
|
76
|
+
criteria: "Outputs are explained — output blocks export values after apply. Uses: display information, pass data between modules (module.vpc.vpc_id), feed into other tools. Attributes: value (required), description, sensitive, depends_on. terraform output command to retrieve values. terraform output -json for machine-readable format. Common errors: referencing attribute that doesn't exist on resource type, referencing resource with count/for_each without index (aws_instance.web[0].public_dns or aws_instance.web[*].public_dns)"
|
|
77
|
+
weight: 0.30
|
|
78
|
+
description: "Outputs"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: count-vs-for-each
|
|
3
|
+
level: 2
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Choose between count and for_each — understand index-based vs key-based resources, migration pitfalls, and when to use each"
|
|
7
|
+
tags: [Terraform, count, for_each, meta-arguments, iteration, intermediate]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Your infrastructure uses count for EC2 instances:
|
|
13
|
+
|
|
14
|
+
```hcl
|
|
15
|
+
variable "instances" {
|
|
16
|
+
default = ["web-1", "web-2", "web-3"]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
resource "aws_instance" "web" {
|
|
20
|
+
count = length(var.instances)
|
|
21
|
+
ami = "ami-0c55b159cbfafe1f0"
|
|
22
|
+
instance_type = "t3.micro"
|
|
23
|
+
tags = {
|
|
24
|
+
Name = var.instances[count.index]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
A developer removes "web-2" from the list. Terraform plan shows:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
# aws_instance.web[1] will be updated in-place (web-3 → web-2 tags)
|
|
33
|
+
# aws_instance.web[2] will be destroyed
|
|
34
|
+
|
|
35
|
+
Plan: 0 to add, 1 to change, 1 to destroy.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The web-3 instance gets renamed to web-2, and the real web-3 instance
|
|
39
|
+
gets destroyed! This is the wrong behavior — you wanted to remove
|
|
40
|
+
web-2, not web-3.
|
|
41
|
+
|
|
42
|
+
Task: Explain count vs for_each, why count causes index shift problems,
|
|
43
|
+
how for_each solves this with stable keys, how to migrate from count
|
|
44
|
+
to for_each safely, and when to use each approach.
|
|
45
|
+
|
|
46
|
+
assertions:
|
|
47
|
+
- type: llm_judge
|
|
48
|
+
criteria: "Count problems are explained — count uses numeric indices: web[0], web[1], web[2]. Removing a middle element shifts all subsequent indices. Removing 'web-2' (index 1) makes 'web-3' become index 1 — Terraform sees index 1 changed and index 2 disappeared. Result: wrong instance modified, wrong instance destroyed. This is a fundamental limitation of count with lists that can have elements removed. Count is safe only when: (1) all elements are identical, (2) you only add/remove from the end, (3) the count is a simple number not derived from a list"
|
|
49
|
+
weight: 0.35
|
|
50
|
+
description: "Count problems"
|
|
51
|
+
- type: llm_judge
|
|
52
|
+
criteria: "for_each solution is explained — for_each uses stable map keys: web['web-1'], web['web-2'], web['web-3']. Removing 'web-2' only affects web['web-2'] — other instances untouched. Implementation: resource 'aws_instance' 'web' { for_each = toset(var.instances), tags = { Name = each.key } } or with a map: for_each = var.instances_map, using each.key and each.value. for_each accepts: set(string) or map. Not list — use toset() to convert. Access instances: aws_instance.web['web-1'].id"
|
|
53
|
+
weight: 0.35
|
|
54
|
+
description: "for_each solution"
|
|
55
|
+
- type: llm_judge
|
|
56
|
+
criteria: "Migration strategy is covered — migrating count to for_each changes resource addresses (web[0] → web['web-1']). Without state management, Terraform destroys and recreates all instances. Safe migration: (1) use moved blocks (Terraform 1.1+): moved { from = aws_instance.web[0], to = aws_instance.web['web-1'] }. (2) Or use terraform state mv: terraform state mv 'aws_instance.web[0]' 'aws_instance.web[\"web-1\"]'. Verify with plan — should show no changes. When to use count: simple numeric repetition (create N identical resources). When to use for_each: named resources, resources that may be individually added/removed"
|
|
57
|
+
weight: 0.30
|
|
58
|
+
description: "Migration"
|