sensu-plugins-aws 0.0.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,7 +16,7 @@
16
16
  # Linux
17
17
  #
18
18
  # DEPENDENCIES:
19
- # gem: aws-sdk
19
+ # gem: aws-sdk-v1
20
20
  # gem: sensu-plugin
21
21
  #
22
22
  # USAGE:
@@ -35,28 +35,41 @@ require 'aws-sdk-v1'
35
35
 
36
36
  class CheckRDSEvents < Sensu::Plugin::Check::CLI
37
37
  option :aws_access_key,
38
- short: '-a AWS_ACCESS_KEY',
39
- long: '--aws-access-key AWS_ACCESS_KEY',
40
- description: "AWS Access Key. Either set ENV['AWS_ACCESS_KEY_ID'] or provide it as an option",
41
- default: ENV['AWS_ACCESS_KEY_ID']
38
+ short: '-a AWS_ACCESS_KEY',
39
+ long: '--aws-access-key AWS_ACCESS_KEY',
40
+ description: "AWS Access Key. Either set ENV['AWS_ACCESS_KEY'] or provide it as an option",
41
+ default: ENV['AWS_ACCESS_KEY']
42
42
 
43
43
  option :aws_secret_access_key,
44
- short: '-s AWS_SECRET_ACCESS_KEY',
45
- long: '--aws-secret-access-key AWS_SECRET_ACCESS_KEY',
46
- description: "AWS Secret Access Key. Either set ENV['AWS_SECRET_ACCESS_KEY'] or provide it as an option",
47
- default: ENV['AWS_SECRET_ACCESS_KEY']
44
+ short: '-k AWS_SECRET_KEY',
45
+ long: '--aws-secret-access-key AWS_SECRET_KEY',
46
+ description: "AWS Secret Access Key. Either set ENV['AWS_SECRET_KEY'] or provide it as an option",
47
+ default: ENV['AWS_SECRET_KEY']
48
48
 
49
49
  option :aws_region,
50
- short: '-r AWS_REGION',
51
- long: '--aws-region REGION',
52
- description: 'AWS Region (such as eu-west-1).',
53
- default: 'us-east-1'
50
+ short: '-r AWS_REGION',
51
+ long: '--aws-region REGION',
52
+ description: 'AWS Region (defaults to us-east-1).',
53
+ default: 'us-east-1'
54
54
 
55
- def run # rubocop:disable AbcSize
56
- rds = AWS::RDS::Client.new(
57
- access_key_id: config[:aws_access_key],
55
+ def aws_config
56
+ { access_key_id: config[:aws_access_key],
58
57
  secret_access_key: config[:aws_secret_access_key],
59
- region: config[:aws_region])
58
+ region: config[:aws_region]
59
+ }
60
+ end
61
+
62
+ def run
63
+ clusters = maint_clusters
64
+ if clusters.empty?
65
+ ok
66
+ else
67
+ critical("Clusters w/ critical events: #{clusters.join(',')}")
68
+ end
69
+ end
70
+
71
+ def maint_clusters
72
+ rds = AWS::RDS::Client.new aws_config
60
73
 
61
74
  begin
62
75
  # fetch all clusters identifiers
@@ -74,11 +87,6 @@ class CheckRDSEvents < Sensu::Plugin::Check::CLI
74
87
  rescue => e
75
88
  unknown "An error occurred processing AWS RDS API: #{e.message}"
76
89
  end
77
-
78
- if maint_clusters.empty?
79
- ok
80
- else
81
- critical("Clusters w/ critical events: #{maint_clusters.join(',')}")
82
- end
90
+ maint_clusters
83
91
  end
84
92
  end
data/bin/check-rds.rb CHANGED
@@ -12,7 +12,7 @@
12
12
  # Linux
13
13
  #
14
14
  # DEPENDENCIES:
15
- # gem: aws-sdk
15
+ # gem: aws-sdk-v1
16
16
  # gem: sensu-plugin
17
17
  #
18
18
  # USAGE:
