Как указано в сообщении об ошибке, значение count
не должно зависеть от любых значений, которые Terraform не будет знать до тех пор, пока не будет завершено применение.В этом случае, похоже, var.azure_lb_public_backend_id
- это идентификатор объекта, который не будет выделен до тех пор, пока этот объект не будет создан, и поэтому Terraform еще не знает, какое значение это будет иметь, и поэтому не может сказать навернякабудет ли оно равным ""
.
Чтобы сделать эту работу, вам вместо этого нужно будет принять решение на основе того, что Terraform знает во время планирования.Один из способов сделать это - обернуть ваше значение идентификатора балансировщика нагрузки в объект, чтобы решение могло быть принято на основе того, установлен ли объект вообще:
variable "load_balancer" {
type = object({
backend_address_pool_id = string
})
default = null
}
resource "azurerm_network_interface_backend_address_pool_association" "vm-if-lb-public-association" {
count = var.load_balancer != null ? var.countvm : 0
network_interface_id = element(azurerm_network_interface.vm-if.*.id, count.index)
ip_configuration_name = "${var.workspace_config.prefix}-${var.profile}-${count.index + 1}"
backend_address_pool_id = var.load_balancer.backend_address_pool_id
}
Теперь решение основано на том,Объект var.load_balancer
имеет значение null, а не значение атрибута backend_address_pool_id
внутри него.Ваш вызывающий модуль может затем установить его, основываясь на том же тесте, который он использовал, чтобы решить, как установить var.enable
для другого модуля:
load_balancer = var.load_balancer_enabled ? {
backend_address_pool_id = module.load_balancer.lb_id
} : null
Если предположить, что var.load_balancer_enabled
является чем-то известным во время планирования, этотеперь должен работать, потому что Terraform может решить, является ли load_balancer
нулевым, и, таким образом, определить значение для count
во всех случаях.
В вышеизложенном я попытался как можно ближе придерживаться того, как вывсе было организовано так, чтобы было легче увидеть, какие изменения я предлагал, но есть несколько разных способов организовать вышеуказанный принцип, который может сделать модули более простыми в использовании для вызывающих.Ниже приведены некоторые примеры, которые значительно отличаются от того, что вы поделились, и показывают, как мы можем скрыть детали этой передачи обслуживания в самих интерфейсах модулей, чтобы добиться более чистой композиции модуля .
ВВаш корневой модуль:
variable "load_balancer_enabled" {
type = bool
default = false
}
resource "azurerm_resource_group" "example" {
name = "example"
location = "West US"
}
module "load_balancer" {
source = "./modules/load-balancer"
resource_group = azurerm_resource_group.example
enabled = var.load_balancer_enabled
}
module "virtual_machines" {
source = "./modules/virtual_machines"
resource_group = azurerm_resource_group.example
vm_count = 4
load_balancer = module.load_balancer
}
В модуле load-balancer
:
variable "resource_group" {
type = object({
name = string
location = string
})
}
variable "enabled" {
type = bool
default = true
}
resource "azurerm_lb" "example" {
count = var.enabled ? 1 : 0
name = "example"
resource_group_name = var.resource_group.name
location = var.resource_group.location
# (and probably a frontend IP allocation)
}
resource "azurerm_lb_backend_address_pool" "example" {
count = length(azurerm_lb.example)
name = "example"
resource_group_name = var.resource_group.name
loadbalancer_id = azurerm_lb.lb[count.index].id
}
output "backend_address_pool" {
# Set only if the load balancer is enabled. Null otherwise.
value = var.enabled ? azurerm_lb_backend_address_pool.example[0] : null
}
В модуле virtual-machine
:
variable "resource_group" {
type = object({
name = string
location = string
})
}
variable "vm_count" {
type = number
}
variable "load_balancer" {
type = object({
# We only need to specify the subset of the module outputs
# that we need here.
backend_address_pool = object({
id = string
})
})
}
resource "azurerm_network_interface" "example" {
count = var.vm_count
# (and whatever other settings you need here)
}
resource "azurerm_network_interface_backend_address_pool_association" "vm-if-lb-public-association" {
count = var.load_balancer.backend_address_pool != null ? var.vm_count : 0
network_interface_id = azurerm_network_interface.example[count.index].id
backend_address_pool_id = var.load_balancer.backend_address_pool.id
}
В этом вариантеМодуль load-balancer
создает объект, представляющий пул внутренних адресов, и имеет дело с установкой его на null
, когда модуль отключен.Затем мы можем просто передать результат всего модуля в модуль virtual-machine
и позволить ему принять решение на основе null
-ности этого объекта, а вызывающий модуль - это просто простое соединение модулей без какой-либо специальной логики.
Опять же, важная деталь заключается в том, что решение в конечном итоге принимается только на основе переменной var.load_balancer_enabled
(косвенно), а не на любых значениях, которые Terraform узнает во время применения.