Answers: <p>You can validate your variable with the following expression:</p>
  <pre><code>validation {
    condition     = length([for launch_type in values(var.ecs_config_map)[*].launch_type: launch_type if !contains([&quot;EC2&quot;, &quot;FARGATE&quot;, &quot;EXTERNAL&quot;], launch_type)]) &lt;= 0
    error_message = &quot;Only EC2, FARGATE, EXTERNAL are allowed values for launch_type.&quot;
  }
  </code></pre>
  <p>This might seem complex so let's brake it donw.</p>
  <p>We can extract the launch types from <code>ecs_config_map</code> with the following <code>for</code> expression:</p>
  <pre><code>output &quot;launch_types&quot; {
    value = [for launch_type in values(var.ecs_config_map)[*].launch_type : launch_type]
  }
  </code></pre>
  <p>The output of this would be something like:</p>
  <pre><code>launch_types = [
    &quot;FARGATE&quot;,
    &quot;FARGATE&quot;,
  ]
  </code></pre>
  <p>Moving on, we would want to filter out those launch types which are not in the allowed types array (<code>[&quot;EC2&quot;, &quot;FARGATE&quot;, &quot;EXTERNAL&quot;]</code>). We can do this as such:</p>
  <pre><code>output &quot;not_allowed_launch_types&quot; {
    value = [for launch_type in values(var.ecs_config_map)[*].launch_type: launch_type if !contains([&quot;EC2&quot;, &quot;FARGATE&quot;, &quot;EXTERNAL&quot;], launch_type)]
  }
  </code></pre>
  <p>If the input is correct, this should output an empty array, otherwise we will have the incorrect launch types as the output.</p>
  <p>Final step is to validate if we have any incorrect launch types. We can do this with the <code>length</code> function, if the length of the array with the incorrect launch types is greater than <code>0</code>, we have an invalid input.</p>
  
Answers: CC BY-SA 4.0
Answers: 2022-05-19T15:13:13.630Z
Answers: Going through the answer indicated where I was going wrong. I was using the `for` loop incorrectly. I used `alltrue` and returned `false` in the for loop expression. But I essentially used the answer. Thank you for breaking the solution down into parts and explaining it.
Answers: shine
Answers: CC BY-SA 4.0
Answers: 2022-05-08T19:06:13.583Z
Answers: 2022-05-08T19:06:13.583Z
Answers: Ervin Szilagyi
Body: <p>I am trying to validate a map of objects that is typed as below :</p>
  <pre><code>variable &quot;ecs_config_map&quot; {
    type = map(object({
      cpu     = number
      memory  = number
      desired = number
  
      capabilities = list(string)
      launch_type  = string
    }))
  }
  </code></pre>
  <p>The value for the variable looks like :</p>
  <pre><code>ecs_config_map = {
    driver = {
      cpu     = 256
      memory  = 512
      desired = 0
  
      capabilities = [&quot;FARGATE&quot;]
      launch_type  = &quot;FARGATE&quot;
    }
    aggregator = {
      cpu     = 256
      memory  = 512
      desired = 0
  
      capabilities = [&quot;FARGATE&quot;]
      launch_type  = &quot;FARGATE&quot;
    }
  }
  </code></pre>
  <hr />
  <p>Now, I want to perform some basic validation, but I cannot seem to get the syntax right.</p>
  <pre><code> validation {
      condition = contains([&quot;EC2&quot;, &quot;FARGATE&quot;, &quot;EXTERNAL&quot;], var.ecs_config_map[*][&quot;launch_type&quot;])
      error_message = &quot;Only EC2, FARGATE, EXTERNAL are allowed values for launch_type.&quot;
    }
  </code></pre>
  <p>This threw <code>Invalid value for &quot;list&quot; parameter: list of bool required.</code></p>
  <hr />
  <p>Debugging on <code>terraform console</code> described :</p>
  <pre><code>&gt; type(var.ecs_config_map)
  map(
      object({
          capabilities: list(string),
          cpu: number,
          desired: number,
          launch_type: string,
          memory: number,
      }),
  )
  &gt; type(var.ecs_config_map[&quot;driver&quot;])
  object({
      capabilities: list(string),
      cpu: number,
      desired: number,
      launch_type: string,
      memory: number,
  })
  &gt; type(var.ecs_config_map[*])
  tuple([
      map(
          object({
              capabilities: list(string),
              cpu: number,
              desired: number,
              launch_type: string,
              memory: number,
          }),
      ),
  ])
  </code></pre>
  <p>which indicated that my problem was because I was trying to iterate over all the objects in the variable. I am using a splat expression when doing <code>var.ecs_config_map[*]</code> which converts the whole map into a tuple of maps of objects.</p>
  <hr />
  <p>Then I tried to use a <code>for</code> expression to perform the validation</p>
  <pre><code> validation {
      condition = can(for task in var.ecs_config_map : contains([&quot;EC2&quot;, &quot;FARGATE&quot;, &quot;EXTERNAL&quot;], task[&quot;launch_type&quot;]))
      error_message = &quot;Only EC2, FARGATE, EXTERNAL are allowed values for launch_type.&quot;
    }
  </code></pre>
  <p>And I got thrown <code>The condition for variable &quot;ecs_config_map&quot; can only refer to the variable itself, using var.ecs_config_map.</code></p>
  <p><code>for_each</code> did not work either.</p>
  <hr />
  <p>Am I messing up the syntax of the validation somewhere? Or am I asking too much from terraform by attempting validation of a complex type?</p>
  
