002 · Domain 1: Scalable Terraform Configuration Design · 20% of the exam
Task 1.6: Implement advanced configurations
The language features of a mature configuration: for expressions that filter and group, dynamic blocks, check blocks, lifecycle rules and custom conditions on resources, data sources and outputs.
Study it
Advanced configuration: for expressions, dynamic blocks, checks and lifecycle
Lesson coming
Sample questions
Try each one before opening the answer. Every option is explained, with the HashiCorp documentation page that proves it.
Question 1 · choose 1
One database module serves every environment. Production databases must be protected by Terraform against any plan that would destroy them, while development copies are created and destroyed daily by the same module. The module receives var.protect (bool). Which approach works?
ASet lifecycle { prevent_destroy = var.protect } on the database resource
BTwo resource blocks gated by count on var.protect, one with prevent_destroy = true
CGenerate the lifecycle block with a dynamic block whose for_each depends on var.protect
DSet lifecycle { ignore_changes = all } on the database whenever var.protect is true
Show the answer and why
ASet lifecycle { prevent_destroy = var.protect } on the database resource
Incorrect
lifecycle settings are processed before expressions can be evaluated, so only literal values are accepted and the reference is an error.
BTwo resource blocks gated by count on var.protect, one with prevent_destroy = true
Correct
Each block uses a literal setting, and count chooses which block exists, so production gets the protected one and development the other.
CGenerate the lifecycle block with a dynamic block whose for_each depends on var.protect
Incorrect
Lifecycle settings are processed before Terraform evaluates expressions, so no construct can make them depend on var.protect.
DSet lifecycle { ignore_changes = all } on the database whenever var.protect is true
Incorrect
ignore_changes stops in-place updates; it does not stop a plan that destroys or replaces the object, and it is also a literal-only setting.
Because lifecycle rules shape the dependency graph, they take only literal values. When protection must vary by environment, choose between blocks that each carry a fixed setting, or enforce it outside the module with a policy.
A security team publishes a user-data template in S3, and the configuration reads it with data "aws_s3_object" "tpl". The template contains ${name} placeholders that must be filled from var.name. Which expression renders it?
Atemplatestring(data.aws_s3_object.tpl.body, { name = var.name })
Btemplatefile(data.aws_s3_object.tpl.body, { name = var.name })
Ctemplatestring("${data.aws_s3_object.tpl.body}", { name = var.name })
D"${data.aws_s3_object.tpl.body}"
Show the answer and why
Atemplatestring(data.aws_s3_object.tpl.body, { name = var.name })
Correct
templatestring renders a string held by a named object in the module as a template, using the given variables.
Btemplatefile(data.aws_s3_object.tpl.body, { name = var.name })
Incorrect
templatefile takes the path of a file that exists on disk when the run starts, not the template text.
Ctemplatestring("${data.aws_s3_object.tpl.body}", { name = var.name })
Incorrect
The first argument must be a reference to an object in the module; you cannot supply a template expression directly.
D"${data.aws_s3_object.tpl.body}"
Incorrect
Interpolation inserts the body as it is; the ${name} placeholders inside it are not rendered.
Use templatefile for templates shipped with the module and templatestring for templates fetched as a string at run time. HashiCorp advises building template text dynamically only when no alternative is feasible.
var.users maps user names to objects with a role attribute. What does { for name, u in var.users : u.role => name... } produce?
AAn error about several users sharing a role
BA map from each role to a list of the names that have it
CA map from each role to only the last of the names that the expression found
DA list of role and name pairs
Show the answer and why
AAn error about several users sharing a role
Incorrect
The trailing ... turns on grouping mode, which allows duplicate keys.
BA map from each role to a list of the names that have it
Correct
In grouping mode, the result collects every value for a key into a list.
CA map from each role to only the last of the names that the expression found
Incorrect
Grouping mode keeps all names, not just one.
DA list of role and name pairs
Incorrect
Braces make an object or map; brackets would make a tuple.
Without ..., duplicate keys in an object-producing for expression are an error; grouping mode is how a for expression collects several values under one key.
A check block contains a nested data "http" source that calls a health endpoint. During an apply, the endpoint is unreachable and the data source returns an error. What happens?
AThe apply fails and stops all remaining changes
BThe plan stops before any change is applied
CTerraform retries the data source until the health endpoint finally responds
DTerraform reports the problem as a warning and the run continues
Show the answer and why
AThe apply fails and stops all remaining changes
Incorrect
Errors from a nested data source in a check block do not stop the operation.
BThe plan stops before any change is applied
Incorrect
Nested data sources in check blocks are read as the last step, and their errors do not block.
CTerraform retries the data source until the health endpoint finally responds
Incorrect
Terraform does not retry; it reports the outcome as a warning.
DTerraform reports the problem as a warning and the run continues
Correct
Provider errors from a check block's nested data source are masked as warnings, so the operation completes.
A nested data source suits health checks of systems that may be briefly unavailable, because its failures surface as warnings in the run output.
An engineer adds lifecycle { ignore_changes = [count] } so that a scaling script can change how many instances exist. Terraform rejects it. Why?
Alifecycle blocks are not allowed in resources that use count
Bignore_changes takes only the all keyword when count is set
Cignore_changes accepts only the resource type's own attributes, not meta-arguments
Dcount must be a literal number before ignore_changes can apply to the instance count
Show the answer and why
Alifecycle blocks are not allowed in resources that use count
Incorrect
count and lifecycle can be used together in a resource.
Bignore_changes takes only the all keyword when count is set
Incorrect
A list of attributes works with count; the issue is what the list names.
Cignore_changes accepts only the resource type's own attributes, not meta-arguments
Correct
Terraform ignores only attributes the resource type defines; it cannot ignore meta-arguments such as count.
Dcount must be a literal number before ignore_changes can apply to the instance count
Incorrect
count accepts expressions known at plan time; that is not the reason.
ignore_changes shares management of attribute values with outside processes. The number of instances is a configuration decision that stays with Terraform.