Can I provide resource arguments using conditional expressions?

My use case is that I have a module that creates AWS instances and EBS volumes based on some parameters I input.

Some of the aws_ebs_volume resource arguments are only valid for particular volume types - for example “throughput” is " Only valid for type of gp3 .", and “iops” has a similar description.

If I want to create an instance with 2 volumes, one of type gp3 and the other of type sc1, using a “volume” module which takes a list of some parameters, what do I do about “throughput”? If I specify to take it’s value from the parameter, is it valid to specify it as “” (empty) for sc1 and a value (if I need one) for gp3, or will terraform generate an error saying that I shouldn’t be providing the “throughput” argument (albeit with an empty value) as the type is “sc1”?

I’m using terraform v0.13.6 and aws provider 3.29.1.

Or is there a way of conditionally specifying an argument, such as “if type = gp3, add the ‘throughput’ argument”? Think of it like when you’re using “count” on a resource, where count=0 if you want to define the code but don’t want it to create any resources…but instead of doing the count at resource level, you’re doing it at resource argument level.

Of course, if terraform doesn’t generate an error if I supply both “iops” and “throughput” arguments regardless of the volume type, but does throw an error if I’m e.g. trying to provide a non-null value for type sc1, then my question is moot; I would just need to know if it would generate an error for non-gp3 types.

Thanks.

Hi @rba1-source,

When you leave a resource configuration argument unset, Terraform treats it as if you had set it to null. Because of that, you can get the effect of conditionally setting something by having one of the conditional result arms be null. For example:

  throughput = var.volume_type = "gp3" ? 5 : null

The above is a simple example but the general requirement is to make sure the result of the expression will be a null value in any case where you need it to be unset.

Because Terraform treats unset optional arguments as null always (even if you just omit it and let Terraform assign the null value automatically), providers can’t distinguish between these two situations and so the behavior will be the same as if you didn’t set it at all.

However, there is one caveat here: if you write a boolean expression in the conditional whose value Terraform can’t determine until apply time then Terraform will tell the provider that the argument is set to an unknown value (what the plan output would call (known after apply)).

The expected convention is for providers to notice the unknown value and skip validating the argument until apply time in that case, but because it’s up to the provider plugin itself to handle that situation you may find that sometimes providers are more conservative, and e.g. may treat the configuration as invalid just in case the argument ultimately ends up being non-null, in which case you’d need to make sure the boolean expression is fully resolvable during the plan phase. I don’t know if this caveat applies to these throughput and iops arguments in particular, and so I’m mentioning this only for completeness.

2 Likes

Thanks @apparentlymart , that’s a wonderfully complete reply!

I confirm this works.

I can supply the arguments “iops” and “throughput” as null if the volume type is unsupported, or if it is supported but no value is provided. terraform successfully deploys gp2 type volumes when no parameters are supplied, uses the “default” values if gp3 is specified with no values, and uses my values for gp3 if I supply them.

This means I can use the same core code for gp2 and gp3, and optionally add extra parameters for gp3 if I want to, on a per-volume basis.

Thanks for the help!