@@ -35,6 +35,10 @@
35
35
  # You can check multiple metrics simultaneously. Highest severity will be reported
36
36
  # check-rds -i sensu-admin-db --cpu-warning-over 80 --cpu-critical-over 90 --memory-warning-over 60 --memory-critical-over 80
37
37
  #
38
+ # You can ignore accept nil values returned for a time periods from Cloudwatch as being an OK. Amazon falls behind in their
39
+ # metrics from time to time and this prevents false positives
40
+ # check-rds -i sensu-admin-db --cpu-critical-over 90 -a
41
+ #
38
42
  # NOTES:
39
43
  #
40
44
  # LICENSE:
@@ -48,24 +52,23 @@ require 'aws-sdk-v1'
48
52
  require 'time'
49
53
 
50
54
  class CheckRDS < Sensu::Plugin::Check::CLI
51
- option :access_key_id,
52
- short: '-k N',
53
- long: '--access-key-id ID',
54
- description: 'AWS access key ID',
55
- default: ENV['AWS_ACCESS_KEY_ID']
56
-
57
- option :secret_access_key,
58
- short: '-s N',
59
- long: '--secret-access-key KEY',
60
- description: 'AWS secret access key',
61
- default: ENV['AWS_SECRET_ACCESS_KEY']
62
-
63
- option :region,
64
- short: '-r R',
65
- long: '--region REGION',
66
- description: 'AWS region',
67
- description: 'AWS Region (such as eu-west-1).',
68
- default: 'us-east-1'
55
+ option :aws_access_key,
56
+ short: '-a AWS_ACCESS_KEY',
57
+ long: '--aws-access-key AWS_ACCESS_KEY',
58
+ description: "AWS Access Key. Either set ENV['AWS_ACCESS_KEY'] or provide it as an option",
59
+ default: ENV['AWS_ACCESS_KEY']
60
+
61
+ option :aws_secret_access_key,
62
+ short: '-k AWS_SECRET_KEY',
63
+ long: '--aws-secret-access-key AWS_SECRET_KEY',
64
+ description: "AWS Secret Access Key. Either set ENV['AWS_SECRET_KEY'] or provide it as an option",
65
+ default: ENV['AWS_SECRET_KEY']
66
+
67
+ option :aws_region,
68
+ short: '-r AWS_REGION',
69
+ long: '--aws-region REGION',
70
+ description: 'AWS Region (defaults to us-east-1).',
71
+ default: 'us-east-1'
69
72
 
70
73
  option :db_instance_id,
71
74
  short: '-i N',
@@ -93,6 +96,12 @@ class CheckRDS < Sensu::Plugin::Check::CLI
93
96
  proc: proc { |a| a.downcase.intern },
94
97
  description: 'CloudWatch statistics method'
95
98
 
99
+ option :accept_nil,
100
+ short: '-n',
101
+ long: '--accept_nil',
102
+ description: 'Continue if CloudWatch provides no metrics for the time period',
103
+ default: false
104
+
96
105
  %w(warning critical).each do |severity|
97
106
  option :"availability_zone_#{severity}",
98
107
  long: "--availability-zone-#{severity} AZ",
@@ -107,10 +116,10 @@ class CheckRDS < Sensu::Plugin::Check::CLI
107
116
  end
108
117
 
109
118
  def aws_config
110
- hash = {}
111
- hash.update access_key_id: config[:access_key_id], secret_access_key: config[:secret_access_key] if config[:access_key_id] && config[:secret_access_key]
112
- hash.update region: config[:region] if config[:region]
113
- hash
119
+ { access_key_id: config[:aws_access_key],
120
+ secret_access_key: config[:aws_secret_access_key],
121
+ region: config[:aws_region]
122
+ }
114
123
  end
115
124
 
116
125
  def rds
@@ -145,8 +154,12 @@ class CheckRDS < Sensu::Plugin::Check::CLI
145
154
  def latest_value(metric, unit)
146
155
  values = metric.statistics(statistics_options.merge unit: unit).datapoints.sort_by { |datapoint| datapoint[:timestamp] }
147
156
 
148
- # handle time periods that are too small to return usable values
149
- values.empty? ? unknown('Requested time period did not return values from Cloudwatch. Try increasing your time period.') : values.last[config[:statistics]]
157
+ # handle time periods that are too small to return usable values. # this is a cozy addition that wouldn't port upstream.
158
+ if values.empty?
159
+ config[:accept_nil] ? ok('Cloudwatch returned no results for time period. Accept nil passed so OK') : unknown('Requested time period did not return values from Cloudwatch. Try increasing your time period.') # rubocop:disable all
160
+ else
161
+ values.last[config[:statistics]]
162
+ end
150
163
  end
151
164
 
152
165
  def flag_alert(severity, message)
@@ -12,7 +12,7 @@
12
12
  # Linux
13
13
  #
14
14
  # DEPENDENCIES:
15
- # gem: aws-sdk
15
+ # gem: aws-sdk-v1
16
16
  # gem: sensu-plugin
17
17
  #
18
18
  # USAGE:
@@ -41,19 +41,19 @@ class CheckRedshiftEvents < Sensu::Plugin::Check::CLI
41
41
  option :aws_access_key,
42
42
  short: '-a AWS_ACCESS_KEY',
43
43
  long: '--aws-access-key AWS_ACCESS_KEY',
44
- description: "AWS Access Key. Either set ENV['AWS_ACCESS_KEY_ID'] or provide it as an option",
45
- default: ENV['AWS_ACCESS_KEY_ID']
44
+ description: "AWS Access Key. Either set ENV['AWS_ACCESS_KEY'] or provide it as an option",
45
+ default: ENV['AWS_ACCESS_KEY']
46
46
 
47
47
  option :aws_secret_access_key,
48
- short: '-s AWS_SECRET_ACCESS_KEY',
49
- long: '--aws-secret-access-key AWS_SECRET_ACCESS_KEY',
50
- description: "AWS Secret Access Key. Either set ENV['AWS_SECRET_ACCESS_KEY'] or provide it as an option",
51
- default: ENV['AWS_SECRET_ACCESS_KEY']
48
+ short: '-k AWS_SECRET_KEY',
49
+ long: '--aws-secret-access-key AWS_SECRET_KEY',
50
+ description: "AWS Secret Access Key. Either set ENV['AWS_SECRET_KEY'] or provide it as an option",
51
+ default: ENV['AWS_SECRET_KEY']
52
52
 
53
53
  option :aws_region,
54
54
  short: '-r AWS_REGION',
55
55
  long: '--aws-region REGION',
56
- description: 'AWS Region (such as eu-west-1).',
56
+ description: 'AWS Region (defaults to us-east-1).',
57
57
  default: 'us-east-1'
58
58
 
59
59
  option :instances,
@@ -63,12 +63,16 @@ class CheckRedshiftEvents < Sensu::Plugin::Check::CLI
63
63
  proc: proc { |a| a.split(',') },
64
64
  default: []
65
65
 
66
+ def aws_config
67
+ { access_key_id: config[:aws_access_key],
68
+ secret_access_key: config[:aws_secret_access_key],
69
+ region: config[:aws_region]
70
+ }
71
+ end
72
+
66
73
  # setup a redshift connection using aws-sdk
67
74
  def redshift
68
- @redshift ||= AWS::Redshift::Client.new(
69
- access_key_id: config[:aws_access_key],
70
- secret_access_key: config[:aws_secret_access_key],
71
- region: config[:aws_region])
75
+ @redshift ||= AWS::Redshift::Client.new aws_config
72
76
  end
73
77
 
74
78
  # fetch all clusters in the region from AWS
@@ -35,14 +35,20 @@ class CheckSESLimit < Sensu::Plugin::Check::CLI
35
35
  option :aws_access_key,
36
36
  short: '-a AWS_ACCESS_KEY',
