5fpro/lita-aws

View on GitHub
lib/lita/handlers/aws-cloudwatch.rb

Summary

Maintainability
A
2 hrs
Test Coverage
module Lita
  module Handlers
    class AwsCloudWatchHandler < AwsBaseHandler

      help = { 'aws ec2-memutil {instance id}[ --ago 2d][ --cal Average|SampleCount|Sum|Minimum|Maximum][ --period 300s][ --profile NAME]' => 'Show memory utilization of EC2 instance.' }
      route(/aws ec2\-memutil ([i][\-][0-9a-zA-Z]+)[ ]*(.*)$/, help: help) do |response|
        opts = get_options_for_cloudwatch(response, ago: '2d', period: '300s', cal: 'Average')
        instance_id = response.matches.first.first
        cmd = "cloudwatch get-metric-statistics --namespace System/Linux --metric-name MemoryUtilization --dimensions Name=InstanceId,Value=#{instance_id} --start-time #{opts[:start_time]} --end-time #{opts[:end_time]} --period #{opts[:period]} --statistics #{opts[:cal]}"
        data = exec_cli_json(cmd, opts[:cmd_opts])
        render_cloudwatch_data(response, data, opts[:cal])
      end

      help = { 'aws ec2-cpuutil {instance id}[ --ago 2d][ --period 300s][ --profile NAME]' => 'Show CPU utilization of EC2 instance.' }
      route(/aws ec2\-cpuutil ([i][\-][0-9a-zA-Z]+)[ ]*(.*)$/, help: help) do |response|
        opts = get_options_for_cloudwatch(response, ago: '2d', period: '300s')
        instance_id = response.matches.first.first
        cmd = "cloudwatch get-metric-statistics --namespace AWS/EC2 --metric-name CPUUtilization --dimensions Name=InstanceId,Value=#{instance_id} --start-time #{opts[:start_time]} --end-time #{opts[:end_time]} --period #{opts[:period]} --statistics Average"
        data = exec_cli_json(cmd, opts[:cmd_opts])
        render_cloudwatch_data(response, data, 'Average')
      end

      help = { 'aws elb-req-sum {ELB name}[ --ago 2d][ --period 300s][ --profile NAME]' => 'Show ELB request count.' }
      route(/aws elb\-req-sum ([0-9a-zA-Z_]+)[ ]*(.*)$/, help: help) do |response|
        opts = get_options_for_cloudwatch(response, ago: '2d', period: '300s')
        elb_name = response.matches.first.first
        cmd = "cloudwatch get-metric-statistics --namespace AWS/ELB --metric-name RequestCount --dimensions Name=LoadBalancerName,Value=#{elb_name} --start-time #{opts[:start_time]} --end-time #{opts[:end_time]} --period #{opts[:period]} --statistics Sum"
        data = exec_cli_json(cmd, opts[:cmd_opts])
        render_cloudwatch_data(response, data, 'Sum')
      end

      help = { 'aws rds-space {RDS Identifier}[ --profile NAME]' => 'Show RDS instance current disk space in GB.' }
      route(/aws rds\-space ([0-9a-zA-Z_]+)[ ]*(.*)$/, help: help) do |response|
        opts = get_options_for_cloudwatch(response)
        rds = response.matches.first.first
        start_time = (Time.now.utc - (12 * 60 * 60)).strftime('%Y-%m-%dT%H:00')
        end_time = Time.now.utc.strftime('%Y-%m-%dT%H:00')
        cmd = "cloudwatch get-metric-statistics --namespace AWS/RDS --metric-name FreeStorageSpace --dimensions Name=DBInstanceIdentifier,Value=#{rds} --start-time #{start_time} --end-time #{end_time} --period 120 --statistics Minimum"
        data = convert_datapoints(exec_cli_json(cmd, opts[:cmd_opts]), 'Minimum')
        render(response, "Free space of #{rds}:\n  #{(data.last || []).last}")
      end

      private

      def get_options_for_cloudwatch(response, defaults = {})
        results = {}
        opts = get_options(response)
        defaults.each { |k, v| results[k] = (opts.delete(k) || v) }

        if results[:ago]
          results[:start_time] = (Time.now - results[:ago].to_i * (60 * 60 * 24)).utc.strftime('%Y-%m-%dT%H:00')
          results[:end_time] = Time.now.utc.strftime('%Y-%m-%dT%H:00')
        end
        results[:period] = results[:period].to_i if results[:period]

        results[:cmd_opts] = opts
        results
      end

      def render_cloudwatch_data(response, data, cal = 'Average')
        data = convert_datapoints(data, cal)
        render(response, format_timeline(data))
      end

      def convert_datapoints(data, cal)
        res = data['Datapoints'].map do |d|
          unit = unit_name(d['Unit'])
          value = convert_value(d['Unit'], d[cal])
          [d['Timestamp'], "#{value}#{unit}"]
        end
        res.sort_by { |d| Time.parse(d[0]).to_i }
      end

      def unit_name(unit)
        case unit
        when 'Percent' then '%'
        when 'Bytes' then 'GB'
        else ''
        end
      end

      def convert_value(unit, value)
        case unit
        when 'Percent' then value.round(2)
        when 'Bytes' then (value / 1024 / 1024 / 1024).round(1)
        else value
        end
      end

      Lita.register_handler(AwsCloudWatchHandler)
    end
  end
end