Reputation: 55
I can't figure out how to dynamically connect disks and networks to virtual machines if they are counted
I expect i will pass variables like this:
module "vps-test" {
source = "../module"
count = 3
server_name = "vpstest"
server_image = "debian-11"
server_type = "cx21"
server_datacenter = "fsn1-dc14"
labels = { groups = "test_offline.test_vps" }
server_network = {
backend_network = {
subnet_id = (data.terraform_remote_state.htz_network.outputs.main-subnet-id)
ip = "" #DHCP
}
custom_network = {
subnet_id = "1867414"
ip = ""
}
}
volumes = {
firts_volume = {
name = "volume1"
size = "20"
}
second_volume = {
name = "volume1"
size = "20"
}
}
hetzner_cloud_token = var.hetzner_cloud_offline_main_api_token
cloud_init_file_path = "../module/scripts/user.yaml"
}
and the module will create 3 identical VMs, where each will have 2 disks and 2 networks
It's Hetznere cloud provider, here is my simple code:
resource "hcloud_server" "vps" {
count = var.server_count
name = var.server_count > 1 ? "${var.server_name}-${count.index}" : var.server_name
image = var.server_image
server_type = var.server_type
datacenter = var.server_datacenter
user_data = data.template_file.ansible_user_data.rendered
labels = var.labels
}
resource "hcloud_volume" "volume" {
for_each = var.volumes
name = tostring(each.value["name"])
size = tonumber(each.value["size"])
server_id = hcloud_server.vps.id
automount = true
format = var.volume_filesystem
}
resource "hcloud_server_network" "network" {
for_each = var.server_network
server_id = hcloud_server.vps.id
subnet_id = each.value["subnet_id"]
ip = tostring(each.value["ip"])
}
Errors:
│ Error: Missing resource instance key
│
│ on ../module/resource.tf line 15, in resource "hcloud_volume" "volume":
│ 15: server_id = hcloud_server.vps.id
│
│ Because hcloud_server.vps has "count" set, its attributes must be accessed on specific instances.
│
│ For example, to correlate with indices of a referring resource, use:
│ hcloud_server.vps[count.index]
╵
╷
│ Error: Missing resource instance key
│
│ on ../module/resource.tf line 22, in resource "hcloud_server_network" "network":
│ 22: server_id = hcloud_server.vps.id
│
│ Because hcloud_server.vps has "count" set, its attributes must be accessed on specific instances.
│
│ For example, to correlate with indices of a referring resource, use:
│ hcloud_server.vps[count.index]
if using recommends from error log
│ Error: Reference to "count" in non-counted context
│
│ on ../module/resource.tf line 15, in resource "hcloud_volume" "volume":
│ 15: server_id = hcloud_server.vps[count.index].id
│
│ The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set.
╵
╷
│ Error: Reference to "count" in non-counted context
│
│ on ../module/resource.tf line 22, in resource "hcloud_server_network" "network":
│ 22: server_id = hcloud_server.vps[count.index].id
│
│ The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set.
but if server_id = hcloud_server.vps[0].id
(or any specific index) - working
where is the correct way
Upvotes: 1
Views: 160
Reputation: 238169
Since you are using both count
and for_each
you need to iterate over both of them. Basically it means you need a double for loop. One way to do it in TF is with the help of setproduct:
resource "hcloud_volume" "volume" {
for_each = {for idx, val in setproduct(range(var.server_count), keys(var.volumes)): idx => val}
name = tostring(var.volume[each.value[1]].name)
size = tonumber(var.volume[each.value[1]].size)
server_id = hcloud_server.vps[each.value[0]].id
automount = true
format = var.volume_filesystem
}
resource "hcloud_server_network" "network" {
for_each = {for idx, val in setproduct(range(var.server_count), keys(var.server_network)): idx => val}
server_id = hcloud_server.vps[each.value[0]].id
subnet_id = var.server_network[each.value[1]].subnet_id
ip = tostring(var.server_network[each.value[1]].ip)
}
Upvotes: 1