cfn-guardian 0.1.0 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +1 -0
  3. data/Dockerfile +19 -0
  4. data/Gemfile.lock +31 -13
  5. data/README.md +441 -42
  6. data/cfn-guardian.gemspec +6 -2
  7. data/lib/cfnguardian.rb +301 -27
  8. data/lib/cfnguardian/cloudwatch.rb +121 -0
  9. data/lib/cfnguardian/codecommit.rb +54 -0
  10. data/lib/cfnguardian/codepipeline.rb +138 -0
  11. data/lib/cfnguardian/compile.rb +58 -17
  12. data/lib/cfnguardian/config/defaults.yaml +94 -0
  13. data/lib/cfnguardian/display_formatter.rb +164 -0
  14. data/lib/cfnguardian/drift.rb +79 -0
  15. data/lib/cfnguardian/log.rb +0 -1
  16. data/lib/cfnguardian/models/alarm.rb +98 -36
  17. data/lib/cfnguardian/models/check.rb +103 -26
  18. data/lib/cfnguardian/models/composite.rb +21 -0
  19. data/lib/cfnguardian/models/event.rb +164 -40
  20. data/lib/cfnguardian/models/metric_filter.rb +28 -0
  21. data/lib/cfnguardian/resources/application_targetgroup.rb +2 -0
  22. data/lib/cfnguardian/resources/base.rb +38 -16
  23. data/lib/cfnguardian/resources/ecs_service.rb +2 -2
  24. data/lib/cfnguardian/resources/http.rb +16 -1
  25. data/lib/cfnguardian/resources/internal_http.rb +74 -0
  26. data/lib/cfnguardian/resources/internal_port.rb +33 -0
  27. data/lib/cfnguardian/resources/internal_sftp.rb +58 -0
  28. data/lib/cfnguardian/resources/log_group.rb +26 -0
  29. data/lib/cfnguardian/resources/network_targetgroup.rb +1 -0
  30. data/lib/cfnguardian/resources/port.rb +25 -0
  31. data/lib/cfnguardian/resources/rds_instance.rb +2 -0
  32. data/lib/cfnguardian/resources/sftp.rb +50 -0
  33. data/lib/cfnguardian/resources/sql.rb +1 -1
  34. data/lib/cfnguardian/resources/tls.rb +66 -0
  35. data/lib/cfnguardian/s3.rb +3 -2
  36. data/lib/cfnguardian/stacks/main.rb +86 -65
  37. data/lib/cfnguardian/stacks/resources.rb +81 -42
  38. data/lib/cfnguardian/string.rb +12 -0
  39. data/lib/cfnguardian/version.rb +1 -1
  40. metadata +102 -5
@@ -31,8 +31,12 @@ Gem::Specification.new do |spec|
31
31
  spec.add_dependency "thor", "~> 0.20"
32
32
  spec.add_dependency 'cfndsl', '~> 1.0', '<2'
33
33
  spec.add_dependency "terminal-table", '~> 1', '<2'
34
- spec.add_dependency 'aws-sdk-s3', '~> 1', '<2'
35
- spec.add_dependency 'aws-sdk-cloudformation', '~> 1', '<2'
34
+ spec.add_dependency 'term-ansicolor', '~> 1', '<2'
35
+ spec.add_dependency 'aws-sdk-s3', '~> 1.60', '<2'
36
+ spec.add_dependency 'aws-sdk-cloudformation', '~> 1.31', '<2'
37
+ spec.add_dependency 'aws-sdk-cloudwatch', '~> 1.28', '<2'
38
+ spec.add_dependency 'aws-sdk-codecommit', '~> 1.28', '<2'
39
+ spec.add_dependency 'aws-sdk-codepipeline', '~> 1.28', '<2'
36
40
 
37
41
  spec.add_development_dependency "bundler", "~> 2.0"
38
42
  spec.add_development_dependency "rake", "~> 10.0"
@@ -1,10 +1,16 @@
1
1
  require 'thor'
2
2
  require 'terminal-table'
3
+ require 'term/ansicolor'
3
4
  require "cfnguardian/log"
