0
votes

A single terraform alarm looks something like this:

resource "aws_cloudwatch_metric_alarm" "ecs_cpu_reservation" {
    alarm_name          = "ecs-cpu-reservation-${var.environment}"
    alarm_description   = "my description"
    namespace           = "AWS/ECS"
    metric_name         = "CPUReservation"
    dimensions {
      ClusterName = "${var.environment}"
    }
    statistic           = "Average"
    period              = "300"
    evaluation_periods  = "${var.acceptable_cpu_reservation_eval_period}"
    comparison_operator = "GreaterThanOrEqualToThreshold"
    threshold           = "${var.acceptable_cpu_reservation}"
    alarm_actions       = ["${data.terraform_remote_state.vpc.my_topic_arn}"]
    actions_enabled     = "${var.alerting_enabled}"
}

I have 10 alarms per table, and 50 tables. Therefore, the tf file will contain 500 of those resource blocks. That's a huge file!

The vast majority of the alarms are identical... the only difference being what table the alarm is for.

Is there a way to loop over a table name list and create the alarms?

From what I read, using the "count" variable (or iterating over a list) will lead to maintenance nightmares.

1

1 Answers

0
votes

One other option to avoid looping would be to wrap things with a module so you need to source that just once to get everything inside the module.

So if you had a module that looked like this:

variable "dynamodb_table_name" {}
variable "consumed_read_units_threshold" {}
variable "consumed_write_units_threshold" {}
...

resource "aws_cloudwatch_metric_alarm" "consumed_read_units" {
  alarm_name                = "dynamodb_${var.dynamodb_table_name}_consumed_read_units"
  comparison_operator       = "GreaterThanOrEqualToThreshold"
  evaluation_periods        = "2"
  metric_name               = "ConsumedReadCapacityUnits"
  namespace                 = "AWS/DynamoDB"
  period                    = "120"
  statistic                 = "Average"
  dimensions {
    TableName = "${var.dynamodb_table_name}"
  }
  threshold                 = "${var.consumed_read_units_threshold}"
  alarm_description         = "This metric monitors DynamoDB ConsumedReadCapacityUnits for ${var.dynamodb_table_name}"
  insufficient_data_actions = []
}


resource "aws_cloudwatch_metric_alarm" "consumed_write_units" {
  alarm_name                = "dynamodb_${var.dynamodb_table_name}_consumed_write_units"
  comparison_operator       = "GreaterThanOrEqualToThreshold"
  evaluation_periods        = "2"
  metric_name               = "ConsumedWriteCapacityUnits"
  namespace                 = "AWS/DynamoDB"
  period                    = "120"
  statistic                 = "Average"
  dimensions {
    TableName = "${var.dynamodb_table_name}"
  }
  threshold                 = "${var.consumed_write_units_threshold}"
  alarm_description         = "This metric monitors DynamoDB ConsumedWriteCapacityUnits for ${var.dynamodb_table_name}"
  insufficient_data_actions = []
}

...

You could define all of your DynamoDB table metrics in a single place and then source that whenever you create your DynamoDB table and they would all get metric alarms for every thing you care about. It's then easy to add/remove/modify these alarms in a single place (the module) and have that automatically applied to your tables on the next terraform apply.

Ideally you'd be able to create a single DynamoDB module that created the table as well as the alarms at the same time but the DynamoDB table resource isn't particularly flexible so it would be a nightmare to design a module that would allow for the flexibility you need (different defined attributes and indexes mostly).

If you wanted you could combine this with looping to reduce some of the module code in exchange for issues around changing the looped things because Terraform will see the resources for things changing and force recreations of even things that shouldn't be affected. In the case where you are just creating alarms (nothing stateful or needs to be up 100%) this isn't a huge issue but be aware that it could require a second terraform apply to fully apply changes done like that.