Reputation: 327
I am trying to provision a cluster with instances across multiple zones in GCP using Terraform. This is what the nodes
variabe looks like:
variable "nodes" {
type = list(object({
machine_type = string
nvme_count = number
node_count = number
zone = string
disk_size = number
}))
default = [
{
zone = "us_east1-b"
machine_type = "n1-standard-4"
nvme_count = 3
node_count = 3
disk_size = 20
},
{
zone = "us_central1-a"
machine_type = "n1-standard-4"
nvme_count = 3
node_count = 3
disk_size = 20
}
]
}
This should mean that I want to ave 3 nodes in us-east1-b and 3 nodes in us-central1-a, with some additional parameters per zone.
This is how I tried to run this:
resource "google_compute_instance" "node-instance" {
for_each = var.nodes
name = "${var.cluster_name}-node-${each.value.zone}"
machine_type = each.value.machine_type
count = each.value.node_count
zone = each.value.zone
tags=["${var.cluster_name}-node"]
boot_disk {
initialize_params {
size = each.value.disk_size
image = data.google_compute_image.g_image.self_link
}
}
metadata = {
sshKeys = "${var.ssh_user}:${file(var.ssh_public_key)}"
}
network_interface {
network = "${var.cluster_name}-vpc"
access_config {
}
}
}
This does not work because apparently count
and for_each
conflict with each other. Is there a solution? I really don't want to hardcode a separate resource for each zone
Upvotes: 1
Views: 702
Reputation: 1050
There are several problems in your code.
First of all for_each accepts only set
or map
. It doesn't work with lists. You can try something like:
for_each = {for node in var.nodes: node.zone => node}
but even this is not enough. There is little can be done with multidimensional objects on the resource level. To achieve what you want you may need to unroll the definition of your nodes or go one level up an use modules.
locals {
nodes = flatten([ for node in var.nodes:
[ for i in range(node.node_count):
{
zone = node.zone
machine_type = node.machine_type
nvme_count = node.nvme_count
disk_size = node.disk_size
}
]
])
}
and then you use this list of nodes local.nodes
together with count = length(local.nodes) or convert it to set or map and use it with for_each.
Upvotes: 2