4
5
  require "cfnguardian/version"
5
6
  require "cfnguardian/compile"
6
7
  require "cfnguardian/validate"
7
8
  require "cfnguardian/deploy"
9
+ require "cfnguardian/cloudwatch"
10
+ require "cfnguardian/display_formatter"
11
+ require "cfnguardian/drift"
12
+ require "cfnguardian/codecommit"
13
+ require "cfnguardian/codepipeline"
8
14
 
9
15
  module CfnGuardian
10
16
  class Cli < Thor
@@ -16,6 +22,8 @@ module CfnGuardian
16
22
  puts CfnGuardian::VERSION
17
23
  end
18
24
 
25
+ class_option :debug, type: :boolean, default: false, desc: "enable debug logging"
26
+
19
27
  desc "compile", "Generate monitoring CloudFormation templates"
20
28
  long_desc <<-LONG
21
29
  Generates CloudFormation templates from the alarm configuration and output to the out/ directory.
@@ -23,15 +31,18 @@ module CfnGuardian
23
31
  method_option :config, aliases: :c, type: :string, desc: "yaml config file", required: true
24
32
  method_option :validate, type: :boolean, default: true, desc: "validate cfn templates"
25
33
  method_option :bucket, type: :string, desc: "provide custom bucket name, will create a default bucket if not provided"
34
+ method_option :path, type: :string, default: "guardian", desc: "S3 path location for nested stacks"
26
35
  method_option :region, aliases: :r, type: :string, desc: "set the AWS region"
27
36
 
28
37
  def compile
38
+ set_log_level(options[:debug])
39
+
29
40
  set_region(options[:region],options[:validate])
30
- s3 = CfnGuardian::S3.new(options[:bucket])
41
+ s3 = CfnGuardian::S3.new(options[:bucket],options[:path])
31
42
 
32
- compiler = CfnGuardian::Compile.new(options,s3.bucket)
43
+ compiler = CfnGuardian::Compile.new(options[:config])
33
44
  compiler.get_resources
34
- compiler.compile_templates
45
+ compiler.compile_templates(s3.bucket,s3.path)
35
46
  logger.info "Clouformation templates compiled successfully in out/ directory"
36
47
  if options[:validate]
37
48
  s3.create_bucket_if_not_exists()
@@ -53,20 +64,23 @@ module CfnGuardian
53
64
  LONG
54
65
  method_option :config, aliases: :c, type: :string, desc: "yaml config file", required: true
55
66
  method_option :bucket, type: :string, desc: "provide custom bucket name, will create a default bucket if not provided"
67
+ method_option :path, type: :string, default: "guardian", desc: "S3 path location for nested stacks"
56
68
  method_option :region, aliases: :r, type: :string, desc: "set the AWS region"
57
- method_option :stack_name, aliases: :r, type: :string, desc: "set the Cloudformation stack name. Defaults to `guardian`"
69
+ method_option :stack_name, aliases: :s, type: :string, desc: "set the Cloudformation stack name. Defaults to `guardian`"
58
70
  method_option :sns_critical, type: :string, desc: "sns topic arn for the critical alamrs"
59
71
  method_option :sns_warning, type: :string, desc: "sns topic arn for the warning alamrs"
60
72
  method_option :sns_task, type: :string, desc: "sns topic arn for the task alamrs"
61
73
  method_option :sns_informational, type: :string, desc: "sns topic arn for the informational alamrs"
62
74
 
63
75
  def deploy
76
+ set_log_level(options[:debug])
77
+
64
78
  set_region(options[:region],true)
65
- s3 = CfnGuardian::S3.new(options[:bucket])
79
+ s3 = CfnGuardian::S3.new(options[:bucket],options[:path])
66
80
 
67
- compiler = CfnGuardian::Compile.new(options,s3.bucket)
81
+ compiler = CfnGuardian::Compile.new(options[:config])
68
82
  compiler.get_resources
69
- compiler.compile_templates
83
+ compiler.compile_templates(s3.bucket,s3.path)
70
84
  logger.info "Clouformation templates compiled successfully in out/ directory"
