Skip to content
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

make detailed type constraints easier to discover from the input variables docs #35570

Open
stonefield opened this issue Aug 15, 2024 · 2 comments
Labels
documentation explained a Terraform Core team member has described the root cause of this issue in code

Comments

@stonefield
Copy link

Terraform Version

Terraform v1.9.3
on darwin_amd64

Use Cases

I try to define an input variable defined as an object, where I would like to set optional attributes to a default value.

Ideal declaration:

variable "db" {
  description = "Database definitions"
  type        = object({
    name = string
    user_name = string
    deletion_protection = optional(boolean)
    backup = optional(boolean)
  })
  default = {
    deletion_protection = true
    backup = true
  }
}

In the case above I would like deletion_protection to default to true. Terraform reports:

This default value is not compatible with the variable's type constraint: attributes "name" and "user_name" are required.

Attempted Solutions

Workaround Removing defaults

allow terraform to run, but now there is no documentation describing the default since it is handled elsewhere.

variable "db" {
  description = "Database definitions"
  type        = object({
    name = string
    user_name = string
    deletion_protection = optional(boolean)
  })
}

Attempt to workaround 1 - unsuccessful

assign the default by using a local variable.

locals {
  db = merge( {deletion_protection = true}, var.db)
}

Now, if specifying only the required attributes, the optional key deletion_protection is still null, because deletion_protection is assigned by terraform as bool(null).

Work around 2 - successful

Using a loop to assign the default:

locals {
  db = { for key, value in var.db :
    key => (
      (key == "deletion_protection" || key == "backup") && value == null ? true : value
      )
  }
}

Work around 3 - successful

Trying to make the code more generic and efficient when default values

locals {
  default_db_values = {
    deletion_protection = true
    backup = false
  }
  
  db = { for key, value in var.db :
    key => (
      value == null && contains(keys(local.default_db_values), key) ? local.default_db_values[key] : value
    )
  }
}

Workaround Assigning required attributes default value of null

variable "db" {
  description = "Database definitions"
  type        = object({
    name = string
    user_name = string
    deletion_protection = optional(bool)
    backup = optional(bool)
  })
  default = {
    name = null
    user_name = null
    deletion_protection = true
    backup = true
  }
  validation {
    condition = var.db.name != null && var.db.user_name != null
    error_message = "Both database name and user_name must be specified"
  }
}

In the scenario above the mandatory keys are assigned to null and validation has to be done in order to fulfill the requirement of mandatory keys. However. The issue with the the default values are still problem as they are assigned null by terraform as long as the object is specified.

Proposal

My initial use case is the optimum solution. Explanation:

If type is declared as object and it contains optional attributes

  • Allow default to only contain optional attributes.

During processing of the variable:

  1. if any optional attributes are missing in the input and a default exists for those attributes, add them to the input
  2. then evaluate the input against the requirement (type specification)
  3. then assume the attribute is valid (with the defaults applied)

My rationale:

  • Clean and intuitive code
  • No unnecessary coding to meet the requirement

If you feel that support for more complex structures hinders implementing of the solution, then my advise would be to only support a reduced number of levels, such as minimum one

References

No response

@stonefield stonefield added enhancement new new issue not yet triaged labels Aug 15, 2024
@jbardin
Copy link
Member

jbardin commented Aug 15, 2024

Hi @stonefield,

I don't think I understand the proposal here, is your goal here is to have defaults for deletion_protection and backup? The default attribute of the variable block is the default value for the entire variable, it does not describe defaults within the type constraint. You also cannot supply null as a value for a required attribute, because null is the absence of a value. Defaults for optional attributes are defined in the type constraint like so

variable "db" {
  description = "Database definitions"
  type        = object({
    name = string
    user_name = string
    deletion_protection = optional(bool, true)
    backup = optional(bool, true)
  })
}

Which would leave name and user_name as required, but provide defaults for the optional deletion_protection and backup attributes. Does that do what you're trying to accomplish?

Thanks!

@stonefield
Copy link
Author

stonefield commented Aug 15, 2024

Thanks @jbardin,

This was a epiphany for me. It is not apparent when reading the documentation for variables here:
https://developer.hashicorp.com/terraform/language/values/variables

It does not give examples that leads to this understanding. However, doing some more research, I found this link:
https://developer.hashicorp.com/terraform/language/expressions/type-constraints

Maybe an update of the documentation will help others revealing this solution.

Feel free to update the documentation and/or close the issue if you wish.

@jbardin jbardin added documentation and removed new new issue not yet triaged labels Aug 15, 2024
@jbardin jbardin changed the title variable does not respect default value for optional attributes of an object make detailed type constraints easier to discover from the input variables docs Aug 15, 2024
@crw crw added explained a Terraform Core team member has described the root cause of this issue in code and removed enhancement labels Aug 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation explained a Terraform Core team member has described the root cause of this issue in code
Projects
None yet
Development

No branches or pull requests

3 participants