Terraform: Constrain input variable to require one of a set of allowed values

Created on 18 Jun 2020  路  3Comments  路  Source: hashicorp/terraform

Current Terraform Version

v0.12.26

Use-cases

Setting allowed values on an input parameter.

Attempted Solutions

I've used this pattern before, but it's clumsy and doesn't provide the user very good error message feedback:

variable "input_parameter" {
    type = string
    description = "input parameter, allowed values are a, b or c"
    default = "a"
}

locals {
    input_parameter_enums = {
        a = "a",
        b = "b",
        c = "c"
    }
    input_parameter = local.input_parameter_enums[var.input_parameter]
}

output "input_parameter" {
    value = local.input_parameter
}

If the value "d" is passed, this is the error given:

Error: Invalid index

  on main.tf line 13, in locals:
  13:     input_parameter = local.input_parameter_enums[var.input_parameter]
    |----------------
    | local.input_parameter_enums is object with 3 attributes
    | var.input_parameter is "d"

Proposal

Add support for specifying enums on variable blocks.

variable "input_parameter" {
    type = string
    description = "input parameter, allowed values are a, b or c"
    enum = ["a", "b", "c"]
    default = "a"
}

Much nicer error message:

Error: Invalid value "d" set for var.input_parameter, allowed values are "a", "b" or "c"
config enhancement

Most helpful comment

That's great, I'll give it a try - I can see how a validation block is more customisable to work with different data types and rules. Thanks for this, I'll definitely use it.

I also think a simpler pattern of allowed values is also worth pursuing. These occur all over the place, and having it would be much simpler than writing a validation block.
Also it would allow for module documentation published on registry.terraform.io to identify the allowed values, and the vscode extension to (in the future) to provide intellisense completion for allowed values when consuming a module directly.

All 3 comments

Hi @AdamCoulterOz,

I think you can get a result similar to what you are looking for using custom variable validation:

variable "input_parameter" {
  type    = string
  default = "a"

  validation {
    condition     = contains(["a", "b", "c"], var.input_parameter)
    error_message = "Allowed values for input_parameter are \"a\", \"b\", or \"c\"."
  }
}

In the current stable release of Terraform that feature is experimental and so requires an opt-in. It has been stabilized for inclusion in the forthcoming Terraform 0.13.0 release, currently in beta, and the stable feature is entirely compatible with the experimental one currently described in the documentation, so you can try it either via the opt-in experiment flag in 0.12 or by trying the latest 0.13.0 beta against an test configuration. The final Terraform 0.13.0 release is expected a few weeks from now, as long as this beta or the release candidate don't yield any release-blocking feedback.

If you give it a try, please let us know how it works out! There's more information on the feature in the 0.13.0 beta guide.

That's great, I'll give it a try - I can see how a validation block is more customisable to work with different data types and rules. Thanks for this, I'll definitely use it.

I also think a simpler pattern of allowed values is also worth pursuing. These occur all over the place, and having it would be much simpler than writing a validation block.
Also it would allow for module documentation published on registry.terraform.io to identify the allowed values, and the vscode extension to (in the future) to provide intellisense completion for allowed values when consuming a module directly.

@apparentlymart I just tried this on v0.12 with the opt-in flag and it seems generally good; perhaps a bit pushy with the failure about needing a capital letter at the start and period or question-mark at the end - does it need to be that opinionated? Does that even support non-roman languages?

That aside, it is not practical for an object value (complex-type) with say 20+ fields to construct a complicated condition on say my_object.first_field, then some arbitrary time later, your colleague wants to add validation on my_object.twenty_nth_field; what sensible/useful error_message can you curate in such a case?

As @AdamCoulterOz has suggested, there is very much still a case for enum([...]) as a schema definition, to get bool-like semantics i.e which could be equivalent to enum([true, false]) if value coercion was tacked on.

Maybe enum(enum_type,[<available-values-of-type-enum_type>]) to remove the need for type interference?

Was this page helpful?
0 / 5 - 0 ratings