Terraform v12 Dynamic Nested Block с несколькими полями содержимого?
У меня проблема с моим модулем для шлюза приложений Azure. Я преобразовал все в динамические блоки, и когда я вызываю свой модуль с вводом для 1 приложения, он отлично работает.
1 приложение:
module "my_appgw" {
source = "../../../modules/module-application-gateway"
location = var.location
resource_group_name = var.rsg
subnet_id = "${data.azurerm_virtual_network.vnet_dmz.id}/subnets/waf"
app = [
{
name = "app1-example.com"
pick_host_name_from_backend = true,
},
]
}
Однако, когда я добавляю второе приложение к своему вызову, я вижу проблемы.
2 приложения
module "my_appgw" {
source = "../../../modules/module-application-gateway"
location = var.location
resource_group_name = var.rsg
subnet_id = "${data.azurerm_virtual_network.vnet_dmz.id}/subnets/waf"
app = [
{
name = "app1-example.com"
pick_host_name_from_backend = true,
},
{
name = "app2-example.com"
}
]
}
При добавлении нового приложения оно имеет как перенаправление 80, так и правило 443. Однако из-за индексации terraform хочет перезаписать мое первое правило приложения так, чтобы оба правила перенаправления 80 были первым и вторым в списке, а затем 443 правила третьим и четвертым в списке. Можем ли мы сделать несколько блоков контента в одном динамическом блоке? Как вы можете видеть, первое приложение меняется, когда я добавляю второе приложение в модуль, из-за чего ключи не совпадают (например, идентификатор app1 не соответствует ключу app2 и т. Д.). То же самое происходит с моим http_listener
Выходные изменения
request_routing_rule {
backend_address_pool_id = "<output omitted>/backendAddressPools/app1-example.com"
backend_address_pool_name = "app1-example.com"
backend_http_settings_id = "<output omitted>/backendHttpSettingsCollection/app1-example.com-https-settings"
backend_http_settings_name = "app1-example.com-https-settings"
http_listener_id = "<output omitted>/httpListeners/app1-example.com-443-https-list"
http_listener_name = "app1-example.com-443-https-list"
id = "<output omitted>/requestRoutingRules/app1-example.com-443"
name = "app1-example.com-443"
rule_type = "Basic"
}
~ request_routing_rule {
+ backend_address_pool_name = "app2-example.com"
+ backend_http_settings_name = "app2-example.com-https-settings"
http_listener_id = "<output omitted>/httpListeners/app1-example.com-http-list"
~ http_listener_name = "app1-example.com-http-list" -> "app2-example.com-443-https-list"
id = "<output omitted>/requestRoutingRules/app1-example.com-http-redirect"
~ name = "app1-example.com-http-redirect" -> "app2-example.com-443"
redirect_configuration_id = "<output omitted>/redirectConfigurations/app1-example.com-redirect"
- redirect_configuration_name = "app1-example.com-redirect" -> null
rule_type = "Basic"
}
+ request_routing_rule {
+ http_listener_name = "app1-example.com-http-list"
+ name = "app1-example.com-http-redirect"
+ redirect_configuration_name = "app1-example.com-redirect"
+ rule_type = "Basic"
}
+ request_routing_rule {
+ http_listener_name = "app2-example.com-http-list"
+ name = "app2-example.com-http-redirect"
+ redirect_configuration_name = "app2-example.com-redirect"
+ rule_type = "Basic"
}
Предлагаемая конфигурация, не работает
Несколько блоков содержимого на динамический блок
for_each = [for i in var.app : {
name = i.name
}]
content {
name = "${http_listener.value.name}-${local.http_listener_name}"
frontend_ip_configuration_name = local.frontend_ip_configuration_name
frontend_port_name = 80
protocol = "Http"
}
content {
name = "${http_listener.value.name}-${http_listener.value.port}-${local.https_listener_name}"
frontend_ip_configuration_name = local.frontend_ip_configuration_name
frontend_port_name = http_listener.value.port
ssl_certificate_name = data.azurerm_key_vault_secret.cert_fe.name
protocol = "Https"
}
}
Или вложенные динамические блоки в динамический блок, тоже не работает
dynamic "http_listener" {
for_each = [for i in var.app : {
name = i.name
}]
content {
name = "${http_listener.value.name}-${local.http_listener_name}"
frontend_ip_configuration_name = local.frontend_ip_configuration_name
frontend_port_name = 80
protocol = "Http"
dynamic "http_listener" {
for_each = [for i in var.app : {
name = i.name
port = lookup(i, "frontend_port", 443)
}]
content {
name = "${http_listener.value.name}-${http_listener.value.port}-${local.https_listener_name}"
frontend_ip_configuration_name = local.frontend_ip_configuration_name
frontend_port_name = http_listener.value.port
ssl_certificate_name = data.azurerm_key_vault_secret.cert_fe.name
protocol = "Https"
}
}
}
Кто-нибудь знает, как это исправить? Делает модуль шлюза приложений непригодным для использования, если существующие приложения будут изменяться и должны быть испорчены и воссозданы каждый раз при добавлении нового приложения.
1 ответ
В итоге я понял это. Вместо нескольких динамических вложенных блоков мне просто нужен был дополнительный цикл for, вложенный в начальный цикл for.
Вот связанный пример кода, который создает прослушиватель HTTP и HTTPS для каждого приложения. Он также создает правило HTTPS для внутреннего пула, а также правило перенаправления HTTP.
dynamic "http_listener" {
for_each = flatten([
for app in var.app: [
for listener in app.listener : {
fqdn = app.fqdn
protocol = listener.protocol
port = listener.port
}
]
])
content {
name = "%{ if http_listener.value.protocol == "https" }${http_listener.value.fqdn}-${http_listener.value.port}-${local.https_listener_name}%{ else }${http_listener.value.fqdn}-${local.http_listener_name}%{ endif }"
frontend_ip_configuration_name = local.frontend_ip_configuration_name
frontend_port_name = http_listener.value.port
host_name = http_listener.value.fqdn
protocol = upper(http_listener.value.protocol)
ssl_certificate_name = "%{ if http_listener.value.protocol == "https" }${data.azurerm_key_vault_secret.cert_fe.name}%{ endif }"
}
}
dynamic "request_routing_rule" {
for_each = flatten([
for app in var.app: [
for listener in app.listener : {
fqdn = app.fqdn
protocol = listener.protocol
port = listener.port
}
]
])
content {
name = "%{ if request_routing_rule.value.protocol == "https" }${request_routing_rule.value.fqdn}-${request_routing_rule.value.port}%{ else }${request_routing_rule.value.fqdn}-redirect%{ endif }"
rule_type = "Basic"
http_listener_name = "%{ if request_routing_rule.value.protocol == "https" }${request_routing_rule.value.fqdn}-${request_routing_rule.value.port}-${local.https_listener_name}%{ else }${request_routing_rule.value.fqdn}-${local.http_listener_name}%{ endif }"
backend_address_pool_name = "%{ if request_routing_rule.value.protocol == "https" }${request_routing_rule.value.fqdn}%{ endif }"
backend_http_settings_name = "%{ if request_routing_rule.value.protocol == "https" }${request_routing_rule.value.fqdn}-${local.backend_https_settings_name}%{ endif }"
redirect_configuration_name = request_routing_rule.value.protocol == "http" ? "${request_routing_rule.value.fqdn}-redirect" : null
}
}
dynamic "redirect_configuration" {
for_each = [for app in var.app : {
fqdn = app.fqdn
port = app.listener.https.port
}]
content {
name = "${redirect_configuration.value.fqdn}-redirect"
redirect_type = "Permanent"
target_listener_name = "${redirect_configuration.value.fqdn}-${redirect_configuration.value.port}-${local.https_listener_name}"
}
#... additional output omitted
А вот и вызов модуля. Вам необходимо указать прослушиватель http и https для приложения. Вы можете указать любой порт, в том числе нестандартный.
module "my_appgw" {
source = "../../../modules/module-application-gateway"
location = var.location
resource_group_name = var.rsg
subnet_id = "${data.azurerm_virtual_network.vnet_dmz.id}/subnets/waf"
app = {
1 = {
fqdn = "app1.com"
pick_host_name_from_backend = true
listener = {
http = {
protocol = "http"
port = 80
}
https = {
protocol = "https"
port = 443
}
}
}
}
#... additional output omitted
}