'specifying values for nested maps

Currently I have a nested map with a default value in a variables.tf file as follows:

variable "node_hosts" {
  type = map(map(object({
      name          = string
      compute_node  = bool
      etcd_instance = string
      ipv4_address  = string
    })))
  default = {
    arc = {
      "node1" = {
        name          = "def"
        compute_node  = true
        etcd_instance = "etcd1"
        ipv4_address  = "12.345.678.90"
      }
    }
  }
}

My code in a main.tf iterates over this without any issues, however when I want to use the exact same variable that derives its value from a .tfvars file (I change the name of the inner map in the variables file from arc to something else):

 arc = {
    "control1" = {
      name          = "z-ca-arc-control1"
      compute_node  = false
      etcd_instance = "etcd1"
      ipv4_address  = "10.225.115.84"
    },
    "control2" =  {
      name          = "z-ca-arc-control2"
      compute_node  = false
      etcd_instance = "etcd2"
      ipv4_address  = "10.225.115.85"
    },
    "compute1" = {
      name          = "z-ca-arc-compute1"
      compute_node  = true
      etcd_instance = "etcd3"
      ipv4_address  = "10.225.115.86"
    },
    "compute2" = {
      name          = "z-ca-arc-compute2"
      compute_node  = true
      etcd_instance = ""
      ipv4_address  = "10.225.115.87"
    },
    "compute3" = {
      name          = "z-ca-arc-compute3"
      compute_node  = true
      etcd_instance = ""
      ipv4_address  = "10.225.115.88"
    }
  }
}

I get the following:

 Error: Invalid index
│ 
│   on modules/kubernetes_cluster/main.tf line 2, in locals:
│    2:    all_nodes_verbose_etcd = [for k, v in var.node_hosts[terraform.workspace]: 
│     ├────────────────
│     │ terraform.workspace is "arc"
│     │ var.node_hosts is map of map of object with 1 element
│ 
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Invalid index
│ 
│   on modules/kubernetes_cluster/main.tf line 6, in locals:
│    6:    all_nodes_verbose      = [for k, v in var.node_hosts[terraform.workspace]:
│     ├────────────────
│     │ terraform.workspace is "arc"
│     │ var.node_hosts is map of map of object with 1 element
│ 
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Invalid index
│ 
│   on modules/kubernetes_cluster/main.tf line 10, in locals:
│   10:    master_nodes           = [for k, v in var.node_hosts[terraform.workspace]:
│     ├────────────────
│     │ terraform.workspace is "arc"
│     │ var.node_hosts is map of map of object with 1 element
│ 
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Invalid index
│ 
│   on modules/kubernetes_cluster/main.tf line 14, in locals:
│   14:    etcd_nodes             = [for k, v in var.node_hosts[terraform.workspace]:
│     ├────────────────
│     │ terraform.workspace is "arc"
│     │ var.node_hosts is map of map of object with 1 element
│ 
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Invalid index
│ 
│   on modules/kubernetes_cluster/main.tf line 18, in locals:
│   18:    all_nodes              = values(var.node_hosts[terraform.workspace])[*].name
│     ├────────────────
│     │ terraform.workspace is "arc"
│     │ var.node_hosts is map of map of object with 1 element
│ 
│ The given key does not identify an element in this collection value.

This is the code I use for dereferencing the map of map objects, note that I use the workspace name as an index:

    locals {
       all_nodes_verbose_etcd = [for k, v in var.node_hosts[terraform.workspace]:
                                   format("%s ip=%s etcd_instance=%s", v.name, v.ipv4_address, v.etcd_instance)
                                   if length(v.etcd_instance) > 0]
    
       all_nodes_verbose      = [for k, v in var.node_hosts[terraform.workspace]:
                                   format("%s ip=%s", v.name, v.ipv4_address)
                                   if length(v.etcd_instance) == 0]
    
       master_nodes           = [for k, v in var.node_hosts[terraform.workspace]:
                                   v.name
                                   if v.compute_node != true]
    
       etcd_nodes             = [for k, v in var.node_hosts[terraform.workspace]:
                                   v.name
                                   if length(v.etcd_instance) > 0]
    
       all_nodes              = values(var.node_hosts[terraform.workspace])[*].name
    
       kubernetes_conf_file = format("%s/kubespray/inventory/%s/group_vars/k8s_cluster/k8s-cluster.yml", pathexpand("~"), terraform.workspace)
       all_conf_file        = format("%s/kubespray/inventory/%s/group_vars/all/all.yml", pathexpand("~"), terraform.workspace)
       context_artifact     = format("%s/kubespray/inventory/%s/artifacts/admin.conf", pathexpand("~"), terraform.workspace)
       kubespray_inv_file   = format("%s/kubespray/inventory/%s/inventory.ini", pathexpand("~"), terraform.workspace)
    }

The code to dereference the map of maps variable is contained in a module directory, if I run the following in that dirfectory:

terraform workspace select arc
terraform apply -auto-approve

Everything works perfectly, however if I try to execute terraform from the root module directory, i.e.:

terraform workspace select arc
terraform apply -target=module.kubernetes_cluster -auto-approve

or

terraform workspace select arc
terraform apply -target=module.kubernetes_cluster -var-file=modules/kubernetes_cluster/terraform.tfvars -auto-approve

(note that the terraform.tfvars should be picked up autoamtically without having to specify it)

I get the errors above.

The module structure is:

kubernetes
main.tf modules
kubernetes_cluster
main.tf variables.tf terraform.tfvars

Note that this issue has nothing to do with EKS or any Kubernetes as a service platform, the issue would seem purely to do with the ability of the code in the main.tf in the child module directory to dereference node_hosts.



Solution 1:[1]

The error founded is the missing variable in the child module, due to this the module used the incorrect default value.

Probably is just a my lack, but is possible that the varfile is not valid?

I haven't error with this

node_hosts = {
  arc = {
    "control1" = {
      name          = "z-ca-arc-control1"
      compute_node  = false
      etcd_instance = "etcd1"
      ipv4_address  = "12.345.678.01"
    },
    "control2" = {
      name          = "z-ca-arc-control2"
      compute_node  = false
      etcd_instance = "etcd2"
      ipv4_address  = "12.345.678.02"
    },
    "compute1" = {
      name          = "z-ca-arc-compute1"
      compute_node  = true
      etcd_instance = "etcd3"
      ipv4_address  = "12.345.678.03"
    },
    "compute2" = {
      name          = "z-ca-arc-compute2"
      compute_node  = true
      etcd_instance = ""
      ipv4_address  = "12.345.678.04"
    },
    "compute3" = {
      name          = "z-ca-arc-compute3"
      compute_node  = true
      etcd_instance = ""
      ipv4_address  = "12.345.678.05"
    }
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1