Terraform v0.9.11
We are creating a module to set up AWS cloudwatch alarms. The module accepts a map containing the configuration for each of the alarms that users want to configure (var.alarms
). Then we instantiate multiple aws_cloudwatch_metric_alarm
resources using count
.
Everything works fine until var.alarms
contains a reference to another resource. In the example, we use the ARN for an SNS topic, but we have tried other resources such as the deployment ARN and it fails as well.
The error message is:
module.api_cloudwatch_alarms.aws_cloudwatch_metric_alarm.alarm: aws_cloudwatch_metric_alarm.alarm: value of 'count' cannot be computed
variable "profile" {
default = ""
}
variable "region" {
default = ""
}
provider "aws" {
profile = "${var.profile}"
region = "${var.region}"
}
resource "aws_api_gateway_rest_api" "api" {
name = "api"
}
resource "aws_api_gateway_deployment" "deployment" {
rest_api_id = "${aws_api_gateway_rest_api.api.id}"
stage_name = "test"
}
module "api_cloudwatch_alarms" {
source = "./api_cloudwatch_monitors"
api_name = "${aws_api_gateway_rest_api.api.name}"
stage_name = "test"
alarms = {
"4XXError" = {
actions = "${aws_sns_topic.topic.arn}"
threshold = 10
}
}
}
resource "aws_sns_topic" "topic" {
name = "topic"
}
variable "api_name" {}
variable "stage_name" {}
variable "alarms" {
type = "map"
default = {}
}
resource "aws_cloudwatch_metric_alarm" "alarm" {
count = "${length(var.alarms)}"
alarm_name = "${format("%s-%s-%s",
var.api_name,
var.stage_name,
element(keys(var.alarms), count.index))}"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = 2
metric_name = "${element(keys(var.alarms), count.index)}"
namespace = "AWS/ApiGateway"
period = 100
threshold = 100
alarm_actions = ["${split(",", lookup(
var.alarms[element(keys(var.alarms), count.index)],
"actions",
""
))}"]
}
https://gist.github.com/betabandido/e4fe821a5d08b1a291e508c7a163c4eb
@betabandido this is expected because since the value of "${aws_sns_topic.topic.arn}"
is not know during the plan/apply
phase, terraform assumes the whole map as an un-computed resource.
main.tf
variable "region" {
default = "us-east-1"
}
provider "aws" {
region = "${var.region}"
}
resource "aws_sns_topic" "topic" {
name = "topic"
}
module "foo" {
source = "./module/"
alarms = {
"4XXError" = {
actions = "${aws_sns_topic.topic.arn}" does not work
# actions = "foo" works
# actions = "arn:aws:sns:<region>:<account>:<topic_name>" works!
threshold = 10
}
}
}
module/main.tf
variable "alarms" {
type = "map"
default = {}
}
resource null_resource "foo" {
count = "${length(keys(var.alarms))}"
provisioner "local-exec" {
command = "echo ${count.index}"
}
}
@apparentlymart gave me a good explanation a while ago. Here you go!
@betabandido by building the sns
topic you don't need to use the extra variable you used here
Isn't it possible to use some sort of lazy evaluation? As the keys in the map are plain strings, their number does not depend on the potential contents of the map values. Therefore, length(keys(var.alarms))
could easily work.
If this is just impossible, I suppose an alternative is to first create the SNS topic using -target
. Is that correct?
@betabandido yep using -target
to create the SNS
first and then the alarms should work. Since our CI server performs the terraforming, it is inconvenient for us to add -target
everywhere and so I build the arn wherever possible.
I'm hitting the same error following the sample in the documentation - is this not valid? https://www.terraform.io/docs/configuration/interpolation.html#using-templates-with-count
This appears to be a massive limitation - "count" appears to be a necessity in reducing the amount of code/text written which helps to keep the code maintainable as it reduces having to duplicate code unnecessarily. I have use of count only to prevent resources in modules from being "run" but "count cannot compute" comes up and scuppers what i wrote.
Using target in a wrapper script once is fine but more than once is often a headache and error prone especially when trying to write "sane" non-complex DRY terraform
This is a Big limitiation
Hitting the same issue. Would be glad to see it fixed.
Most helpful comment
This appears to be a massive limitation - "count" appears to be a necessity in reducing the amount of code/text written which helps to keep the code maintainable as it reduces having to duplicate code unnecessarily. I have use of count only to prevent resources in modules from being "run" but "count cannot compute" comes up and scuppers what i wrote.
Using target in a wrapper script once is fine but more than once is often a headache and error prone especially when trying to write "sane" non-complex DRY terraform
This is a Big limitiation