Yes, sometimes you only want to create/set up a certain block within a resource only when a specific part of a variable is set..
…and yes, it’s possible, thanks to try and dynamic blocks as well as for_each :)
Let me show you how to achieve this.
As an example, let’s say, you want to create several different buckets in gcp and you want to use a terraform variable for ‘additional’ definition of some details, apart from ‘default’ settings defined in your .tf file.
Let this be your buckets config variable, let’s name it gcp_buckets
, which is understandably in json format:
{
"test-bucket": {
"cors": [
{
"origin": [
"*"
],
"method": [
"GET",
"HEAD"
],
"responseHeader": [
"Content-Type"
],
"maxAgeSeconds": 3600
}
]
},
"test-bucket-two": {
"ttlDays": 2
}
}
Now, you only want to create ‘cors’ block when an ‘bucket’ object in variable gcp_buckets
has a key named ‘cors’ and take configuration from there, also you only want to set up specific lifecycle rule only if there is a key named ’ttlDays’ and take value from there..
This is how I do it, let me explain basics.
- This resource is only generated when a variable gcp_storage exists and thanks to above mentioned
try
function it tries to extract json encoded data and if it fails it returns empty object which means no resources are generated, otherwise it generates a resource per each object that we iterate over usingfor_each
. - As explained above, block
cors
for a resource is only ‘dynamically’ created when a keycors
exists within the object and then it uses values from there. - Same as with cors block, one of the
lifecycle_rule
-s is also only generated when key with name ttlDays exists and then takes value from there. - Last non-dynamic lifecycle_rule serves as an example of ‘default’ block that is being created for every created resource, same as with definition of options for this resource etc..
resource "google_storage_bucket" "global" {
for_each = try(jsondecode(var.gcp_storage), {})
name = each.key
project = google_project.project.project_id
location = "US-EAST1"
storage_class = "STANDARD"
requester_pays = "false"
default_event_based_hold = "false"
force_destroy = "false"
uniform_bucket_level_access = "false"
dynamic "cors" {
for_each = try(each.value.cors, {})
content {
max_age_seconds = cors.value.maxAgeSeconds
method = cors.value.method
origin = cors.value.origin
response_header = cors.value.responseHeader
}
}
dynamic "lifecycle_rule" {
for_each = try(["${each.value.ttlDays}"], {})
content {
action {
type = "Delete"
}
condition {
age = lifecycle_rule.value
created_before = ""
days_since_custom_time = "0"
days_since_noncurrent_time = "0"
num_newer_versions = "0"
with_state = "ANY"
}
}
}
lifecycle_rule {
action {
type = "Delete"
}
condition {
age = "0"
created_before = ""
days_since_custom_time = "0"
days_since_noncurrent_time = "30"
num_newer_versions = "0"
with_state = "ANY"
}
}
versioning {
enabled = "true"
}
lifecycle {
ignore_changes = [labels,]
}
}
Hope this is helpful to you and enjoy working with Terraform !