cfn-guardian 0.1.0 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dockerignore +1 -0
- data/.github/workflows/build-gem.yml +25 -0
- data/.github/workflows/release-gem.yml +25 -0
- data/.github/workflows/release-image.yml +33 -0
- data/.rspec +1 -0
- data/Dockerfile +19 -0
- data/Gemfile.lock +39 -21
- data/README.md +9 -378
- data/cfn-guardian.gemspec +7 -5
- data/docs/alarm_templates.md +130 -0
- data/docs/cli.md +182 -0
- data/docs/composite_alarms.md +24 -0
- data/docs/custom_checks/azure_file_check.md +28 -0
- data/docs/custom_checks/domain_expiry.md +10 -0
- data/docs/custom_checks/http.md +59 -0
- data/docs/custom_checks/log_group_metric_filters.md +27 -0
- data/docs/custom_checks/nrpe.md +29 -0
- data/docs/custom_checks/port.md +40 -0
- data/docs/custom_checks/sftp.md +73 -0
- data/docs/custom_checks/sql.md +44 -0
- data/docs/custom_checks/tls.md +25 -0
- data/docs/custom_metrics.md +71 -0
- data/docs/event_subscriptions.md +67 -0
- data/docs/maintenance_mode.md +85 -0
- data/docs/notifiers.md +33 -0
- data/docs/overview.md +22 -0
- data/docs/resources.md +93 -0
- data/docs/variables.md +58 -0
- data/lib/cfnguardian.rb +325 -37
- data/lib/cfnguardian/cloudwatch.rb +132 -0
- data/lib/cfnguardian/codecommit.rb +54 -0
- data/lib/cfnguardian/codepipeline.rb +138 -0
- data/lib/cfnguardian/compile.rb +142 -18
- data/lib/cfnguardian/config/defaults.yaml +103 -0
- data/lib/cfnguardian/deploy.rb +2 -16
- data/lib/cfnguardian/display_formatter.rb +163 -0
- data/lib/cfnguardian/drift.rb +79 -0
- data/lib/cfnguardian/error.rb +4 -0
- data/lib/cfnguardian/log.rb +0 -1
- data/lib/cfnguardian/models/alarm.rb +193 -59
- data/lib/cfnguardian/models/check.rb +128 -33
- data/lib/cfnguardian/models/composite.rb +21 -0
- data/lib/cfnguardian/models/event.rb +201 -49
- data/lib/cfnguardian/models/event_subscription.rb +96 -0
- data/lib/cfnguardian/models/metric_filter.rb +28 -0
- data/lib/cfnguardian/resources/amazonmq_rabbitmq.rb +136 -0
- data/lib/cfnguardian/resources/application_targetgroup.rb +2 -0
- data/lib/cfnguardian/resources/azure_file.rb +20 -0
- data/lib/cfnguardian/resources/base.rb +155 -33
- data/lib/cfnguardian/resources/ec2_instance.rb +11 -0
- data/lib/cfnguardian/resources/ecs_service.rb +2 -2
- data/lib/cfnguardian/resources/http.rb +17 -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_cluster.rb +14 -0
- data/lib/cfnguardian/resources/rds_instance.rb +73 -0
- data/lib/cfnguardian/resources/redshift_cluster.rb +2 -2
- data/lib/cfnguardian/resources/sftp.rb +50 -0
- data/lib/cfnguardian/resources/sql.rb +3 -3
- data/lib/cfnguardian/resources/tls.rb +66 -0
- data/lib/cfnguardian/s3.rb +3 -2
- data/lib/cfnguardian/stacks/main.rb +94 -72
- data/lib/cfnguardian/stacks/resources.rb +111 -43
- data/lib/cfnguardian/string.rb +12 -0
- data/lib/cfnguardian/version.rb +1 -1
- metadata +133 -10
@@ -0,0 +1,96 @@
|
|
1
|
+
module CfnGuardian
|
2
|
+
module Models
|
3
|
+
class BaseEventSubscription
|
4
|
+
|
5
|
+
attr_reader :type, :group
|
6
|
+
attr_writer :detail
|
7
|
+
attr_accessor :name,
|
8
|
+
:enabled,
|
9
|
+
:hash,
|
10
|
+
:topic,
|
11
|
+
:resource_id,
|
12
|
+
:resource_arn,
|
13
|
+
:source,
|
14
|
+
:detail_type,
|
15
|
+
:detail
|
16
|
+
|
17
|
+
def initialize(resource)
|
18
|
+
@type = 'EventSubscription'
|
19
|
+
@group = self.class.name.split('::').last
|
20
|
+
@name = ''
|
21
|
+
@hash = Digest::MD5.hexdigest resource['Id']
|
22
|
+
@enabled = true
|
23
|
+
@events = []
|
24
|
+
@topic = 'Events'
|
25
|
+
@resource_id = resource['Id']
|
26
|
+
@resource_arn = ''
|
27
|
+
@source = ''
|
28
|
+
@detail_type = ''
|
29
|
+
@detail = {}
|
30
|
+
end
|
31
|
+
|
32
|
+
def detail
|
33
|
+
return @detail
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class RDSEventSubscription < BaseEventSubscription
|
38
|
+
attr_accessor :source_id, :rds_event_category, :message
|
39
|
+
|
40
|
+
def initialize(resource)
|
41
|
+
super(resource)
|
42
|
+
@source = 'aws.rds'
|
43
|
+
@detail_type = 'RDS DB Instance Event'
|
44
|
+
@source_id = ''
|
45
|
+
@rds_event_category = ''
|
46
|
+
@message = ''
|
47
|
+
end
|
48
|
+
|
49
|
+
def detail
|
50
|
+
return {
|
51
|
+
EventCategories: [@rds_event_category],
|
52
|
+
SourceType: [@source_type],
|
53
|
+
SourceIdentifier: ["rds:#{@resource_id}"],
|
54
|
+
Message: [@message]
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class RDSInstanceEventSubscription < RDSEventSubscription
|
60
|
+
def initialize(resource)
|
61
|
+
super(resource)
|
62
|
+
@source_type = 'DB_INSTANCE'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class RDSClusterEventSubscription < RDSEventSubscription
|
67
|
+
def initialize(resource)
|
68
|
+
super(resource)
|
69
|
+
@source_type = 'DB_CLUSTER'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class Ec2InstanceEventSubscription < BaseEventSubscription
|
74
|
+
def initialize(resource)
|
75
|
+
super(resource)
|
76
|
+
@source = 'aws.ec2'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class ApiGatewayEventSubscription < BaseEventSubscription; end
|
81
|
+
class ApplicationTargetGroupEventSubscription < BaseEventSubscription; end
|
82
|
+
class AmazonMQBrokerEventSubscription < BaseEventSubscription; end
|
83
|
+
class CloudFrontDistributionEventSubscription < BaseEventSubscription; end
|
84
|
+
class AutoScalingGroupEventSubscription < BaseEventSubscription; end
|
85
|
+
class DynamoDBTableEventSubscription < BaseEventSubscription; end
|
86
|
+
class Ec2InstanceEventSubscription < BaseEventSubscription; end
|
87
|
+
class ECSClusterEventSubscription < BaseEventSubscription; end
|
88
|
+
class ECSServiceEventSubscription < BaseEventSubscription; end
|
89
|
+
class ElastiCacheReplicationGroupEventSubscription < BaseEventSubscription; end
|
90
|
+
class ElasticLoadBalancerEventSubscription < BaseEventSubscription; end
|
91
|
+
class ElasticFileSystemEventSubscription < BaseEventSubscription; end
|
92
|
+
class LambdaEventSubscription < BaseEventSubscription; end
|
93
|
+
class NetworkTargetGroupEventSubscription < BaseEventSubscription; end
|
94
|
+
class RedshiftClusterEventSubscription < BaseEventSubscription; end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'cfnguardian/string'
|
2
|
+
require 'digest/md5'
|
3
|
+
|
4
|
+
module CfnGuardian
|
5
|
+
module Models
|
6
|
+
class MetricFilter
|
7
|
+
|
8
|
+
attr_reader :type,
|
9
|
+
:metric_namespace,
|
10
|
+
:name
|
11
|
+
attr_accessor :log_group,
|
12
|
+
:pattern,
|
13
|
+
:metric_value,
|
14
|
+
:metric_name
|
15
|
+
|
16
|
+
def initialize(log_group,filter)
|
17
|
+
@type = 'MetricFilter'
|
18
|
+
@name = Digest::MD5.hexdigest(log_group + filter['MetricName'])
|
19
|
+
@log_group = log_group
|
20
|
+
@pattern = filter['Pattern']
|
21
|
+
@metric_value = filter.fetch('MetricValue', '1').to_s
|
22
|
+
@metric_name = filter['MetricName']
|
23
|
+
@metric_namespace = "MetricFilters"
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module CfnGuardian::Resource
|
2
|
+
class AmazonMQRabbitMQBroker < Base
|
3
|
+
|
4
|
+
def default_alarms
|
5
|
+
alarm = CfnGuardian::Models::AmazonMQRabbitMQBrokerAlarm.new(@resource)
|
6
|
+
alarm.name = 'ConnectionCountCritical'
|
7
|
+
alarm.metric_name = 'ConnectionCount'
|
8
|
+
alarm.comparison_operator = 'GreaterThanThreshold'
|
9
|
+
alarm.statistic = 'Maximum'
|
10
|
+
alarm.threshold = 50
|
11
|
+
alarm.evaluation_periods = 5
|
12
|
+
alarm.treat_missing_data = 'notBreaching'
|
13
|
+
@alarms.push(alarm)
|
14
|
+
|
15
|
+
alarm = CfnGuardian::Models::AmazonMQRabbitMQBrokerAlarm.new(@resource)
|
16
|
+
alarm.name = 'ConnectionCountWarn'
|
17
|
+
alarm.metric_name = 'ConnectionCount'
|
18
|
+
alarm.comparison_operator = 'GreaterThanThreshold'
|
19
|
+
alarm.statistic = 'Maximum'
|
20
|
+
alarm.threshold = 25
|
21
|
+
alarm.evaluation_periods = 5
|
22
|
+
alarm.treat_missing_data = 'notBreaching'
|
23
|
+
alarm.alarm_action = 'Warning'
|
24
|
+
@alarms.push(alarm)
|
25
|
+
|
26
|
+
alarm = CfnGuardian::Models::AmazonMQRabbitMQBrokerAlarm.new(@resource)
|
27
|
+
alarm.name = 'MessageCountCritical'
|
28
|
+
alarm.metric_name = 'MessageCount'
|
29
|
+
alarm.comparison_operator = 'GreaterThanThreshold'
|
30
|
+
alarm.statistic = 'Maximum'
|
31
|
+
alarm.threshold = 500
|
32
|
+
alarm.evaluation_periods = 5
|
33
|
+
alarm.treat_missing_data = 'notBreaching'
|
34
|
+
@alarms.push(alarm)
|
35
|
+
|
36
|
+
alarm = CfnGuardian::Models::AmazonMQRabbitMQBrokerAlarm.new(@resource)
|
37
|
+
alarm.name = 'MessageCountWarn'
|
38
|
+
alarm.metric_name = 'MessageCount'
|
39
|
+
alarm.comparison_operator = 'GreaterThanThreshold'
|
40
|
+
alarm.statistic = 'Maximum'
|
41
|
+
alarm.threshold = 250
|
42
|
+
alarm.evaluation_periods = 5
|
43
|
+
alarm.treat_missing_data = 'notBreaching'
|
44
|
+
alarm.alarm_action = 'Warning'
|
45
|
+
@alarms.push(alarm)
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class AmazonMQRabbitMQQueue < Base
|
51
|
+
|
52
|
+
def default_alarms
|
53
|
+
|
54
|
+
alarm = CfnGuardian::Models::AmazonMQRabbitMQQueueAlarm.new(@resource)
|
55
|
+
alarm.name = 'MessageCountHighWarn'
|
56
|
+
alarm.metric_name = 'MessageCount'
|
57
|
+
alarm.comparison_operator = 'GreaterThanThreshold'
|
58
|
+
alarm.statistic = 'Maximum'
|
59
|
+
alarm.threshold = 100
|
60
|
+
alarm.evaluation_periods = 5
|
61
|
+
alarm.treat_missing_data = 'notBreaching'
|
62
|
+
alarm.alarm_action = 'Warning'
|
63
|
+
@alarms.push(alarm)
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class AmazonMQRabbitMQNode < Base
|
69
|
+
|
70
|
+
def default_alarms
|
71
|
+
alarm = CfnGuardian::Models::AmazonMQRabbitMQNodeAlarm.new(@resource)
|
72
|
+
alarm.name = 'SystemCpuUtilizationCritical'
|
73
|
+
alarm.metric_name = 'SystemCpuUtilization'
|
74
|
+
alarm.comparison_operator = 'GreaterThanThreshold'
|
75
|
+
alarm.statistic = 'Maximum'
|
76
|
+
alarm.threshold = 95
|
77
|
+
alarm.evaluation_periods = 10
|
78
|
+
alarm.treat_missing_data = 'notBreaching'
|
79
|
+
@alarms.push(alarm)
|
80
|
+
|
81
|
+
alarm = CfnGuardian::Models::AmazonMQRabbitMQNodeAlarm.new(@resource)
|
82
|
+
alarm.name = 'SystemCpuUtilizationHighBase'
|
83
|
+
alarm.metric_name = 'SystemCpuUtilization'
|
84
|
+
alarm.comparison_operator = 'GreaterThanThreshold'
|
85
|
+
alarm.statistic = 'Maximum'
|
86
|
+
alarm.threshold = 75
|
87
|
+
alarm.evaluation_periods = 30
|
88
|
+
alarm.treat_missing_data = 'notBreaching'
|
89
|
+
alarm.alarm_action = 'Warning'
|
90
|
+
@alarms.push(alarm)
|
91
|
+
|
92
|
+
alarm = CfnGuardian::Models::AmazonMQRabbitMQNodeAlarm.new(@resource)
|
93
|
+
alarm.name = 'RabbitMQMemUsedCritical'
|
94
|
+
alarm.metric_name = 'RabbitMQMemUsed'
|
95
|
+
alarm.comparison_operator = 'GreaterThanThreshold'
|
96
|
+
alarm.statistic = 'Maximum'
|
97
|
+
alarm.threshold = 390000000
|
98
|
+
alarm.evaluation_periods = 5
|
99
|
+
alarm.treat_missing_data = 'notBreaching'
|
100
|
+
@alarms.push(alarm)
|
101
|
+
|
102
|
+
alarm = CfnGuardian::Models::AmazonMQRabbitMQNodeAlarm.new(@resource)
|
103
|
+
alarm.name = 'RabbitMQMemUsedWarn'
|
104
|
+
alarm.metric_name = 'RabbitMQMemUsed'
|
105
|
+
alarm.comparison_operator = 'GreaterThanThreshold'
|
106
|
+
alarm.statistic = 'Maximum'
|
107
|
+
alarm.threshold = 350000000
|
108
|
+
alarm.evaluation_periods = 5
|
109
|
+
alarm.treat_missing_data = 'notBreaching'
|
110
|
+
alarm.alarm_action = 'Warning'
|
111
|
+
@alarms.push(alarm)
|
112
|
+
|
113
|
+
alarm = CfnGuardian::Models::AmazonMQRabbitMQNodeAlarm.new(@resource)
|
114
|
+
alarm.name = 'RabbitMQDiskFreeLimitCritical'
|
115
|
+
alarm.metric_name = 'RabbitMQDiskFreeLimit'
|
116
|
+
alarm.comparison_operator = 'LessThanThreshold'
|
117
|
+
alarm.statistic = 'Maximum'
|
118
|
+
alarm.threshold = 1200000000
|
119
|
+
alarm.evaluation_periods = 5
|
120
|
+
alarm.treat_missing_data = 'notBreaching'
|
121
|
+
@alarms.push(alarm)
|
122
|
+
|
123
|
+
alarm = CfnGuardian::Models::AmazonMQRabbitMQNodeAlarm.new(@resource)
|
124
|
+
alarm.name = 'RabbitMQDiskFreeLimitWarn'
|
125
|
+
alarm.metric_name = 'RabbitMQDiskFreeLimit'
|
126
|
+
alarm.comparison_operator = 'LessThanThreshold'
|
127
|
+
alarm.statistic = 'Maximum'
|
128
|
+
alarm.threshold = 1200000000
|
129
|
+
alarm.evaluation_periods = 5
|
130
|
+
alarm.treat_missing_data = 'notBreaching'
|
131
|
+
alarm.alarm_action = 'Warning'
|
132
|
+
@alarms.push(alarm)
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -5,9 +5,11 @@ module CfnGuardian::Resource
|
|
5
5
|
alarm = CfnGuardian::Models::ApplicationTargetGroupAlarm.new(@resource)
|
6
6
|
alarm.name = 'HealthyHosts'
|
7
7
|
alarm.metric_name = 'HealthyHostCount'
|
8
|
+
alarm.comparison_operator = 'LessThanThreshold'
|
8
9
|
alarm.statistic = 'Minimum'
|
9
10
|
alarm.threshold = 2
|
10
11
|
alarm.evaluation_periods = 1
|
12
|
+
alarm.comparison_operator = 'LessThanThreshold'
|
11
13
|
@alarms.push(alarm)
|
12
14
|
|
13
15
|
alarm = CfnGuardian::Models::ApplicationTargetGroupAlarm.new(@resource)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CfnGuardian::Resource
|
2
|
+
class AzureFile < Base
|
3
|
+
|
4
|
+
def default_alarms
|
5
|
+
alarm = CfnGuardian::Models::AzureFileAlarm.new(@resource)
|
6
|
+
alarm.name = 'FileExpired'
|
7
|
+
alarm.metric_name = 'FileExpired'
|
8
|
+
@alarms.push(alarm)
|
9
|
+
end
|
10
|
+
|
11
|
+
def default_events
|
12
|
+
@events.push(CfnGuardian::Models::AzureFileEvent.new(@resource))
|
13
|
+
end
|
14
|
+
|
15
|
+
def default_checks
|
16
|
+
@checks.push(CfnGuardian::Models::AzureFileCheck.new(@resource))
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -1,95 +1,208 @@
|
|
1
1
|
require 'cfnguardian/string'
|
2
|
+
require 'cfnguardian/cloudwatch'
|
2
3
|
require 'cfnguardian/models/alarm'
|
3
4
|
require 'cfnguardian/models/event'
|
4
5
|
require 'cfnguardian/models/check'
|
6
|
+
require 'cfnguardian/models/metric_filter'
|
7
|
+
require 'cfnguardian/models/event_subscription'
|
5
8
|
|
6
9
|
module CfnGuardian::Resource
|
7
10
|
class Base
|
8
11
|
include Logging
|
9
12
|
|
10
|
-
def initialize(resource)
|
13
|
+
def initialize(resource, override_group = nil)
|
11
14
|
@resource = resource
|
15
|
+
@override_group = override_group
|
12
16
|
@alarms = []
|
13
17
|
@events = []
|
14
18
|
@checks = []
|
19
|
+
@metric_filters = []
|
20
|
+
@event_subscriptions = []
|
15
21
|
end
|
16
22
|
|
23
|
+
# Overidden by inheritted classes to define default alarms
|
17
24
|
def default_alarms()
|
18
25
|
return @alarms
|
19
26
|
end
|
20
27
|
|
21
|
-
def get_alarms(overides={})
|
28
|
+
def get_alarms(group,overides={})
|
22
29
|
# generate default alarms
|
23
30
|
default_alarms()
|
24
|
-
|
31
|
+
|
32
|
+
# override any group properties
|
33
|
+
group_overrides = overides.has_key?('GroupOverrides') ? overides['GroupOverrides'] : {}
|
34
|
+
overides.delete('GroupOverrides')
|
35
|
+
if group_overrides.any?
|
36
|
+
@alarms.each do |alarm|
|
37
|
+
logger.debug("overriding #{alarm.name} alarm properties for resource #{alarm.resource_id} in resource group #{group} via group overrides")
|
38
|
+
group_overrides.each {|attr,value| update_object(alarm,attr,value)}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
25
42
|
# loop over each override template for the service
|
26
|
-
overides.each do |name,properties|
|
27
|
-
|
43
|
+
overides.each do |name,properties|
|
28
44
|
# disable default alarms
|
29
45
|
if [false].include?(properties)
|
30
|
-
|
46
|
+
alarms = find_alarms(name)
|
31
47
|
|
32
|
-
if !
|
33
|
-
|
34
|
-
|
48
|
+
if !alarms.nil?
|
49
|
+
alarms.each do |alarm|
|
50
|
+
alarm.enabled = false
|
51
|
+
logger.info "disabling alarm '#{name}' for resource #{alarm.resource_id}"
|
52
|
+
end
|
35
53
|
next
|
36
54
|
end
|
37
55
|
end
|
38
|
-
|
56
|
+
|
57
|
+
# continue if the override is in the incorrect format
|
39
58
|
unless properties.is_a?(Hash)
|
40
59
|
if name != 'Inherit'
|
41
|
-
logger.warn "
|
60
|
+
logger.warn "incorrect format for alarm '#{name}'. Should be of type 'Hash', instead got type '#{properties.group}'"
|
42
61
|
end
|
43
62
|
next
|
44
63
|
end
|
45
|
-
|
64
|
+
|
65
|
+
properties.merge!(group_overrides)
|
66
|
+
|
67
|
+
# Create a new alarm inheriting the defaults of an existing alarm
|
46
68
|
if properties.has_key?('Inherit')
|
47
69
|
alarm = find_alarm(properties['Inherit'])
|
48
70
|
if !alarm.nil?
|
71
|
+
logger.debug("creating new alarm #{name} for alarm group #{self.class.to_s.split('::').last} inheriting properties from alarm #{properties['Inherit']}")
|
49
72
|
inheritited_alarm = alarm.clone
|
50
73
|
alarm.name = name
|
51
|
-
properties.each {|attr,value|
|
74
|
+
properties.each {|attr,value| update_object(inheritited_alarm,attr,value)}
|
52
75
|
@alarms.push(inheritited_alarm)
|
53
76
|
else
|
54
|
-
logger.warn "
|
77
|
+
logger.warn "alarm '#{properties['Inherit']}' doesn't exists and cannot be inherited"
|
55
78
|
end
|
56
79
|
next
|
57
80
|
end
|
58
81
|
|
59
|
-
|
60
|
-
|
61
|
-
if
|
62
|
-
alarm
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
82
|
+
alarms = find_alarms(name)
|
83
|
+
|
84
|
+
if alarms.empty?
|
85
|
+
# if the alarm doesn't exist and it's not being inherited from another alarm create a new alarm
|
86
|
+
resources = @resource.has_key?('Hosts') ? @resource['Hosts'] : [@resource]
|
87
|
+
resources.each do |res|
|
88
|
+
alarm = Kernel.const_get("CfnGuardian::Models::#{self.class.to_s.split('::').last}Alarm").new(res)
|
89
|
+
properties.each {|attr,value| update_object(alarm,attr,value)}
|
90
|
+
alarm.name = name
|
91
|
+
logger.debug("created new alarm #{alarm.name} for resource #{alarm.resource_id} in resource group #{group}")
|
92
|
+
@alarms.push(alarm)
|
93
|
+
end
|
94
|
+
else
|
95
|
+
# if there is an existing alarm update the properties
|
96
|
+
alarms.each do |alarm|
|
97
|
+
logger.debug("overriding #{alarm.name} alarm properties for resource #{alarm.resource_id} in resource group #{group} via alarm overrides")
|
98
|
+
properties.each {|attr,value| update_object(alarm,attr,value)}
|
99
|
+
end
|
67
100
|
end
|
68
|
-
|
69
|
-
properties.each {|attr,value| update_alarm(alarm,attr,value)}
|
70
|
-
@alarms.push(alarm)
|
71
|
-
|
72
101
|
end
|
73
102
|
|
74
|
-
|
103
|
+
unless @override_group.nil?
|
104
|
+
@alarms.each {|a| a.group = @override_group}
|
105
|
+
end
|
106
|
+
|
107
|
+
# String interpolation for alarm dimensions
|
108
|
+
@alarms.each do |alarm|
|
109
|
+
next if alarm.dimensions.nil?
|
110
|
+
alarm.dimensions.each do |k,v|
|
111
|
+
if v.match?(/^\${Resource::.*[A-Za-z]}$/)
|
112
|
+
resource_key = v.tr('${}', '').split('Resource::').last
|
113
|
+
if @resource.has_key?(resource_key)
|
114
|
+
logger.debug "overriding alarm #{alarm.name} dimension key '#{k}' with value '#{@resource[resource_key]}'"
|
115
|
+
alarm.dimensions[k] = @resource[resource_key]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
return @alarms.select{|a| a.enabled}
|
75
122
|
end
|
76
123
|
|
124
|
+
# Overidden by inheritted classes to define default events
|
77
125
|
def default_events()
|
78
126
|
return @events
|
79
127
|
end
|
80
128
|
|
81
129
|
def get_events()
|
82
130
|
default_events()
|
83
|
-
return @events.select{|e| e.enabled}
|
131
|
+
return @events.select{|e| e.enabled}
|
84
132
|
end
|
85
133
|
|
134
|
+
# Overidden by inheritted classes to define default checks
|
86
135
|
def default_checks()
|
87
136
|
return @checks
|
88
137
|
end
|
89
138
|
|
90
139
|
def get_checks()
|
91
140
|
default_checks()
|
92
|
-
return @checks
|
141
|
+
return @checks
|
142
|
+
end
|
143
|
+
|
144
|
+
# Overidden by inheritted classes to define default checks
|
145
|
+
def default_metric_filters()
|
146
|
+
return @metric_filters
|
147
|
+
end
|
148
|
+
|
149
|
+
def get_metric_filters()
|
150
|
+
default_metric_filters()
|
151
|
+
return @metric_filters
|
152
|
+
end
|
153
|
+
|
154
|
+
# Overidden by inheritted classes to define default checks
|
155
|
+
def default_event_subscriptions()
|
156
|
+
return @event_subscriptions
|
157
|
+
end
|
158
|
+
|
159
|
+
def get_event_subscriptions(group, overides)
|
160
|
+
# generate defailt event subscriptions
|
161
|
+
default_event_subscriptions()
|
162
|
+
|
163
|
+
# overide the defaults
|
164
|
+
overides.each do |name, properties|
|
165
|
+
event_subscription = find_event_subscriptions(name)
|
166
|
+
|
167
|
+
# disbable the event subscription if the value is false
|
168
|
+
if [false].include?(properties)
|
169
|
+
unless event_subscription.nil?
|
170
|
+
event_subscription.enabled = false
|
171
|
+
logger.info "Disabling event subscription #{name} for #{group} #{event_subscription.resource_id}"
|
172
|
+
end
|
173
|
+
|
174
|
+
next
|
175
|
+
end
|
176
|
+
|
177
|
+
# ignore all properties not in a proper format
|
178
|
+
next unless properties.is_a?(Hash)
|
179
|
+
|
180
|
+
# Create a new event subscription by inheriting an existing one
|
181
|
+
if properties.has_key?('Inherit')
|
182
|
+
inherit_event_subscription = find_event_subscriptions(properties['Inherit'])
|
183
|
+
|
184
|
+
if inherit_event_subscription.nil?
|
185
|
+
logger.warn "Unable to create #{topic} RDSEventSubscription by inheriting #{properties['Inherit']} as it cannot be found"
|
186
|
+
next
|
187
|
+
end
|
188
|
+
|
189
|
+
event_subscription = inherit_event_subscription.clone
|
190
|
+
event_subscription.enabled = true
|
191
|
+
event_subscription.name = name
|
192
|
+
@event_subscriptions.push(event_subscription)
|
193
|
+
logger.debug "Inheriting RDSEventSubscription #{properties['Inherit']}"
|
194
|
+
end
|
195
|
+
|
196
|
+
if event_subscription.nil?
|
197
|
+
event_subscription = Kernel.const_get("CfnGuardian::Models::#{self.class.to_s.split('::').last}EventSubscription").new(@resource)
|
198
|
+
event_subscription.name = name
|
199
|
+
@event_subscriptions.push(event_subscription)
|
200
|
+
end
|
201
|
+
|
202
|
+
properties.each {|attr,value| update_object(event_subscription,attr,value)}
|
203
|
+
end
|
204
|
+
|
205
|
+
return @event_subscriptions.select {|es| es.enabled }
|
93
206
|
end
|
94
207
|
|
95
208
|
def get_cost()
|
@@ -101,13 +214,22 @@ module CfnGuardian::Resource
|
|
101
214
|
def find_alarm(name)
|
102
215
|
@alarms.detect {|alarm| alarm.name == name}
|
103
216
|
end
|
104
|
-
|
105
|
-
def
|
217
|
+
|
218
|
+
def find_alarms(name)
|
219
|
+
@alarms.find_all {|alarm| alarm.name == name}
|
220
|
+
end
|
221
|
+
|
222
|
+
def find_event_subscriptions(name)
|
223
|
+
@event_subscriptions.detect {|es| es.name == name}
|
224
|
+
end
|
225
|
+
|
226
|
+
def update_object(obj,attr,value)
|
227
|
+
logger.debug("overriding #{obj.type} property '#{attr}' with value #{value} for resource id: #{obj.resource_id}")
|
106
228
|
begin
|
107
|
-
|
229
|
+
obj.send("#{attr.to_underscore}=",value.clone)
|
108
230
|
rescue NoMethodError => e
|
109
231
|
if !e.message.match?(/inherit/)
|
110
|
-
logger.warn "Unknown
|
232
|
+
logger.warn "Unknown property '#{attr}' for type: #{obj.type} and resource id: #{obj.resource_id}"
|
111
233
|
end
|
112
234
|
end
|
113
235
|
end
|