cloud-mu 1.9.0.pre.beta → 2.0.0.pre.alpha
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/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
|