1

I have a module that accepts a variable with a validation as follows


variable "policy_statements" {
  description = "The statements of the policies to be created"
  type = map(object({
    path         = string
    capabilities = set(string)
  }))

  validation {
    condition     = contains(["create", "read", "update", "patch", "delete", "list"], var.policy_statements.capabilities)
    error_message = "Valid values for capabilities are (\"create\", \"read\", \"update\", \"patch\", \"delete\", \"list\")."
  }
}

I am then calling this module from another tf module:

module "policies" {
  source = "../../../../path/to"

  for_each = var.policies

  policy_statements = each.value

}

In the outer module, the policies variable is declared as

variable "policies" {
  description = "The statements of the policies to be created"
  type           = map(any)
}

Invocation fails with:

│   on ../../../../path/to/variables.tf line 13, in variable "policy_statements":
│   13:     condition     = contains(["create", "read", "update", "patch", "delete", "list"], var.policy_statements.capabilities)
│     ├────────────────
│     │ var.policy_statements is map of object with 2 elements
│
│ This map does not have an element with the key "capabilities".

The outer module reads the policies variable in a terragrunt.hcl as below:

locals {
  policies = yamldecode(file("config.yaml"))
}

inputs = {
  policies = local.policies
}

where config.yaml


policies:
  policy-test-1:
    capabilities:
      - read
      - create
    path: /foo/lala
  policy-test-2:
    capabilities:
      - update
      - delete
    path: /foo/lala

What is the reason of the validation failure?

1 Answer 1

1

As the error message notes, var.policy_statements is a map of objects, not just a single object. In your example data, the keys of that map are policy-test-1 and policy-test-2, so it's correct that there is no map key named "capabilities".

I think you are intending to check that condition for each element of the map, to verify that all of the objects meet the condition. If so, you can use a for expression in conjunction with the alltrue function to generate a list of condition results for each element in the map and then fail if any of them are false:

  validation {
    condition = alltrue([
      for stmt in var.policy_statements :
      contains(["create", "read", "update", "patch", "delete", "list"], stmt.capabilities)
    ])
    error_message = "Valid values for capabilities are (\"create\", \"read\", \"update\", \"patch\", \"delete\", \"list\")."
  }

Notice that in this example the capabilities attribute is checked for each stmt object and therefore each object in the map, rather than treating capabilities as a key for the map itself.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.