71
85
 
72
86
  s3.create_bucket_if_not_exists
@@ -85,46 +99,291 @@ module CfnGuardian
85
99
  deployer.execute_change_set(change_set.id)
86
100
  deployer.wait_for_execute(change_set_type)
87
101
  end
102
+
103
+ desc "show-drift", "Cloudformation drift detection"
104
+ long_desc <<-LONG
105
+ Displays any cloudformation drift detection in the cloudwatch alarms from the deployed stacks
106
+ LONG
107
+ method_option :stack_name, aliases: :s, type: :string, default: 'guardian', desc: "set the Cloudformation stack name"
108
+ method_option :region, aliases: :r, type: :string, desc: "set the AWS region"
109
+
110
+ def show_drift
111
+ set_region(options[:region],true)
112
+
113
+ rows = []
114
+ drift = CfnGuardian::Drift.new(options[:stack_name])
115
+ nested_stacks = drift.find_nested_stacks
116
+ nested_stacks.each do |stack|
117
+ drift.detect_drift(stack)
118
+ rows << drift.get_drift(stack)
119
+ end
120
+
121
+ if rows.any?
122
+ puts Terminal::Table.new(
123
+ :title => "Guardian Alarm Drift".green,
124
+ :headings => ['Alarm Name', 'Property', 'Expected', 'Actual', 'Type'],
125
+ :rows => rows.flatten(1))
126
+ exit(1)
127
+ end
128
+ end
88
129
 
89
130
  desc "show-alarms", "Shows alarm settings"
90
131
  long_desc <<-LONG
91
132
  Displays the configured settings for each alarm. Can be filtered by resource group and alarm name.
92
133
  Defaults to show all configured alarms.
93
134
  LONG
94
- method_option :config, aliases: :c, type: :string, desc: "yaml config file", required: true
135
+ method_option :config, aliases: :c, type: :string, desc: "yaml config file"
136
+ method_option :defaults, type: :boolean, desc: "display default alarms and properties"
137
+ method_option :region, aliases: :r, type: :string, desc: "set the AWS region"
95
138
  method_option :group, aliases: :g, type: :string, desc: "resource group"
96
- method_option :name, aliases: :n, type: :string, desc: "alarm name"
97
- method_option :resource, aliases: :r, type: :string, desc: "resource id"
139
+ method_option :alarm, aliases: :a, type: :string, desc: "alarm name"
140
+ method_option :id, type: :string, desc: "resource id"
141
+ method_option :compare, type: :boolean, default: false, desc: "compare config to deployed alarms"
142
+
98
143
  def show_alarms
99
- compiler = CfnGuardian::Compile.new(options,'no-bucket')
144
+ set_log_level(options[:debug])
145
+
146
+ set_region(options[:region],options[:compare])
147
+
148
+ if options[:config]
149
+ config_file = options[:config]
150
+ elsif options[:defaults]
151
+ config_file = default_config()
152
+ else
153
+ logger.error('one of `--config YAML` or `--defaults` must be supplied')
154
+ exit -1
155
+ end
156
+
157
+ compiler = CfnGuardian::Compile.new(config_file)
100
158
  compiler.get_resources
159
+ alarms = filter_alarms(compiler.alarms,options)
160
+
161
+ if alarms.empty?
162
+ logger.error "No matches found"
163
+ exit 1
164
+ end
165
+
166
+ headings = ['Property', 'Config']
167
+ formatter = CfnGuardian::DisplayFormatter.new(alarms)
101
168
 
102
- alarms = compiler.resources.select{|h| h[:type] == 'Alarm'}
103
- groups = alarms.group_by{|h| h[:class]}
169
+ if options[:compare] && !options[:defaults]
170
+ metric_alarms = CfnGuardian::CloudWatch.get_alarms(alarms)
171
+ formatted_alarms = formatter.compare_alarms(metric_alarms)
172
+ headings.push('Deployed')
173
+ else
174
+ formatted_alarms = formatter.alarms()
175
+ end
104
176
 