37
37
  long: '--aws-access-key AWS_ACCESS_KEY',
38
- description: "AWS Access Key. Either set ENV['AWS_ACCESS_KEY_ID'] or provide it as an option",
39
- required: true
38
+ description: "AWS Access Key. Either set ENV['AWS_ACCESS_KEY'] or provide it as an option",
39
+ default: ENV['AWS_ACCESS_KEY']
40
40
 
41
41
  option :aws_secret_access_key,
42
- short: '-s AWS_SECRET_ACCESS_KEY',
43
- long: '--aws-secret-access-key AWS_SECRET_ACCESS_KEY',
44
- description: "AWS Secret Access Key. Either set ENV['AWS_SECRET_ACCESS_KEY'] or provide it as an option",
45
- required: true
42
+ short: '-k AWS_SECRET_KEY',
43
+ long: '--aws-secret-access-key AWS_SECRET_KEY',
44
+ description: "AWS Secret Access Key. Either set ENV['AWS_SECRET_KEY'] or provide it as an option",
45
+ default: ENV['AWS_SECRET_KEY']
46
+
47
+ option :aws_region,
48
+ short: '-r AWS_REGION',
49
+ long: '--aws-region REGION',
50
+ description: 'AWS Region (defaults to us-east-1).',
51
+ default: 'us-east-1'
46
52
 
47
53
  option :warn_percent,
48
54
  short: '-W WARN_PERCENT',
@@ -59,10 +65,10 @@ class CheckSESLimit < Sensu::Plugin::Check::CLI
59
65
  proc: proc(&:to_i)
60
66
 
61
67
  def aws_config
62
- hash = {}
63
- hash.update access_key_id: config[:aws_access_key], secret_access_key: config[:aws_secret_access_key]\
64
- if config[:aws_access_key] && config[:aws_secret_access_key]
65
- hash
68
+ { access_key_id: config[:aws_access_key],
69
+ secret_access_key: config[:aws_secret_access_key],
70
+ region: config[:aws_region]
71
+ }
66
72
  end
67
73
 
68
74
  def run
@@ -12,7 +12,7 @@
12
12
  # Linux
13
13
  #
14
14
  # DEPENDENCIES:
15
- # gem: aws-sdk
15
+ # gem: aws-sdk-v1
16
16
  # gem: sensu-plugin
17
17
  #
18
18
  # USAGE:
@@ -37,17 +37,19 @@ class SQSMsgs < Sensu::Plugin::Check::CLI
37
37
  option :aws_access_key,
38
38
  short: '-a AWS_ACCESS_KEY',
39
39
  long: '--aws-access-key AWS_ACCESS_KEY',
40
- description: "AWS Access Key. Either set ENV['AWS_ACCESS_KEY_ID'] or provide it as an option"
40
+ description: "AWS Access Key. Either set ENV['AWS_ACCESS_KEY'] or provide it as an option",
41
+ default: ENV['AWS_ACCESS_KEY']
41
42
 
42
43
  option :aws_secret_access_key,
43
- short: '-s AWS_SECRET_ACCESS_KEY',
44
- long: '--aws-secret-access-key AWS_SECRET_ACCESS_KEY',
45
- description: "AWS Secret Access Key. Either set ENV['AWS_SECRET_ACCESS_KEY'] or provide it as an option"
44
+ short: '-k AWS_SECRET_KEY',
45
+ long: '--aws-secret-access-key AWS_SECRET_KEY',
46
+ description: "AWS Secret Access Key. Either set ENV['AWS_SECRET_KEY'] or provide it as an option",
47
+ default: ENV['AWS_SECRET_KEY']
46
48
 
47
49
  option :aws_region,
48
- description: 'AWS Region (such as us-east-1)',
49
50
  short: '-r AWS_REGION',
50
- long: '--aws-region AWS_REGION',
51
+ long: '--aws-region REGION',
52
+ description: 'AWS Region (defaults to us-east-1).',
51
53
  default: 'us-east-1'
52
54
 
