Moshe
Moshe

Reputation: 5159

How do I create dynamic configmaps for Kubernetes without empty data?

I try to create kubernetes_config_map using for_each loop, when all of the data is inside a variable:

variables.tf:

variable "extra_configmaps" {
  type = list(object({
    name      = string
    namespace = string
    data      = object({})
  }))
  default = []
}

terraform.tfvars:

extra_configmaps = [
  {
    name      = "common"
    namespace = "production"
    data = {
      "somekey" = "somevalue"
    }
  }
]

main.tf:

resource "kubernetes_config_map" "extra_configmaps" {
  for_each = { for record in var.extra_configmaps : record.name => record }
  metadata {
    name      = each.key
    namespace = each.value.namespace
  }

  data = tomap(each.value.data)
}

However, the configmap is created with no data!

# kubernetes_config_map.extra_configmaps["common"] will be created
  + resource "kubernetes_config_map" "extra_configmaps" {
      + id = (known after apply)

      + metadata {
          + generation       = (known after apply)
          + name             = "common"
          + namespace        = "production"
          + resource_version = (known after apply)
          + self_link        = (known after apply)
          + uid              = (known after apply)
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

I know data expects a map, but the plan doesn't show it even thoughI have provided it.

How do I create dynamic configmaps for Kubernetes without empty data? How do I create dynamic configmaps for Kubernetes without empty data?

Upvotes: 0

Views: 1898

Answers (1)

Martin Atkins
Martin Atkins

Reputation: 74574

You've specified that the type constraint of the data attribute is object({}), which is an object type with no attributes at all. Object type constraints require that at least the given attributes are present, but since you didn't specify any attributes this constraint will match any object value but it will also discard all its attributes during type conversion, because none are specified in the type constraint.

This behavior for a totally-empty object type is, of course, a bit weird. It's a natural but perhaps awkward consequence of the rule that allows declaring an object type constraint that is a subset of an object type defined by a provider's resource type, to allow callers the convenience of passing the whole resource in without having to write out all of the attributes that the module doesn't actually need or care about:

variable "aws_vpc" {
  type = object({
    id         = string
    cidr_block = string

    # aws_vpc's object type has many other attributes,
    # but this module only needs the two above so it
    # will accept and silently discard all of the
    # others. Caller can therefore do this:
    #     aws_vpc = aws_vpc.example
  })
}

The data attribute of kubernetes_config_map is defined with the type constraint map(string), so I think the best way to get the result you were looking for here is to echo that same type constraint in your variable, like this:

variable "extra_configmaps" {
  type = list(object({
    name      = string
    namespace = string
    data      = map(string)
  }))
  default = []
}

There's more information about Terraform's type conversion rules in Conversion of Complex Types, which is part of the documentation on Type Constraints.

Upvotes: 2

Related Questions