sensu-plugins-aws 3.2.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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"