53
55
  option :queue,
@@ -85,11 +87,10 @@ class SQSMsgs < Sensu::Plugin::Check::CLI
85
87
  proc: proc(&:to_i)
86
88
 
87
89
  def aws_config
88
- hash = {}
89
- hash.update access_key_id: config[:aws_access_key], secret_access_key: config[:aws_secret_access_key]\
90
- if config[:aws_access_key] && config[:aws_secret_access_key]
91
- hash.update region: config[:aws_region]
92
- hash
90
+ { access_key_id: config[:aws_access_key],
91
+ secret_access_key: config[:aws_secret_access_key],
92
+ region: config[:aws_region]
93
+ }
93
94
  end
94
95
 
95
96
  def run
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
3
  # CHANGELOG:
4
+ # * 0.5.0:
5
+ # - Adds configuration to filter by state reason
4
6
  # * 0.4.0:
5
7
  # - Adds ability to specify a list of states an individual client can have in
6
8
  # EC2. If none is specified, it filters out 'terminated' and 'stopped'
@@ -22,18 +24,21 @@
22
24
  # Optionally, you may specify a client attribute `ec2_states`, a list of valid
23
25
  # states an instance may have.
24
26
  #
27
+ # You may also specify a client attribute `ec2_state_reasons`, a list of regular
28
+ # expressions to match state reasons against. This is useful if you want to fail
29
+ # on any `Client.*` state reason or on `Server.*` state reason. The default is
30
+ # to match any state reason `.*` Regardless, eventually a client will be
31
+ # deleted once AWS stops responding that the instance id exists.
32
+ #
25
33
  # NOTE: The implementation for correlating Sensu clients to EC2 instances may
26
34
  # need to be modified to fit your organization. The current implementation
27
35
  # assumes that Sensu clients' names are the same as their instance IDs in EC2.
28
36
  # If this is not the case, you can either sub-class this handler and override
29
- # `ec2_node_exists?` in your own organization-specific handler, or modify this
37
+ # `ec2_node_should_be_deleted?` in your own organization-specific handler, or modify this
30
38
  # handler to suit your needs.
31
39
  #
32
- # Requires the following Rubygems (`gem install $GEM`):
33
- # - sensu-plugin
34
- # - fog
35
40
  #
36
- # Requires a Sensu configuration snippet:
41
+ # Optional a Sensu configuration snippet:
37
42
  # {
38
43
  # "aws": {
39
44
  # "access_key": "adsafdafda",
@@ -47,6 +52,11 @@
47
52
  # - AWS_SECRET_ACCESS_KEY
48
53
  # - EC2_REGION
49
54
  #
55
+ # If none of the settings are found it will then attempt to
56
+ # generate temporary credentials from the IAM instance profile
57
+ #
58
+ # If region is not specified in either of the above 2 mechanisms
59
+ # we will make a request for the EC2 instances current region.
50
60
  #
51
61
  # To use, you can set it as the keepalive handler for a client:
52
62
  # {
@@ -92,17 +102,21 @@
92
102
 
93
103
  require 'timeout'
94
104
  require 'sensu-handler'
95
- require 'fog'
105
+ require 'net/http'
106
+ require 'uri'
107
+ require 'aws-sdk'
108
+ require 'sensu-plugins-aws'
96
109
 
97
110
  class Ec2Node < Sensu::Handler
111
+ include Common
112
+
98
113
  def filter; end
99
114
 
100
115
  def handle
101
- # #YELLOW
102
- unless ec2_node_exists? # rubocop:disable UnlessElse
116
+ if ec2_node_should_be_deleted?
103
117
  delete_sensu_client!
104
118
  else
105
- puts "[EC2 Node] #{@event['client']['name']} appears to exist in EC2"
119
+ puts "[EC2 Node] #{@event['client']['name']} is in an invalid state"
106
120
  end
107
121
  end
108
122
 
@@ -111,46 +125,55 @@ class Ec2Node < Sensu::Handler
111
125
  deletion_status(response)
