Search code examples
amazon-web-servicesterraformcloudwatch-alarms

Cloudwatch alarm for list of servers


I am trying to set a few alerts across a list of servers, I have my servers defined in locals as below:

  locals {
      my_list = [
        "server1",
        "server2"
      ]
    }

I then defined my cloudwatch alerts as so: (This is one such alert)

resource "aws_cloudwatch_metric_alarm" "ec2-high-cpu-warning" {
  for_each            = toset(local.my_list)
  alarm_name          = "ec2-high-cpu-warning-for-${each.key}"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = "1"
  metric_name         = "CPUUtilization"
  namespace           = "AWS/EC2"
  dimensions = {
    instanceid   = values(data.aws_instances.my_instances)[*].ids
    instancename = local.my_list
  }

  period                    = "60"
  statistic                 = "Average"
  threshold                 = "11"
  alarm_description         = "This warning is for high cpu utilization for ${each.key}"
  actions_enabled           = true
  alarm_actions             = [data.aws_sns_topic.my_sns.arn]
  insufficient_data_actions = []
  treat_missing_data        = "notBreaching"
}

I also defined data source as so:

data "aws_instances" "my_instances" {

  for_each = toset(local.my_list)

  instance_tags = {
    Name = each.key
  }
}

Now when i run terraform plan i get an error:

| data.aws_instances.my_instances is object with 2 attributes

Inappropriate value for attribute "dimensions": element "instanceid": string required.


Solution

  • In your for_each you should use data.aws_instance.my_instances:

    resource "aws_cloudwatch_metric_alarm" "ec2-high-cpu-warning" {
    
      for_each            = data.aws_instance.my_instances
      
      alarm_name          = "ec2-high-cpu-warning-for-${each.key}"
      comparison_operator = "GreaterThanThreshold"
      evaluation_periods  = "1"
      metric_name         = "CPUUtilization"
      namespace           = "AWS/EC2"
      
      dimensions = {
        instanceid   = each.value.id
        instancename = each.key
      }
    
      period                    = "60"
      statistic                 = "Average"
      threshold                 = "11"
      alarm_description         = "This warning is for high cpu utilization for ${each.key}"
      actions_enabled           = true
      alarm_actions             = [data.aws_sns_topic.my_sns.arn]
      insufficient_data_actions = []
      treat_missing_data        = "notBreaching"
    }
    

    The above will create two alarms for your two instances (one alarm per instance) where instancename will be server1 or ``server2`.