Is there a way AND/OR conditional operator in terraform?

This is more appropriate in the actual version (0.12.X)

The supported operators are:

Equality: == and !=
Numerical comparison: >, <, >=, <=
Boolean logic: &&, ||, unary !

https://www.terraform.io/docs/configuration/interpolation.html#conditionals

condition_one and condition two:

count = var.condition_one && var.condition_two ? 1 : 0

condition_one and NOT condition_two:

count = var.condition_one && !var.condition_two ? 1 : 0

condition_one OR condition_two:

count = var.condition_one || var.condition_two ? 1 : 0

Terraform 0.8 added first class support for conditional logic rather than the previous hacky workarounds.

This uses the classic ternary syntax so now you can do something like this:

variable "env" { default = "development" }

resource "aws_instance" "production_server" {
  count = "${var.env == "production" ? 1 : 0}"
  ...
}

Now this will only create the production_server EC2 instance when env is set to "production".

You can also use it in other places too such as setting a variable/parameter like this:

variable "env" { default = "development" }
variable "production_variable" { default = "foo" }
variable "development_variable" { default = "bar" }

output "example" {
  value = "${var.env == "production" ? var.production_variable : var.development_variable}"
}

One thing to be aware of is that Terraform actually evaluates both sides before then choosing the value used in the ternary statement rather than lazily evaluating just the side of the ternary that the logic will trigger.

This means you can't do something like this recent example of me trying to hack around an issue with the aws_route53_zone data source:

variable "vpc"    {}
variable "domain" {}

variable "private_zone"  { default = "true" }

data "aws_vpc" "vpc" {
  filter {
    name   =   "tag-key"
    values = [ "Name" ]
  }
  filter {
    name   =   "tag-value"
    values = [ "${var.vpc}" ]
  }
}

data "aws_route53_zone" "private_zone" {
  count        = "${var.private_zone == "true" ? 1 : 0}"
  name         = "${var.domain}"
  vpc_id       = "${data.aws_vpc.vpc.id}"
  private_zone = "true"
}

data "aws_route53_zone" "public_zone" {
  count        = "${var.private_zone == "true" ? 0 : 1}"
  name         = "${var.domain}"
  private_zone = "false"
}

output "zone_id" {
  value = "${var.private_zone == "true" ? data.aws_route53_zone.private_zone.zone_id : data.aws_route53_zone.public_zone.zone_id}"
}

In the above example this will fail on the plan because either data.aws_route53_zone.private_zone.zone_id or data.aws_route53_zone.public_zone.zone_id is not defined depending on whether public_zone is set to true or false.


The answer by deniszh is pretty close, but I thought I'd clarify it a bit and clean up the syntax.

In Terraform, a boolean true is converted to a 1 and a boolean false is converted to a 0. So if you have two boolean variables, var.foo and var.bar, you can represent AND using simple multiplication:

count = "${var.foo * var.bar}"

In the code above, count will be 1 only if var.foo AND var.bar are both true, as 1 * 1 is 1. In all other cases (1 * 0, 0 * 1, 0 * 0), you get 0.

To represent OR, you can take advantage of the function signum(x), which returns 1 if the x you pass in is a positive number, 0 if x is 0, and -1 if x is a negative number. Taking this into account, here is OR:

count = "${signum(var.foo + var.bar)}"

In the code above, count will be 1 if either var.foo OR var.bar is true and 0 only if both are false (signum(1 + 1) = 1, signum(1 + 0) = 1, signum(0 + 1) = 1, signum(0 + 0) = 0).

Note that to use the techniques above, you must take care to set the variables to a boolean and NOT a string. You want this:

variable "foo" {
  # Proper boolean usage
  default = true
}

NOT this:

variable "foo" {
  # THIS WILL NOT WORK!
  default = "true"
}

For more info on how to do a variety of Terraform conditionals, check out Terraform tips & tricks: loops, if-statements, and gotchas and Terraform: Up & Running.


There's no binary type defined in Terraform. But you can try to use simple math

E.g.

OR equivalent

 count = signum(${var.I_am_true} + ${var.I_am_false})

AND equivalent

 count = ${var.I_am_true} * ${var.I_am_false}

Both will work if I_am_true == 1 and I_am_false == 0.

Didn't try both, though.

Tags:

Terraform