-
Notifications
You must be signed in to change notification settings - Fork 9.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A more expressive way to define assertions for multiple input variables or resources #36176
Comments
The purpose of It sounds like you are asking for a different way to express variable validations, aside from the existing |
Thanks @jbardin, I was unaware of the
Since my goal is to check for duplicates in two separate lists, I would need the ability to iterate |
Thanks @JonathonAnderson, Anything that can be expressed through a resource's I don't think there's any reason to tie this to |
@jbardin I noticed Also, |
This is a bit tangential to the original problem because I'm only comparing a single resource type, and my original problem was comparing two different resource types. To give you a better picture of the direction I'm going, here's the code I worked out for the simpler problem locals {
groups = concat(local.default-groups, var.entra.groups)
}
resource terraform_data validate-unique-group-names {
for_each = { for names in
flatten([ for index, group1 in local.groups :
[ for group2 in slice(local.groups, index + 1, length(local.groups)) :
{
group1-name = group1.display-name
group2-name = group2.display-name
}
]
]) : format("%s :: %s", names.group1-name, names.group2-name) => names
}
lifecycle {
precondition {
condition = upper(each.value.group1-name) != upper(each.value.group2-name)
error_message = "Groups must have unique display names"
}
}
} This produces an informative error message that directs the user to exactly which group is violating the constraint
By contrast, when using the variable validation variable entra {
type = object({
groups = list(object({
display-name = string
}))
validation {
condition = length(distinct(concat(local.default-groups.*.display-name, var.entra.groups.*.display-name))) == length(concat(local.default-groups.*.display-name, var.entra.groups.*.display-name))
error_message = "All groups must have a unique display name"
} The error message doesn't contain any specific values that point the user to the group that needs to be corrected
The drawback to the first method, using The drawback to the second method, using |
Thanks @JonathonAnderson, that's what I had in mind here. You are essentially using the |
@jbardin could you explain fragile and dependent on order? |
@JonathonAnderson, OK it's not as much of a problem as I thought at first glance, I originally read that as matching items between lists by index, but rather it's just creating all the combinations of items. It's still not going to reach the validation if there is a duplicate though, since you can't create a map from a for expression with duplicate keys, so you will get an error like |
@jbardin I was running the resource terraform_data validate-unique-group-names {
for_each = { for names in
flatten([ for index0, group1 in local.groups :
[ for index1, group2 in slice(local.groups, index0 + 1, length(local.groups)) :
{
group1-name = group1.display-name
group2-name = group2.display-name
}
]
]) : format("%s :: %s :: %s", names.group1-name, names.group2-name, index1) => names
}
lifecycle {
precondition {
condition = upper(each.value.group1-name) != upper(each.value.group2-name)
error_message = "Groups must have unique display names"
}
}
} Basically, add an index to the inner loop and append it to the format string for the key. That way if the same item is present at position 3, 7, and 11, they key will have a unique value for each combination of items |
@jbardin I'm beating a dead horse a bit here, so I apologize, but the above solution also only works for identical lists. A more generic solution for any two lists would be more like this resource terraform_data validate-unique-group-names {
for_each = { for names in
flatten([ for index0, group0 in local.groups0 :
[ for index1, group1 in local.groups1 :
{
group0-name = group0.display-name
group1-name = group1.display-name
}
]
]) : format("%s :: %s :: %s :: %s", names.group0-name, index0, names.group1-name, index1) => names
}
lifecycle {
precondition {
condition = upper(each.value.group0-name) != upper(each.value.group1-name)
error_message = "Groups must have unique display names"
}
}
} |
Terraform Version
Use Cases
I am doing some complex validation on inputs that don't fit neatly into the module declarations that are depending on the input. I'm essentially creating nested "for" loops iterating over resources of different types that will be fed into different modules to determine if the combined set is suitable for deployment. The validation doesn't belong to either set individually, and applying it to both doesn't seem like an elegant solution because "Do Not Repeat Yourself". The "terraform_data" resource works nicely for validation, but I don't want to add data to my state file. When I try to change the type from "resource" to "ephemeral" I receive an error:
Attempted Solutions
Attempted to change resource type for "terraform_data" from "resource" to "ephemeral"
Proposal
Enable "terraform_data" to be an "ephemeral" resource
References
No response
The text was updated successfully, but these errors were encountered: