cfn-guardian 0.1.0 → 0.6.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/.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,132 @@
|
|
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_by_prefix(prefix:, state: nil, action_prefix: nil)
|
14
|
+
client = Aws::CloudWatch::Client.new()
|
15
|
+
options = {max_records: 100}
|
16
|
+
options[:alarm_name_prefix] = prefix
|
17
|
+
|
18
|
+
unless state.nil?
|
19
|
+
options[:state_value] = state
|
20
|
+
end
|
21
|
+
|
22
|
+
unless action_prefix.nil?
|
23
|
+
options[:action_prefix] = action_prefix
|
24
|
+
end
|
25
|
+
|
26
|
+
resp = client.describe_alarms(options)
|
27
|
+
return resp.metric_alarms
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.get_alarms_by_name(alarm_names:, state: nil, action_prefix: nil)
|
31
|
+
client = Aws::CloudWatch::Client.new()
|
32
|
+
options = {max_records: 100}
|
33
|
+
|
34
|
+
unless state.nil?
|
35
|
+
options[:state_value] = state
|
36
|
+
end
|
37
|
+
|
38
|
+
unless action_prefix.nil?
|
39
|
+
options[:action_prefix] = "arn:aws:sns:#{Aws.config[:region]}:#{aws_account_id()}:#{action_prefix}"
|
40
|
+
end
|
41
|
+
|
42
|
+
metric_alarms = []
|
43
|
+
alarm_names.each_slice(100) do |batch|
|
44
|
+
options[:alarm_names] = batch
|
45
|
+
resp = client.describe_alarms(options)
|
46
|
+
metric_alarms.push(*resp.metric_alarms)
|
47
|
+
end
|
48
|
+
|
49
|
+
return metric_alarms
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.filter_alarms(filters:, alarms:)
|
53
|
+
return alarms unless filters.is_a?(Hash)
|
54
|
+
filters = filters.slice('group', 'resource', 'alarm', 'stack-id')
|
55
|
+
|
56
|
+
filtered_alarms = []
|
57
|
+
alarms.each do |alarm|
|
58
|
+
if filters.values.all? {|filter| alarm.alarm_name.include? (filter)}
|
59
|
+
filtered_alarms << alarm
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
return filtered_alarms
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.get_alarm_history(alarm_name,type)
|
67
|
+
client = Aws::CloudWatch::Client.new()
|
68
|
+
|
69
|
+
logger.debug "Searching #{type} history for #{alarm_name}"
|
70
|
+
|
71
|
+
resp = client.describe_alarm_history({
|
72
|
+
alarm_name: alarm_name,
|
73
|
+
history_item_type: type,
|
74
|
+
start_date: (Time.now.utc.to_date - 7),
|
75
|
+
end_date: (Time.now.utc.to_date + 1),
|
76
|
+
max_records: 100
|
77
|
+
})
|
78
|
+
|
79
|
+
return resp.alarm_history_items
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.get_alarm_names(action_prefix=nil,alarm_name_prefix='guardian')
|
83
|
+
alarms = []
|
84
|
+
client = Aws::CloudWatch::Client.new
|
85
|
+
|
86
|
+
options = {
|
87
|
+
alarm_types: ["CompositeAlarm","MetricAlarm"],
|
88
|
+
alarm_name_prefix: alarm_name_prefix
|
89
|
+
}
|
90
|
+
|
91
|
+
unless action_prefix.nil?
|
92
|
+
options[:action_prefix] = "arn:aws:sns:#{Aws.config[:region]}:#{aws_account_id()}:#{action_prefix}"
|
93
|
+
end
|
94
|
+
|
95
|
+
client.describe_alarms(options).each do |response|
|
96
|
+
alarms.concat response.composite_alarms.map(&:alarm_name)
|
97
|
+
alarms.concat response.metric_alarms.map(&:alarm_name)
|
98
|
+
end
|
99
|
+
|
100
|
+
return alarms
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.disable_alarms(alarms)
|
104
|
+
client = Aws::CloudWatch::Client.new
|
105
|
+
alarms.each_slice(100) do |batch|
|
106
|
+
client.disable_alarm_actions({alarm_names: batch})
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.enable_alarms(alarms)
|
111
|
+
client = Aws::CloudWatch::Client.new
|
112
|
+
alarms.each_slice(100) do |batch|
|
113
|
+
client.enable_alarm_actions({alarm_names: batch})
|
114
|
+
end
|
115
|
+
|
116
|
+
alarms.each do |alarm|
|
117
|
+
client.set_alarm_state({
|
118
|
+
alarm_name: alarm,
|
119
|
+
state_value: "OK",
|
120
|
+
state_reason: "End of guardian maintenance peroid"
|
121
|
+
})
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.aws_account_id()
|
126
|
+
sts = Aws::STS::Client.new
|
127
|
+
account = sts.get_caller_identity().account
|
128
|
+
return account
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'aws-sdk-codecommit'
|
2
|
+
require 'time'
|
3
|
+
require 'cfnguardian/log'
|
4
|
+
|
5
|
+
module CfnGuardian
|
6
|
+
class CodeCommit
|
7
|
+
include Logging
|
8
|
+
|
9
|
+
def initialize(repo_name)
|
10
|
+
@repo_name = repo_name
|
11
|
+
@client = Aws::CodeCommit::Client.new()
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_last_commit(branch='master')
|
15
|
+
resp = @client.get_branch({
|
16
|
+
repository_name: @repo_name,
|
17
|
+
branch_name: branch,
|
18
|
+
})
|
19
|
+
return resp.branch.commit_id
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_commit_history(branch='master',count=10)
|
23
|
+
history = []
|
24
|
+
commit = get_last_commit(branch)
|
25
|
+
|
26
|
+
count.times do
|
27
|
+
|
28
|
+
resp = @client.get_commit({
|
29
|
+
repository_name: @repo_name,
|
30
|
+
commit_id: commit
|
31
|
+
})
|
32
|
+
|
33
|
+
time = Time.strptime(resp.commit.committer.date,'%s')
|
34
|
+
|
35
|
+
history << {
|
36
|
+
message: resp.commit.message,
|
37
|
+
author: resp.commit.author.name,
|
38
|
+
date: time.localtime.strftime("%d/%m/%Y %I:%M %p"),
|
39
|
+
id: resp.commit.commit_id
|
40
|
+
}
|
41
|
+
|
42
|
+
if resp.commit.parents.any?
|
43
|
+
commit = resp.commit.parents.first
|
44
|
+
else
|
45
|
+
break
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
return history
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'aws-sdk-codepipeline'
|
2
|
+
require 'time'
|
3
|
+
require 'cfnguardian/log'
|
4
|
+
|
5
|
+
module CfnGuardian
|
6
|
+
class CodePipeline
|
7
|
+
include Logging
|
8
|
+
|
9
|
+
def initialize(pipeline_name)
|
10
|
+
@pipeline_name = pipeline_name
|
11
|
+
client = Aws::CodePipeline::Client.new()
|
12
|
+
@pipeline = client.get_pipeline_state({
|
13
|
+
name: @pipeline_name
|
14
|
+
})
|
15
|
+
end
|
16
|
+
|
17
|
+
def retry()
|
18
|
+
resp = client.start_pipeline_execution({
|
19
|
+
name: @pipeline_name,
|
20
|
+
client_request_token: "ClientRequestToken",
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_stage(stage_name)
|
25
|
+
return @pipeline.stage_states.find {|stage| stage.stage_name == stage_name}
|
26
|
+
end
|
27
|
+
|
28
|
+
def colour_rows(rows, status)
|
29
|
+
if status == 'Failed'
|
30
|
+
rows.map! {|row| row.map! {|r| r.red } }
|
31
|
+
elsif status == 'Succeeded'
|
32
|
+
rows.map! {|row| row.map! {|r| r.green } }
|
33
|
+
elsif status == 'InProgress'
|
34
|
+
rows.map! {|row| row.map! {|r| r.blue } }
|
35
|
+
elsif ["Stopped", "Stopping"].include? status
|
36
|
+
rows.map! {|row| row.map! {|r| r.yellow } }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_source()
|
41
|
+
source_stage = get_stage("Source")
|
42
|
+
action = source_stage.action_states.first
|
43
|
+
status = source_stage.latest_execution.status
|
44
|
+
state = {
|
45
|
+
stage: action.action_name,
|
46
|
+
rows: [
|
47
|
+
['Status', status],
|
48
|
+
['Commit', action.current_revision.revision_id],
|
49
|
+
['Last Status Change', action.latest_execution.last_status_change.localtime.strftime("%d/%m/%Y %I:%M %p")]
|
50
|
+
]
|
51
|
+
}
|
52
|
+
|
53
|
+
unless action.latest_execution.error_details.nil?
|
54
|
+
state[:rows].push(
|
55
|
+
['Error Message', action.latest_execution.error_details.message]
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
colour_rows(state[:rows],status)
|
60
|
+
|
61
|
+
return state
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_build()
|
65
|
+
source_stage = get_stage("Build")
|
66
|
+
action = source_stage.action_states.first
|
67
|
+
status = source_stage.latest_execution.status
|
68
|
+
state = {
|
69
|
+
stage: action.action_name,
|
70
|
+
rows: [
|
71
|
+
['Status', status],
|
72
|
+
['Build Id', action.latest_execution.external_execution_id],
|
73
|
+
['Last Status Change', action.latest_execution.last_status_change.localtime.strftime("%d/%m/%Y %I:%M %p")],
|
74
|
+
['Logs', action.latest_execution.external_execution_url]
|
75
|
+
]
|
76
|
+
}
|
77
|
+
|
78
|
+
unless action.latest_execution.error_details.nil?
|
79
|
+
state[:rows].push(
|
80
|
+
['Error Message', action.latest_execution.error_details.message]
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
colour_rows(state[:rows],status)
|
85
|
+
|
86
|
+
return state
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_create_changeset()
|
90
|
+
source_stage = get_stage("Deploy")
|
91
|
+
action = source_stage.action_states.find {|action| action.action_name == "CreateChangeSet"}
|
92
|
+
status = source_stage.latest_execution.status
|
93
|
+
state = {
|
94
|
+
stage: action.action_name,
|
95
|
+
rows: [
|
96
|
+
['Status', status],
|
97
|
+
['Summary', action.latest_execution.summary],
|
98
|
+
['Last Status Change', action.latest_execution.last_status_change.localtime.strftime("%d/%m/%Y %I:%M %p")],
|
99
|
+
]
|
100
|
+
}
|
101
|
+
|
102
|
+
unless action.latest_execution.error_details.nil?
|
103
|
+
state[:rows].push(
|
104
|
+
['Error Message', action.latest_execution.error_details.message]
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
colour_rows(state[:rows],status)
|
109
|
+
|
110
|
+
return state
|
111
|
+
end
|
112
|
+
|
113
|
+
def get_deploy_changeset()
|
114
|
+
source_stage = get_stage("Deploy")
|
115
|
+
action = source_stage.action_states.find {|action| action.action_name == "DeployChangeSet"}
|
116
|
+
status = source_stage.latest_execution.status
|
117
|
+
state = {
|
118
|
+
stage: action.action_name,
|
119
|
+
rows: [
|
120
|
+
['Status', status],
|
121
|
+
['Summary', action.latest_execution.summary],
|
122
|
+
['Last Status Change', action.latest_execution.last_status_change.localtime.strftime("%d/%m/%Y %I:%M %p")],
|
123
|
+
]
|
124
|
+
}
|
125
|
+
|
126
|
+
unless action.latest_execution.error_details.nil?
|
127
|
+
state[:rows].push(
|
128
|
+
['Error Message', action.latest_execution.error_details.message]
|
129
|
+
)
|
130
|
+
end
|
131
|
+
|
132
|
+
colour_rows(state[:rows],status)
|
133
|
+
|
134
|
+
return state
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
data/lib/cfnguardian/compile.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'fileutils'
|
2
3
|
require 'cfnguardian/string'
|
3
4
|
require 'cfnguardian/stacks/resources'
|
4
5
|
require 'cfnguardian/stacks/main'
|
6
|
+
require 'cfnguardian/models/composite'
|
5
7
|
require 'cfnguardian/resources/base'
|
6
8
|
require 'cfnguardian/resources/apigateway'
|
7
9
|
require 'cfnguardian/resources/application_targetgroup'
|
@@ -18,6 +20,9 @@ require 'cfnguardian/resources/elastic_file_system'
|
|
18
20
|
require 'cfnguardian/resources/elasticache_replication_group'
|
19
21
|
require 'cfnguardian/resources/elastic_loadbalancer'
|
20
22
|
require 'cfnguardian/resources/http'
|
23
|
+
require 'cfnguardian/resources/internal_http'
|
24
|
+
require 'cfnguardian/resources/port'
|
25
|
+
require 'cfnguardian/resources/internal_port'
|
21
26
|
require 'cfnguardian/resources/nrpe'
|
22
27
|
require 'cfnguardian/resources/lambda'
|
23
28
|
require 'cfnguardian/resources/network_targetgroup'
|
@@ -26,24 +31,41 @@ require 'cfnguardian/resources/rds_instance'
|
|
26
31
|
require 'cfnguardian/resources/redshift_cluster'
|
27
32
|
require 'cfnguardian/resources/sql'
|
28
33
|
require 'cfnguardian/resources/sqs_queue'
|
34
|
+
require 'cfnguardian/resources/log_group'
|
35
|
+
require 'cfnguardian/resources/sftp'
|
36
|
+
require 'cfnguardian/resources/internal_sftp'
|
37
|
+
require 'cfnguardian/resources/tls'
|
38
|
+
require 'cfnguardian/resources/azure_file'
|
39
|
+
require 'cfnguardian/resources/amazonmq_rabbitmq'
|
40
|
+
require 'cfnguardian/version'
|
41
|
+
require 'cfnguardian/error'
|
29
42
|
|
30
43
|
module CfnGuardian
|
31
44
|
class Compile
|
32
45
|
include Logging
|
33
46
|
|
34
|
-
attr_reader :cost, :resources
|
47
|
+
attr_reader :cost, :resources, :topics
|
35
48
|
|
36
|
-
def initialize(
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
config = YAML.load_file(opts.fetch(:config))
|
49
|
+
def initialize(config_file)
|
50
|
+
config = YAML.load_file(config_file)
|
51
|
+
|
41
52
|
@resource_groups = config.fetch('Resources',{})
|
53
|
+
@composites = config.fetch('Composites',{})
|
42
54
|
@templates = config.fetch('Templates',{})
|
55
|
+
@topics = config.fetch('Topics',{})
|
56
|
+
@maintenance_groups = config.fetch('MaintenaceGroups', {})
|
57
|
+
@event_subscriptions = config.fetch('EventSubscriptions', {})
|
43
58
|
|
59
|
+
# Make sure the default topics exist if they aren't supplied in the alarms.yaml
|
60
|
+
%w(Critical Warning Task Informational Events).each do |topic|
|
61
|
+
@topics[topic] = '' unless @topics.has_key?(topic)
|
62
|
+
end
|
63
|
+
|
64
|
+
@maintenance_group_list = @maintenance_groups.keys.map {|group| "#{group}MaintenanceGroup"}
|
44
65
|
@resources = []
|
45
66
|
@stacks = []
|
46
67
|
@checks = []
|
68
|
+
@ssm_parameters = []
|
47
69
|
|
48
70
|
@cost = 0
|
49
71
|
end
|
@@ -57,7 +79,7 @@ module CfnGuardian
|
|
57
79
|
rescue NameError => e
|
58
80
|
if @templates.has_key?(group) && @templates[group].has_key?('Inherit')
|
59
81
|
begin
|
60
|
-
resource_class = Kernel.const_get("CfnGuardian::Resource::#{@templates[group]['Inherit']}").new(resource)
|
82
|
+
resource_class = Kernel.const_get("CfnGuardian::Resource::#{@templates[group]['Inherit']}").new(resource, group)
|
61
83
|
logger.debug "Inheritited resource group #{@templates[group]['Inherit']} for group #{group}"
|
62
84
|
rescue NameError => e
|
63
85
|
logger.warn "'#{@templates[group]['Inherit']}' resource group doesn't exist and is unable to be inherited from"
|
@@ -69,41 +91,106 @@ module CfnGuardian
|
|
69
91
|
end
|
70
92
|
end
|
71
93
|
|
72
|
-
|
73
|
-
@resources.concat resource_class.get_alarms(
|
94
|
+
template_overides = @templates.has_key?(group) ? @templates[group] : {}
|
95
|
+
@resources.concat resource_class.get_alarms(group,template_overides)
|
96
|
+
|
97
|
+
@resources.concat resource_class.get_metric_filters()
|
74
98
|
@resources.concat resource_class.get_events()
|
99
|
+
|
100
|
+
event_subscriptions = @event_subscriptions.has_key?(group) ? @event_subscriptions[group] : {}
|
101
|
+
@resources.concat resource_class.get_event_subscriptions(group,event_subscriptions)
|
102
|
+
|
75
103
|
@checks.concat resource_class.get_checks()
|
76
104
|
|
77
105
|
@cost += resource_class.get_cost
|
78
106
|
end
|
79
107
|
end
|
108
|
+
|
109
|
+
@maintenance_groups.each do |maintenance_group,resource_groups|
|
110
|
+
resource_groups.each do |group, alarms|
|
111
|
+
alarms.each do |alarm, resources|
|
112
|
+
resources.each do |resource|
|
113
|
+
|
114
|
+
res = @resources.find {|r|
|
115
|
+
(r.type == 'Alarm') &&
|
116
|
+
(r.group == group && r.name == alarm) &&
|
117
|
+
(r.resource_id == resource['Id'] || r.resource_name == resource['Name'])}
|
118
|
+
|
119
|
+
unless res.nil?
|
120
|
+
res.maintenance_groups.append("#{maintenance_group}MaintenanceGroup")
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
@composites.each do |name,params|
|
129
|
+
@resources.push CfnGuardian::Models::Composite.new(name,params)
|
130
|
+
@cost += 0.50
|
131
|
+
end
|
132
|
+
|
133
|
+
@ssm_parameters = @resources.select {|resource| resource.type == 'Event'}.map {|event| event.ssm_parameters}.flatten.uniq
|
134
|
+
|
135
|
+
validate_resources()
|
80
136
|
end
|
81
137
|
|
82
|
-
def
|
138
|
+
def alarms
|
139
|
+
@resources.select {|resource| resource.type == 'Alarm'}
|
140
|
+
end
|
141
|
+
|
142
|
+
def validate_resources()
|
143
|
+
errors = []
|
144
|
+
@resources.each do |resource|
|
145
|
+
case resource.type
|
146
|
+
when 'Alarm'
|
147
|
+
%w(metric_name namespace).each do |property|
|
148
|
+
if resource.send(property).nil?
|
149
|
+
errors << "Alarm #{resource.name} for resource #{resource.resource_id} has nil value for property #{property.to_camelcase}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
when 'Check'
|
153
|
+
# no validation check yet
|
154
|
+
when 'Event'
|
155
|
+
# no validation check yet
|
156
|
+
when 'Composite'
|
157
|
+
# no validation check yet
|
158
|
+
when 'EventSubscription'
|
159
|
+
# no validation check yet
|
160
|
+
when 'MetricFilter'
|
161
|
+
# no validation check yet
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
raise CfnGuardian::ValidationError, "#{errors.size} errors found\n[*] #{errors.join("\n[*] ")}" if errors.any?
|
166
|
+
end
|
167
|
+
|
168
|
+
def split_resources(bucket,path)
|
83
169
|
split = @resources.each_slice(200).to_a
|
84
170
|
split.each_with_index do |resources,index|
|
85
171
|
@stacks.push({
|
86
172
|
'Name' => "GuardianStack#{index}",
|
87
|
-
'TemplateURL' => "https://#{
|
173
|
+
'TemplateURL' => "https://#{bucket}.s3.amazonaws.com/#{path}/guardian-stack-#{index}.compiled.yaml",
|
88
174
|
'Reference' => index
|
89
175
|
})
|
90
176
|
end
|
91
177
|
return split
|
92
178
|
end
|
93
179
|
|
94
|
-
def compile_templates
|
180
|
+
def compile_templates(bucket,path)
|
95
181
|
clean_out_directory()
|
96
|
-
resources = split_resources()
|
182
|
+
resources = split_resources(bucket,path)
|
97
183
|
|
98
184
|
main_stack = CfnGuardian::Stacks::Main.new()
|
99
|
-
|
100
|
-
valid = template.validate
|
185
|
+
main_stack.build_template(@stacks,@checks,@topics,@maintenance_group_list,@ssm_parameters)
|
186
|
+
valid = main_stack.template.validate
|
187
|
+
FileUtils.mkdir_p 'out'
|
101
188
|
File.write("out/guardian.compiled.yaml", JSON.parse(valid.to_json).to_yaml)
|
102
189
|
|
103
190
|
resources.each_with_index do |resources,index|
|
104
|
-
stack = CfnGuardian::Stacks::Resources.new()
|
105
|
-
|
106
|
-
valid = template.validate
|
191
|
+
stack = CfnGuardian::Stacks::Resources.new(main_stack.parameters,index)
|
192
|
+
stack.build_template(resources)
|
193
|
+
valid = stack.template.validate
|
107
194
|
File.write("out/guardian-stack-#{index}.compiled.yaml", JSON.parse(valid.to_json).to_yaml)
|
108
195
|
end
|
109
196
|
end
|
@@ -111,6 +198,43 @@ module CfnGuardian
|
|
111
198
|
def clean_out_directory
|
112
199
|
Dir["out/*.yaml"].each {|file| File.delete(file)}
|
113
200
|
end
|
201
|
+
|
202
|
+
def load_parameters(options)
|
203
|
+
parameters = {}
|
204
|
+
# Load sns topic parameters in order of preference
|
205
|
+
@topics.each do |key, value|
|
206
|
+
# if parameter is passed in as a command line option
|
207
|
+
if options.has_key?("sns_#{key.downcase}")
|
208
|
+
parameters[key.to_sym] = options["sns_#{key.downcase}"]
|
209
|
+
# if parameter is in config
|
210
|
+
elsif !value.empty?
|
211
|
+
parameters[key.to_sym] = value
|
212
|
+
# if parameter is set as environment variable
|
213
|
+
elsif ENV.has_key?("GUARDIAN_TOPIC_#{key.upcase}")
|
214
|
+
parameters[key.to_sym] = ENV["GUARDIAN_TOPIC_#{key.upcase}"]
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
return parameters
|
219
|
+
end
|
220
|
+
|
221
|
+
def genrate_template_config(parameters)
|
222
|
+
template = {
|
223
|
+
Tags: {
|
224
|
+
'guardian:version': CfnGuardian::VERSION
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
if ENV.has_key?('CODEBUILD_RESOLVED_SOURCE_VERSION')
|
229
|
+
template[:Tags][:'guardian:config:commit'] = ENV['CODEBUILD_RESOLVED_SOURCE_VERSION']
|
230
|
+
end
|
231
|
+
|
232
|
+
unless parameters.empty?
|
233
|
+
template[:Parameters] = parameters
|
234
|
+
end
|
235
|
+
|
236
|
+
File.write("out/template-config.guardian.json", template.to_json)
|
237
|
+
end
|
114
238
|
|
115
239
|
end
|
116
240
|
end
|