MrDuk
MrDuk

Reputation: 18322

What is the equivalent of "" for booleans in terraform?

I have a module that controls a handful of similar resources, and many of the settings in those resources are the same; so I've created global defaults that all of the resources in my module can refer to.

I want to have a set of default variables in my module and a set of variables that can override the default if the caller of my module decides to pass those in. What I've been using for strings is below (these are all in the same variables.tf file in my module).

My defaults:

variable "default_env" {default="test"}

My placeholder variables to allow calling resources to set them:

variable "x_env" {default=""}
variable "y_env" {default=""}
variable "z_env" {default=""}

And my attempt at guiding the user of the module towards which variables should be available for being overridden:

locals {
    env = "${var.x_env != "" ? var.x_env : "${var.default_env}"}"
    env = "${var.y_env != "" ? var.y_env : "${var.default_env}"}"
    env = "${var.z_env != "" ? var.z_env : "${var.default_env}"}"
}

However, I can't figure out how to do this properly with booleans because I can't figure out how to create an empty boolean variable. My only option seems to be to also set a default value as part of my override variables:

variable "x_lock" {default=true}

Is there a way I can declare this in such a way that we don't have to maintain two sets of default values (1: variable "default_lock" {default=true}, 2: variable "x_lock" {default=true})?

I've tried doing:

variable "x_lock" {
    type = bool
    default = ""
}

But I obviously get an error that "" is not compatible with bool.

How else can I go about this?

Upvotes: 0

Views: 4956

Answers (1)

Martin Atkins
Martin Atkins

Reputation: 74584

The absence of a value is represented in Terraform by the keyword null, which is valid for any type.

Given that, in order to distinguish between true, false, and not set at all you can define a variable like this:

variable "x_lock" {
  type    = bool
  default = null
}

Note that it's not really true to say that this is "the equivalent of an empty string for booleans". An empty string is not equal to null, and so if you want to explicitly represent the absence of a string it can often be best to use null for that too:

variable "x_env" {
  type    = string
  default = null
}

...that way you can recognize an empty string as distinct from no string at all, similar to distinguishing false from no boolean at all.


null has a slightly different meaning in the context of a default than it does elsewhere. Setting default = null specifies that an input variable is optional without providing a default value for it. Or, if you like, saying that its default value is null.

An advantage of using null in this way is that you can pass that argument on as-is to any optional resource argument and it will be interpreted as if that argument were not set at all, rather than as if it were set to a default value.

There is also a further "special power" for null: if you use the splat operator [*] with a non-list value then it will return a single-element list for a non-null value and an empty list for a null value. This can be particularly useful if you are intending to use the "null-ness" of the value to decide whether or not to create a resource or a nested block:

variable "subscription_id" {
  type    = string
  default = null
}

data "azurerm_subscription" "example" {
  # Will be an empty set if `var.subscription_id` is null, or
  # a single-item set if it is a non-null string.
  for_each = toset(var.subscription_id[*])

  subscription_id = each.key
}

Upvotes: 4

Related Questions