class CfnMonitor::Query

Public Class Methods

query_stacks(config,cfClient,elbClient,stack,stackResources={template:{},physical_resource_id:{}},location='') click to toggle source
# File lib/cfn_monitor/query.rb, line 90
def self.query_stacks (config,cfClient,elbClient,stack,stackResources={template:{},physical_resource_id:{}},location='')
  stackResourceCount = 0
  stackResourceCountLocal = 0
  begin
    resp = cfClient.list_stack_resources({
      stack_name: stack
    })
  rescue Aws::CloudFormation::Errors::ServiceError => e
    puts "Error: #{e}"
    exit 1
  end

  resp.stack_resource_summaries.each do | resource |
    if resource['resource_type'] == 'AWS::CloudFormation::Stack'
      query = query_stacks(config,cfClient,elbClient,resource['physical_resource_id'],stackResources,"#{location}.#{resource['logical_resource_id']}")
      stackResourceCount += query[:stackResourceCount]
    end
    if config['resource_defaults'].key? resource['resource_type']
      if resource['resource_type'] == 'AWS::ElasticLoadBalancingV2::TargetGroup'
        begin
          tg = elbClient.describe_target_groups({
            target_group_arns: [ resource['physical_resource_id'] ]
          })
        rescue Aws::ElasticLoadBalancingV2::Errors::ServiceError => e
          puts "Error: #{e}"
          exit 1
        end
        stackResources[:template]["#{location[1..-1]}.#{resource['logical_resource_id']}/#{tg['target_groups'][0]['load_balancer_arns'][0]}"] = config['resource_defaults'][resource['resource_type']]
      else
        if location[1..-1].nil?
            stackResources[:template]["#{stack}::#{resource['logical_resource_id']}"] = config['resource_defaults'][resource['resource_type']]
        else
            stackResources[:template]["#{location[1..-1]}.#{resource['logical_resource_id']}"] = config['resource_defaults'][resource['resource_type']]
        end
      end
      stackResourceCount += 1
      stackResourceCountLocal += 1
      if location[1..-1].nil?
        print "#{stack}: Found #{stackResourceCount} resource#{"s" if stackResourceCount != 1}\r"
       else
        print "#{location[1..-1]}: Found #{stackResourceCount} resource#{"s" if stackResourceCount != 1}\r"
       end
      sleep 0.2
    elsif resource['resource_type'] == 'AWS::ElasticLoadBalancingV2::LoadBalancer'
      stackResources[:physical_resource_id][resource['physical_resource_id']] = "#{location[1..-1]}.#{resource['logical_resource_id']}"
    end
  end
  stackResourceQuery = {
    stackResourceCount: stackResourceCount,
    stackResources: stackResources
  }
  sleep 0.2
  puts "#{stack if location == ''}#{location[1..-1]}: Found #{stackResourceCountLocal} resource#{"s" if stackResourceCountLocal != 1}"
  stackResourceQuery
end
run(options) click to toggle source
# File lib/cfn_monitor/query.rb, line 7
def self.run(options)

  if !options['stack']
    raise "No stack specified"
  end

  if options['application']
    application = options['application']
    custom_alarms_config_file = "#{application}/alarms.yml"
  else
    application = File.basename(Dir.getwd)
    custom_alarms_config_file = "alarms.yml"
  end

  config_path = File.join(File.dirname(__FILE__),'../config/config.yml')
  # Load global config files
  config = YAML.load(File.read(config_path))

  custom_alarms_config_file = "#{application}/alarms.yml"

  # Load custom config files
  custom_alarms_config = YAML.load(File.read(custom_alarms_config_file)) if File.file?(custom_alarms_config_file)
  custom_alarms_config ||= {}
  custom_alarms_config['resources'] ||= {}

  puts "-----------------------------------------------"
  puts "stack: #{options['stack']}"
  puts "application: #{application}"
  puts "-----------------------------------------------"
  puts "Searching Stacks for Monitorable Resources"
  puts "-----------------------------------------------"

  cfClient = Aws::CloudFormation::Client.new()
  elbClient = Aws::ElasticLoadBalancingV2::Client.new()

  stackResourceQuery = query_stacks(config,cfClient,elbClient,options['stack'])
  stackResourceCount = stackResourceQuery[:stackResourceCount]
  stackResources = stackResourceQuery[:stackResources]

  configResourceCount = custom_alarms_config['resources'].keys.count
  configResources = []
  keyUpdates = []

  stackResources[:template].each do | k,v |
    if stackResources[:physical_resource_id].key? k.partition('/').last
      keyUpdates << k
    end
  end

  keyUpdates.each do | k |
    stackResources[:template]["#{k.partition('/').first}/#{stackResources[:physical_resource_id][k.partition('/').last]}"] = stackResources[:template].delete(k)
  end

  stackResources[:template].each do | k,v |
    if !custom_alarms_config['resources'].any? {|x, y| x == k}
      configResources.push("#{k}: #{v}")
    end
  end

  puts "-----------------------------------------------"
  puts "Monitorable Resources (with default templates)"
  puts "-----------------------------------------------"
  stackResources[:template].each do | k,v |
    puts "#{k}: #{v}"
  end
  puts "-----------------------------------------------"
  if configResourceCount < stackResourceCount
    puts "Missing resources (with default templates)"
    puts "-----------------------------------------------"
    configResources.each do | r |
      puts r
    end
    puts "-----------------------------------------------"
  end
  puts "Monitorable resources in #{options['stack']} stack: #{stackResourceCount}"
  puts "Resources in #{application} alarms config: #{configResourceCount}"
  if stackResourceCount > 0
    puts "Coverage: #{100-(configResources.count*100/stackResourceCount)}%"
  end
  puts "-----------------------------------------------"

end