Tags: <terraform>
Title: validating map of objects
UserDisplayName: shine
ThreadText: # validating map of objects
  
  (Asked by: username_0 on 2022-05-08)
  
  I am trying to validate a map of objects that is typed as below :
  
  ```
  variable "ecs_config_map" {
    type = map(object({
      cpu     = number
      memory  = number
      desired = number
  
      capabilities = list(string)
      launch_type  = string
    }))
  }
  
  ```
  
  The value for the variable looks like :
  
  ```
  ecs_config_map = {
    driver = {
      cpu     = 256
      memory  = 512
      desired = 0
  
      capabilities = ["FARGATE"]
      launch_type  = "FARGATE"
    }
    aggregator = {
      cpu     = 256
      memory  = 512
      desired = 0
  
      capabilities = ["FARGATE"]
      launch_type  = "FARGATE"
    }
  }
  
  ```
  
  ---
  
  Now, I want to perform some basic validation, but I cannot seem to get the syntax right.
  
  ```
   validation {
      condition = contains(["EC2", "FARGATE", "EXTERNAL"], var.ecs_config_map[*]["launch_type"])
      error_message = "Only EC2, FARGATE, EXTERNAL are allowed values for launch_type."
    }
  
  ```
  
  This threw `Invalid value for "list" parameter: list of bool required.`
  
  ---
  
  Debugging on `terraform console` described :
  
  ```
  > type(var.ecs_config_map)
  map(
      object({
          capabilities: list(string),
          cpu: number,
          desired: number,
          launch_type: string,
          memory: number,
      }),
  )
  > type(var.ecs_config_map["driver"])
  object({
      capabilities: list(string),
      cpu: number,
      desired: number,
      launch_type: string,
      memory: number,
  })
  > type(var.ecs_config_map[*])
  tuple([
      map(
          object({
              capabilities: list(string),
              cpu: number,
              desired: number,
              launch_type: string,
              memory: number,
          }),
      ),
  ])
  
  ```
  
  which indicated that my problem was because I was trying to iterate over all the objects in the variable. I am using a splat expression when doing `var.ecs_config_map[*]` which converts the whole map into a tuple of maps of objects.
  
  ---
  
  Then I tried to use a `for` expression to perform the validation
  
  ```
   validation {
      condition = can(for task in var.ecs_config_map : contains(["EC2", "FARGATE", "EXTERNAL"], task["launch_type"]))
      error_message = "Only EC2, FARGATE, EXTERNAL are allowed values for launch_type."
    }
  
  ```
  
  And I got thrown `The condition for variable "ecs_config_map" can only refer to the variable itself, using var.ecs_config_map.`
  
  `for_each` did not work either.
  
  ---
  
  Am I messing up the syntax of the validation somewhere? Or am I asking too much from terraform by attempting validation of a complex type?
  
  **Tags:** terraform
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2022-05-08. Score: 2 | Accepted answer
  
  You can validate your variable with the following expression:
  
  ```
  validation {
    condition     = length([for launch_type in values(var.ecs_config_map)[*].launch_type: launch_type if !contains(["EC2", "FARGATE", "EXTERNAL"], launch_type)]) <= 0
    error_message = "Only EC2, FARGATE, EXTERNAL are allowed values for launch_type."
  }
  
  ```
  
  This might seem complex so let's brake it donw.
  
  We can extract the launch types from `ecs_config_map` with the following `for` expression:
  
  ```
  output "launch_types" {
    value = [for launch_type in values(var.ecs_config_map)[*].launch_type : launch_type]
  }
  
  ```
  
  The output of this would be something like:
  
  ```
  launch_types = [
    "FARGATE",
    "FARGATE",
  ]
  
  ```
  
  Moving on, we would want to filter out those launch types which are not in the allowed types array (`["EC2", "FARGATE", "EXTERNAL"]`). We can do this as such:
  
  ```
  output "not_allowed_launch_types" {
    value = [for launch_type in values(var.ecs_config_map)[*].launch_type: launch_type if !contains(["EC2", "FARGATE", "EXTERNAL"], launch_type)]
  }
  
  ```
  
  If the input is correct, this should output an empty array, otherwise we will have the incorrect launch types as the output.
  
  Final step is to validate if we have any incorrect launch types. We can do this with the `length` function, if the length of the array with the incorrect launch types is greater than `0`, we have an invalid input.
  
  > **Comments:**
  > **username_0**: Going through the answer indicated where I was going wrong. I was using the `for` loop incorrectly. I used `alltrue` and returned `false` in the for loop expression. But I essentially used the answer. Thank you for breaking the solution down into parts and explaining it.  
  
  ---
  
  