sensu-plugins-aws 3.2.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -27,11 +27,17 @@
27
27
  # for details.
28
28
  #
29
29
 
30
- require 'sensu-plugins-aws/cloudwatch-common'
30
+ require 'sensu-plugins-aws'
31
31
  require 'sensu-plugin/check/cli'
32
32
  require 'aws-sdk'
33
33
 
34
34
  class CloudWatchMetricCheck < Sensu::Plugin::Check::CLI
35
+ option :aws_region,
36
+ short: '-r AWS_REGION',
37
+ long: '--aws-region REGION',
38
+ description: 'AWS Region (defaults to us-east-1).',
39
+ default: 'us-east-1'
40
+
35
41
  option :namespace,
36
42
  description: 'CloudWatch namespace for metric',
37
43
  short: '-n NAME',
@@ -0,0 +1,96 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-ebs-burst-limit
4
+ #
5
+ # DESCRIPTION:
6
+ # Check EC2 Attached Volumes for volumes with low burst balance
7
+ #
8
+ # OUTPUT:
9
+ # plain-text
10
+ #
11
+ # PLATFORMS:
12
+ # Linux
13
+ #
14
+ # DEPENDENCIES:
15
+ # gem: aws-sdk
16
+ # gem: sensu-plugin
17
+ #
18
+ # USAGE:
19
+ # ./check-ebs-burst-limit.rb -r ${you_region}
20
+ # ./check-ebs-burst-limit.rb -r ${you_region} -c 50
21
+ # ./check-ebs-burst-limit.rb -r ${you_region} -w 50 -c 10
22
+ #
23
+ # LICENSE:
24
+ # Barry Martin <nyxcharon@gmail.com>
25
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
26
+ # for details.
27
+ #
28
+
29
+ require 'sensu-plugin/check/cli'
30
+ require 'sensu-plugins-aws'
31
+ require 'aws-sdk'
32
+
33
+ class CheckEbsBurstLimit < Sensu::Plugin::Check::CLI
34
+ include CloudwatchCommon
35
+
36
+ option :aws_region,
37
+ short: '-r R',
38
+ long: '--region REGION',
39
+ description: 'AWS region',
40
+ default: 'us-east-1'
41
+
42
+ option :critical,
43
+ description: 'Trigger a critical when ebs purst limit is under VALUE',
44
+ short: '-c VALUE',
45
+ long: '--critical VALUE',
46
+ proc: proc(&:to_f),
47
+ required: true
48
+
49
+ option :warning,
50
+ description: 'Trigger a warning when ebs purst limit is under VALUE',
51
+ short: '-w VALUE',
52
+ long: '--warning VALUE',
53
+ proc: proc(&:to_f)
54
+
55
+ def run
56
+ errors = []
57
+ ec2 = Aws::EC2::Client.new
58
+ volumes = ec2.describe_volumes(
59
+ filters: [
60
+ {
61
+ name: 'attachment.status',
62
+ values: ['attached']
63
+ }
64
+ ]
65
+ )
66
+ config[:metric_name] = 'BurstBalance'
67
+ config[:namespace] = 'AWS/EBS'
68
+ config[:statistics] = 'Average'
69
+ config[:period] = 60
70
+ crit = false
71
+ should_warn = false
72
+
73
+ volumes[:volumes].each do |volume|
74
+ config[:dimensions] = []
75
+ config[:dimensions] << { name: 'VolumeId', value: volume[:volume_id] }
76
+ resp = client.get_metric_statistics(metrics_request(config))
77
+ unless resp.datapoints.first.nil?
78
+ if resp.datapoints.first[:average] < config[:critical]
79
+ errors << "#{volume[:volume_id]} #{resp.datapoints.first[:average]}"
80
+ crit = true
81
+ elsif resp.datapoints.first[:average] < config[:warning]
82
+ errors << "#{volume[:volume_id]} #{resp.datapoints.first[:average]}"
83
+ should_warn = true
84
+ end
85
+ end
86
+ end
87
+
88
+ if crit
89
+ critical "Volume(s) have exceeded critical threshold: #{errors}"
90
+ elsif should_warn
91
+ warning "Volume(s) have exceeded warning threshold: #{errors}"
92
+ else
93
+ ok 'No volume(s) exceed thresholds'
94
+ end
95
+ end
96
+ end
@@ -93,10 +93,10 @@ class EC2CpuBalance < Sensu::Plugin::Check::CLI
93
93
  unless result.nil?
