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,80 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: dependency-management
|
|
3
|
+
level: 2
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Manage resource dependencies — debug dependency graphs, resolve circular references, use depends_on correctly, and understand the DAG"
|
|
7
|
+
tags: [Terraform, dependencies, DAG, circular, depends-on, intermediate]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Your infrastructure has a complex dependency chain that's causing
|
|
13
|
+
issues during apply:
|
|
14
|
+
|
|
15
|
+
```hcl
|
|
16
|
+
resource "aws_iam_role" "lambda" {
|
|
17
|
+
name = "lambda-role"
|
|
18
|
+
assume_role_policy = jsonencode({...})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
resource "aws_iam_role_policy" "lambda" {
|
|
22
|
+
role = aws_iam_role.lambda.name
|
|
23
|
+
policy = jsonencode({
|
|
24
|
+
Statement = [{
|
|
25
|
+
Action = "s3:GetObject"
|
|
26
|
+
Resource = aws_s3_bucket.data.arn
|
|
27
|
+
}]
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
resource "aws_lambda_function" "processor" {
|
|
32
|
+
function_name = "processor"
|
|
33
|
+
role = aws_iam_role.lambda.arn
|
|
34
|
+
handler = "index.handler"
|
|
35
|
+
runtime = "nodejs18.x"
|
|
36
|
+
filename = "lambda.zip"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
resource "aws_s3_bucket_notification" "trigger" {
|
|
40
|
+
bucket = aws_s3_bucket.data.id
|
|
41
|
+
lambda_function {
|
|
42
|
+
lambda_function_arn = aws_lambda_function.processor.arn
|
|
43
|
+
events = ["s3:ObjectCreated:*"]
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
resource "aws_lambda_permission" "s3" {
|
|
48
|
+
action = "lambda:InvokeFunction"
|
|
49
|
+
function_name = aws_lambda_function.processor.function_name
|
|
50
|
+
principal = "s3.amazonaws.com"
|
|
51
|
+
source_arn = aws_s3_bucket.data.arn
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Error:
|
|
56
|
+
```
|
|
57
|
+
Error: error creating S3 Bucket Notification: Unable to validate
|
|
58
|
+
the following destination configurations: Lambda function ARN
|
|
59
|
+
|
|
60
|
+
The Lambda function doesn't have permission to be invoked by S3 yet
|
|
61
|
+
(the permission resource hasn't been created).
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Task: Explain the Terraform dependency graph (DAG), implicit vs
|
|
65
|
+
explicit dependencies, how to debug dependency ordering issues,
|
|
66
|
+
terraform graph command, and depends_on best practices.
|
|
67
|
+
|
|
68
|
+
assertions:
|
|
69
|
+
- type: llm_judge
|
|
70
|
+
criteria: "DAG and implicit dependencies are explained — Terraform builds a directed acyclic graph (DAG) from resource references. Implicit: when resource A uses resource B's attribute, A depends on B. The chain: role → role_policy (references role.name), role → lambda (references role.arn), bucket → notification (references bucket.id), lambda → notification (references lambda.arn). The error: s3_bucket_notification depends on lambda (implicit) but NOT on lambda_permission (no attribute reference). S3 notification tries to verify the Lambda ARN but permission doesn't exist yet"
|
|
71
|
+
weight: 0.35
|
|
72
|
+
description: "DAG explained"
|
|
73
|
+
- type: llm_judge
|
|
74
|
+
criteria: "The fix uses depends_on correctly — add depends_on = [aws_lambda_permission.s3] to the aws_s3_bucket_notification resource. This creates an explicit dependency where no implicit one exists. depends_on is needed because the notification resource doesn't reference any attribute of the permission resource, but the permission must exist for the notification to succeed. terraform graph: visualize dependencies with terraform graph | dot -Tsvg > graph.svg. Look for missing edges that represent real-world dependencies"
|
|
75
|
+
weight: 0.35
|
|
76
|
+
description: "Fix with depends_on"
|
|
77
|
+
- type: llm_judge
|
|
78
|
+
criteria: "depends_on best practices are covered — use depends_on sparingly: prefer implicit dependencies (reference attributes). depends_on forces sequential creation (reduces parallelism). Common scenarios needing depends_on: IAM permissions before resources that need them, DNS records before health checks, network resources before resources placed in them (when ID isn't directly referenced). Anti-pattern: depends_on everywhere 'just in case' — slows down apply. Use terraform graph to verify dependency order before adding depends_on. Module-level depends_on: depends_on on module blocks waits for entire module to complete"
|
|
79
|
+
weight: 0.30
|
|
80
|
+
description: "Best practices"
|
package/courses/terraform-infrastructure-setup/scenarios/level-2/intermediate-debugging-shift.yaml
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: intermediate-debugging-shift
|
|
3
|
+
level: 2
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Combined intermediate shift — handle module errors, state corruption, and lifecycle issues during a busy infrastructure day"
|
|
7
|
+
tags: [Terraform, troubleshooting, combined, shift-simulation, intermediate]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Three issues hit your team today:
|
|
13
|
+
|
|
14
|
+
Issue 1 — Module version conflict:
|
|
15
|
+
```
|
|
16
|
+
$ terraform init -upgrade
|
|
17
|
+
|
|
18
|
+
Error: Failed to query available provider packages
|
|
19
|
+
|
|
20
|
+
Module "vpc" (source: terraform-aws-modules/vpc/aws, version 5.5.0)
|
|
21
|
+
requires aws provider >= 5.30.0, but the root module constrains
|
|
22
|
+
aws to ~> 4.0.
|
|
23
|
+
```
|
|
24
|
+
The VPC module was upgraded but the root module still pins an old
|
|
25
|
+
provider version.
|
|
26
|
+
|
|
27
|
+
Issue 2 — State file corruption:
|
|
28
|
+
```
|
|
29
|
+
$ terraform plan
|
|
30
|
+
|
|
31
|
+
Error: Failed to load state: unsupported state file format
|
|
32
|
+
|
|
33
|
+
The state file could not be loaded. Terraform detected that the
|
|
34
|
+
state file is not a supported format.
|
|
35
|
+
```
|
|
36
|
+
Someone manually edited the state file and introduced a JSON syntax
|
|
37
|
+
error.
|
|
38
|
+
|
|
39
|
+
Issue 3 — Unexpected resource replacement:
|
|
40
|
+
```
|
|
41
|
+
$ terraform plan
|
|
42
|
+
|
|
43
|
+
# aws_db_instance.main must be replaced
|
|
44
|
+
-/+ resource "aws_db_instance" "main" {
|
|
45
|
+
~ engine_version = "14.9" -> "14.11" # forces replacement
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
Updating the PostgreSQL minor version triggers a full database
|
|
49
|
+
replacement (destroy + create) instead of an in-place upgrade!
|
|
50
|
+
|
|
51
|
+
Task: Diagnose and resolve all three issues with proper explanations
|
|
52
|
+
and preventive measures.
|
|
53
|
+
|
|
54
|
+
assertions:
|
|
55
|
+
- type: llm_judge
|
|
56
|
+
criteria: "Issue 1 (provider version conflict) is resolved — the module requires aws >= 5.30.0 but root constrains to ~> 4.0 (allows 4.x only). Fix options: (1) update root provider constraint to ~> 5.0 (breaking changes between v4 and v5 — review changelog), (2) pin module to an older version compatible with aws ~> 4.0, (3) gradually migrate by testing with aws ~> 5.0 in dev first. Prevention: use version ranges that allow updates (~> 5.0 not = 5.5.0), test module upgrades in non-prod first, terraform init -upgrade in CI to catch conflicts early"
|
|
57
|
+
weight: 0.35
|
|
58
|
+
description: "Version conflict"
|
|
59
|
+
- type: llm_judge
|
|
60
|
+
criteria: "Issue 2 (state corruption) is resolved — state file is JSON, manual edits can break it. Recovery: (1) if using S3 backend with versioning: restore previous version from S3 version history. (2) terraform state pull from backup. (3) If no backup: terraform import all resources again (last resort). Prevention: NEVER manually edit state files — use terraform state mv/rm/import commands. Enable S3 versioning on state bucket. Set up automated state backups. Use DynamoDB locking to prevent concurrent writes"
|
|
61
|
+
weight: 0.35
|
|
62
|
+
description: "State corruption"
|
|
63
|
+
- type: llm_judge
|
|
64
|
+
criteria: "Issue 3 (unexpected replacement) is resolved — some RDS parameter changes force replacement instead of in-place modification. The engine_version change: check AWS provider docs for which attributes force replacement. Fix options: (1) use allow_major_version_upgrade or apply_immediately for in-place upgrades, (2) check if the provider version has a bug (some versions incorrectly force replacement), (3) use lifecycle { ignore_changes = [engine_version] } and manage upgrades outside Terraform. Prevention: always review plan for -/+ changes, test infrastructure changes in dev before prod, pin exact engine versions and upgrade deliberately"
|
|
65
|
+
weight: 0.30
|
|
66
|
+
description: "Unexpected replacement"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: lifecycle-rules
|
|
3
|
+
level: 2
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Use lifecycle meta-arguments — configure create_before_destroy, prevent_destroy, ignore_changes, and replace_triggered_by for safe resource management"
|
|
7
|
+
tags: [Terraform, lifecycle, create-before-destroy, prevent-destroy, ignore-changes, intermediate]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Three lifecycle issues in your infrastructure:
|
|
13
|
+
|
|
14
|
+
Issue 1 — Zero-downtime deployment:
|
|
15
|
+
Changing the launch template for an ASG causes recreation. During the
|
|
16
|
+
gap between destroy and create, no instances serve traffic:
|
|
17
|
+
```
|
|
18
|
+
-/+ aws_launch_template.web (forces replacement)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Issue 2 — Accidental database deletion:
|
|
22
|
+
A developer runs terraform destroy targeting a specific module but
|
|
23
|
+
accidentally includes the RDS instance:
|
|
24
|
+
```
|
|
25
|
+
aws_db_instance.production: Destroying... [id=prod-db]
|
|
26
|
+
aws_db_instance.production: Destruction complete
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Issue 3 — Auto-scaling interference:
|
|
30
|
+
Terraform keeps resetting the ASG desired_capacity back to 2, undoing
|
|
31
|
+
auto-scaling that scaled to 5 during peak traffic:
|
|
32
|
+
```
|
|
33
|
+
~ desired_capacity = 5 -> 2
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Task: Explain all lifecycle meta-arguments, when to use each,
|
|
37
|
+
common pitfalls, and real-world patterns for safe resource management.
|
|
38
|
+
|
|
39
|
+
assertions:
|
|
40
|
+
- type: llm_judge
|
|
41
|
+
criteria: "create_before_destroy is explained — lifecycle { create_before_destroy = true }: creates the new resource before destroying the old one. Fixes Issue 1: new launch template created first, ASG updated to use it, then old template destroyed. Use for: resources that must have zero downtime (load balancers, launch templates, security groups). Pitfall: some resources have unique constraints (names must be unique) — use name_prefix instead of name to allow both to exist simultaneously. Not all resources support this — some have global uniqueness requirements"
|
|
42
|
+
weight: 0.35
|
|
43
|
+
description: "create_before_destroy"
|
|
44
|
+
- type: llm_judge
|
|
45
|
+
criteria: "prevent_destroy and ignore_changes are explained — prevent_destroy = true: Terraform errors if any operation would destroy the resource. Fixes Issue 2: protects databases, S3 buckets, encryption keys. To actually destroy: remove prevent_destroy first, then destroy. ignore_changes = [desired_capacity]: tells Terraform to ignore changes to specific attributes. Fixes Issue 3: auto-scaling can change desired_capacity without Terraform reverting it. Use ignore_changes for: attributes managed by external systems (auto-scaling, external controllers). ignore_changes = all: ignore all attribute changes (resource only managed for creation)"
|
|
46
|
+
weight: 0.35
|
|
47
|
+
description: "prevent and ignore"
|
|
48
|
+
- type: llm_judge
|
|
49
|
+
criteria: "replace_triggered_by and patterns are covered — replace_triggered_by = [aws_ami.latest.id]: force replacement when a different resource changes. Use for: instances that should be recreated when AMI updates. Lifecycle patterns: databases always get prevent_destroy, ASGs get ignore_changes on desired_capacity, stateless resources get create_before_destroy for zero downtime. Pitfall: ignore_changes can mask drift — use sparingly and document why. Lifecycle rules are meta-arguments, not resource arguments — they go in the lifecycle {} block inside the resource"
|
|
50
|
+
weight: 0.30
|
|
51
|
+
description: "Patterns"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: locals-and-expressions
|
|
3
|
+
level: 2
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Use locals and expressions effectively — simplify complex configurations with local values, for expressions, conditionals, and built-in functions"
|
|
7
|
+
tags: [Terraform, locals, expressions, functions, conditionals, intermediate]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Your Terraform configuration has duplicated logic everywhere:
|
|
13
|
+
|
|
14
|
+
```hcl
|
|
15
|
+
resource "aws_instance" "web" {
|
|
16
|
+
tags = {
|
|
17
|
+
Name = "web-${var.environment}-${var.region}"
|
|
18
|
+
Environment = var.environment
|
|
19
|
+
Project = var.project
|
|
20
|
+
ManagedBy = "terraform"
|
|
21
|
+
CostCenter = var.environment == "prod" ? "CC-100" : "CC-200"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
resource "aws_s3_bucket" "data" {
|
|
26
|
+
tags = {
|
|
27
|
+
Name = "data-${var.environment}-${var.region}"
|
|
28
|
+
Environment = var.environment
|
|
29
|
+
Project = var.project
|
|
30
|
+
ManagedBy = "terraform"
|
|
31
|
+
CostCenter = var.environment == "prod" ? "CC-100" : "CC-200"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# Same tags repeated on 20 more resources...
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
You also need to transform a list of subnet CIDRs into a map keyed
|
|
39
|
+
by availability zone, and conditionally create resources based on
|
|
40
|
+
environment.
|
|
41
|
+
|
|
42
|
+
Task: Explain locals (local values), Terraform expressions (for,
|
|
43
|
+
conditionals, splat), built-in functions (lookup, merge, concat,
|
|
44
|
+
flatten, try), and how to use them to simplify configurations.
|
|
45
|
+
|
|
46
|
+
assertions:
|
|
47
|
+
- type: llm_judge
|
|
48
|
+
criteria: "Locals are explained — locals { common_tags = { Environment = var.environment, Project = var.project, ManagedBy = 'terraform', CostCenter = var.environment == 'prod' ? 'CC-100' : 'CC-200' } }. Reference: tags = merge(local.common_tags, { Name = 'web-server' }). Locals compute values once and reuse them. Use for: common tags, computed names, complex expressions used multiple times. Locals vs variables: variables are inputs from outside, locals are computed inside the configuration. Don't overuse locals — if a value is used once, just inline it"
|
|
49
|
+
weight: 0.35
|
|
50
|
+
description: "Locals"
|
|
51
|
+
- type: llm_judge
|
|
52
|
+
criteria: "Expressions are covered — for expression: [for s in var.subnets : s.cidr] (list), {for s in var.subnets : s.az => s.cidr} (map). Conditional: var.create_vpc ? 1 : 0 with count for conditional resource creation. Splat: aws_instance.web[*].id gets all IDs. Ternary: condition ? true_val : false_val. for with filtering: [for s in var.subnets : s.cidr if s.public]. String templates: 'Hello ${var.name}'. Heredoc: <<-EOT for multi-line strings"
|
|
53
|
+
weight: 0.35
|
|
54
|
+
description: "Expressions"
|
|
55
|
+
- type: llm_judge
|
|
56
|
+
criteria: "Built-in functions are practical — merge(): combine maps (merge(local.common_tags, local.extra_tags)). lookup(): safe map access with default (lookup(var.amis, var.region, 'ami-default')). concat(): join lists. flatten(): flatten nested lists. try(): return first non-error value (try(var.config.setting, 'default')). coalesce(): first non-null value. keys()/values(): extract from maps. length(): collection size. format/formatlist(): string formatting. cidrsubnet(): calculate subnet CIDRs. templatefile(): render template files. Type conversion: toset(), tomap(), tolist(), tonumber(), tostring()"
|
|
57
|
+
weight: 0.30
|
|
58
|
+
description: "Functions"
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: module-structure
|
|
3
|
+
level: 2
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Design Terraform modules — create reusable module structure, handle input/output contracts, and debug module composition errors"
|
|
7
|
+
tags: [Terraform, modules, reusability, composition, inputs, intermediate]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Your team copies and pastes VPC configuration across 8 environments.
|
|
13
|
+
Every copy has drifted slightly. You're tasked with creating a reusable
|
|
14
|
+
VPC module, but your first attempt has issues:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
modules/vpc/
|
|
18
|
+
├── main.tf
|
|
19
|
+
├── variables.tf
|
|
20
|
+
└── outputs.tf
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```hcl
|
|
24
|
+
# modules/vpc/main.tf
|
|
25
|
+
resource "aws_vpc" "this" {
|
|
26
|
+
cidr_block = var.cidr_block
|
|
27
|
+
tags = var.tags
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
resource "aws_subnet" "public" {
|
|
31
|
+
count = length(var.public_subnets)
|
|
32
|
+
vpc_id = aws_vpc.this.id
|
|
33
|
+
cidr_block = var.public_subnets[count.index]
|
|
34
|
+
availability_zone = var.azs[count.index]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```hcl
|
|
39
|
+
# Root module calling it
|
|
40
|
+
module "vpc" {
|
|
41
|
+
source = "./modules/vpc"
|
|
42
|
+
# forgot to pass required variables
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
resource "aws_instance" "web" {
|
|
46
|
+
subnet_id = module.vpc.public_subnet_ids[0]
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Errors:
|
|
51
|
+
```
|
|
52
|
+
Error: Missing required argument
|
|
53
|
+
The argument "cidr_block" is required, but no definition was found.
|
|
54
|
+
|
|
55
|
+
Error: Unsupported attribute
|
|
56
|
+
module.vpc.public_subnet_ids is object with no attribute "public_subnet_ids"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Task: Explain Terraform module design, required vs optional variables
|
|
60
|
+
with defaults, output contracts between modules, module sources
|
|
61
|
+
(local, registry, git), and module composition best practices.
|
|
62
|
+
|
|
63
|
+
assertions:
|
|
64
|
+
- type: llm_judge
|
|
65
|
+
criteria: "Module structure is explained — a module is a directory with .tf files: main.tf (resources), variables.tf (inputs), outputs.tf (exported values), versions.tf (required providers). Modules encapsulate reusable infrastructure. Required variables have no default — callers must provide them. The error: cidr_block has no default in the module, and the root module didn't pass it. Fix: module 'vpc' { source = './modules/vpc', cidr_block = '10.0.0.0/16', public_subnets = [...], azs = [...], tags = {...} }. Module outputs must be explicitly declared — the second error is because public_subnet_ids wasn't defined in outputs.tf"
|
|
66
|
+
weight: 0.35
|
|
67
|
+
description: "Module structure"
|
|
68
|
+
- type: llm_judge
|
|
69
|
+
criteria: "Module sources are covered — local: source = './modules/vpc'. Terraform Registry: source = 'terraform-aws-modules/vpc/aws', version = '~> 5.0'. Git: source = 'git::https://github.com/org/modules.git//vpc?ref=v1.0.0'. S3: source = 's3::https://bucket.s3.amazonaws.com/modules/vpc.zip'. Best practice: use versioned sources (git tags, registry versions) for stability. Local modules for project-specific code. Registry modules for common patterns (VPC, EKS, RDS). Pin versions: never use unversioned git sources in production"
|
|
70
|
+
weight: 0.35
|
|
71
|
+
description: "Module sources"
|
|
72
|
+
- type: llm_judge
|
|
73
|
+
criteria: "Composition best practices are practical — module contract: clearly document required vs optional inputs with descriptions. Use validation blocks on variables. Output everything consumers might need. Keep modules focused (one concern per module). Avoid deeply nested modules (max 2-3 levels). Module composition: root module calls multiple child modules, passes outputs between them. Example: module.vpc.vpc_id → module.eks.vpc_id. Don't put provider configuration in modules — pass it from root. Use for_each on modules to create multiple instances"
|
|
74
|
+
weight: 0.30
|
|
75
|
+
description: "Best practices"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: provisioner-pitfalls
|
|
3
|
+
level: 2
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Avoid provisioner pitfalls — understand why provisioners are a last resort, debug connection failures, and use better alternatives"
|
|
7
|
+
tags: [Terraform, provisioners, remote-exec, local-exec, user-data, intermediate]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
A developer uses remote-exec to install software on EC2 instances:
|
|
13
|
+
|
|
14
|
+
```hcl
|
|
15
|
+
resource "aws_instance" "web" {
|
|
16
|
+
ami = "ami-0c55b159cbfafe1f0"
|
|
17
|
+
instance_type = "t3.micro"
|
|
18
|
+
key_name = "deploy-key"
|
|
19
|
+
|
|
20
|
+
provisioner "remote-exec" {
|
|
21
|
+
inline = [
|
|
22
|
+
"sudo apt-get update",
|
|
23
|
+
"sudo apt-get install -y nginx",
|
|
24
|
+
"sudo systemctl enable nginx"
|
|
25
|
+
]
|
|
26
|
+
connection {
|
|
27
|
+
type = "ssh"
|
|
28
|
+
user = "ubuntu"
|
|
29
|
+
private_key = file("~/.ssh/deploy-key.pem")
|
|
30
|
+
host = self.public_ip
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Problems encountered:
|
|
37
|
+
```
|
|
38
|
+
Error: timeout - last error: dial tcp 54.1.2.3:22:
|
|
39
|
+
connect: connection refused
|
|
40
|
+
|
|
41
|
+
Error: remote-exec provisioner error
|
|
42
|
+
Status: 100 (apt-get returned non-zero)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The instance was created but the provisioner failed. Now the resource
|
|
46
|
+
is tainted and will be destroyed and recreated on next apply.
|
|
47
|
+
|
|
48
|
+
Task: Explain provisioners (local-exec, remote-exec, file), why
|
|
49
|
+
they're problematic, connection debugging, taint behavior on failure,
|
|
50
|
+
and better alternatives (user_data, Packer, Ansible).
|
|
51
|
+
|
|
52
|
+
assertions:
|
|
53
|
+
- type: llm_judge
|
|
54
|
+
criteria: "Provisioner types and problems are explained — local-exec: runs command on the machine running Terraform. remote-exec: runs command on the created resource via SSH/WinRM. file: copies files to the resource. Problems: (1) not declarative — can't detect drift, (2) failure taints the resource (forces recreation), (3) non-idempotent (running twice may break), (4) SSH connection is fragile (timing, security groups, key issues), (5) Terraform can't model what provisioners do in state. The connection refused error: instance not ready yet when SSH attempted, or security group doesn't allow port 22"
|
|
55
|
+
weight: 0.35
|
|
56
|
+
description: "Provisioner problems"
|
|
57
|
+
- type: llm_judge
|
|
58
|
+
criteria: "Debugging and taint behavior are covered — connection debugging: (1) check security group allows SSH from Terraform runner, (2) instance may not be ready (cloud-init still running), (3) wrong SSH user for AMI (ubuntu vs ec2-user vs admin), (4) private key permissions or format issues. Taint on failure: when provisioner fails, Terraform marks the resource as tainted. Next apply: destroy and recreate the entire instance. This is wasteful and disruptive. on_failure = continue skips the error (resource not tainted but may be misconfigured). on_failure = fail (default) taints the resource"
|
|
59
|
+
weight: 0.35
|
|
60
|
+
description: "Debugging and taint"
|
|
61
|
+
- type: llm_judge
|
|
62
|
+
criteria: "Better alternatives are recommended — (1) user_data: cloud-init script runs on first boot, no SSH needed, retries handled by OS, idempotent with proper scripting. (2) Packer: build pre-configured AMIs with all software installed, Terraform just launches them. (3) Ansible/Chef/Puppet: proper configuration management tools run after Terraform creates infrastructure. (4) AWS Systems Manager Run Command: no SSH needed, agents already on Amazon AMIs. Best practice: Terraform creates infrastructure, other tools configure it. Use provisioners only as absolute last resort"
|
|
63
|
+
weight: 0.30
|
|
64
|
+
description: "Alternatives"
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: remote-state-backend
|
|
3
|
+
level: 2
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Configure remote state backend — set up S3+DynamoDB locking, migrate from local to remote state, and troubleshoot backend errors"
|
|
7
|
+
tags: [Terraform, state, backend, S3, DynamoDB, locking, intermediate]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Your team has been using local state files. Problems are mounting:
|
|
13
|
+
- Two engineers ran apply simultaneously, corrupting the state
|
|
14
|
+
- A laptop crash lost the state file for the staging environment
|
|
15
|
+
- No one knows who changed what or when
|
|
16
|
+
|
|
17
|
+
You're migrating to S3 backend with DynamoDB locking. During migration:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
$ terraform init -migrate-state
|
|
21
|
+
|
|
22
|
+
Initializing the backend...
|
|
23
|
+
Do you want to copy existing state to the new backend?
|
|
24
|
+
Enter a value: yes
|
|
25
|
+
|
|
26
|
+
Error: Failed to save state
|
|
27
|
+
|
|
28
|
+
Error saving state: failed to upload state: AccessDenied:
|
|
29
|
+
Access Denied
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
After fixing permissions, another error:
|
|
33
|
+
```
|
|
34
|
+
Error: Error acquiring the state lock
|
|
35
|
+
|
|
36
|
+
Error message: ConditionalCheckFailedException
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Task: Explain remote state setup (S3 + DynamoDB), state migration
|
|
40
|
+
from local to remote, state locking mechanics, backend configuration
|
|
41
|
+
options, and how to share state across teams using terraform_remote_state.
|
|
42
|
+
|
|
43
|
+
assertions:
|
|
44
|
+
- type: llm_judge
|
|
45
|
+
criteria: "S3 backend setup is complete — backend configuration: bucket (S3 bucket name), key (state file path), region, encrypt = true (SSE), dynamodb_table (for locking). Bootstrap: create S3 bucket with versioning enabled, create DynamoDB table with LockID partition key (String). The AccessDenied error: IAM policy needs s3:GetObject, s3:PutObject, s3:ListBucket on the bucket, plus dynamodb:GetItem, dynamodb:PutItem, dynamodb:DeleteItem on the lock table. State migration: terraform init -migrate-state copies local state to S3"
|
|
46
|
+
weight: 0.35
|
|
47
|
+
description: "Backend setup"
|
|
48
|
+
- type: llm_judge
|
|
49
|
+
criteria: "State locking mechanics are explained — DynamoDB locking: before any state-modifying operation, Terraform writes a lock record to DynamoDB with a unique ID, who holds it, and operation type. If lock exists, operation fails with ConditionalCheckFailedException. Lock released after operation completes. Stale locks: if process crashes, lock remains. Fix: terraform force-unlock <LOCK_ID> (only if holder process is confirmed dead). S3 versioning: enables state recovery if corruption occurs. terraform state pull to download, terraform state push to upload manually"
|
|
50
|
+
weight: 0.35
|
|
51
|
+
description: "Locking mechanics"
|
|
52
|
+
- type: llm_judge
|
|
53
|
+
criteria: "Cross-team state sharing is covered — terraform_remote_state data source reads another team's state outputs: data 'terraform_remote_state' 'network' { backend = 's3', config = { bucket = '...', key = 'network/terraform.tfstate' } }. Reference: data.terraform_remote_state.network.outputs.vpc_id. State file organization: separate state per environment and per team/service to limit blast radius. Pattern: s3://state-bucket/<env>/<service>/terraform.tfstate. IAM: restrict which teams can read/write which state files using S3 bucket policies"
|
|
54
|
+
weight: 0.30
|
|
55
|
+
description: "State sharing"
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: terraform-import
|
|
3
|
+
level: 2
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Import existing resources into Terraform — bring console-created infrastructure under IaC management without recreation"
|
|
7
|
+
tags: [Terraform, import, existing-resources, migration, IaC-adoption, intermediate]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Your company has 50 AWS resources created via console that need to
|
|
13
|
+
come under Terraform management. You start importing:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
$ terraform import aws_instance.legacy i-0abc123def456
|
|
17
|
+
|
|
18
|
+
aws_instance.legacy: Importing from ID "i-0abc123def456"...
|
|
19
|
+
aws_instance.legacy: Import prepared!
|
|
20
|
+
Imported aws_instance.legacy
|
|
21
|
+
|
|
22
|
+
$ terraform plan
|
|
23
|
+
|
|
24
|
+
# aws_instance.legacy will be updated in-place
|
|
25
|
+
~ resource "aws_instance" "legacy" {
|
|
26
|
+
~ ami = "ami-current123" -> "ami-wrong456"
|
|
27
|
+
~ instance_type = "t3.large" -> "t3.micro"
|
|
28
|
+
~ tags = {
|
|
29
|
+
- "ManagedBy" = "console" -> null
|
|
30
|
+
+ "Environment" = "prod"
|
|
31
|
+
}
|
|
32
|
+
# ... 20 more attribute changes
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The plan shows changes because your .tf file doesn't match the
|
|
37
|
+
actual resource configuration!
|
|
38
|
+
|
|
39
|
+
Task: Explain terraform import workflow, how to write matching
|
|
40
|
+
configuration after import, the new import block syntax (Terraform 1.5+),
|
|
41
|
+
bulk import strategies, and common import pitfalls.
|
|
42
|
+
|
|
43
|
+
assertions:
|
|
44
|
+
- type: llm_judge
|
|
45
|
+
criteria: "Import workflow is explained — (1) write a resource block in .tf file, (2) run terraform import <address> <id>, (3) run terraform plan to see differences, (4) update .tf file to match actual configuration until plan shows no changes. The plan shows changes because the .tf config was written with incorrect values — must match reality exactly. Use terraform state show aws_instance.legacy to see imported attributes and copy them to .tf file. Iterate: import → plan → fix config → plan again until clean"
|
|
46
|
+
weight: 0.35
|
|
47
|
+
description: "Import workflow"
|
|
48
|
+
- type: llm_judge
|
|
49
|
+
criteria: "Import block syntax (1.5+) is covered — import { to = aws_instance.legacy, id = 'i-0abc123def456' }. Benefits over CLI import: (1) can be code-reviewed in PRs, (2) terraform plan -generate-config-out=generated.tf generates matching configuration automatically, (3) supports for_each for bulk imports. The generated config is a starting point — review and clean up. Import blocks are removed after successful apply. This is the recommended approach for Terraform 1.5+"
|
|
50
|
+
weight: 0.35
|
|
51
|
+
description: "Import blocks"
|
|
52
|
+
- type: llm_judge
|
|
53
|
+
criteria: "Bulk import and pitfalls are practical — bulk strategy: (1) inventory all resources (AWS Config, resource explorer), (2) write import blocks for all, (3) generate config, (4) review and customize, (5) apply. Pitfalls: (1) some resources don't support import (check provider docs), (2) imported resources may reference other non-imported resources, (3) secrets in imported state (passwords, keys) — rotate after import, (4) complex resources (EKS, RDS) may need manual config adjustment. Tools: terraformer for auto-generating both config and import commands from existing cloud infrastructure"
|
|
54
|
+
weight: 0.30
|
|
55
|
+
description: "Bulk import"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: workspace-management
|
|
3
|
+
level: 2
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Manage Terraform workspaces — understand workspace isolation, limitations, and when to use workspaces vs directory-based environments"
|
|
7
|
+
tags: [Terraform, workspaces, environments, isolation, multi-env, intermediate]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Your team uses workspaces for environment separation:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
$ terraform workspace list
|
|
16
|
+
default
|
|
17
|
+
dev
|
|
18
|
+
staging
|
|
19
|
+
* prod
|
|
20
|
+
|
|
21
|
+
$ terraform workspace select staging
|
|
22
|
+
Switched to workspace "staging".
|
|
23
|
+
|
|
24
|
+
$ terraform plan
|
|
25
|
+
# Accidentally planning against staging with prod-sized resources
|
|
26
|
+
# because terraform.tfvars has prod values!
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
A developer selected the wrong workspace and applied prod-sized
|
|
30
|
+
(expensive) resources to staging. Monthly bill spiked by $5K.
|
|
31
|
+
|
|
32
|
+
Another issue: you can't use different provider versions for dev
|
|
33
|
+
vs prod because all workspaces share the same root module.
|
|
34
|
+
|
|
35
|
+
Task: Explain Terraform workspaces, their proper use cases,
|
|
36
|
+
limitations, the terraform.workspace variable, and compare
|
|
37
|
+
workspaces vs directory-based environment separation.
|
|
38
|
+
|
|
39
|
+
assertions:
|
|
40
|
+
- type: llm_judge
|
|
41
|
+
criteria: "Workspaces are explained — workspaces create separate state files within the same backend. terraform workspace new dev creates a new workspace. State stored at: env:/dev/terraform.tfstate. terraform.workspace variable returns current workspace name — use for conditional logic: locals { instance_type = terraform.workspace == 'prod' ? 't3.large' : 't3.micro' }. Workspaces share the same code, providers, and backend config. The accident: wrong workspace selected, wrong tfvars applied because workspaces don't enforce which tfvars to use"
|
|
42
|
+
weight: 0.35
|
|
43
|
+
description: "Workspaces explained"
|
|
44
|
+
- type: llm_judge
|
|
45
|
+
criteria: "Limitations are clearly stated — workspaces are NOT ideal for environment separation because: (1) same code for all environments (can't have different provider versions), (2) easy to apply to wrong workspace (no guardrails), (3) shared backend makes cross-environment blast radius larger, (4) terraform.workspace checks scattered through code make it hard to read. Proper use cases: testing infrastructure changes (ephemeral workspaces), feature branch environments, temporary environments for demos. NOT for: long-lived dev/staging/prod separation"
|
|
46
|
+
weight: 0.35
|
|
47
|
+
description: "Limitations"
|
|
48
|
+
- type: llm_judge
|
|
49
|
+
criteria: "Directory-based alternative is recommended — separate directories per environment: environments/dev/, environments/staging/, environments/prod/. Each has its own backend config, tfvars, and can pin different module/provider versions. Benefits: complete isolation, clear boundaries, can't accidentally apply to wrong environment, independent state. Shared logic through modules: environments call common modules with environment-specific variables. Terraform Cloud workspaces are different from CLI workspaces — they provide true isolation with separate runs, variables, and permissions"
|
|
50
|
+
weight: 0.30
|
|
51
|
+
description: "Directory alternative"
|
package/courses/terraform-infrastructure-setup/scenarios/level-3/advanced-debugging-shift.yaml
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
meta:
|
|
2
|
+
id: advanced-debugging-shift
|
|
3
|
+
level: 3
|
|
4
|
+
course: terraform-infrastructure-setup
|
|
5
|
+
type: output
|
|
6
|
+
description: "Combined advanced shift — handle state surgery, cross-account issues, and drift remediation in a single complex incident"
|
|
7
|
+
tags: [Terraform, troubleshooting, combined, shift-simulation, advanced]
|
|
8
|
+
|
|
9
|
+
state: {}
|
|
10
|
+
|
|
11
|
+
trigger: |
|
|
12
|
+
Three interconnected issues escalate during your on-call shift:
|
|
13
|
+
|
|
14
|
+
Issue 1 — State divergence after team split:
|
|
15
|
+
Team A split their resources from the shared state last week using
|
|
16
|
+
state mv. But they missed moving aws_iam_policy.shared, which is
|
|
17
|
+
now in both state files:
|
|
18
|
+
```
|
|
19
|
+
Team A state: contains aws_iam_policy.shared
|
|
20
|
+
Team B state: contains aws_iam_policy.shared (original)
|
|
21
|
+
|
|
22
|
+
Team A runs apply → modifies the policy
|
|
23
|
+
Team B runs apply → overwrites Team A's changes
|
|
24
|
+
```
|
|
25
|
+
The same resource is managed by two state files!
|
|
26
|
+
|
|
27
|
+
Issue 2 — Cross-account module failure:
|
|
28
|
+
A module deployed to the DR account references resources in the
|
|
29
|
+
primary account via terraform_remote_state:
|
|
30
|
+
```
|
|
31
|
+
Error: error reading S3 bucket: AccessDenied
|
|
32
|
+
|
|
33
|
+
The DR account's Terraform role doesn't have cross-account
|
|
34
|
+
permission to read the primary account's state bucket.
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Issue 3 — Drift from security incident response:
|
|
38
|
+
The security team disabled public access on 15 S3 buckets during
|
|
39
|
+
an incident. Now terraform plan shows 15 buckets will have public
|
|
40
|
+
access re-enabled (reverting the security fix):
|
|
41
|
+
```
|
|
42
|
+
~ resource "aws_s3_bucket_public_access_block" "data" {
|
|
43
|
+
~ block_public_acls = true -> false
|
|
44
|
+
~ block_public_policy = true -> false
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Task: Resolve all three issues with proper procedures and
|
|
49
|
+
establish preventive measures.
|
|
50
|
+
|
|
51
|
+
assertions:
|
|
52
|
+
- type: llm_judge
|
|
53
|
+
criteria: "Issue 1 (dual-managed resource) is resolved — a resource in two state files is extremely dangerous: both try to manage it, last writer wins. Fix: (1) immediately terraform state rm aws_iam_policy.shared from Team A's state (they don't own it). (2) If Team A needs it: create a separate policy for Team A. (3) If shared: move to a shared-infrastructure state that both teams read via terraform_remote_state. Prevention: during state splits, verify no resource appears in multiple states using terraform state list on all states. Use terraform state list | sort to compare"
|
|
54
|
+
weight: 0.35
|
|
55
|
+
description: "Dual-managed resource"
|
|
56
|
+
- type: llm_judge
|
|
57
|
+
criteria: "Issue 2 (cross-account state access) is resolved — the DR account's Terraform role needs S3 read permissions on the primary account's state bucket. Fix: (1) add S3 bucket policy on primary's state bucket allowing DR account's role to s3:GetObject, (2) or use assume_role in the terraform_remote_state data source to assume a role in the primary account. Alternative: use Terraform Cloud with cross-workspace state sharing (no S3 permissions needed). Prevention: when setting up multi-account, plan state access patterns upfront and document IAM requirements"
|
|
58
|
+
weight: 0.35
|
|
59
|
+
description: "Cross-account access"
|
|
60
|
+
- type: llm_judge
|
|
61
|
+
criteria: "Issue 3 (security drift) is resolved — the security fix was correct, Terraform code is wrong. Fix: update all 15 S3 bucket configurations to block_public_acls = true, block_public_policy = true. This aligns code with the desired secure state. Do NOT apply the current plan (it would revert the security fix). Workflow: (1) update .tf files, (2) run plan to verify no changes, (3) commit code. Prevention: security changes should always be reflected in Terraform code. Establish a process: security team opens PR with Terraform changes, not just console modifications"
|
|
62
|
+
weight: 0.30
|
|
63
|
+
description: "Security drift"
|