cloud-mu 1.9.0.pre.beta → 2.0.0.pre.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Berksfile +16 -54
- data/Berksfile.lock +14 -62
- data/bin/mu-aws-setup +131 -108
- data/bin/mu-configure +311 -74
- data/bin/mu-gcp-setup +84 -62
- data/bin/mu-load-config.rb +46 -2
- data/bin/mu-self-update +11 -9
- data/bin/mu-upload-chef-artifacts +4 -4
- data/{mu.gemspec → cloud-mu.gemspec} +2 -2
- data/cookbooks/awscli/Berksfile +8 -0
- data/cookbooks/mu-activedirectory/Berksfile +11 -0
- data/cookbooks/mu-firewall/Berksfile +9 -0
- data/cookbooks/mu-firewall/metadata.rb +1 -1
- data/cookbooks/mu-glusterfs/Berksfile +10 -0
- data/cookbooks/mu-jenkins/Berksfile +14 -0
- data/cookbooks/mu-master/Berksfile +23 -0
- data/cookbooks/mu-master/attributes/default.rb +1 -1
- data/cookbooks/mu-master/metadata.rb +2 -2
- data/cookbooks/mu-master/recipes/default.rb +1 -1
- data/cookbooks/mu-master/recipes/init.rb +7 -3
- data/cookbooks/mu-master/recipes/ssl-certs.rb +1 -0
- data/cookbooks/mu-mongo/Berksfile +10 -0
- data/cookbooks/mu-openvpn/Berksfile +11 -0
- data/cookbooks/mu-php54/Berksfile +13 -0
- data/cookbooks/mu-splunk/Berksfile +10 -0
- data/cookbooks/mu-tools/Berksfile +21 -0
- data/cookbooks/mu-tools/files/default/Mu_CA.pem +15 -15
- data/cookbooks/mu-utility/Berksfile +9 -0
- data/cookbooks/mu-utility/metadata.rb +2 -1
- data/cookbooks/nagios/Berksfile +7 -4
- data/cookbooks/s3fs/Berksfile +9 -0
- data/environments/dev.json +6 -6
- data/environments/prod.json +6 -6
- data/modules/mu.rb +20 -42
- data/modules/mu/cleanup.rb +102 -100
- data/modules/mu/cloud.rb +90 -28
- data/modules/mu/clouds/aws.rb +449 -218
- data/modules/mu/clouds/aws/alarm.rb +29 -17
- data/modules/mu/clouds/aws/cache_cluster.rb +78 -64
- data/modules/mu/clouds/aws/collection.rb +25 -18
- data/modules/mu/clouds/aws/container_cluster.rb +73 -66
- data/modules/mu/clouds/aws/database.rb +124 -116
- data/modules/mu/clouds/aws/dnszone.rb +27 -20
- data/modules/mu/clouds/aws/firewall_rule.rb +30 -22
- data/modules/mu/clouds/aws/folder.rb +18 -3
- data/modules/mu/clouds/aws/function.rb +77 -23
- data/modules/mu/clouds/aws/group.rb +19 -12
- data/modules/mu/clouds/aws/habitat.rb +153 -0
- data/modules/mu/clouds/aws/loadbalancer.rb +59 -52
- data/modules/mu/clouds/aws/log.rb +30 -23
- data/modules/mu/clouds/aws/msg_queue.rb +29 -20
- data/modules/mu/clouds/aws/notifier.rb +222 -0
- data/modules/mu/clouds/aws/role.rb +178 -90
- data/modules/mu/clouds/aws/search_domain.rb +40 -24
- data/modules/mu/clouds/aws/server.rb +169 -137
- data/modules/mu/clouds/aws/server_pool.rb +60 -83
- data/modules/mu/clouds/aws/storage_pool.rb +59 -31
- data/modules/mu/clouds/aws/user.rb +36 -27
- data/modules/mu/clouds/aws/userdata/linux.erb +101 -93
- data/modules/mu/clouds/aws/vpc.rb +250 -189
- data/modules/mu/clouds/azure.rb +132 -0
- data/modules/mu/clouds/cloudformation.rb +65 -1
- data/modules/mu/clouds/cloudformation/alarm.rb +8 -0
- data/modules/mu/clouds/cloudformation/cache_cluster.rb +7 -0
- data/modules/mu/clouds/cloudformation/collection.rb +7 -0
- data/modules/mu/clouds/cloudformation/database.rb +7 -0
- data/modules/mu/clouds/cloudformation/dnszone.rb +7 -0
- data/modules/mu/clouds/cloudformation/firewall_rule.rb +9 -2
- data/modules/mu/clouds/cloudformation/loadbalancer.rb +7 -0
- data/modules/mu/clouds/cloudformation/log.rb +7 -0
- data/modules/mu/clouds/cloudformation/server.rb +7 -0
- data/modules/mu/clouds/cloudformation/server_pool.rb +7 -0
- data/modules/mu/clouds/cloudformation/vpc.rb +7 -0
- data/modules/mu/clouds/google.rb +214 -110
- data/modules/mu/clouds/google/container_cluster.rb +42 -24
- data/modules/mu/clouds/google/database.rb +15 -6
- data/modules/mu/clouds/google/firewall_rule.rb +17 -25
- data/modules/mu/clouds/google/group.rb +13 -5
- data/modules/mu/clouds/google/habitat.rb +105 -0
- data/modules/mu/clouds/google/loadbalancer.rb +28 -20
- data/modules/mu/clouds/google/server.rb +93 -354
- data/modules/mu/clouds/google/server_pool.rb +18 -10
- data/modules/mu/clouds/google/user.rb +22 -14
- data/modules/mu/clouds/google/vpc.rb +97 -69
- data/modules/mu/config.rb +133 -38
- data/modules/mu/config/alarm.rb +25 -0
- data/modules/mu/config/cache_cluster.rb +5 -3
- data/modules/mu/config/cache_cluster.yml +23 -0
- data/modules/mu/config/database.rb +25 -16
- data/modules/mu/config/database.yml +3 -3
- data/modules/mu/config/function.rb +1 -2
- data/modules/mu/config/{project.rb → habitat.rb} +10 -10
- data/modules/mu/config/notifier.rb +85 -0
- data/modules/mu/config/notifier.yml +9 -0
- data/modules/mu/config/role.rb +1 -1
- data/modules/mu/config/search_domain.yml +2 -2
- data/modules/mu/config/server.rb +13 -1
- data/modules/mu/config/server.yml +3 -3
- data/modules/mu/config/server_pool.rb +3 -1
- data/modules/mu/config/storage_pool.rb +3 -1
- data/modules/mu/config/storage_pool.yml +19 -0
- data/modules/mu/config/vpc.rb +70 -8
- data/modules/mu/groomers/chef.rb +2 -3
- data/modules/mu/kittens.rb +500 -122
- data/modules/mu/master.rb +5 -5
- data/modules/mu/mommacat.rb +151 -91
- data/modules/tests/super_complex_bok.yml +12 -0
- data/modules/tests/super_simple_bok.yml +12 -0
- data/spec/mu/clouds/azure_spec.rb +82 -0
- data/spec/spec_helper.rb +105 -0
- metadata +26 -5
- data/modules/mu/clouds/aws/notification.rb +0 -139
- data/modules/mu/config/notification.rb +0 -44
@@ -38,7 +38,7 @@ module MU
|
|
38
38
|
@config["log_group_name"] = @mu_name
|
39
39
|
@config["log_stream_name"] =
|
40
40
|
if @config["enable_cloudtrail_logging"]
|
41
|
-
"#{MU.
|
41
|
+
"#{MU::Cloud::AWS.credToAcct(@config['credentials'])}_CloudTrail_#{@config["region"]}"
|
42
42
|
else
|
43
43
|
@mu_name
|
44
44
|
end
|
@@ -56,7 +56,7 @@ module MU
|
|
56
56
|
end
|
57
57
|
|
58
58
|
MU.log "Creating log group #{@mu_name}"
|
59
|
-
MU::Cloud::AWS.cloudwatchlogs(@config["region"]).create_log_group(
|
59
|
+
MU::Cloud::AWS.cloudwatchlogs(region: @config["region"], credentials: @config["credentials"]).create_log_group(
|
60
60
|
log_group_name: @config["log_group_name"],
|
61
61
|
tags: tags
|
62
62
|
)
|
@@ -76,19 +76,19 @@ module MU
|
|
76
76
|
end
|
77
77
|
end while resp.nil?
|
78
78
|
|
79
|
-
MU::Cloud::AWS.cloudwatchlogs(@config["region"]).create_log_stream(
|
79
|
+
MU::Cloud::AWS.cloudwatchlogs(region: @config["region"], credentials: @config["credentials"]).create_log_stream(
|
80
80
|
log_group_name: @config["log_group_name"],
|
81
81
|
log_stream_name: @config["log_stream_name"]
|
82
82
|
)
|
83
83
|
|
84
|
-
MU::Cloud::AWS.cloudwatchlogs(@config["region"]).put_retention_policy(
|
84
|
+
MU::Cloud::AWS.cloudwatchlogs(region: @config["region"], credentials: @config["credentials"]).put_retention_policy(
|
85
85
|
log_group_name: @config["log_group_name"],
|
86
86
|
retention_in_days: @config["retention_period"]
|
87
87
|
)
|
88
88
|
|
89
89
|
if @config["filters"] && !@config["filters"].empty?
|
90
90
|
@config["filters"].each{ |filter|
|
91
|
-
MU::Cloud::AWS.cloudwatchlogs(@config["region"]).put_metric_filter(
|
91
|
+
MU::Cloud::AWS.cloudwatchlogs(region: @config["region"], credentials: @config["credentials"]).put_metric_filter(
|
92
92
|
log_group_name: @config["log_group_name"],
|
93
93
|
filter_name: filter["name"],
|
94
94
|
filter_pattern: filter["search_pattern"],
|
@@ -102,8 +102,8 @@ module MU
|
|
102
102
|
end
|
103
103
|
|
104
104
|
if @config["enable_cloudtrail_logging"]
|
105
|
-
trail_resp = MU::Cloud::AWS.cloudtrail(@config["region"]).describe_trails.trail_list.first
|
106
|
-
raise MuError, "Can't find a cloudtrail in #{MU.
|
105
|
+
trail_resp = MU::Cloud::AWS.cloudtrail(region: @config["region"], credentials: @config["credentials"]).describe_trails.trail_list.first
|
106
|
+
raise MuError, "Can't find a cloudtrail in #{MU::Cloud::AWS.credToAcct(@config['credentials'])}/#{@config["region"]}. Please create cloudtrail before enabling logging on it" unless trail_resp
|
107
107
|
|
108
108
|
iam_policy = '{
|
109
109
|
"Version": "2012-10-17",
|
@@ -116,7 +116,7 @@ module MU
|
|
116
116
|
"logs:PutLogEventsBatch",
|
117
117
|
"logs:PutLogEvents"
|
118
118
|
],
|
119
|
-
"Resource": "arn:'+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+':logs:'+@config["region"]+':'+MU.
|
119
|
+
"Resource": "arn:'+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+':logs:'+@config["region"]+':'+MU::Cloud::AWS.credToAcct(@config['credentials'])+':log-group:'+@config["log_group_name"]+':log-stream:'+@config["log_stream_name"]+'*"
|
120
120
|
}
|
121
121
|
]
|
122
122
|
}'
|
@@ -141,12 +141,12 @@ module MU
|
|
141
141
|
|
142
142
|
iam_role_name = "#{@mu_name}-CloudTrail"
|
143
143
|
MU.log "Creating IAM role #{iam_role_name}"
|
144
|
-
iam_resp = MU::Cloud::AWS.iam
|
144
|
+
iam_resp = MU::Cloud::AWS.iam.create_role(
|
145
145
|
role_name: iam_role_name,
|
146
146
|
assume_role_policy_document: iam_assume_role_policy
|
147
147
|
)
|
148
148
|
|
149
|
-
MU::Cloud::AWS.iam
|
149
|
+
MU::Cloud::AWS.iam.put_role_policy(
|
150
150
|
role_name: iam_role_name,
|
151
151
|
policy_name: "CloudTrail_CloudWatchLogs",
|
152
152
|
policy_document: iam_policy
|
@@ -156,7 +156,7 @@ module MU
|
|
156
156
|
|
157
157
|
retries = 0
|
158
158
|
begin
|
159
|
-
MU::Cloud::AWS.cloudtrail(@config["region"]).update_trail(
|
159
|
+
MU::Cloud::AWS.cloudtrail(region: @config["region"], credentials: @config["credentials"]).update_trail(
|
160
160
|
name: trail_resp.name,
|
161
161
|
cloud_watch_logs_log_group_arn: log_group_resp.arn,
|
162
162
|
cloud_watch_logs_role_arn: iam_resp.role.arn
|
@@ -183,7 +183,7 @@ module MU
|
|
183
183
|
prettyname = service.sub(/\..*/, "").capitalize
|
184
184
|
doc = '{ "Version": "2012-10-17", "Statement": [ { "Sid": "'+prettyname+'LogsToCloudWatchLogs", "Effect": "Allow", "Principal": { "Service": [ "'+service+'" ] }, "Action": [ "logs:PutLogEvents", "logs:PutLogEventsBatch", "logs:CreateLogStream" ], "Resource": "'+log_arn+'" } ] }'
|
185
185
|
|
186
|
-
MU::Cloud::AWS.cloudwatchlogs(region).put_resource_policy(
|
186
|
+
MU::Cloud::AWS.cloudwatchlogs(region: region).put_resource_policy(
|
187
187
|
policy_name: "Allow"+prettyname,
|
188
188
|
policy_document: doc
|
189
189
|
)
|
@@ -209,15 +209,22 @@ module MU
|
|
209
209
|
}
|
210
210
|
end
|
211
211
|
|
212
|
+
# Does this resource type exist as a global (cloud-wide) artifact, or
|
213
|
+
# is it localized to a region/zone?
|
214
|
+
# @return [Boolean]
|
215
|
+
def self.isGlobal?
|
216
|
+
false
|
217
|
+
end
|
218
|
+
|
212
219
|
# Remove all logs associated with the currently loaded deployment.
|
213
220
|
# @param noop [Boolean]: If true, will only print what would be done
|
214
221
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
215
222
|
# @param region [String]: The cloud provider region
|
216
223
|
# @return [void]
|
217
|
-
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, flags: {})
|
224
|
+
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
218
225
|
log_groups =
|
219
226
|
begin
|
220
|
-
MU::Cloud::AWS.cloudwatchlogs(region).describe_log_groups.log_groups
|
227
|
+
MU::Cloud::AWS.cloudwatchlogs(credentials: credentials, region: region).describe_log_groups.log_groups
|
221
228
|
# TO DO: Why is it returning UnknownOperationException instead of valid error?
|
222
229
|
rescue Aws::CloudWatchLogs::Errors::UnknownOperationException => e
|
223
230
|
MU.log e.inspect
|
@@ -227,10 +234,10 @@ module MU
|
|
227
234
|
if !log_groups.empty?
|
228
235
|
log_groups.each{ |lg|
|
229
236
|
if lg.log_group_name.match(MU.deploy_id)
|
230
|
-
log_streams = MU::Cloud::AWS.cloudwatchlogs(region).describe_log_streams(log_group_name: lg.log_group_name).log_streams
|
237
|
+
log_streams = MU::Cloud::AWS.cloudwatchlogs(credentials: credentials, region: region).describe_log_streams(log_group_name: lg.log_group_name).log_streams
|
231
238
|
if !log_streams.empty?
|
232
239
|
log_streams.each{ |ls|
|
233
|
-
MU::Cloud::AWS.cloudwatchlogs(region).delete_log_stream(
|
240
|
+
MU::Cloud::AWS.cloudwatchlogs(credentials: credentials, region: region).delete_log_stream(
|
234
241
|
log_group_name: lg.log_group_name,
|
235
242
|
log_stream_name: ls.log_stream_name
|
236
243
|
) unless noop
|
@@ -239,7 +246,7 @@ module MU
|
|
239
246
|
}
|
240
247
|
end
|
241
248
|
|
242
|
-
MU::Cloud::AWS.cloudwatchlogs(region).delete_log_group(
|
249
|
+
MU::Cloud::AWS.cloudwatchlogs(credentials: credentials, region: region).delete_log_group(
|
243
250
|
log_group_name: lg.log_group_name
|
244
251
|
) unless noop
|
245
252
|
MU.log "Deleted log group #{lg.log_group_name}"
|
@@ -248,7 +255,7 @@ module MU
|
|
248
255
|
end
|
249
256
|
|
250
257
|
unless noop
|
251
|
-
MU::Cloud::AWS.iam.list_roles.roles.each{ |role|
|
258
|
+
MU::Cloud::AWS.iam(credentials: credentials).list_roles.roles.each{ |role|
|
252
259
|
match_string = "#{MU.deploy_id}.*CloudTrail"
|
253
260
|
# Maybe we should have a more generic way to delete IAM profiles and policies. The call itself should be moved from MU::Cloud::AWS::Server.
|
254
261
|
# MU::Cloud::AWS::Server.removeIAMProfile(role.role_name) if role.role_name.match(match_string)
|
@@ -261,13 +268,13 @@ module MU
|
|
261
268
|
# @param region [String]: The cloud provider region.
|
262
269
|
# @param flags [Hash]: Optional flags
|
263
270
|
# @return [OpenStruct]: The cloud provider's complete descriptions of matching log group.
|
264
|
-
def self.find(cloud_id: nil, region: MU.curRegion, flags: {})
|
271
|
+
def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
|
265
272
|
found = nil
|
266
273
|
if !cloud_id.nil? and !cloud_id.match(/^arn:/i)
|
267
274
|
found ||= {}
|
268
|
-
found[cloud_id] = MU::Cloud::AWS::Log.getLogGroupByName(cloud_id, region: region)
|
275
|
+
found[cloud_id] = MU::Cloud::AWS::Log.getLogGroupByName(cloud_id, region: region, credentials: nil)
|
269
276
|
else
|
270
|
-
resp = MU::Cloud::AWS.cloudwatchlogs(region).describe_log_groups.log_groups.each { |group|
|
277
|
+
resp = MU::Cloud::AWS.cloudwatchlogs(region: region, credentials: credentials).describe_log_groups.log_groups.each { |group|
|
271
278
|
if group.arn == cloud_id or group.arn.sub(/:\*$/, "") == cloud_id
|
272
279
|
found ||= {}
|
273
280
|
found[group.log_group_name] = group
|
@@ -354,8 +361,8 @@ module MU
|
|
354
361
|
# @param name [String]: The cloud provider's identifier for this log group.
|
355
362
|
# @param region [String]: The cloud provider region
|
356
363
|
# @return [OpenStruct]
|
357
|
-
def self.getLogGroupByName(name, region: MU.curRegion)
|
358
|
-
MU::Cloud::AWS.cloudwatchlogs(region).describe_log_groups(log_group_name_prefix: name).log_groups.first
|
364
|
+
def self.getLogGroupByName(name, region: MU.curRegion, credentials: nil)
|
365
|
+
MU::Cloud::AWS.cloudwatchlogs(region: region, credentials: credentials).describe_log_groups(log_group_name_prefix: name).log_groups.first
|
359
366
|
end
|
360
367
|
end
|
361
368
|
end
|
@@ -48,7 +48,7 @@ module MU
|
|
48
48
|
namestr += ".fifo" if attrs['FifoQueue']
|
49
49
|
|
50
50
|
MU.log "Creating SQS queue #{namestr}", details: attrs
|
51
|
-
resp = MU::Cloud::AWS.sqs(@config['region']).create_queue(
|
51
|
+
resp = MU::Cloud::AWS.sqs(region: @config['region'], credentials: @config['credentials']).create_queue(
|
52
52
|
queue_name: namestr,
|
53
53
|
attributes: attrs
|
54
54
|
)
|
@@ -75,7 +75,7 @@ module MU
|
|
75
75
|
}
|
76
76
|
if changed
|
77
77
|
MU.log "Updating SQS queue #{@mu_name}", MU::NOTICE, details: new_attrs
|
78
|
-
resp = MU::Cloud::AWS.sqs(@config['region']).set_queue_attributes(
|
78
|
+
resp = MU::Cloud::AWS.sqs(region: @config['region'], credentials: @config['credentials']).set_queue_attributes(
|
79
79
|
queue_url: @cloud_id,
|
80
80
|
attributes: new_attrs
|
81
81
|
)
|
@@ -86,7 +86,7 @@ module MU
|
|
86
86
|
# Canonical Amazon Resource Number for this resource
|
87
87
|
# @return [String]
|
88
88
|
def arn
|
89
|
-
"arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":sqs:"+@config['region']+":"+MU.
|
89
|
+
"arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":sqs:"+@config['region']+":"+MU::Cloud::AWS.credToAcct(@config['credentials'])+":"+@cloud_id
|
90
90
|
end
|
91
91
|
|
92
92
|
# Retrieve the AWS descriptor for this SQS queue. AWS doesn't exactly
|
@@ -94,7 +94,7 @@ module MU
|
|
94
94
|
# @return [Hash]: AWS doesn't return anything but the SQS URL, so supplement with attributes
|
95
95
|
def cloud_desc
|
96
96
|
if !@cloud_id
|
97
|
-
resp = MU::Cloud::AWS.sqs(@config['region']).list_queues(
|
97
|
+
resp = MU::Cloud::AWS.sqs(region: @config['region'], credentials: @config['credentials']).list_queues(
|
98
98
|
queue_name_prefix: @mu_name
|
99
99
|
)
|
100
100
|
return nil if !resp or !resp.queue_urls
|
@@ -109,7 +109,8 @@ module MU
|
|
109
109
|
return nil if !@cloud_id
|
110
110
|
MU::Cloud::AWS::MsgQueue.find(
|
111
111
|
cloud_id: @cloud_id.dup,
|
112
|
-
region: @config['region']
|
112
|
+
region: @config['region'],
|
113
|
+
credentials: @config['credentials']
|
113
114
|
)
|
114
115
|
end
|
115
116
|
|
@@ -119,18 +120,26 @@ module MU
|
|
119
120
|
cloud_desc
|
120
121
|
deploy_struct = MU::Cloud::AWS::MsgQueue.find(
|
121
122
|
cloud_id: @cloud_id,
|
122
|
-
region: @config['region']
|
123
|
+
region: @config['region'],
|
124
|
+
credentials: @config['credentials']
|
123
125
|
)
|
124
126
|
return deploy_struct
|
125
127
|
end
|
126
128
|
|
129
|
+
# Does this resource type exist as a global (cloud-wide) artifact, or
|
130
|
+
# is it localized to a region/zone?
|
131
|
+
# @return [Boolean]
|
132
|
+
def self.isGlobal?
|
133
|
+
false
|
134
|
+
end
|
135
|
+
|
127
136
|
# Remove all msg_queues associated with the currently loaded deployment.
|
128
137
|
# @param noop [Boolean]: If true, will only print what would be done
|
129
138
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
130
139
|
# @param region [String]: The cloud provider region
|
131
140
|
# @return [void]
|
132
|
-
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, flags: {})
|
133
|
-
resp = MU::Cloud::AWS.sqs(region).list_queues(
|
141
|
+
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
142
|
+
resp = MU::Cloud::AWS.sqs(credentials: credentials, region: region).list_queues(
|
134
143
|
queue_name_prefix: MU.deploy_id
|
135
144
|
)
|
136
145
|
if resp and resp.queue_urls
|
@@ -139,7 +148,7 @@ module MU
|
|
139
148
|
threads << Thread.new {
|
140
149
|
MU.log "Deleting SQS queue #{url}"
|
141
150
|
if !noop
|
142
|
-
MU::Cloud::AWS.sqs(region).delete_queue(
|
151
|
+
MU::Cloud::AWS.sqs(credentials: credentials, region: region).delete_queue(
|
143
152
|
queue_url: url
|
144
153
|
)
|
145
154
|
sleep 60 # per API docs, this is how long it takes to really delete
|
@@ -157,14 +166,14 @@ module MU
|
|
157
166
|
# @param region [String]: The cloud provider region.
|
158
167
|
# @param flags [Hash]: Optional flags
|
159
168
|
# @return [Hash]: AWS doesn't return anything but the SQS URL, so supplement with attributes
|
160
|
-
def self.find(cloud_id: nil, region: MU.curRegion, flags: {})
|
169
|
+
def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
|
161
170
|
flags['account'] ||= MU.account_number
|
162
171
|
return nil if !cloud_id
|
163
172
|
|
164
173
|
# If it's a URL, make sure it's good
|
165
174
|
begin
|
166
175
|
if cloud_id.match(/^https?:/i)
|
167
|
-
resp = MU::Cloud::AWS.sqs(region).get_queue_attributes(
|
176
|
+
resp = MU::Cloud::AWS.sqs(region: region, credentials: credentials).get_queue_attributes(
|
168
177
|
queue_url: cloud_id,
|
169
178
|
attribute_names: ["All"]
|
170
179
|
)
|
@@ -175,7 +184,7 @@ module MU
|
|
175
184
|
end
|
176
185
|
else
|
177
186
|
# If it's a plain queue name, resolve it to a URL
|
178
|
-
resp = MU::Cloud::AWS.sqs(region).get_queue_url(
|
187
|
+
resp = MU::Cloud::AWS.sqs(region: region, credentials: credentials).get_queue_url(
|
179
188
|
queue_name: cloud_id,
|
180
189
|
queue_owner_aws_account_id: flags['account']
|
181
190
|
)
|
@@ -186,7 +195,7 @@ module MU
|
|
186
195
|
|
187
196
|
# Go fetch its attributes
|
188
197
|
if cloud_id
|
189
|
-
resp = MU::Cloud::AWS.sqs(region).get_queue_attributes(
|
198
|
+
resp = MU::Cloud::AWS.sqs(region: region, credentials: credentials).get_queue_attributes(
|
190
199
|
queue_url: cloud_id,
|
191
200
|
attribute_names: ["All"]
|
192
201
|
)
|
@@ -372,7 +381,7 @@ MU.log "RETURNING FROM FIND ON #{cloud_id}", MU::WARN, details: caller
|
|
372
381
|
ok = false
|
373
382
|
end
|
374
383
|
begin
|
375
|
-
MU::Cloud::AWS.kms(queue['region']).describe_key(key_id: queue['kms']['key_id'])
|
384
|
+
MU::Cloud::AWS.kms(region: queue['region']).describe_key(key_id: queue['kms']['key_id'])
|
376
385
|
rescue Aws::KMS::Errors::NotFoundException => e
|
377
386
|
MU.log "KMS key '#{queue['kms']['key_id']}' specified in Queue '#{queue['name']}' was not found.", MU::ERR, details: "Key IDs are of the form bf64a093-2c3d-46fa-0d4f-8232fa7ed53. Keys can be created at https://console.aws.amazon.com/iam/home#/encryptionKeys/#{queue['region']}"
|
378
387
|
ok = false
|
@@ -402,18 +411,18 @@ MU.log "RETURNING FROM FIND ON #{cloud_id}", MU::WARN, details: caller
|
|
402
411
|
}
|
403
412
|
|
404
413
|
if @config['failqueue']
|
405
|
-
sibling = @deploy.findLitterMate(type: "msg_queue", name: config['failqueue']['name'])
|
406
|
-
id = config['failqueue']['name']
|
414
|
+
sibling = @deploy.findLitterMate(type: "msg_queue", name: @config['failqueue']['name'])
|
415
|
+
id = @config['failqueue']['name']
|
407
416
|
if sibling # resolve sibling queues to something useful
|
408
417
|
id = sibling.cloud_id
|
409
418
|
end
|
410
|
-
desc = MU::Cloud::AWS::MsgQueue.find(cloud_id: id)
|
419
|
+
desc = MU::Cloud::AWS::MsgQueue.find(cloud_id: id, credentials: @config['credentials'])
|
411
420
|
if !desc
|
412
|
-
raise MuError, "Failed to get cloud descriptor for SQS queue #{config['failqueue']['name']}"
|
421
|
+
raise MuError, "Failed to get cloud descriptor for SQS queue #{@config['failqueue']['name']}"
|
413
422
|
end
|
414
423
|
rdr_pol = {
|
415
424
|
"deadLetterTargetArn" => desc["QueueArn"],
|
416
|
-
"maxReceiveCount" => config['failqueue']['retries_before_fail']
|
425
|
+
"maxReceiveCount" => @config['failqueue']['retries_before_fail']
|
417
426
|
}
|
418
427
|
attrs["RedrivePolicy"] = JSON.generate(rdr_pol)
|
419
428
|
end
|
@@ -465,7 +474,7 @@ MU.log "RETURNING FROM FIND ON #{cloud_id}", MU::WARN, details: caller
|
|
465
474
|
end
|
466
475
|
|
467
476
|
begin
|
468
|
-
MU::Cloud::AWS.sqs(@config['region']).tag_queue(
|
477
|
+
MU::Cloud::AWS.sqs(region: @config['region'], credentials: @config['credentials']).tag_queue(
|
469
478
|
queue_url: url,
|
470
479
|
tags: tags
|
471
480
|
)
|
@@ -0,0 +1,222 @@
|
|
1
|
+
# Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved
|
2
|
+
#
|
3
|
+
# Licensed under the BSD-3 license (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License in the root of the project or at
|
6
|
+
#
|
7
|
+
# http://egt-labs.com/mu/LICENSE.html
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module MU
|
16
|
+
class Cloud
|
17
|
+
class AWS
|
18
|
+
# Support for AWS SNS
|
19
|
+
class Notifier < MU::Cloud::Notifier
|
20
|
+
@deploy = nil
|
21
|
+
@config = nil
|
22
|
+
|
23
|
+
attr_reader :mu_name
|
24
|
+
attr_reader :config
|
25
|
+
attr_reader :cloud_id
|
26
|
+
|
27
|
+
# @param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member.
|
28
|
+
# @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::logs}
|
29
|
+
def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil)
|
30
|
+
@deploy = mommacat
|
31
|
+
@config = MU::Config.manxify(kitten_cfg)
|
32
|
+
@cloud_id ||= cloud_id
|
33
|
+
@mu_name ||= @deploy.getResourceName(@config["name"])
|
34
|
+
end
|
35
|
+
|
36
|
+
# Called automatically by {MU::Deploy#createResources}
|
37
|
+
def create
|
38
|
+
MU::Cloud::AWS.sns(region: @config['region'], credentials: @config['credentials']).create_topic(name: @mu_name)
|
39
|
+
@cloud_id = @mu_name
|
40
|
+
MU.log "Created SNS topic #{@mu_name}"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Called automatically by {MU::Deploy#createResources}
|
44
|
+
def groom
|
45
|
+
if @config['subscriptions']
|
46
|
+
@config['subscriptions'].each { |sub|
|
47
|
+
MU::Cloud::AWS::Notifier.subscribe(
|
48
|
+
arn: arn,
|
49
|
+
endpoint: sub['endpoint'],
|
50
|
+
region: @config['region'],
|
51
|
+
credentials: @config['credentials'],
|
52
|
+
protocol: sub['type']
|
53
|
+
)
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Does this resource type exist as a global (cloud-wide) artifact, or
|
59
|
+
# is it localized to a region/zone?
|
60
|
+
# @return [Boolean]
|
61
|
+
def self.isGlobal?
|
62
|
+
false
|
63
|
+
end
|
64
|
+
|
65
|
+
# Remove all notifiers associated with the currently loaded deployment.
|
66
|
+
# @param noop [Boolean]: If true, will only print what would be done
|
67
|
+
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
68
|
+
# @param region [String]: The cloud provider region
|
69
|
+
# @return [void]
|
70
|
+
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
71
|
+
MU::Cloud::AWS.sns(region: region, credentials: credentials).list_topics.topics.each { |topic|
|
72
|
+
if topic.topic_arn.match(MU.deploy_id)
|
73
|
+
# We don't have a way to tag our SNS topics, so we will delete any topic that has the MU-ID in its ARN.
|
74
|
+
# This may fail to find notifier groups in some cases (eg. cache_cluster) so we might want to delete from each API as well.
|
75
|
+
MU::Cloud::AWS.sns(region: region, credentials: credentials).delete_topic(topic_arn: topic.topic_arn)
|
76
|
+
MU.log "Deleted SNS topic: #{topic.topic_arn}"
|
77
|
+
end
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
# Canonical Amazon Resource Number for this resource
|
82
|
+
# @return [String]
|
83
|
+
def arn
|
84
|
+
"arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":sns:"+@config['region']+":"+MU::Cloud::AWS.credToAcct(@config['credentials'])+":"+@cloud_id
|
85
|
+
end
|
86
|
+
|
87
|
+
# Return the metadata for this user cofiguration
|
88
|
+
# @return [Hash]
|
89
|
+
def notify
|
90
|
+
desc = MU::Cloud::AWS.sns(region: @config["region"], credentials: @config["credentials"]).get_topic_attributes(topic_arn: arn).attributes
|
91
|
+
MU.structToHash(desc)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Locate an existing notifier.
|
95
|
+
# @param cloud_id [String]: The cloud provider's identifier for this resource.
|
96
|
+
# @param region [String]: The cloud provider region.
|
97
|
+
# @param flags [Hash]: Optional flags
|
98
|
+
# @return [OpenStruct]: The cloud provider's complete descriptions of matching notifier.
|
99
|
+
def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
|
100
|
+
found = {}
|
101
|
+
if cloud_id
|
102
|
+
arn = "arn:"+(MU::Cloud::AWS.isGovCloud?(region) ? "aws-us-gov" : "aws")+":sns:"+region+":"+MU::Cloud::AWS.credToAcct(credentials)+":"+cloud_id
|
103
|
+
desc = MU::Cloud::AWS.sns(region: region, credentials: credentials).get_topic_attributes(topic_arn: arn).attributes
|
104
|
+
found[cloud_id] = desc if desc
|
105
|
+
end
|
106
|
+
found
|
107
|
+
end
|
108
|
+
|
109
|
+
# Cloud-specific configuration properties.
|
110
|
+
# @param config [MU::Config]: The calling MU::Config object
|
111
|
+
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
112
|
+
def self.schema(config)
|
113
|
+
toplevel_required = []
|
114
|
+
schema = {
|
115
|
+
"subscriptions" => {
|
116
|
+
"type" => "array",
|
117
|
+
"items" => {
|
118
|
+
"type" => "object",
|
119
|
+
"required" => ["endpoint"],
|
120
|
+
"properties" => {
|
121
|
+
"type" => {
|
122
|
+
"type" => "string",
|
123
|
+
"description" => "",
|
124
|
+
"enum" => ["http", "https", "email", "email-json", "sms", "sqs", "application", "lambda"]
|
125
|
+
}
|
126
|
+
}
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
}
|
131
|
+
[toplevel_required, schema]
|
132
|
+
end
|
133
|
+
|
134
|
+
# Cloud-specific pre-processing of {MU::Config::BasketofKittens::notifier}, bare and unvalidated.
|
135
|
+
|
136
|
+
# @param notifier [Hash]: The resource to process and validate
|
137
|
+
# @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
138
|
+
# @return [Boolean]: True if validation succeeded, False otherwise
|
139
|
+
def self.validateConfig(notifier, configurator)
|
140
|
+
ok = true
|
141
|
+
|
142
|
+
if notifier['subscriptions']
|
143
|
+
notifier['subscriptions'].each { |sub|
|
144
|
+
if !sub["type"]
|
145
|
+
if sub["endpoint"].match(/^http:/i)
|
146
|
+
sub["type"] = "http"
|
147
|
+
elsif sub["endpoint"].match(/^https:/i)
|
148
|
+
sub["type"] = "https"
|
149
|
+
elsif sub["endpoint"].match(/^sqs:/i)
|
150
|
+
sub["type"] = "sqs"
|
151
|
+
elsif sub["endpoint"].match(/^\+?[\d\-]+$/)
|
152
|
+
sub["type"] = "sms"
|
153
|
+
elsif sub["endpoint"].match(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i)
|
154
|
+
sub["type"] = "email"
|
155
|
+
else
|
156
|
+
MU.log "Notifier #{notifier['name']} subscription #{sub['endpoint']} did not specify a type, and I'm unable to guess one", MU::ERR
|
157
|
+
ok = false
|
158
|
+
end
|
159
|
+
end
|
160
|
+
}
|
161
|
+
end
|
162
|
+
|
163
|
+
ok
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
# Subscribe to a notifier group. This can either be an email address, SQS queue, application endpoint, etc...
|
168
|
+
# Will create the subscription only if it doesn't already exist.
|
169
|
+
# @param arn [String]: The cloud provider's identifier of the notifier group.
|
170
|
+
# @param protocol [String]: The type of the subscription (eg. email,https, etc..).
|
171
|
+
# @param endpoint [String]: The endpoint of the subscription. This will depend on the 'protocol' (as an example if protocol is email, endpoint will be the email address) ..
|
172
|
+
# @param region [String]: The cloud provider region.
|
173
|
+
def self.subscribe(arn: nil, protocol: nil, endpoint: nil, region: MU.curRegion, credentials: nil)
|
174
|
+
retries = 0
|
175
|
+
begin
|
176
|
+
resp = MU::Cloud::AWS.sns(region: region, credentials: credentials).list_subscriptions_by_topic(topic_arn: arn).subscriptions
|
177
|
+
rescue Aws::SNS::Errors::NotFound
|
178
|
+
if retries < 5
|
179
|
+
MU.log "Couldn't find topic #{arn}, retrying several times in case of a lagging resource"
|
180
|
+
retries += 1
|
181
|
+
sleep 30
|
182
|
+
retry
|
183
|
+
else
|
184
|
+
raise MuError, "Couldn't find topic #{arn}, giving up"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
already_subscribed = false
|
189
|
+
if resp && !resp.empty?
|
190
|
+
resp.each { |subscription|
|
191
|
+
already_subscribed = true if subscription.protocol == protocol && subscription.endpoint == endpoint
|
192
|
+
}
|
193
|
+
end
|
194
|
+
|
195
|
+
unless already_subscribed
|
196
|
+
MU::Cloud::AWS.sns(region: region, credentials: credentials).subscribe(topic_arn: arn, protocol: protocol, endpoint: endpoint)
|
197
|
+
MU.log "Subscribed #{endpoint} to SNS topic #{arn}"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# Test if a notifier group exists
|
202
|
+
# Create a new notifier group. Will check if the group exists before creating it.
|
203
|
+
# @param topic_name [String]: The cloud provider's name for the notifier group.
|
204
|
+
# @param region [String]: The cloud provider region.
|
205
|
+
# @param account_number [String]: The cloud provider account number.
|
206
|
+
# @return [string]: The cloud provider's identifier.
|
207
|
+
def self.topicExist(topic_name, region: MU.curRegion, account_number: MU.account_number, credentials: nil)
|
208
|
+
arn = "arn:#{MU::Cloud::AWS.isGovCloud?(region) ? "aws-us-gov" : "aws"}:sns:#{region}:#{account_number}:#{topic_name}"
|
209
|
+
match = nil
|
210
|
+
MU::Cloud::AWS.sns(region: region, credentials: credentials).list_topics.topics.each { |topic|
|
211
|
+
if topic.topic_arn == arn
|
212
|
+
match = topic.topic_arn
|
213
|
+
break
|
214
|
+
end
|
215
|
+
}
|
216
|
+
return match
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|