105
- if options[:group]
106
- groups = groups.fetch(options[:group],{}).group_by{|h| h[:class]}
107
- if options[:resource]
108
- groups = groups[options[:group]].select{|h| h[:resource] == options[:resource]}.group_by{|h| h[:class]}
177
+ if formatted_alarms.any?
178
+ formatted_alarms.each do |fa|
179
+ puts Terminal::Table.new(
180
+ :title => fa[:title],
181
+ :headings => headings,
182
+ :rows => fa[:rows])
109
183
  end
110
- if options[:name]
111
- groups = groups[options[:group]].select{|h| h[:name] == options[:name]}.group_by{|h| h[:class]}
184
+ else
185
+ if options[:compare] && !options[:defaults]
186
+ logger.info "No difference found between you config and alarms in deployed AWS"
187
+ else
188
+ logger.warn "No alarms found"
112
189
  end
113
190
  end
191
+ end
192
+
193
+ desc "show-state", "Shows alarm state in cloudwatch"
194
+ long_desc <<-LONG
195
+ Displays the current cloudwatch alarm state
196
+ LONG
197
+ method_option :config, aliases: :c, type: :string, desc: "yaml config file"
198
+ method_option :region, aliases: :r, type: :string, desc: "set the AWS region"
199
+ method_option :group, aliases: :g, type: :string, desc: "resource group"
200
+ method_option :alarm, aliases: :a, type: :string, desc: "alarm name"
201
+ method_option :id, type: :string, desc: "resource id"
202
+ method_option :state, aliases: :s, type: :string, enum: %w(OK ALARM INSUFFICIENT_DATA), desc: "filter by alarm state"
203
+ method_option :alarm_names, type: :array, desc: "CloudWatch alarm name if not providing config"
204
+ method_option :alarm_prefix, type: :string, desc: "CloudWatch alarm name prefix if not providing config"
205
+
206
+ def show_state
207
+ set_log_level(options[:debug])
208
+ set_region(options[:region],true)
209
+
210
+ formatter = CfnGuardian::DisplayFormatter.new()
211
+
212
+ if !options[:config].nil?
213
+ compiler = CfnGuardian::Compile.new(options[:config])
214
+ compiler.get_resources
215
+ alarms = filter_alarms(compiler.alarms,options)
216
+ metric_alarms = CfnGuardian::CloudWatch.get_alarm_state(config_alarms: alarms, state: options[:state])
217
+ elsif !options[:alarm_names].nil?
218
+ metric_alarms = CfnGuardian::CloudWatch.get_alarm_state(alarm_names: options[:alarm_names], state: options[:state])
219
+ elsif !options[:alarm_prefix].nil?
220
+ metric_alarms = CfnGuardian::CloudWatch.get_alarm_state(alarm_prefix: options[:alarm_prefix], state: options[:state])
221
+ else
222
+ logger.error "one of `--config` `--alarm-prefix` `--alarm-names` must be supplied"
223
+ exit 1
224
+ end
225
+
226
+ rows = formatter.alarm_state(metric_alarms)
114
227
 
