Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Count in output vars with terraform 0.12+

I conditionally create a resource with count:

resource "aws_kms_key" "this" {
  count       = var.create_kms_key == true ? 1 : 0
  ...
}

How do I then conditionally output the value of this resource? I tried playing around and Terraform seems to contradict itself

First it tells me to use count in output.

For example, to correlate with indices of a referring resource, use:
    aws_kms_key.this[count.index]

Then when I try that it says I can't use count.

The "count" object can be used only in "resource" and "data" blocks, and only
when the "count" argument is set.

Previously we were able to do something like below but this now triggers the count error I posted previously.

output "kms_key_arn" {
    value = aws_kms_key.this.*.arn
}

Any idea how this works now?

Thanks,

like image 522
rix Avatar asked Sep 02 '19 11:09

rix


People also ask

Can I use count in an output Terraform?

zone_id │ │ The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set.

How do you use count in Terraform?

What is count in Terraform? When you define a resource block in Terraform, by default, this specifies one resource that will be created. To manage several of the same resources, you can use either count or for_each , which removes the need to write a separate block of code for each one.

Can Terraform module have count?

count is a meta-argument defined by the Terraform language. It can be used with modules and with every resource type. The count meta-argument accepts a whole number, and creates that many instances of the resource or module.

How do you use Terraform output values?

Terraform Output Command Output values are stored in the state Terraform file. Since we have successfully applied our plan, we can now access these output values at will. We can leverage the terraform output command for this purpose. To get the raw value without quotes, use the -raw flag.


1 Answers

When count is set for a resource, references to that resource then return a list of objects rather than a single object, and so we need to write our other expressions with that in mind.

In your case, that list can either have zero or one elements, and so we must handle both of those cases in any expression that refers to it.

To write an output that propagates an attribute from that resource, we need to decide what we'll return in the situation where the list is empty. For example, we could choose to set the output to null in that case:

output "kms_key_arn" {
    value = concat(aws_kms_key.this.*.arn, [null])[0]
}

The technique here is to change from having a list with zero or one elements into a list with one or two elements, and then take the first element. There are two possibilities for what that concat function might return:

["arn:aws:....", null]
[null]

In both cases, it is valid to take the zeroth element using [0]. In the second case, it will select null as the result.


If you have other resources that are also conditional on var.create_kms_key, there is a variant on this approach:

resource "aws_kms_key" "example" {
  count = var.create_kms_key ? 1 : 0

  # ...
}

resource "anything_else" "example" {
  count = length(aws_kms_key.example) # only if KMS key is created

  any_argument = aws_kms_key.example[count.index].arn
}

This variant relies on the fact that both of these resources have the same value for count and thus we can use count.index in the second resource in order to correlate with instances of the first. count.index can only be used inside a resource where count is set, but in this particular situation it is set, and because we set count to the length of the other resource we know that all count.index values will be in range for that resource's object list.

like image 53
Martin Atkins Avatar answered Jan 01 '23 18:01

Martin Atkins