cfn-guardian 0.1.0 → 0.3.3
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.
- checksums.yaml +4 -4
- data/.dockerignore +1 -0
- data/Dockerfile +19 -0
- data/Gemfile.lock +31 -13
- data/README.md +441 -42
- data/cfn-guardian.gemspec +6 -2
- data/lib/cfnguardian.rb +301 -27
- data/lib/cfnguardian/cloudwatch.rb +121 -0
- data/lib/cfnguardian/codecommit.rb +54 -0
- data/lib/cfnguardian/codepipeline.rb +138 -0
- data/lib/cfnguardian/compile.rb +58 -17
- data/lib/cfnguardian/config/defaults.yaml +94 -0
- data/lib/cfnguardian/display_formatter.rb +164 -0
- data/lib/cfnguardian/drift.rb +79 -0
- data/lib/cfnguardian/log.rb +0 -1
- data/lib/cfnguardian/models/alarm.rb +98 -36
- data/lib/cfnguardian/models/check.rb +103 -26
- data/lib/cfnguardian/models/composite.rb +21 -0
- data/lib/cfnguardian/models/event.rb +164 -40
- data/lib/cfnguardian/models/metric_filter.rb +28 -0
- data/lib/cfnguardian/resources/application_targetgroup.rb +2 -0
- data/lib/cfnguardian/resources/base.rb +38 -16
- data/lib/cfnguardian/resources/ecs_service.rb +2 -2
- data/lib/cfnguardian/resources/http.rb +16 -1
- data/lib/cfnguardian/resources/internal_http.rb +74 -0
- data/lib/cfnguardian/resources/internal_port.rb +33 -0
- data/lib/cfnguardian/resources/internal_sftp.rb +58 -0
- data/lib/cfnguardian/resources/log_group.rb +26 -0
- data/lib/cfnguardian/resources/network_targetgroup.rb +1 -0
- data/lib/cfnguardian/resources/port.rb +25 -0
- data/lib/cfnguardian/resources/rds_instance.rb +2 -0
- data/lib/cfnguardian/resources/sftp.rb +50 -0
- data/lib/cfnguardian/resources/sql.rb +1 -1
- data/lib/cfnguardian/resources/tls.rb +66 -0
- data/lib/cfnguardian/s3.rb +3 -2
- data/lib/cfnguardian/stacks/main.rb +86 -65
- data/lib/cfnguardian/stacks/resources.rb +81 -42
- data/lib/cfnguardian/string.rb +12 -0
- data/lib/cfnguardian/version.rb +1 -1
- metadata +102 -5
data/cfn-guardian.gemspec
CHANGED
@@ -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 '
|
35
|
-
spec.add_dependency 'aws-sdk-
|
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"
|
data/lib/cfnguardian.rb
CHANGED
@@ -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
|
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: :
|
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
|
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"
|
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 :
|
97
|
-
method_option :
|
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
|
-
|
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
|
-
|
103
|
-
|
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
|
106
|
-
|
107
|
-
|
108
|
-
|
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
|
-
|
111
|
-
|
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
|
-
|
116
|
-
puts
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|
122
|
-
:headings =>
|
123
|
-
:rows => rows
|
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
|