115
- groups.each do |grp,alarms|
116
- puts "\n\s\s#{grp}\n"
117
- alarms.each do |alarm|
118
- rows = alarm.reject {|k,v| [:type,:class,:name].include?(k)}
119
- .sort_by {|k,v| k}
228
+ if rows.any?
229
+ puts Terminal::Table.new(
230
+ :title => "Alarm State",
231
+ :headings => ['Alarm Name', 'State', 'Changed', 'Notifications'],
232
+ :rows => rows)
233
+ else
234
+ logger.warn "No alarms found"
235
+ end
236
+ end
237
+
238
+ desc "show-history", "Shows alarm history for the last 7 days"
239
+ long_desc <<-LONG
240
+ Displays the alarm state or config history for the last 7 days
241
+ LONG
242
+ method_option :config, aliases: :c, type: :string, desc: "yaml config file"
243
+ method_option :region, aliases: :r, type: :string, desc: "set the AWS region"
244
+ method_option :group, aliases: :g, type: :string, desc: "resource group"
245
+ method_option :alarm, aliases: :a, type: :string, desc: "alarm name"
246
+ method_option :alarm_names, type: :array, desc: "CloudWatch alarm name if not providing config"
247
+ method_option :id, type: :string, desc: "resource id"
248
+ method_option :type, aliases: :t, type: :string,
249
+ enum: %w(state config), default: 'state', desc: "filter by alarm state"
250
+
251
+ def show_history
252
+ set_log_level(options[:debug])
253
+ set_region(options[:region],true)
254
+
255
+ if !options[:config].nil?
256
+ compiler = CfnGuardian::Compile.new(options[:config])
257
+ compiler.get_resources
258
+ config_alarms = filter_alarms(compiler.alarms,options)
259
+ alarms = config_alarms.map {|alarm| CfnGuardian::CloudWatch.get_alarm_name(alarm)}
260
+ elsif !options[:alarm_names].nil?
261
+ alarms = options[:alarm_names]
262
+ else
263
+ logger.error "one of `--config` `--alarm-names` must be supplied"
264
+ exit 1
265
+ end
266
+
267
+
268
+ case options[:type]
269
+ when 'state'
270
+ type = 'StateUpdate'
271
+ headings = ['Date', 'Summary', 'Reason']
272
+ when 'config'
273
+ type = 'ConfigurationUpdate'
274
+ headings = ['Date', 'Summary', 'Type']
275
+ end
276
+
277
+ formatter = CfnGuardian::DisplayFormatter.new()
278
+
279
+ alarms.each do |alarm|
280
+ history = CfnGuardian::CloudWatch.get_alarm_history(alarm,type)
281
+ rows = formatter.alarm_history(history,type)
282
+ if rows.any?
120
283
  puts Terminal::Table.new(
121
- :title => alarm[:name],
122
- :headings => ['property', 'Value'],
123
- :rows => rows.map! {|k,v| [k,v.to_s]})
284
+ :title => alarm.green,
285
+ :headings => headings,
286
+ :rows => rows)
287
+ puts "\n"
124
288
  end
125
289
  end
126
290
  end
127
291
 