94
94
  if result < config[:critical]
95
95
  level = 2
96
- messages << "#{id} is below critical threshold [#{config[:critical]} < #{result}]\n"
96
+ messages << "#{id} is below critical threshold [#{result} < #{config[:critical]}]\n"
97
97
  elsif config[:warning] && result < config[:warning]
98
98
  level = 1 if level == 0
99
- messages << "#{id} is below warning threshold [#{config[:warning]} < #{result}]\n"
99
+ messages << "#{id} is below warning threshold [#{result} < #{config[:warning]}]\n"
100
100
  end
101
101
  end
102
102
  end
@@ -75,12 +75,24 @@ class EC2Filter < Sensu::Plugin::Check::CLI
75
75
  short: '-c COUNT',
76
76
  long: '--critical COUNT'
77
77
 
78
+ option :exclude_tags,
79
+ short: '-e {<tag-key>:[VAL1, VAL2]} {<tag-key>:[VAL1, VAL2] }',
80
+ long: '--exclude_tags {<tag-key>:[VAL1, VAL2] } {<tag-key>:[VAL1, VAL2] }',
81
+ description: 'Tag Values to exclude by. Values treated as regex. Any matching value will result in exclusion.',
82
+ default: '{}'
83
+
78
84
  option :compare,
79
85
  description: 'Comparision operator for threshold: equal, not, greater, less',
80
86
  short: '-o OPERATION',
81
87
  long: '--operator OPERATION',
82
88
  default: 'equal'
83
89
 
90
+ option :detailed_message,
91
+ short: '-d',
92
+ long: '--detailed-message',
93
+ boolean: true,
94
+ default: false
95
+
84
96
  def aws_config
