Search code examples
terraformterraform0.12+terraform-provider-kubernetes

An argument or block definition is required here


I am using kubernetes_network_policy resource. I am trying loop over the ports and getting this issue.

╷
│ Error: Argument or block definition required
│
│   on main.tf line 16, in resource "kubernetes_network_policy" "example-policy":
│   16:     { for i in range(length(val.egress_number)):
│
│ An argument or block definition is required here.

My Resource

resource "kubernetes_network_policy" "example-policy" {
  for_each = var.inputs
  metadata {
    name      = each.value.name
    namespace = each.value.namespace
  }
  spec {
    pod_selector {
      match_labels = {
        app = each.value.selector
      }
    }
    policy_types = each.value.policy

    egress {
    { for i in range(length(egress_number)):
      ports {
          port     = egress_number[i]
          protocol = egress_protocol[i]
      }
    }
      to {
        namespace_selector {
          match_labels = {
            app = each.value.egress_label
          }
        }
      }
    }
  }
}

My varibale.tf

variable "inputs" {
  type = map(object({
    name            = string
    namespace       = string
    selector        = string
    policy          = list(string)
    egress_number   = list(string)
    egress_protocol = list(string)
    egress_label    = string
  }))
  default = {}
}

My tfvars

  inputs = {
    app = {
      name           = "nignx"
      namespace       = "default"
      selector        = "nignix-app"
      policy          = ["Egress"]
      egress_label    = "play"
      egress_number   = ["443", "8080"]
      egress_protocol = ["TCP", "TCP"]
    }
  }

Solution

  • You have to use dynamic blocks:

    resource "kubernetes_network_policy" "example-policy" {
      for_each = var.inputs
      metadata {
        name      = each.value.name
        namespace = each.value.namespace
      }
      spec {
        pod_selector {
          match_labels = {
            app = each.value.selector
          }
        }
        policy_types = each.value.policy
        
        dynamic "egress" {
            
            for_each = range(length(each.value.egress_number))
            
            content {
                ports {
                    port     = each.value.egress_number[egress.value]
                    protocol = each.value.egress_protocol[egress.value]
                }
                
                to {
                    namespace_selector {
                        match_labels = {
                            app = each.value.egress_label
                        }
                    }
               } 
          }       
        }    
      }
    }
    

    Instead of using range and length, one could also use zipmap in your case.