Search code examples
kubernetesterraformconditional-statements

Terraform - kubernetes - create spec env-from if variable exixts


I try to create resources based on variables. variable.tf

variable "apps" {
  default = null
  type = map(object({
      name          = string
      type          = string
      secrets       = optional(map(string))
  }))
}

terraform.tfvars

apps = {

    "myfirst" = {
        name = "myfirst"
        type = "deploy"
        secrets = {
            "FIRST_VAR" = "TestVariable",
            "SECOND_VAR" = "SecontTestVariable",
            "THIRD" = "NothingHere"
        }
    },
    "second" ={
        name = "second"
        type = "deploy"
        secrets = {
            "SECRET_VAR" = "SecretVar"
        }
    },
    "simlepod" ={
        name = "simplepod"
        type = "deploy"
    },
    "another" ={
        name = "another"
        type = "pod"

And my main.tf

terraform {
  required_providers {
    kubernetes = {
      source = "hashicorp/kubernetes"
      version = "2.9.0"
    }
  }
  experiments = [module_variable_optional_attrs]
}

provider "kubernetes" {
    config_path    = "~/.kube/config"
  # Configuration options
}

resource "kubernetes_secret" "secret" {
  
  for_each = { for k in compact([for k, v in var.apps: v.secrets != null ? k : ""]): k => var.apps[k] }


  metadata {
    name = "${each.value.name}-secret"
  }

  data = each.value["secrets"]

}

resource "kubernetes_pod" "test" {

  for_each = { for k in compact([for k, v in var.apps: v.type =="deploy" ? k : ""]): k => var.apps[k] }

  metadata {
    name = "app-${each.value.name}"
  }

  spec {
    container {
      image = "nginx:1.21.6"
      name  = "test-${each.value.name}"

      
      env_from {
        secret_ref {
          name = kubernetes_secret.secret[each.value.name].metadata[0].name
        }
      }

      resources {
        limits = {
          cpu          = "0.5"
          memory       = "512Mi"
        }

        requests = {
          cpu          = "250m"
          memory       = "50Mi"
        }
      }
    }
  }

  timeouts {
    create = "60s"

  }
}

And this produces error because not all objects in apps have secret variable.

 terraform plan
╷
│ Warning: Experimental feature "module_variable_optional_attrs" is active
│ 
│   on main.tf line 8, in terraform:
│    8:   experiments = [module_variable_optional_attrs]
│ 
│ Experimental features are subject to breaking changes in future minor or patch
│ releases, based on feedback.
│ 
│ If you have feedback on the design of this feature, please open a GitHub issue to
│ discuss it.
╵
╷
│ Error: Unsupported block type
│ 
│   on main.tf line 68, in resource "kubernetes_pod" "test":
│   68:   dynamic "secret" {
│ 
│ Blocks of type "secret" are not expected here.

How to use expression to create env_from only when object has secrets variable?


Solution

  • I've found solution

    ...
          dynamic "env_from" {
            for_each = each.value.secrets[*]
            content {
              secret_ref {
                name = kubernetes_secret.secret[each.value.name].metadata[0].name
              }
            }
          }
    ...
    

    and seems to work. More details can be found in the Terraform docs on dynamic blocks.