sensu-plugins-aws 0.0.4 → 1.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.
@@ -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