112
126
  end
113
127
 
114
- def ec2_node_exists?
115
- states = acquire_valid_states
116
- filtered_instances = ec2.servers.select { |s| states.include?(s.state) }
117
- instance_ids = filtered_instances.map(&:id)
118
- instance_ids.each do |id|
119
- return true if id == @event['client']['name']
128
+ def ec2_node_should_be_deleted?
129
+ ec2 = Aws::EC2::Client.new(region: region)
130
+ states = @event['client']['ec2_states'] || settings['ec2_node']['ec2_states'] || ['shutting-down', 'terminated', 'stopping', 'stopped']
131
+ begin
132
+ instances = ec2.describe_instances(instance_ids: [@event['client']['name']]).reservations[0]
133
+ if instances.nil?
134
+ true
135
+ else
136
+ instance = instances.instances[0]
137
+ state_reason = instance.state_reason.code
138
+ state = instance.state.name
139
+ states.include?(state) && state_reasons.any? { |reason| Regexp.new(reason) =~ state_reason }
140
+ end
141
+ rescue Aws::EC2::Errors::InvalidInstanceIDNotFound
142
+ true
120
143
  end
121
- false # no match found, node doesn't exist
122
144
  end
123
145
 
124
- def ec2
125
- @ec2 ||= begin
126
- key = settings['aws']['access_key'] || ENV['AWS_ACCESS_KEY_ID']
127
- secret = settings['aws']['secret_key'] || ENV['AWS_SECRET_ACCESS_KEY']
128
- region = settings['aws']['region'] || ENV['EC2_REGION']
129
- Fog::Compute.new(provider: 'AWS',
130
- aws_access_key_id: key,
131
- aws_secret_access_key: secret,
132
- region: region)
146
+ def region
147
+ @region ||= begin
148
+ region_check = ENV['EC2_REGION']
149
+ region_check = settings['aws']['region'] if settings.key? 'aws'
150
+ if region_check.nil? || region_check.empty?
151
+ region_check = Net::HTTP.get(URI('http://169.254.169.254/latest/meta-data/placement/availability-zone'))
152
+ matches = /(\w+\-\w+\-\d+)/.match(region_check)
153
+ if !matches.nil? && !matches.captures.empty?
154
+ region_check = matches.captures[0]
155
+ end
156
+ end
157
+ region_check
133
158
  end
134
159
  end
135
160
 
161
+ def state_reasons
162
+ default_reasons = %w('UserInitiatedShutdown', 'SpotInstanceTermination', 'InstanceInitiatedShutdown')
163
+ reasons = @event['client']['ec2_state_reasons'] || settings['ec2_node']['ec2_state_reasons'] || default_reasons
164
+ @state_reasons ||= reasons.each { |reason| Regexp.new(reason) }
165
+ end
166
+
136
167
  def deletion_status(code)
137
168
  case code
138
169
  when '202'
139
- puts "[EC2 Node] 202: Successfully deleted Sensu client: #{node}"
170
+ puts "[EC2 Node] 202: Successfully deleted Sensu client: #{@event['client']['name']}"
140
171
  when '404'
141
- puts "[EC2 Node] 404: Unable to delete #{node}, doesn't exist!"
172
+ puts "[EC2 Node] 404: Unable to delete #{@event['client']['name']}, doesn't exist!"
142
173
  when '500'
143
- puts "[EC2 Node] 500: Miscellaneous error when deleting #{node}"
144
- else
145
- puts "[EC2 Node] #{res}: Completely unsure of what happened!"
146
- end
147
- end
148
-
149
- def acquire_valid_states
150
- if @event['client'].key?('ec2_states')
151
- return @event['client']['ec2_states']
174
+ puts "[EC2 Node] 500: Miscellaneous error when deleting #{@event['client']['name']}"
152
175
  else
153
- return ['running']
176
+ puts "[EC2 Node] #{code}: Completely unsure of what happened!"
154
177
  end
155
178
  end
156
179
  end