sensu-plugins/sensu-plugins-aws

View on GitHub
bin/check-elb-health-sdk.rb

Summary

Maintainability
B
7 hrs
Test Coverage
#!/usr/bin/env ruby
#
# check-elb-health-sdk
#
# DESCRIPTION:
#   This plugin checks the health of an Amazon Elastic Load Balancer or all ELBs in a given region.
#
# OUTPUT:
#   plain-text
#
# PLATFORMS:
#   Linux
#
# DEPENDENCIES:
#   gem: aws-sdk
#   gem: sensu-plugin
#
# USAGE:
#   check-elb-health-sdk.rb -r region
#   check-elb-health-sdk.rb -r region -n my-elb
#   check-elb-health-sdk.rb -r region -n my-elb -i instance1,instance2
#   check-alb-health-sdk.rb -r all
#
# Copyright (c) 2015, Benjamin Kett <bkett@umn.edu>
#
# Released under the same terms as Sensu (the MIT license); see LICENSE
# for details.

require 'sensu-plugin/check/cli'
require 'sensu-plugins-aws'
require 'aws-sdk'

class ELBHealth < Sensu::Plugin::Check::CLI
  include Common

  option :aws_region,
         short: '-r AWS_REGION',
         long: '--aws-region REGION',
         description: 'AWS Region (defaults to us-east-1).',
         default: 'us-east-1'

  option :elb_name,
         short: '-n ELB_NAME',
         long: '--elb-name ELB_NAME',
         description: 'The Elastic Load Balancer name of which you want to check the health'

  option :instance_tag,
         short: '-t',
         long: '--instance-tag INSTANCE_TAG',
         description: "Specify instance tag to be included in the check output. E.g. 'Name' tag"

  option :instances,
         short: '-i INSTANCES',
         long: '--instances INSTANCES',
         description: 'Comma separated list of specific instances IDs inside the ELB of which you want to check the health'

  option :verbose,
         short: '-v',
         long: '--verbose',
         description: 'Enable a little bit more verbose reports about instance health',
         boolean: true,
         default: false

  option :warn_only,
         short: '-w',
         long: '--warn-only',
         description: 'Warn instead of critical when unhealthy instances are found',
         default: false

  def aws_config
    { access_key_id: config[:aws_access_key],
      secret_access_key: config[:aws_secret_access_key],
      region: config[:aws_region] }
  end

  def elb
    @elb = Aws::ElasticLoadBalancing::Client.new(aws_config)
  end

  def ec2
    @ec2 = Aws::EC2::Client.new(aws_config)
  end

  def ec2_regions
    Aws.partition('aws').regions.map(&:name)
  end

  def instances_to_check(instances)
    all_instances = instances.split(',')
    all_instances.map! { |instance| { instance_id: instance } }
  end

  def elbs
    @elbs = elb.describe_load_balancers.load_balancer_descriptions.to_a
    @elbs.select! { |elb| config[:elb_name].include? elb.load_balancer_name } if config[:elb_name]
    @elbs
  end

  def check_health(elb)
    unhealthy_instances = {}
    instance_health = if config[:instances]
                        @elb.describe_instance_health(
                          load_balancer_name: elb.load_balancer_name,
                          instances: instances_to_check(config[:instances])
                        )
                      else
                        @elb.describe_instance_health(load_balancer_name: elb.load_balancer_name)
                      end

    instance_health.instance_states.each do |instance_health_states|
      if instance_health_states.state != 'InService'
        instance_id = instance_health_states.instance_id
        state_message = instance_health_states.state

        if config[:instance_tag]
          selected_tag = ec2.describe_tags(
            filters: [{ name: 'resource-id', values: [instance_id] }]
          ).tags.select { |tag| tag[:key] == config[:instance_tag] }
          unless selected_tag.empty?
            state_message = "#{selected_tag[0][:value]}::#{instance_health_states[:state]}"
          end
        end

        unhealthy_instances[instance_id] = state_message
      end
    end
    if unhealthy_instances.empty?
      'OK'
    else
      unhealthy_instances
    end
  end

  def run
    aws_regions = ec2_regions
    @message = ''
    critical = false

    unless config[:aws_region].casecmp('all').zero?
      if aws_regions.include? config[:aws_region]
        aws_regions.clear.push(config[:aws_region])
      else
        critical 'Invalid region specified!'
      end
    end

    aws_regions.each do |r| # Iterate each possible region
      config[:aws_region] = r
      region_critical = false
      @message += (elbs.size > 1 ? config[:aws_region] + ': ' : '')
      elbs.each do |elb|
        result = check_health(elb)
        if result != 'OK'
          @message += "#{elb.load_balancer_name} unhealthy => #{result.map { |id, state| '[' + id + '::' + state + ']' }.join(' ')}. "
          critical = true
          region_critical = true
        else
          @message += "#{elb.load_balancer_name} => healthy. " unless config[:verbose] == false
        end
      end
      if elbs.size > 1 && config[:verbose] != true && region_critical == false
        @message += 'OK. '
      end
    end

    if critical
      if config[:warn_only]
        warning @message
      else
        critical @message
      end
    else
      ok @message
    end
  end
end