Dynamic argument with if conditional

Could we use if-conditional to apply argument ?
Example
main.tf

resource "google_compute_backend_service" "bs" {
 ...
if var.iaps == "true" then
   iap {
     oauth2_client_id = var.iapsid
     oauth2_client_secret = var.iapssecret
     oauth2_client_secret_sha256 = var.iaps256
   }
fi
}

variables.tf

variable "iaps" { default = false }

terraform.tfvars

iaps = true
iapsid = "AAXX"
iapssecret = "1234AA"
iaps256 = "d3eb1a"

Result is the terraform will process the iap block argument, but if other developer set iaps to false then terraform will not apply iap block argument

Is there a way to do like above ?
I want to make terraform script customizable. So, i don’t need to create 2 different main.tf

Yes you can do that via the use of dynamic blocks.

In this case try something like:

dynamic "iap" {
  for_each = var.iaps ? [""] : []

  content {
    oauth2_client_id            = var.iapsid
    oauth2_client_secret        = var.iapssecret
    oauth2_client_secret_sha256 = var.iaps256
  }
}
1 Like

The way I’d write this is to make a single variable that can be null to disable the feature altogether, like this:

variable "iap" {
  type = object({
    client_id            = string
    client_secret        = string
    client_secret_sha256 = string
  })
  default = null
}

resource "google_compute_backend_service" "bs" {
  # ...

  dynamic "iap" {
    for_each = var.iap[*]
    content {
      oauth2_client_id            = iap.value.client_id
      oauth2_client_secret        = iap.value.client_secret
      oauth2_client_secret_sha256 = iap.value.client_secret_sha256
    }
  }
}

With the above configuration, if you leave iap unset or explicitly set it to null in your terraform.tfvars file then Terraform will generate no iap blocks at all, or you can write a valid iap object in the terraform.tfvars file to enable it:

iap = {
  client_id         = "AAXX"
  client_secret     = "1234AA"
  client_secret_256 = "d3eb1a"
}

The example above relies on a special behavior of the [*] operator: if it is applied to something that isn’t a list, it will either return a zero-element list or a one-element list depending on whether the operand is null. That therefore makes it a concise way to convert from a value that could conditionally be null into the collection of zero or one elements which Terraform language repetition features expect.

1 Like

Thank you @stuart-c and @apparentlymart for enlightening me :grinning:
I tried both answers and it works.
Will bookmark this since i don’t find this way in tech article :sweat_smile:

@stuart-c @apparentlymart would you like to share docs about [""] or [*] usage ?
Sorry, i am not familiar with terraform. Have been looking on docs and badluck for me :sweat_smile:
Really appreciate for your time to help me for this.

Hi @merceskoba,

The [*] operator is called the “splat” operator, and you can find documentation about it in the section Splat Expressions. In particular, the special behavior of turning a null value into an empty list is covered at the end of that section:

Splat expressions are for lists only (and thus cannot be used to reference resources created with for_each, which are represented as maps in Terraform). However, if a splat expression is applied to a value that is not a list or tuple then the value is automatically wrapped in a single-element list before processing.

For example, var.single_object[*].id is equivalent to [var.single_object][*].id, or effectively [var.single_object.id]. This behavior is not interesting in most cases, but it is particularly useful when referring to resources that may or may not have count set, and thus may or may not produce a tuple value:

aws_instance.example[*].id

The above will produce a list of ids whether aws_instance.example has count set or not, avoiding the need to revise various other expressions in the configuration when a particular resource switches to and from having count set.

The documentation talks about count resources as its main example. It doesn’t talk about a variable that might be null or not, but it’s a different application of the same behavior.

1 Like