292
+ desc "show-config-history", "Shows the last 10 commits made to the codecommit repo"
293
+ long_desc <<-LONG
294
+ Shows the last 10 commits made to the codecommit repo
295
+ LONG
296
+ method_option :config, aliases: :c, type: :string, desc: "yaml config file"
297
+ method_option :region, aliases: :r, type: :string, desc: "set the AWS region"
298
+ method_option :repository, type: :string, default: 'guardian', desc: "codecommit repository name"
299
+
300
+ def show_config_history
301
+ set_region(options[:region],true)
302
+
303
+ history = CfnGuardian::CodeCommit.new(options[:repository]).get_commit_history()
304
+ puts Terminal::Table.new(
305
+ :headings => history.first.keys.map{|h| h.to_s.to_heading},
306
+ :rows => history.map(&:values))
307
+ end
308
+
309
+ desc "show-pipeline", "Shows the current state of the AWS code pipeline"
310
+ long_desc <<-LONG
311
+ Shows the current state of the AWS code pipeline
312
+ LONG
313
+ method_option :region, aliases: :r, type: :string, desc: "set the AWS region"
314
+ method_option :pipeline, aliases: :p, type: :string, default: 'guardian', desc: "codepipeline name"
315
+
316
+ def show_pipeline
317
+ set_region(options[:region],true)
318
+ pipeline = CfnGuardian::CodePipeline.new(options[:pipeline])
319
+ source = pipeline.get_source()
320
+ build = pipeline.get_build()
321
+ create = pipeline.get_create_changeset()
322
+ deploy = pipeline.get_deploy_changeset()
323
+
324
+ puts Terminal::Table.new(
325
+ :title => "Stage: #{source[:stage]}",
326
+ :rows => source[:rows])
327
+
328
+ puts "\t|"
329
+ puts "\t|"
330
+
331
+ puts Terminal::Table.new(
332
+ :title => "Stage: #{build[:stage]}",
333
+ :rows => build[:rows])
334
+
335
+ puts "\t|"
336
+ puts "\t|"
337
+
338
+ puts Terminal::Table.new(
339
+ :title => "Stage: #{create[:stage]}",
340
+ :rows => create[:rows])
341
+
342
+ puts "\t|"
343
+ puts "\t|"
344
+
345
+ puts Terminal::Table.new(
346
+ :title => "Stage: #{deploy[:stage]}",
347
+ :rows => deploy[:rows])
348
+ end
349
+
350
+ desc "disable-alarms", "Disable cloudwatch alarm notifications"
351
+ long_desc <<-LONG
352
+ Disable cloudwatch alarm notifications for a maintenance group or for specific alarms.
353
+ LONG
354
+ method_option :region, aliases: :r, type: :string, desc: "set the AWS region"
355
+ method_option :group, aliases: :g, type: :string, desc: "name of the maintenance group defined in the config"
356
+ method_option :alarm_prefix, type: :string, desc: "cloud watch alarm name prefix"
357
+ method_option :alarms, type: :array, desc: "List of cloudwatch alarm names"
358
+
359
+ def disable_alarms
360
+ set_region(options[:region],true)
361
+
362
+ alarm_names = CfnGuardian::CloudWatch.get_alarm_names(options[:group],options[:alarm_prefix])
363
+ CfnGuardian::CloudWatch.disable_alarms(alarm_names)
364
+
365
+ logger.info "Disabled #{alarm_names.length} alarms"
366
+ end
367
+
368
+ desc "enable-alarms", "Enable cloudwatch alarm notifications"
369
+ long_desc <<-LONG
370
+ Enable cloudwatch alarm notifications for a maintenance group or for specific alarms.
371
+ Once alarms are enable the state is set back to OK to re send notifications of any failed alarms.
372
+ LONG
373
+ method_option :region, aliases: :r, type: :string, desc: "set the AWS region"
374
+ method_option :group, aliases: :g, type: :string, desc: "name of the maintenance group defined in the config"
375
+ method_option :alarm_prefix, type: :string, desc: "cloud watch alarm name prefix"
376
+ method_option :alarms, type: :array, desc: "List of cloudwatch alarm names"
377
+
378
+ def enable_alarms
379
+ set_region(options[:region],true)
380
+
381
+ alarm_names = CfnGuardian::CloudWatch.get_alarm_names(options[:group],options[:alarm_prefix])
382
+ CfnGuardian::CloudWatch.enable_alarms(alarm_names)
383
+
384
+ logger.info "#{alarm_names.length} alarms enabled"
385
+ end
386
+
128
387
  private
129
388
 
130
389
  def set_region(region,required)
@@ -142,5 +401,20 @@ module CfnGuardian
142
401
  end
143
402
  end
144
403
 
404
+ def set_log_level(debug)
405
+ logger.level = debug ? Logger::DEBUG : Logger::INFO
406
+ end
407
+
408
+ def filter_alarms(alarms,options)
409
+ alarms.select! {|alarm| alarm.group.downcase == options[:group].downcase} if options[:group]
410
+ alarms.select! {|alarm| alarm.resource_id.downcase == options[:id].downcase} if options[:id]
411
+ alarms.select! {|alarm| alarm.name.downcase.include? options[:alarm].downcase} if options[:alarm]
412
+ return alarms
413
+ end
414
+
415
+ def default_config()
416
+ return "#{File.expand_path(File.dirname(__FILE__))}/cfnguardian/config/defaults.yaml"
417
+ end
418
+
145
419
  end
146
420
  end