85
97
  { access_key_id: config[:aws_access_key],
86
98
  secret_access_key: config[:aws_secret_access_key],
@@ -102,6 +114,16 @@ class EC2Filter < Sensu::Plugin::Check::CLI
102
114
  end
103
115
 
104
116
  def run
117
+ filter_list = config[:exclude_tags].split(/}\s?{/).map do |x|
118
+ x.gsub(/[{}]/, '')
119
+ end
120
+ filter_list = filter_list.map do |y|
121
+ _, h2, h3 = y.split(/(.*):(.*)/)
122
+ { h2 => h3 }
123
+ end.reduce(:merge)
124
+ filter_list.delete(nil)
125
+ filter_list.each { |x, y| filter_list[x] = y.strip.gsub(/[\[\]]/, '') }
126
+
105
127
  client = Aws::EC2::Client.new aws_config
106
128
 
107
129
  filter = Filter.parse(config[:filter])
@@ -114,17 +136,28 @@ class EC2Filter < Sensu::Plugin::Check::CLI
114
136
 
115
137
  data = client.describe_instances(options)
116
138
 
117
- instance_ids = Set.new
139
+ aws_instances = Set.new
140
+ data.reservations.each do |r|
141
+ r.instances.each do |i|
142
+ aws_instances << {
143
+ id: i[:instance_id],
144
+ tags: i.tags
145
+ }
146
+ end
147
+ end
118
148
 
119
- data[:reservations].each do |res|
120
- res[:instances].each do |i|
121
- instance_ids << i[:instance_id]
149
+ aws_instances.delete_if do |instance|
150
+ instance[:tags].any? do |key|
151
+ filter_list.keys.include?(key.key) && filter_list[key.key].split(',').any? do |v|
152
+ key.value.match(/#{v.strip}/)
153
+ end
122
154
  end
123
155
  end
124
156
 
125
- count = instance_ids.count
157
+ count = aws_instances.count
126
158
  op = convert_operator
127
159
  message = "Current count: #{count}"
160
+ message += " - #{aws_instances.collect { |x| x[:id] }.join(',')}" if config[:detailed_message] && count > 0
128
161
 
129
162
  unless config[:critical].nil?
130
163
  if op.call count, config[:critical].to_i
@@ -61,6 +61,12 @@ class CheckEcsServiceHealth < Sensu::Plugin::Check::CLI
61
61
  long: '--warn_as_crit',
62
62
  description: 'Consider it critical when any desired tasks are not running. Otherwise, only 0 is critical.'
63
63
 
64
+ option :primary_status,
65
+ short: '-p',
66
+ long: '--primary_status',
67
+ description: 'Checking for deployments which only have a Primary Status.',
68
+ default: false
69
+
64
70
  def ecs_client
65
71
  @ecs_client ||= Aws::ECS::Client.new
66
72
  end
@@ -95,22 +101,47 @@ class CheckEcsServiceHealth < Sensu::Plugin::Check::CLI
95
101
  end
96
102
 
97
103
  # Unhealthy if service has fewer running tasks than desired
98
- def services_by_health(cluster = 'default', services = nil)
99
- service_details(cluster, services).group_by { |s| bucket_service(s[:running_count], s[:desired_count]) }
104
+ def services_by_health(cluster = 'default', services = nil, primary_status = false)
105
+ bucket = nil
106
+ service_details(cluster, services).group_by do |service|
107
+ if primary_status
108
+ service.deployments.each do |x|
109
+ if x[:status].include? 'PRIMARY'
110
+ bucket = bucket_service(x[:running_count], x[:desired_count])
111
+ end
112
+ end
113
+ else
114
+ bucket = bucket_service(service[:running_count], service[:desired_count])
115
+ end
116
+ bucket
117
+ end
100
118
  end
101
119
 
102
120
  def run
103
- service_healths = services_by_health(config[:cluster_name], config[:services])
121
+ service_healths = services_by_health(config[:cluster_name], config[:services], config[:primary_status])
104
122
 
105
123
  unhealthy = []
106
124
  unhealthy.concat(service_healths[:critical]) if service_healths.key? :critical
107
125
  unhealthy.concat(service_healths[:warn]) if service_healths.key? :warn
108
- unhealthy = unhealthy.collect { |s| "#{s.service_name} (#{s.running_count}/#{s.desired_count})" }
126
+
127
+ if config[:primary_status]
128
+ unhealthy_p = nil
129
+ unhealthy = unhealthy.collect do |s|
130
+ s.deployments.each do |x|
131
+ if x[:status].include? 'PRIMARY'
132
+ unhealthy_p = "#{s.service_name} (#{x.running_count}/#{x.desired_count})"
133
+ end
134
+ end
135
+ unhealthy_p
136
+ end
137
+ else
138
+ unhealthy = unhealthy.collect { |s| "#{s.service_name} (#{s.running_count}/#{s.desired_count})" }
139
+ end
109
140
 
110
141
  if service_healths.key?(:critical) || (config[:warn_as_crit] && service_healths.key?(:warn))
111
- critical("Unhealthy ECS Services: #{unhealthy.join ', '}")
142
+ critical("Unhealthy ECS Services(Primary only = #{config[:primary_status]}): #{unhealthy.join ', '}")
112
143
  elsif service_healths.key?(:warn)
113
- warning("Unhealthy ECS Services: #{unhealthy.join ', '}")
144
+ warning("Unhealthy ECS Services(Primary only = #{config[:primary_status]}): #{unhealthy.join ', '}")
114
145
  else
115
146
  ok
116
147
  end
@@ -0,0 +1,103 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-elb-instance-inservice
4
+ #
5
+ # DESCRIPTION:
6
+ # Check Elastic Loudbalancer Instances are inService.
7
+ #
8
+ # OUTPUT:
9
+ # plain-text
10
+ #
11
+ # PLATFORMS:
12
+ # Linux
13
+ #
14
+ # DEPENDENCIES:
15
+ # gem: aws-sdk
16
+ # gem: sensu-plugin
17
+ #
18
+ # USAGE:
19
+ # all LoadBalancers
20
+ # ./check-elb-instance-inservice -r ${your_region}
21
+ # one loadBalancer
22
+ # ./check-elb-instance-inservice -r ${your_region} -l 'LoadBalancerName'
23
+ #
24
+ # NOTES:
25
+ # Based heavily on Peter Hoppe check-autoscaling-instances-inservices
26
+ #
27
+ # LICENSE:
28
+ # Peter Hoppe <peter.hoppe.extern@bertelsmann.de>
29
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
30
+ # for details.
31
+ #
32
+
33
+ require 'sensu-plugin/check/cli'
34
+ require 'aws-sdk'
35
+ require 'sensu-plugins-aws'
36
+
37
+ class CheckElbInstanceInService < Sensu::Plugin::Check::CLI
38
+ include Common
39
+ option :aws_region,
40
+ short: '-r AWS_REGION',
41
+ long: '--aws-region REGION',
42
+ description: 'AWS Region (defaults to us-east-1).',
43
+ default: ENV['AWS_REGION']
44
+
45
+ option :load_balancer,
46
+ short: '-l L',
47
+ long: '--load_balancer LoudBalancer',
48
+ description: 'LoadBalancer Name to check'
49
+
50
+ def elb
51
+ @elb ||= Aws::ElasticLoadBalancing::Client.new
52
+ end
53
+
54
+ def describe_elb(elb_name)
55
+ elb.describe_instance_health(
56
+ load_balancer_name: elb_name.to_s
57
+ )
58
+ end
59
+
60
+ def run
61
+ warning = 0
62
+ critical = 0
63
+ result = ''
64
+ if config[:load_balancer].nil?
65
+ elb.describe_load_balancers.load_balancer_descriptions.each do |load_balancer|
66
+ describe_elb(load_balancer.load_balancer_name).each do |instances|
67
+ instances.instance_states.each do |instance|
68
+ if instance.state == 'InService'
69
+ result += "#{instance.instance_id} state InService "
70
+ else
71
+ result += "#{instance.instance_id} state not InService "
72
+ warning += 1
73
+ end
74
+ end
75
+ if warning == instances.instance_states.length
76
+ critical = 1
77
+ end
78
+ end
79
+ end
80
+ else
81
+ describe_elb(config[:load_balancer]).each do |instances|
82
+ instances.instance_states.each do |instance|
83
+ if instance.state == 'InService'
84
+ result += "#{instance.instance_id} state InService "
85
+ else
86
+ result += "#{instance.instance_id} state not InService "
87
+ warning += 1
88
+ end
89
+ end
90
+ if warning == instances.instance_states.length
91
+ critical = 1
92
+ end
93
+ end
94
+ end
95
+ if critical == 1
96
+ critical result
97
+ elsif warning >= 1
98
+ warning result
99
+ else
100
+ ok result
101
+ end
102
+ end
103
+ end
@@ -28,7 +28,7 @@
28
28
  #
29
29
 
30
30
  require 'sensu-plugin/check/cli'
31
- require 'aws-sdk-v1'
31
+ require 'aws-sdk'
32
32
 
33
33
  class CheckInstanceEvents < Sensu::Plugin::Check::CLI
34
34
  option :aws_access_key,
@@ -74,10 +74,7 @@ class CheckInstanceEvents < Sensu::Plugin::Check::CLI
74
74
  end
75
75
 
76
76
  def ec2_regions
77
- # This is for SDK v2
78
- # Aws.partition('aws').regions.map(&:name)
79
-
80
- AWS::EC2.regions.map(&:name)
77
+ Aws.partition('aws').regions.map(&:name)
81
78
  end
82
79
 
83
80
  def run
@@ -100,15 +97,15 @@ class CheckInstanceEvents < Sensu::Plugin::Check::CLI
100
97
  end
101
98
 
102
99
  aws_regions.each do |r| # Iterate each possible region
103
- ec2 = AWS::EC2::Client.new(aws_config.merge!(region: r))
100
+ ec2 = Aws::EC2::Client.new(aws_config.merge!(region: r))
104
101
  begin
105
102
  describe_instance_options = {}
106
103
  if config[:instance_id].any?
107
104
  describe_instance_options = describe_instance_options.merge(instance_ids: config[:instance_id])
108
105
  end
109
106
 
110
- ec2.describe_instance_status(describe_instance_options)[:instance_status_set].each do |i|
111
- next if i[:events_set].empty?
107
+ ec2.describe_instance_status(describe_instance_options).instance_statuses.each do |i|
108
+ next if i[:events].empty?
112
109
 
113
110
  # Exclude completed reboots since the events API appearently returns these even after they have been completed:
114
111
  # Example:
@@ -121,7 +118,7 @@ class CheckInstanceEvents < Sensu::Plugin::Check::CLI
121
118
  # }
122
119
  # ]
123
120
  useful_events =
124
- i[:events_set].reject { |x| (x[:code] =~ /system-reboot|instance-stop|system-maintenance/) && (x[:description] =~ /\[Completed\]|\[Canceled\]/) }
121
+ i[:events].reject { |x| (x[:code] =~ /system-reboot|instance-reboot|instance-stop|system-maintenance/) && (x[:description] =~ /\[Completed\]|\[Canceled\]/) }
125
122
 
126
123
  unless useful_events.empty?
127
124
  if config[:include_name]
@@ -132,9 +129,9 @@ class CheckInstanceEvents < Sensu::Plugin::Check::CLI
132
129
  rescue => e
133
130
  puts "Issue getting instance details for #{i[:instance_id]} (#{r}). Exception = #{e}"
134
131
  end
135
- event_instances << "#{name} (#{i[:instance_id]} #{r}) (#{i[:events_set][0][:code]}) #{i[:events_set][0][:description]}"
132
+ event_instances << "#{name} (#{i[:instance_id]} #{r}) (#{i[:events][0][:code]}) #{i[:events][0][:description]}"
136
133
  else
137
- event_instances << "#{i[:instance_id]} (#{r}) (#{i[:events_set][0][:code]}) #{i[:events_set][0][:description]}"
134
+ event_instances << "#{i[:instance_id]} (#{r}) (#{i[:events][0][:code]}) #{i[:events][0][:description]}"
138
135
  end
139
136
  end
140
137
  end
@@ -39,6 +39,11 @@ class CheckInstanceEvents < Sensu::Plugin::Check::CLI
39
39
  long: '--aws-region REGION',
40
40
  description: 'AWS Region (defaults to us-east-1).',
41
41
  default: 'us-east-1'
42
+ option :filter,
43
+ short: '-f FILTER',
44
+ long: '--filter FILTER',
45
+ description: 'String representation of the filter to apply',
46
+ default: '{}'
42
47
 
43
48
  def gather_events(events)
44
49
  useful_events = events.reject { |x| (x[:code] =~ /system-reboot|instance-stop|system-maintenance/) && (x[:description] =~ /\[Completed\]|\[Canceled\]/) }
@@ -50,10 +55,28 @@ class CheckInstanceEvents < Sensu::Plugin::Check::CLI
50
55
  end
51
56
 
52
57
  def run
58
+ filter = Filter.parse(config[:filter])
59
+ options = if filter.empty?
60
+ {}
61
+ else
62
+ { filters: filter }
63
+ end
64
+
53
65
  messages = []
66
+
54
67
  ec2 = Aws::EC2::Client.new
68
+ instance_ids = []
69
+
70
+ instances = ec2.describe_instances(options)
71
+ instances.reservations.each do |r|
72
+ r.instances.each do |i|
73
+ instance_ids.push(i[:instance_id])
74
+ end
75
+ end
76
+
55
77
  begin
56
- ec2.describe_instance_status.instance_statuses.each do |item|
78
+ resp = ec2.describe_instance_status(instance_ids: instance_ids)
79
+ resp.instance_statuses.each do |item|
57
80
  id = item.instance_id
58
81
  if gather_events(item.events)
59
82
  messages << "#{id} has unscheduled events"