sctx
sctx

Reputation: 168

Terraform loops with both index and values

I'm creating an Openstack LoadBalancer with Terraform and I need to loop through a collection of instances and use at the same time the index.

In particular, I have 2 nodes:

output "nodes_1" {
  value = [
    for vm in openstack_compute_instance_v2.type_1_instance[*] : tomap({
      name       = "${vm.name}",
      private_ip = "${vm.network[0].fixed_ip_v4}"
    })
  ]
}

output "nodes_2" {
  value = [
    for vm in openstack_compute_instance_v2.type_2_instance[*] : tomap({
      name       = "${vm.name}",
      private_ip = "${vm.network[0].fixed_ip_v4}"
    })
  ]
}

Then I concat these outputs to have a single list:

cluster_nodes = concat(module.cluster_compute.nodes_1, module.cluster_compute.nodes_2)

And at the end I need to create an Openstack LoadBalancer using both instances "name" and "private_ip" and the index of the object:

resource "openstack_lb_listener_v2" "loadbalancer_listener" {
  count = local.total_nodes

  name            = "lb-listener"
  loadbalancer_id = openstack_lb_loadbalancer_v2.cluster_loadbalancer.id
  protocol_port   = sum([local.starting_port, count.index])
}

resource "openstack_lb_pool_v2" "load_balancer_pool" {
  for_each = {
    for index, vm in local.cluster_nodes :
    vm.name => vm
  }

  name        = "pool-${each.value.name}"
  listener_id = openstack_lb_listener_v2.loadbalancer_listener[index(local.cluster_nodes, each.value)].id
}

resource "openstack_lb_member_v2" "load_balancer_member" {
  for_each = {
    for index, vm in local.cluster_nodes :
    vm.name => vm
  }

  name          = "lb-member-${each.value.name}"
  pool_id       = openstack_lb_pool_v2.ssh_load_balancer_pool[index(local.cluster_nodes, each.value)].id
  address       = each.value.private_ip
}

How can I iterate and use both instances values and loop index?

Upvotes: 1

Views: 544

Answers (1)

Anton
Anton

Reputation: 1966

You could use count in both resources:

resource "openstack_lb_listener_v2" "loadbalancer_listener" {
  count = length(local.cluster_nodes)

  name            = "lb-listener"
  loadbalancer_id = openstack_lb_loadbalancer_v2.cluster_loadbalancer.id
  protocol_port   = sum([local.starting_port, count.index])
}

resource "openstack_lb_pool_v2" "load_balancer_pool" {
  count = length(local.cluster_nodes)

  name        = "pool-${local.cluster_nodes[count.index].name}"
  listener_id = openstack_lb_listener_v2.loadbalancer_listener[count.index].id
}

Another option might be to construct a map of node objects that include ports and use it with for_each to create all related resources:

locals {
  cluster_nodes_map = {
    for index, vm in local.cluster_nodes :
    vm.name => {
      name = vm.name
      private_ip = vm.private_ip
      port = sum([local.starting_port, count.index])
    }
  }
}

However, this still uses the node index to assign the port number, so if you removed a node, the ports would shift.

You may want to come up with a different way to assign the ports.

Upvotes: 2

Related Questions