user2062360
user2062360

Reputation: 1543

Is there an AND/OR conditional operator?

Is there a way to use something like this in Terraform?

count = "${var.I_am_true}"&&"${var.I_am_false}"

Upvotes: 54

Views: 139285

Answers (5)

hbceylan
hbceylan

Reputation: 1282

All the answers are enough but there is another case too.

For example, you have multiple environments like;

  • master
  • dev
  • staging

and you need to set value of OBJECT_ENABLE key based on these environments. You can do this like following:

OBJECT_ENABLE = var.app_env == "master" || var.app_env == "dev" ? "true" : "false"

According to the above condition value of the OBJECT_ENABLE key will be the following;

for master : OBJECT_ENABLE is true

for dev : OBJECT_ENABLE is true

for staging : OBJECT_ENABLE is false

Upvotes: 6

NicoKowe
NicoKowe

Reputation: 3445

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

Upvotes: 141

ydaetskcoR
ydaetskcoR

Reputation: 56997

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.

Upvotes: 13

Yevgeniy Brikman
Yevgeniy Brikman

Reputation: 9391

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.

Upvotes: 32

deniszh
deniszh

Reputation: 794

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.

Upvotes: 4

Related Questions