Reputation: 474
I wanted to create google_compute_health_check
in terraform and I'm thinking about how to make them the most versatile. My code atm looks like that
application.hcl
inputs = {
health_checks = {
tcp-health-check = {
name = "tcp-health-check"
desc = "Health check via tcp"
port = 80
timeout_sec = 4
check_interval_sec = 30
}
}
main terragrunt.hcl
include {
path = find_in_parent_folders()
}
terraform { source ...}
locals {
app_vars = read_terragrunt_config(find_in_parent_folders("application.hcl"))
}
inputs = {
# and my idea was that every invocation of the module, picks it's own set
# of health checks that it wants to use
health_checks = [local.app_vars.inputs.health_checks.tcp-health-check]
}
now the module main.tf
looks like so
locals {
checks = { for check in var.health_checks: check.name => check }
}
resource "google_compute_health_check" "main" {
for_each = local.checks
name = each.value.name
timeout_sec = each.value.timeout_sec
check_interval_sec = each.value.check_interval_sec
dynamic tcp_health_check {
#for_each = each.value.name == "tcp_health_check" ? each.value : []
#for_each = lookup(each.value, "tcp_health_check", [])
for_each = contains(keys(each.value), "tcp_health_check") != null ? each.value : {}
content {
port = 80
# port = each.value.port
# port_name = each.value.name
}
}
and I'm stuck in the dynamic block - how to make it work so that it only is applied when I pass the tcp
health_check, and when I pass, ssh
it creates dynamic ssh
block (I know there is no ssh block in the code atm, but in future I'll expand the module by whichever healht-check I'll need)
The errors I get are as followed with contains
Error: List longer than MaxItems
on main.tf line 30, in resource "google_compute_health_check" "main":
30: resource "google_compute_health_check" "main" {
Attribute supports 1 item maximum, config has 7 declared
ERRO[0011] 1 error occurred:
* exit status 1
with lookup
Error: ExactlyOne
on main.tf line 30, in resource "google_compute_health_check" "main":
30: resource "google_compute_health_check" "main" {
"ssl_health_check": one of
`grpc_health_check,http2_health_check,http_health_check,https_health_check,ssl_health_check,tcp_health_check`
must be specified
ERRO[0005] 1 error occurred:
* exit status 1
and with ==
comparison
Error: Inconsistent conditional result types
on main.tf line 44, in resource "google_compute_health_check" "main":
44: for_each = each.value.name == "tcp_health_check" ? each.value : []
|----------------
| each.value is object with 7 attributes
| each.value.name is "tcp-health-check"
The true and false result expressions must have consistent types. The given
expressions are object and tuple, respectively.
ERRO[0005] 1 error occurred:
* exit status 1
Ok solved it doing it the other way, but thanks for the answer Marcin
terragrunt.hcl
inputs = {
name = "nat-health-check"
used_for = "used for NATs"
check_interval_sec = 30
timeout_sec = 5
healthy_threshold = 1
unhealthy_threshold = 5
http_checks = local.app_vars.inputs.health_checks.nat-http
}
and modules main.tf
resource "google_compute_health_check" "main" {
name = var.name
timeout_sec = var.timeout_sec
check_interval_sec = var.check_interval_sec
description = "${var.name} - ${var.used_for}"
dynamic "http_health_check" {
for_each = var.http_checks != null ? [1] : []
content {
port = var.http_checks.port
request_path = var.http_checks.request_path
port_specification = var.http_checks.port_specification
}
}
}
Upvotes: 1
Views: 1239
Reputation: 238081
The following
contains(keys(each.value), "tcp_health_check") != null ? each.value : {}
fails because when this is true, your dynamic block tcp_health_check
will be executed more then once, since your each.value
is just a map of values. You can't have more then one tcp_health_check
block.
The second
for_each = lookup(each.value, "tcp_health_check", [])
does not fail and is correct. But since it results in false
, your tcp_health_check
block is not created. This fails as you are not providing any of the alternative blocks grpc_health_check,http2_health_check,http_health_check,https_health_check,ssl_health_check,tcp_health_check
.
The last attempt:
for_each = each.value.name == "tcp_health_check" ? each.value : []
fails because it should be for_each = each.value.name == "tcp_health_check" ? each.value : {}
. But if you fix this issue, each.value
will again fail as before.
To sum up, you are always doomed fot fail, since when you eliminate your block tcp_health_check
as in the second case, you are not providing any alternatives to it. And if your condition is true
, each.value
will try to create multiple blocks.
The closes solution would be (does not account for false case, where you need to provide alternatives):
dynamic tcp_health_check {
for_each = each.value.name == "tcp_health_check" ? [1] : []
content {
port = each.value.port
port_name = each.value.name
}
}
Upvotes: 2