@@ -0,0 +1,121 @@
1
+ require 'aws-sdk-cloudwatch'
2
+ require 'time'
3
+
4
+ module CfnGuardian
5
+ class CloudWatch
6
+ include Logging
7
+
8
+ def self.get_alarm_name(alarm)
9
+ alarm_id = alarm.resource_name.nil? ? alarm.resource_id : alarm.resource_name
10
+ return "guardian-#{alarm.group}-#{alarm_id}-#{alarm.name}"
11
+ end
12
+
13
+ def self.get_alarms(alarms)
14
+ alarm_names = alarms.map {|alarm| self.get_alarm_name(alarm)}
15
+
16
+ client = Aws::CloudWatch::Client.new()
17
+ metric_alarms = []
18
+ alarm_names.each_slice(100) do |batch|
19
+ resp = client.describe_alarms({alarm_names: batch, max_records: 100})
20
+ metric_alarms.push(*resp.metric_alarms)
21
+ end
22
+
23
+ return metric_alarms
24
+ end
25
+
26
+ def self.get_alarm_state(config_alarms: [], alarm_names: [], alarm_prefix: nil, state: nil)
27
+ rows = []
28
+
29
+ if config_alarms.any?
30
+ alarm_names = config_alarms.map {|alarm| self.get_alarm_name(alarm)}
31
+ end
32
+
33
+ client = Aws::CloudWatch::Client.new()
34
+
35
+ options = {max_records: 100}
36
+ options[:state_value] = state if !state.nil?
37
+
38
+ cw_alarms = []
39
+ if !alarm_prefix.nil?
40
+ options[:alarm_name_prefix] = alarm_prefix
41
+ resp = client.describe_alarms(options)
42
+ cw_alarms = resp.metric_alarms
43
+ else
44
+ alarm_names.each_slice(100) do |batch|
45
+ options[:alarm_names] = batch
46
+ resp = client.describe_alarms(options)
47
+ cw_alarms.push(*resp.metric_alarms)
48
+ end
49
+ end
50
+
51
+ return cw_alarms
52
+ end
53
+
54
+ def self.get_alarm_history(alarm_name,type)
55
+ rows = []
56
+ client = Aws::CloudWatch::Client.new()
57
+
58
+ logger.debug "Searching #{type} history for #{alarm_name}"
59
+
60
+ resp = client.describe_alarm_history({
61
+ alarm_name: alarm_name,
62
+ history_item_type: type,
63
+ start_date: (Time.now.utc.to_date - 7),
64
+ end_date: (Time.now.utc.to_date + 1),
65
+ max_records: 100
66
+ })
67
+
68
+ return resp.alarm_history_items
69
+ end
70
+
71
+ def self.get_alarm_names(action_prefix=nil,alarm_name_prefix='guardian')
72
+ alarms = []
73
+ client = Aws::CloudWatch::Client.new
74
+
75
+ options = {
76
+ alarm_types: ["CompositeAlarm","MetricAlarm"],
77
+ alarm_name_prefix: alarm_name_prefix
78
+ }
79
+
80
+ unless action_prefix.nil?
81
+ options[:action_prefix] = "arn:aws:sns:#{Aws.config[:region]}:#{aws_account_id()}:#{action_prefix}"
82
+ end
83
+
84
+ client.describe_alarms(options).each do |response|
85
+ alarms.concat response.composite_alarms.map(&:alarm_name)
86
+ alarms.concat response.metric_alarms.map(&:alarm_name)
87
+ end
88
+
89
+ return alarms
90
+ end
91
+
92
+ def self.disable_alarms(alarms)
93
+ client = Aws::CloudWatch::Client.new
94
+ alarms.each_slice(100) do |batch|
95
+ client.disable_alarm_actions({alarm_names: batch})
96
+ end
97
+ end
98
+
99
+ def self.enable_alarms(alarms)
100
+ client = Aws::CloudWatch::Client.new
101
+ alarms.each_slice(100) do |batch|
102
+ client.enable_alarm_actions({alarm_names: batch})
103
+ end
104
+
105
+ alarms.each do |alarm|
106
+ client.set_alarm_state({
107
+ alarm_name: alarm,
108
+ state_value: "OK",
109
+ state_reason: "End of guardian maintenance peroid"
110
+ })
111
+ end
112
+ end
113
+
114
+ def self.aws_account_id()
115
+ sts = Aws::STS::Client.new
116
+ account = sts.get_caller_identity().account
117
+ return account
118
+ end
119
+
120
+ end
121
+ end