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
@@ -42,7 +42,8 @@ module MU
|
|
42
42
|
params = genParams
|
43
43
|
|
44
44
|
MU.log "Creating ElasticSearch domain #{@config['domain_name']}", details: params
|
45
|
-
|
45
|
+
pp params
|
46
|
+
resp = MU::Cloud::AWS.elasticsearch(region: @config['region'], credentials: @config['credentials']).create_elasticsearch_domain(params).domain_status
|
46
47
|
|
47
48
|
tagDomain
|
48
49
|
|
@@ -58,7 +59,7 @@ module MU
|
|
58
59
|
waitWhileProcessing # wait until the create finishes, if still going
|
59
60
|
|
60
61
|
MU.log "Updating ElasticSearch domain #{@config['domain_name']}", MU::NOTICE, details: params
|
61
|
-
MU::Cloud::AWS.elasticsearch(@config['region']).update_elasticsearch_domain_config(params)
|
62
|
+
MU::Cloud::AWS.elasticsearch(region: @config['region'], credentials: @config['credentials']).update_elasticsearch_domain_config(params)
|
62
63
|
end
|
63
64
|
|
64
65
|
waitWhileProcessing # don't return until creation/updating is complete
|
@@ -69,11 +70,11 @@ module MU
|
|
69
70
|
# our druthers.
|
70
71
|
def cloud_desc
|
71
72
|
if @config['domain_name']
|
72
|
-
MU::Cloud::AWS.elasticsearch(@config['region']).describe_elasticsearch_domain(
|
73
|
+
MU::Cloud::AWS.elasticsearch(region: @config['region'], credentials: @config['credentials']).describe_elasticsearch_domain(
|
73
74
|
domain_name: @config['domain_name']
|
74
75
|
).domain_status
|
75
|
-
elsif @deploydata['domain_name']
|
76
|
-
MU::Cloud::AWS.elasticsearch(@config['region']).describe_elasticsearch_domain(
|
76
|
+
elsif @deploydata and @deploydata['domain_name']
|
77
|
+
MU::Cloud::AWS.elasticsearch(region: @config['region'], credentials: @config['credentials']).describe_elasticsearch_domain(
|
77
78
|
domain_name: @deploydata['domain_name']
|
78
79
|
).domain_status
|
79
80
|
else
|
@@ -91,7 +92,7 @@ module MU
|
|
91
92
|
# @return [Hash]
|
92
93
|
def notify
|
93
94
|
deploy_struct = MU.structToHash(cloud_desc)
|
94
|
-
tags = MU::Cloud::AWS.elasticsearch(@config['region']).list_tags(arn: deploy_struct[:arn]).tag_list
|
95
|
+
tags = MU::Cloud::AWS.elasticsearch(region: @config['region'], credentials: @config['credentials']).list_tags(arn: deploy_struct[:arn]).tag_list
|
95
96
|
deploy_struct['tags'] = tags.map { |t| { t.key => t.value } }
|
96
97
|
if deploy_struct['endpoint']
|
97
98
|
deploy_struct['kibana'] = deploy_struct['endpoint']+"/_plugin/kibana/"
|
@@ -100,23 +101,30 @@ module MU
|
|
100
101
|
deploy_struct
|
101
102
|
end
|
102
103
|
|
104
|
+
# Does this resource type exist as a global (cloud-wide) artifact, or
|
105
|
+
# is it localized to a region/zone?
|
106
|
+
# @return [Boolean]
|
107
|
+
def self.isGlobal?
|
108
|
+
false
|
109
|
+
end
|
110
|
+
|
103
111
|
# Remove all search_domains associated with the currently loaded deployment.
|
104
112
|
# @param noop [Boolean]: If true, will only print what would be done
|
105
113
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
106
114
|
# @param region [String]: The cloud provider region
|
107
115
|
# @return [void]
|
108
|
-
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, flags: {})
|
109
|
-
list = MU::Cloud::AWS.elasticsearch(region).list_domain_names
|
116
|
+
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
117
|
+
list = MU::Cloud::AWS.elasticsearch(region: region).list_domain_names
|
110
118
|
if list and list.domain_names and list.domain_names.size > 0
|
111
|
-
descs = MU::Cloud::AWS.elasticsearch(region).describe_elasticsearch_domains(domain_names: list.domain_names.map { |d| d.domain_name } )
|
119
|
+
descs = MU::Cloud::AWS.elasticsearch(region: region).describe_elasticsearch_domains(domain_names: list.domain_names.map { |d| d.domain_name } )
|
112
120
|
|
113
121
|
descs.domain_status_list.each { |domain|
|
114
|
-
tags = MU::Cloud::AWS.elasticsearch(region).list_tags(arn: domain.arn)
|
122
|
+
tags = MU::Cloud::AWS.elasticsearch(region: region).list_tags(arn: domain.arn)
|
115
123
|
tags.tag_list.each { |tag|
|
116
124
|
if tag.key == "MU-ID" and tag.value == MU.deploy_id
|
117
125
|
MU.log "Deleting ElasticSearch Domain #{domain.domain_name}"
|
118
126
|
if !noop
|
119
|
-
MU::Cloud::AWS.elasticsearch(region).delete_elasticsearch_domain(domain_name: domain.domain_name)
|
127
|
+
MU::Cloud::AWS.elasticsearch(region: region).delete_elasticsearch_domain(domain_name: domain.domain_name)
|
120
128
|
end
|
121
129
|
break
|
122
130
|
end
|
@@ -142,14 +150,14 @@ module MU
|
|
142
150
|
# @param region [String]: The cloud provider region.
|
143
151
|
# @param flags [Hash]: Optional flags
|
144
152
|
# @return [OpenStruct]: The cloud provider's complete descriptions of matching search_domain.
|
145
|
-
def self.find(cloud_id: nil, region: MU.curRegion, flags: {})
|
153
|
+
def self.find(cloud_id: nil, region: MU.curRegion, credentials: nil, flags: {})
|
146
154
|
if cloud_id
|
147
155
|
# Annoyingly, we might expect one of several possible artifacts,
|
148
156
|
# since AWS couldn't decide what the real identifier of these
|
149
157
|
# things should be
|
150
|
-
list = MU::Cloud::AWS.elasticsearch(region).list_domain_names
|
158
|
+
list = MU::Cloud::AWS.elasticsearch(region: region, credentials: credentials).list_domain_names
|
151
159
|
if list and list.domain_names and list.domain_names.size > 0
|
152
|
-
descs = MU::Cloud::AWS.elasticsearch(region).describe_elasticsearch_domains(domain_names: list.domain_names.map { |d| d.domain_name } )
|
160
|
+
descs = MU::Cloud::AWS.elasticsearch(region: region, credentials: credentials).describe_elasticsearch_domains(domain_names: list.domain_names.map { |d| d.domain_name } )
|
153
161
|
descs.domain_status_list.each { |domain|
|
154
162
|
return domain if domain.arn == cloud_id
|
155
163
|
return domain if domain.domain_name == cloud_id
|
@@ -180,6 +188,10 @@ module MU
|
|
180
188
|
end
|
181
189
|
|
182
190
|
schema = {
|
191
|
+
"name" => {
|
192
|
+
"type" => "string",
|
193
|
+
"pattern" => '^[a-z][a-z0-9\-]+$'
|
194
|
+
},
|
183
195
|
"elasticsearch_version" => {
|
184
196
|
"type" => "string",
|
185
197
|
"default" => versions.first,
|
@@ -269,12 +281,12 @@ module MU
|
|
269
281
|
# @return [Boolean]: True if validation succeeded, False otherwise
|
270
282
|
def self.validateConfig(dom, configurator)
|
271
283
|
ok = true
|
272
|
-
versions = MU::Cloud::AWS.elasticsearch(dom['region']).list_elasticsearch_versions.elasticsearch_versions
|
284
|
+
versions = MU::Cloud::AWS.elasticsearch(region: dom['region']).list_elasticsearch_versions.elasticsearch_versions
|
273
285
|
if !versions.include?(dom["elasticsearch_version"])
|
274
286
|
MU.log "Invalid ElasticSearch version '#{dom["elasticsearch_version"]}' in SearchDomain '#{dom['name']}'", MU::ERR, details: versions
|
275
287
|
ok = false
|
276
288
|
else
|
277
|
-
resp = MU::Cloud::AWS.elasticsearch(dom['region']).list_elasticsearch_instance_types(
|
289
|
+
resp = MU::Cloud::AWS.elasticsearch(region: dom['region']).list_elasticsearch_instance_types(
|
278
290
|
elasticsearch_version: dom["elasticsearch_version"]
|
279
291
|
)
|
280
292
|
|
@@ -330,7 +342,7 @@ module MU
|
|
330
342
|
if configurator.haveLitterMate?(dom['slow_logs'], "log")
|
331
343
|
dom['dependencies'] << { "name" => dom['slow_logs'], "type" => "log" }
|
332
344
|
else
|
333
|
-
log_group = MU::Cloud::AWS::Log.find(cloud_id: dom['slow_logs'], region: dom['region'])
|
345
|
+
log_group = MU::Cloud::AWS::Log.find(cloud_id: dom['slow_logs'], region: dom['region']).values.first
|
334
346
|
if !log_group
|
335
347
|
MU.log "Specified slow_logs CloudWatch log group '#{dom['slow_logs']}' in SearchDomain '#{dom['name']}' doesn't appear to exist", MU::ERR
|
336
348
|
ok = false
|
@@ -340,7 +352,10 @@ module MU
|
|
340
352
|
end
|
341
353
|
else
|
342
354
|
dom['slow_logs'] = dom['name']+"-slowlog"
|
343
|
-
log_group = {
|
355
|
+
log_group = {
|
356
|
+
"name" => dom['slow_logs'],
|
357
|
+
"credentials" => dom['credentials']
|
358
|
+
}
|
344
359
|
ok = false if !configurator.insertKitten(log_group, "logs")
|
345
360
|
dom['dependencies'] << { "name" => dom['slow_logs'], "type" => "log" }
|
346
361
|
end
|
@@ -353,7 +368,7 @@ module MU
|
|
353
368
|
|
354
369
|
if dom['cognito']
|
355
370
|
begin
|
356
|
-
MU::Cloud::AWS.cognito_ident(dom['region']).describe_identity_pool(
|
371
|
+
MU::Cloud::AWS.cognito_ident(region: dom['region']).describe_identity_pool(
|
357
372
|
identity_pool_id: dom['cognito']['identity_pool_id']
|
358
373
|
)
|
359
374
|
rescue ::Aws::CognitoIdentity::Errors::ValidationException, Aws::CognitoIdentity::Errors::ResourceNotFoundException => e
|
@@ -361,7 +376,7 @@ module MU
|
|
361
376
|
ok = false
|
362
377
|
end
|
363
378
|
begin
|
364
|
-
MU::Cloud::AWS.cognito_user(dom['region']).describe_user_pool(
|
379
|
+
MU::Cloud::AWS.cognito_user(region: dom['region']).describe_user_pool(
|
365
380
|
user_pool_id: dom['cognito']['user_pool_id']
|
366
381
|
)
|
367
382
|
rescue ::Aws::CognitoIdentityProvider::Errors::InvalidParameterException, Aws::CognitoIdentityProvider::Errors::ResourceNotFoundException => e
|
@@ -373,10 +388,10 @@ module MU
|
|
373
388
|
rolename = dom['cognito']['role_arn'].sub(/.*?:role\/([a-z0-9-]+)$/, '\1')
|
374
389
|
begin
|
375
390
|
if !dom['cognito']['role_arn'].match(/^arn:/)
|
376
|
-
role = MU::Cloud::AWS.iam
|
391
|
+
role = MU::Cloud::AWS.iam.get_role(role_name: rolename)
|
377
392
|
dom['cognito']['role_arn'] = role.role.arn
|
378
393
|
end
|
379
|
-
pols = MU::Cloud::AWS.iam
|
394
|
+
pols = MU::Cloud::AWS.iam.list_attached_role_policies(role_name: rolename).attached_policies
|
380
395
|
found = false
|
381
396
|
pols.each { |policy|
|
382
397
|
found = true if policy.policy_name == "AmazonESCognitoAccess"
|
@@ -391,6 +406,7 @@ module MU
|
|
391
406
|
else
|
392
407
|
roledesc = {
|
393
408
|
"name" => dom['name']+"cognitorole",
|
409
|
+
"credentials" => dom['credentials'],
|
394
410
|
"can_assume" => [
|
395
411
|
{
|
396
412
|
"entity_id" => "es.amazonaws.com",
|
@@ -471,7 +487,7 @@ module MU
|
|
471
487
|
arn = @config['slow_logs']
|
472
488
|
else
|
473
489
|
log_group = @deploy.findLitterMate(type: "log", name: @config['slow_logs'])
|
474
|
-
log_group = MU::Cloud::AWS::Log.find(cloud_id: log_group.mu_name, region: log_group.cloudobj.config['region'])
|
490
|
+
log_group = MU::Cloud::AWS::Log.find(cloud_id: log_group.mu_name, region: log_group.cloudobj.config['region']).values.first
|
475
491
|
if log_group.nil? or log_group.arn.nil?
|
476
492
|
raise MuError, "Failed to retrieve ARN of sibling LogGroup '#{@config['slow_logs']}'"
|
477
493
|
end
|
@@ -619,7 +635,7 @@ module MU
|
|
619
635
|
raise MU::MuError, "Can't tag ElasticSearch domain, cloud descriptor came back without an ARN"
|
620
636
|
end
|
621
637
|
|
622
|
-
MU::Cloud::AWS.elasticsearch(@config['region']).add_tags(
|
638
|
+
MU::Cloud::AWS.elasticsearch(region: @config['region'], credentials: @config['credentials']).add_tags(
|
623
639
|
arn: domain.arn,
|
624
640
|
tag_list: tags
|
625
641
|
)
|
@@ -210,15 +210,15 @@ module MU
|
|
210
210
|
# @param tag_value [String]: The value of the tag to attach.
|
211
211
|
# @param region [String]: The cloud provider region
|
212
212
|
# @return [void]
|
213
|
-
def self.tagVolumes(instance_id, device: nil, tag_name: "MU-ID", tag_value: MU.deploy_id, region: MU.curRegion)
|
214
|
-
MU::Cloud::AWS.ec2(region).describe_volumes(filters: [name: "attachment.instance-id", values: [instance_id]]).each { |vol|
|
213
|
+
def self.tagVolumes(instance_id, device: nil, tag_name: "MU-ID", tag_value: MU.deploy_id, region: MU.curRegion, credentials: nil)
|
214
|
+
MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_volumes(filters: [name: "attachment.instance-id", values: [instance_id]]).each { |vol|
|
215
215
|
vol.volumes.each { |volume|
|
216
216
|
volume.attachments.each { |attachment|
|
217
217
|
vol_parent = attachment.instance_id
|
218
218
|
vol_id = attachment.volume_id
|
219
219
|
vol_dev = attachment.device
|
220
220
|
if vol_parent == instance_id and (vol_dev == device or device.nil?)
|
221
|
-
MU::MommaCat.createTag(vol_id, tag_name, tag_value, region: region)
|
221
|
+
MU::MommaCat.createTag(vol_id, tag_name, tag_value, region: region, credentials: credentials)
|
222
222
|
break
|
223
223
|
end
|
224
224
|
}
|
@@ -246,8 +246,8 @@ module MU
|
|
246
246
|
end
|
247
247
|
MU::MommaCat.unlock(instance.instance_id+"-create")
|
248
248
|
else
|
249
|
-
MU::MommaCat.createStandardTags(instance.instance_id, region: @config['region'])
|
250
|
-
MU::MommaCat.createTag(instance.instance_id, "Name", @mu_name, region: @config['region'])
|
249
|
+
MU::MommaCat.createStandardTags(instance.instance_id, region: @config['region'], credentials: @config['credentials'])
|
250
|
+
MU::MommaCat.createTag(instance.instance_id, "Name", @mu_name, region: @config['region'], credentials: @config['credentials'])
|
251
251
|
end
|
252
252
|
done = true
|
253
253
|
rescue Exception => e
|
@@ -258,7 +258,7 @@ module MU
|
|
258
258
|
parent_thread_id = Thread.current.object_id
|
259
259
|
Thread.new {
|
260
260
|
MU.dupGlobals(parent_thread_id)
|
261
|
-
MU::Cloud::AWS::Server.cleanup(noop: false, ignoremaster: false,
|
261
|
+
MU::Cloud::AWS::Server.cleanup(noop: false, ignoremaster: false, region: @config['region'], credentials: @config['credentials'], flags: { "skipsnapshots" => true } )
|
262
262
|
}
|
263
263
|
end
|
264
264
|
end
|
@@ -286,7 +286,6 @@ module MU
|
|
286
286
|
|
287
287
|
arn = nil
|
288
288
|
if @config['generate_iam_role']
|
289
|
-
# @config['iam_role'], @cfm_role_name, @cfm_prof_name, arn = MU::Cloud::AWS::Server.createIAMProfile(@mu_name, base_profile: @config['iam_role'], extra_policies: @config['iam_policies'])
|
290
289
|
role = @deploy.findLitterMate(name: @config['name'], type: "roles")
|
291
290
|
s3_objs = ["#{@deploy.deploy_id}-secret", "#{role.mu_name}.pfx", "#{role.mu_name}.crt", "#{role.mu_name}.key", "#{role.mu_name}-winrm.crt", "#{role.mu_name}-winrm.key"].map { |file|
|
292
291
|
'arn:'+(MU::Cloud::AWS.isGovCloud?(@config['region']) ? "aws-us-gov" : "aws")+':s3:::'+MU.adminBucketName+'/'+file
|
@@ -349,10 +348,10 @@ module MU
|
|
349
348
|
instance_descriptor[:user_data] = Base64.encode64(@userdata)
|
350
349
|
end
|
351
350
|
|
352
|
-
MU::Cloud::AWS::Server.waitForAMI(@config["ami_id"], region: @config['region'])
|
351
|
+
MU::Cloud::AWS::Server.waitForAMI(@config["ami_id"], region: @config['region'], credentials: @config['credentials'])
|
353
352
|
|
354
353
|
# Figure out which devices are embedded in the AMI already.
|
355
|
-
image = MU::Cloud::AWS.ec2(@config['region']).describe_images(image_ids: [@config["ami_id"]]).images.first
|
354
|
+
image = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_images(image_ids: [@config["ami_id"]]).images.first
|
356
355
|
ext_disks = {}
|
357
356
|
if !image.block_device_mappings.nil?
|
358
357
|
image.block_device_mappings.each { |disk|
|
@@ -391,7 +390,7 @@ module MU
|
|
391
390
|
|
392
391
|
retries = 0
|
393
392
|
begin
|
394
|
-
response = MU::Cloud::AWS.ec2(@config['region']).run_instances(instance_descriptor)
|
393
|
+
response = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).run_instances(instance_descriptor)
|
395
394
|
rescue Aws::EC2::Errors::InvalidGroupNotFound, Aws::EC2::Errors::InvalidSubnetIDNotFound, Aws::EC2::Errors::InvalidParameterValue => e
|
396
395
|
if retries < 10
|
397
396
|
if retries > 7
|
@@ -419,40 +418,40 @@ module MU
|
|
419
418
|
if hard
|
420
419
|
groupname = nil
|
421
420
|
if !@config['basis'].nil?
|
422
|
-
resp = MU::Cloud::AWS.autoscale(@config['region']).describe_auto_scaling_instances(
|
421
|
+
resp = MU::Cloud::AWS.autoscale(region: @config['region'], credentials: @config['credentials']).describe_auto_scaling_instances(
|
423
422
|
instance_ids: [@cloud_id]
|
424
423
|
)
|
425
424
|
groupname = resp.auto_scaling_instances.first.auto_scaling_group_name
|
426
425
|
MU.log "Pausing Autoscale processes in #{groupname}", MU::NOTICE
|
427
|
-
MU::Cloud::AWS.autoscale(@config['region']).suspend_processes(
|
426
|
+
MU::Cloud::AWS.autoscale(region: @config['region'], credentials: @config['credentials']).suspend_processes(
|
428
427
|
auto_scaling_group_name: groupname
|
429
428
|
)
|
430
429
|
end
|
431
430
|
begin
|
432
431
|
MU.log "Stopping #{@mu_name} (#{@cloud_id})", MU::NOTICE
|
433
|
-
MU::Cloud::AWS.ec2(@config['region']).stop_instances(
|
432
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).stop_instances(
|
434
433
|
instance_ids: [@cloud_id]
|
435
434
|
)
|
436
|
-
MU::Cloud::AWS.ec2(@config['region']).wait_until(:instance_stopped, instance_ids: [@cloud_id]) do |waiter|
|
435
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).wait_until(:instance_stopped, instance_ids: [@cloud_id]) do |waiter|
|
437
436
|
waiter.before_attempt do |attempts|
|
438
437
|
MU.log "Waiting for #{@mu_name} to stop for hard reboot"
|
439
438
|
end
|
440
439
|
end
|
441
440
|
MU.log "Starting #{@mu_name} (#{@cloud_id})"
|
442
|
-
MU::Cloud::AWS.ec2(@config['region']).start_instances(
|
441
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).start_instances(
|
443
442
|
instance_ids: [@cloud_id]
|
444
443
|
)
|
445
444
|
ensure
|
446
445
|
if !groupname.nil?
|
447
446
|
MU.log "Resuming Autoscale processes in #{groupname}", MU::NOTICE
|
448
|
-
MU::Cloud::AWS.autoscale(@config['region']).resume_processes(
|
447
|
+
MU::Cloud::AWS.autoscale(region: @config['region'], credentials: @config['credentials']).resume_processes(
|
449
448
|
auto_scaling_group_name: groupname
|
450
449
|
)
|
451
450
|
end
|
452
451
|
end
|
453
452
|
else
|
454
453
|
MU.log "Rebooting #{@mu_name} (#{@cloud_id})"
|
455
|
-
MU::Cloud::AWS.ec2(@config['region']).reboot_instances(
|
454
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).reboot_instances(
|
456
455
|
instance_ids: [@cloud_id]
|
457
456
|
)
|
458
457
|
end
|
@@ -468,7 +467,7 @@ module MU
|
|
468
467
|
return nil if @config.nil? or @deploy.nil?
|
469
468
|
|
470
469
|
nat_ssh_key = nat_ssh_user = nat_ssh_host = nil
|
471
|
-
if !@config["vpc"].nil? and !MU::Cloud::AWS::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'])
|
470
|
+
if !@config["vpc"].nil? and !MU::Cloud::AWS::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'], credentials: @config['credentials'])
|
472
471
|
if !@nat.nil?
|
473
472
|
if @nat.is_a?(Struct) && @nat.nat_gateway_id && @nat.nat_gateway_id.start_with?("nat-")
|
474
473
|
raise MuError, "Configured to use NAT Gateway, but I have no route to instance. Either use Bastion, or configure VPC peering"
|
@@ -516,18 +515,18 @@ module MU
|
|
516
515
|
return false if !MU::MommaCat.lock(instance.instance_id+"-orchestrate", true)
|
517
516
|
return false if !MU::MommaCat.lock(instance.instance_id+"-groom", true)
|
518
517
|
|
519
|
-
MU::MommaCat.createStandardTags(instance.instance_id, region: @config['region'])
|
520
|
-
MU::MommaCat.createTag(instance.instance_id, "Name", node, region: @config['region'])
|
518
|
+
MU::MommaCat.createStandardTags(instance.instance_id, region: @config['region'], credentials: @config['credentials'])
|
519
|
+
MU::MommaCat.createTag(instance.instance_id, "Name", node, region: @config['region'], credentials: @config['credentials'])
|
521
520
|
|
522
521
|
if @config['optional_tags']
|
523
522
|
MU::MommaCat.listOptionalTags.each { |key, value|
|
524
|
-
MU::MommaCat.createTag(instance.instance_id, key, value, region: @config['region'])
|
523
|
+
MU::MommaCat.createTag(instance.instance_id, key, value, region: @config['region'], credentials: @config['credentials'])
|
525
524
|
}
|
526
525
|
end
|
527
526
|
|
528
527
|
if !@config['tags'].nil?
|
529
528
|
@config['tags'].each { |tag|
|
530
|
-
MU::MommaCat.createTag(instance.instance_id, tag['key'], tag['value'], region: @config['region'])
|
529
|
+
MU::MommaCat.createTag(instance.instance_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
|
531
530
|
}
|
532
531
|
end
|
533
532
|
MU.log "Tagged #{node} (#{instance.instance_id}) with MU-ID=#{MU.deploy_id}", MU::DEBUG
|
@@ -552,7 +551,7 @@ module MU
|
|
552
551
|
end
|
553
552
|
sleep 40
|
554
553
|
# Get a fresh AWS descriptor
|
555
|
-
instance = MU::Cloud::Server.find(cloud_id: @cloud_id, region: @config['region']).values.first
|
554
|
+
instance = MU::Cloud::Server.find(cloud_id: @cloud_id, region: @config['region'], credentials: @config['credentials']).values.first
|
556
555
|
if instance and instance.state.name == "terminated"
|
557
556
|
raise MuError, "EC2 instance #{node} (#{@cloud_id}) terminating during bootstrap!"
|
558
557
|
end
|
@@ -572,6 +571,8 @@ module MU
|
|
572
571
|
|
573
572
|
# If we came up via AutoScale, the Alarm module won't have had our
|
574
573
|
# instance ID to associate us with itself. So invoke that here.
|
574
|
+
# XXX might be possible to do this with regular alarm resources and
|
575
|
+
# dependencies now
|
575
576
|
if !@config['basis'].nil? and @config["alarms"] and !@config["alarms"].empty?
|
576
577
|
@config["alarms"].each { |alarm|
|
577
578
|
alarm_obj = MU::MommaCat.findStray(
|
@@ -584,8 +585,8 @@ module MU
|
|
584
585
|
alarm["dimensions"] = [{:name => "InstanceId", :value => @cloud_id}]
|
585
586
|
|
586
587
|
if alarm["enable_notifications"]
|
587
|
-
topic_arn = MU::Cloud::AWS::Notification.createTopic(alarm["notification_group"], region: @config["region"])
|
588
|
-
MU::Cloud::AWS::Notification.subscribe(arn: topic_arn, protocol: alarm["notification_type"], endpoint: alarm["notification_endpoint"], region: @config["region"])
|
588
|
+
topic_arn = MU::Cloud::AWS::Notification.createTopic(alarm["notification_group"], region: @config["region"], credentials: @config['credentials'])
|
589
|
+
MU::Cloud::AWS::Notification.subscribe(arn: topic_arn, protocol: alarm["notification_type"], endpoint: alarm["notification_endpoint"], region: @config["region"], credentials: @config["credentials"])
|
589
590
|
alarm["alarm_actions"] = [topic_arn]
|
590
591
|
alarm["ok_actions"] = [topic_arn]
|
591
592
|
end
|
@@ -606,7 +607,8 @@ module MU
|
|
606
607
|
evaluation_periods: alarm["evaluation_periods"],
|
607
608
|
threshold: alarm["threshold"],
|
608
609
|
comparison_operator: alarm["comparison_operator"],
|
609
|
-
region: @config["region"]
|
610
|
+
region: @config["region"],
|
611
|
+
credentials: @config['credentials']
|
610
612
|
)
|
611
613
|
}
|
612
614
|
end
|
@@ -635,7 +637,7 @@ module MU
|
|
635
637
|
|
636
638
|
if !@config['src_dst_check'] and !@config["vpc"].nil?
|
637
639
|
MU.log "Disabling source_dest_check #{node} (making it NAT-worthy)"
|
638
|
-
MU::Cloud::AWS.ec2(@config['region']).modify_instance_attribute(
|
640
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_instance_attribute(
|
639
641
|
instance_id: @cloud_id,
|
640
642
|
source_dest_check: {:value => false}
|
641
643
|
)
|
@@ -643,7 +645,7 @@ module MU
|
|
643
645
|
|
644
646
|
# Set console termination protection. Autoscale nodes won't set this
|
645
647
|
# by default.
|
646
|
-
MU::Cloud::AWS.ec2(@config['region']).modify_instance_attribute(
|
648
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).modify_instance_attribute(
|
647
649
|
instance_id: @cloud_id,
|
648
650
|
disable_api_termination: {:value => true}
|
649
651
|
)
|
@@ -651,7 +653,7 @@ module MU
|
|
651
653
|
has_elastic_ip = false
|
652
654
|
if !instance.public_ip_address.nil?
|
653
655
|
begin
|
654
|
-
resp = MU::Cloud::AWS.ec2(
|
656
|
+
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_addresses(public_ips: [instance.public_ip_address])
|
655
657
|
if resp.addresses.size > 0 and resp.addresses.first.instance_id == @cloud_id
|
656
658
|
has_elastic_ip = true
|
657
659
|
end
|
@@ -737,7 +739,7 @@ module MU
|
|
737
739
|
end
|
738
740
|
|
739
741
|
nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
|
740
|
-
if subnet.private? and !nat_ssh_host and !MU::Cloud::AWS::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'])
|
742
|
+
if subnet.private? and !nat_ssh_host and !MU::Cloud::AWS::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'], credentials: @config['credentials'])
|
741
743
|
raise MuError, "#{node} is in a private subnet (#{subnet}), but has no NAT host configured, and I have no other route to it"
|
742
744
|
end
|
743
745
|
|
@@ -749,23 +751,23 @@ module MU
|
|
749
751
|
@vpc.subnets { |subnet|
|
750
752
|
subnet_id = subnet.cloud_id
|
751
753
|
MU.log "Adding network interface on subnet #{subnet_id} for #{node}"
|
752
|
-
iface = MU::Cloud::AWS.ec2(@config['region']).create_network_interface(subnet_id: subnet_id).network_interface
|
753
|
-
MU::MommaCat.createStandardTags(iface.network_interface_id, region: @config['region'])
|
754
|
-
MU::MommaCat.createTag(iface.network_interface_id, "Name", node+"-ETH"+device_index.to_s, region: @config['region'])
|
754
|
+
iface = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_network_interface(subnet_id: subnet_id).network_interface
|
755
|
+
MU::MommaCat.createStandardTags(iface.network_interface_id, region: @config['region'], credentials: @config['credentials'])
|
756
|
+
MU::MommaCat.createTag(iface.network_interface_id, "Name", node+"-ETH"+device_index.to_s, region: @config['region'], credentials: @config['credentials'])
|
755
757
|
|
756
758
|
if @config['optional_tags']
|
757
759
|
MU::MommaCat.listOptionalTags.each { |key, value|
|
758
|
-
MU::MommaCat.createTag(iface.network_interface_id, key, value, region: @config['region'])
|
760
|
+
MU::MommaCat.createTag(iface.network_interface_id, key, value, region: @config['region'], credentials: @config['credentials'])
|
759
761
|
}
|
760
762
|
end
|
761
763
|
|
762
764
|
if !@config['tags'].nil?
|
763
765
|
@config['tags'].each { |tag|
|
764
|
-
MU::MommaCat.createTag(iface.network_interface_id, tag['key'], tag['value'], region: @config['region'])
|
766
|
+
MU::MommaCat.createTag(iface.network_interface_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
|
765
767
|
}
|
766
768
|
end
|
767
769
|
|
768
|
-
MU::Cloud::AWS.ec2(@config['region']).attach_network_interface(
|
770
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).attach_network_interface(
|
769
771
|
network_interface_id: iface.network_interface_id,
|
770
772
|
instance_id: instance.instance_id,
|
771
773
|
device_index: device_index
|
@@ -805,29 +807,29 @@ module MU
|
|
805
807
|
|
806
808
|
# Tag volumes with all our standard tags.
|
807
809
|
# Maybe replace tagVolumes with this? There is one more place tagVolumes is called from
|
808
|
-
volumes = MU::Cloud::AWS.ec2(@config['region']).describe_volumes(filters: [name: "attachment.instance-id", values: [instance.instance_id]])
|
810
|
+
volumes = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_volumes(filters: [name: "attachment.instance-id", values: [instance.instance_id]])
|
809
811
|
volumes.each { |vol|
|
810
812
|
vol.volumes.each { |volume|
|
811
813
|
volume.attachments.each { |attachment|
|
812
814
|
MU::MommaCat.listStandardTags.each_pair { |key, value|
|
813
|
-
MU::MommaCat.createTag(attachment.volume_id, key, value, region: @config['region'])
|
815
|
+
MU::MommaCat.createTag(attachment.volume_id, key, value, region: @config['region'], credentials: @config['credentials'])
|
814
816
|
|
815
817
|
if attachment.device == "/dev/sda" or attachment.device == "/dev/sda1"
|
816
|
-
MU::MommaCat.createTag(attachment.volume_id, "Name", "ROOT-#{MU.deploy_id}-#{@config["name"].upcase}", region: @config['region'])
|
818
|
+
MU::MommaCat.createTag(attachment.volume_id, "Name", "ROOT-#{MU.deploy_id}-#{@config["name"].upcase}", region: @config['region'], credentials: @config['credentials'])
|
817
819
|
else
|
818
|
-
MU::MommaCat.createTag(attachment.volume_id, "Name", "#{MU.deploy_id}-#{@config["name"].upcase}-#{attachment.device.upcase}", region: @config['region'])
|
820
|
+
MU::MommaCat.createTag(attachment.volume_id, "Name", "#{MU.deploy_id}-#{@config["name"].upcase}-#{attachment.device.upcase}", region: @config['region'], credentials: @config['credentials'])
|
819
821
|
end
|
820
822
|
}
|
821
823
|
|
822
824
|
if @config['optional_tags']
|
823
825
|
MU::MommaCat.listOptionalTags.each { |key, value|
|
824
|
-
MU::MommaCat.createTag(attachment.volume_id, key, value, region: @config['region'])
|
826
|
+
MU::MommaCat.createTag(attachment.volume_id, key, value, region: @config['region'], credentials: @config['credentials'])
|
825
827
|
}
|
826
828
|
end
|
827
829
|
|
828
830
|
if @config['tags']
|
829
831
|
@config['tags'].each { |tag|
|
830
|
-
MU::MommaCat.createTag(attachment.volume_id, tag['key'], tag['value'], region: @config['region'])
|
832
|
+
MU::MommaCat.createTag(attachment.volume_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
|
831
833
|
}
|
832
834
|
end
|
833
835
|
}
|
@@ -842,7 +844,7 @@ module MU
|
|
842
844
|
instance.network_interfaces.each { |int|
|
843
845
|
if int.private_ip_address == instance.private_ip_address and int.private_ip_addresses.size < (@config['add_private_ips'] + 1)
|
844
846
|
MU.log "Adding #{@config['add_private_ips']} extra private IP addresses to #{instance.instance_id}"
|
845
|
-
MU::Cloud::AWS.ec2(@config['region']).assign_private_ip_addresses(
|
847
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).assign_private_ip_addresses(
|
846
848
|
network_interface_id: int.network_interface_id,
|
847
849
|
secondary_private_ip_address_count: @config['add_private_ips'],
|
848
850
|
allow_reassignment: false
|
@@ -853,31 +855,33 @@ module MU
|
|
853
855
|
end
|
854
856
|
|
855
857
|
begin
|
856
|
-
if
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
@
|
861
|
-
|
862
|
-
if !@groomer.haveBootstrapped?
|
863
|
-
session = getWinRMSession(50, 60, reboot_on_problems: true)
|
864
|
-
initialWinRMTasks(session)
|
865
|
-
begin
|
866
|
-
session.close
|
867
|
-
rescue Exception
|
868
|
-
# this is allowed to fail- we're probably rebooting anyway
|
858
|
+
if @config['groom'].nil? or @config['groom']
|
859
|
+
if windows?
|
860
|
+
# kick off certificate generation early; WinRM will need it
|
861
|
+
cert, key = @deploy.nodeSSLCerts(self)
|
862
|
+
if @config.has_key?("basis")
|
863
|
+
@deploy.nodeSSLCerts(self, true)
|
869
864
|
end
|
870
|
-
|
871
|
-
|
872
|
-
session
|
873
|
-
|
874
|
-
|
875
|
-
|
865
|
+
if !@groomer.haveBootstrapped?
|
866
|
+
session = getWinRMSession(50, 60, reboot_on_problems: true)
|
867
|
+
initialWinRMTasks(session)
|
868
|
+
begin
|
869
|
+
session.close
|
870
|
+
rescue Exception
|
871
|
+
# this is allowed to fail- we're probably rebooting anyway
|
872
|
+
end
|
873
|
+
else # for an existing Windows node: WinRM, then SSH if it fails
|
874
|
+
begin
|
875
|
+
session = getWinRMSession(1, 60)
|
876
|
+
rescue Exception # yeah, yeah
|
877
|
+
session = getSSHSession(1, 60)
|
878
|
+
# XXX maybe loop at least once if this also fails?
|
879
|
+
end
|
876
880
|
end
|
881
|
+
else
|
882
|
+
session = getSSHSession(40, 30)
|
883
|
+
initialSSHTasks(session)
|
877
884
|
end
|
878
|
-
else
|
879
|
-
session = getSSHSession(40, 30)
|
880
|
-
initialSSHTasks(session)
|
881
885
|
end
|
882
886
|
rescue BootstrapTempFail
|
883
887
|
sleep 45
|
@@ -922,14 +926,16 @@ module MU
|
|
922
926
|
# we're done.
|
923
927
|
if @groomer.haveBootstrapped?
|
924
928
|
MU.log "Node #{node} has already been bootstrapped, skipping groomer setup.", MU::NOTICE
|
925
|
-
@
|
929
|
+
if @config['groom'].nil? or @config['groom']
|
930
|
+
@groomer.saveDeployData
|
931
|
+
end
|
926
932
|
MU::MommaCat.unlock(instance.instance_id+"-orchestrate")
|
927
933
|
MU::MommaCat.unlock(instance.instance_id+"-groom")
|
928
934
|
return true
|
929
935
|
end
|
930
936
|
|
931
937
|
begin
|
932
|
-
@groomer.bootstrap
|
938
|
+
@groomer.bootstrap if @config['groom'].nil? or @config['groom']
|
933
939
|
rescue MU::Groomer::RunError
|
934
940
|
MU::MommaCat.unlock(instance.instance_id+"-groom")
|
935
941
|
MU::MommaCat.unlock(instance.instance_id+"-orchestrate")
|
@@ -954,11 +960,11 @@ module MU
|
|
954
960
|
# @param region [String]: The cloud provider region
|
955
961
|
# @param tag_key [String]: A tag key to search.
|
956
962
|
# @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
|
957
|
-
# @param ip [String]: An IP address associated with the instance
|
958
963
|
# @param flags [Hash]: Optional flags
|
959
964
|
# @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching instances
|
960
|
-
def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil,
|
965
|
+
def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, credentials: nil, flags: {})
|
961
966
|
# XXX put that 'ip' value into opts
|
967
|
+
ip ||= flags['ip']
|
962
968
|
instance = nil
|
963
969
|
if !region.nil?
|
964
970
|
regions = [region]
|
@@ -977,7 +983,7 @@ module MU
|
|
977
983
|
MU.log "Hunting for instance with cloud id '#{cloud_id}' in #{region}", MU::DEBUG
|
978
984
|
retries = 0
|
979
985
|
begin
|
980
|
-
MU::Cloud::AWS.ec2(region).describe_instances(
|
986
|
+
MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_instances(
|
981
987
|
instance_ids: [cloud_id],
|
982
988
|
filters: [
|
983
989
|
{name: "instance-state-name", values: ["running", "pending"]}
|
@@ -1018,7 +1024,7 @@ module MU
|
|
1018
1024
|
if instance.nil? and !ip.nil?
|
1019
1025
|
MU.log "Hunting for instance by IP '#{ip}'", MU::DEBUG
|
1020
1026
|
["ip-address", "private-ip-address"].each { |filter|
|
1021
|
-
response = MU::Cloud::AWS.ec2(region).describe_instances(
|
1027
|
+
response = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_instances(
|
1022
1028
|
filters: [
|
1023
1029
|
{name: filter, values: [ip]},
|
1024
1030
|
{name: "instance-state-name", values: ["running", "pending"]}
|
@@ -1035,7 +1041,7 @@ module MU
|
|
1035
1041
|
# Fine, let's try it by tag.
|
1036
1042
|
if !tag_value.nil?
|
1037
1043
|
MU.log "Searching for instance by tag '#{tag_key}=#{tag_value}'", MU::DEBUG
|
1038
|
-
MU::Cloud::AWS.ec2(region).describe_instances(
|
1044
|
+
MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_instances(
|
1039
1045
|
filters: [
|
1040
1046
|
{name: "tag:#{tag_key}", values: [tag_value]},
|
1041
1047
|
{name: "instance-state-name", values: ["running", "pending"]}
|
@@ -1158,7 +1164,7 @@ module MU
|
|
1158
1164
|
|
1159
1165
|
punchAdminNAT
|
1160
1166
|
|
1161
|
-
MU::Cloud::AWS::Server.tagVolumes(@cloud_id)
|
1167
|
+
MU::Cloud::AWS::Server.tagVolumes(@cloud_id, credentials: @config['credentials'])
|
1162
1168
|
|
1163
1169
|
# If we have a loadbalancer configured, attach us to it
|
1164
1170
|
if !@config['loadbalancers'].nil?
|
@@ -1182,10 +1188,14 @@ module MU
|
|
1182
1188
|
# }
|
1183
1189
|
# end
|
1184
1190
|
|
1185
|
-
@
|
1191
|
+
if @config['groom'].nil? or @config['groom']
|
1192
|
+
@groomer.saveDeployData
|
1193
|
+
end
|
1186
1194
|
|
1187
1195
|
begin
|
1188
|
-
@
|
1196
|
+
if @config['groom'].nil? or @config['groom']
|
1197
|
+
@groomer.run(purpose: "Full Initial Run", max_retries: 15, reboot_first_fail: windows?, timeout: @config['groomer_timeout'])
|
1198
|
+
end
|
1189
1199
|
rescue MU::Groomer::RunError => e
|
1190
1200
|
MU.log "Proceeding after failed initial Groomer run, but #{node} may not behave as expected!", MU::WARN, details: e.message
|
1191
1201
|
rescue Exception => e
|
@@ -1221,13 +1231,15 @@ module MU
|
|
1221
1231
|
copy_to_regions: img_cfg['copy_to_regions'],
|
1222
1232
|
make_public: img_cfg['public'],
|
1223
1233
|
region: @config['region'],
|
1224
|
-
tags: @config['tags']
|
1234
|
+
tags: @config['tags'],
|
1235
|
+
credentials: @config['credentials']
|
1236
|
+
)
|
1225
1237
|
@deploy.notify("images", @config['name'], {"image_id" => ami_id})
|
1226
1238
|
@config['image_created'] = true
|
1227
1239
|
if img_cfg['image_then_destroy']
|
1228
|
-
MU::Cloud::AWS::Server.waitForAMI(ami_id, region: @config['region'])
|
1240
|
+
MU::Cloud::AWS::Server.waitForAMI(ami_id, region: @config['region'], credentials: @config['credentials'])
|
1229
1241
|
MU.log "AMI #{ami_id} ready, removing source node #{node}"
|
1230
|
-
MU::Cloud::AWS::Server.terminateInstance(id: @cloud_id, region: @config['region'], deploy_id: @deploy.deploy_id, mu_name: @mu_name)
|
1242
|
+
MU::Cloud::AWS::Server.terminateInstance(id: @cloud_id, region: @config['region'], deploy_id: @deploy.deploy_id, mu_name: @mu_name, credentials: @config['credentials'])
|
1231
1243
|
destroy
|
1232
1244
|
end
|
1233
1245
|
end
|
@@ -1238,7 +1250,7 @@ module MU
|
|
1238
1250
|
# Canonical Amazon Resource Number for this resource
|
1239
1251
|
# @return [String]
|
1240
1252
|
def arn
|
1241
|
-
"arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":ec2:"+@config['region']+":"+MU.
|
1253
|
+
"arn:"+(MU::Cloud::AWS.isGovCloud?(@config["region"]) ? "aws-us-gov" : "aws")+":ec2:"+@config['region']+":"+MU::Cloud::AWS.credToAcct(@config['credentials'])+":instance/"+@cloud_id
|
1242
1254
|
end
|
1243
1255
|
|
1244
1256
|
def cloud_desc
|
@@ -1246,7 +1258,7 @@ module MU
|
|
1246
1258
|
retries = 0
|
1247
1259
|
if !@cloud_id.nil?
|
1248
1260
|
begin
|
1249
|
-
return MU::Cloud::AWS.ec2(@config['region']).describe_instances(instance_ids: [@cloud_id]).reservations.first.instances.first
|
1261
|
+
return MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_instances(instance_ids: [@cloud_id]).reservations.first.instances.first
|
1250
1262
|
rescue Aws::EC2::Errors::InvalidInstanceIDNotFound
|
1251
1263
|
return nil
|
1252
1264
|
rescue NoMethodError => e
|
@@ -1291,7 +1303,7 @@ module MU
|
|
1291
1303
|
# Our deploydata gets corrupted often with server pools, this will cause us to use the wrong IP to identify a node
|
1292
1304
|
# which will cause us to create certificates, DNS records and other artifacts with incorrect information which will cause our deploy to fail.
|
1293
1305
|
# The cloud_id is always correct so lets use 'cloud_desc' to get the correct IPs
|
1294
|
-
if MU::Cloud::AWS::VPC.haveRouteToInstance?(cloud_desc, region: @config['region']) or @deploydata["public_ip_address"].nil?
|
1306
|
+
if MU::Cloud::AWS::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'], credentials: @config['credentials']) or @deploydata["public_ip_address"].nil?
|
1295
1307
|
@config['canonical_ip'] = instance.private_ip_address
|
1296
1308
|
@deploydata["private_ip_address"] = instance.private_ip_address
|
1297
1309
|
return instance.private_ip_address
|
@@ -1311,7 +1323,7 @@ module MU
|
|
1311
1323
|
# @param copy_to_regions [Array<String>]: Copy the resulting AMI into the listed regions.
|
1312
1324
|
# @param tags [Array<String>]: Extra/override tags to apply to the image.
|
1313
1325
|
# @return [String]: The cloud provider identifier of the new machine image.
|
1314
|
-
def self.createImage(name: nil, instance_id: nil, storage: {}, exclude_storage: false, make_public: false, region: MU.curRegion, copy_to_regions: [], tags: [])
|
1326
|
+
def self.createImage(name: nil, instance_id: nil, storage: {}, exclude_storage: false, make_public: false, region: MU.curRegion, copy_to_regions: [], tags: [], credentials: nil)
|
1315
1327
|
ami_descriptor = {
|
1316
1328
|
:instance_id => instance_id,
|
1317
1329
|
:name => name,
|
@@ -1344,18 +1356,18 @@ module MU
|
|
1344
1356
|
MU.log "Creating AMI from #{name}", details: ami_descriptor
|
1345
1357
|
resp = nil
|
1346
1358
|
begin
|
1347
|
-
resp = MU::Cloud::AWS.ec2(region).create_image(ami_descriptor)
|
1359
|
+
resp = MU::Cloud::AWS.ec2(region: region).create_image(ami_descriptor)
|
1348
1360
|
rescue Aws::EC2::Errors::InvalidAMINameDuplicate => e
|
1349
1361
|
MU.log "AMI #{name} already exists, skipping", MU::WARN
|
1350
1362
|
return nil
|
1351
1363
|
end
|
1352
1364
|
ami = resp.image_id
|
1353
|
-
MU::MommaCat.createStandardTags(ami, region: region)
|
1354
|
-
MU::MommaCat.createTag(ami, "Name", name, region: region)
|
1365
|
+
MU::MommaCat.createStandardTags(ami, region: region, credentials: credentials)
|
1366
|
+
MU::MommaCat.createTag(ami, "Name", name, region: region, credentials: credentials)
|
1355
1367
|
MU.log "AMI of #{name} in region #{region}: #{ami}"
|
1356
1368
|
if make_public
|
1357
|
-
MU::Cloud::AWS::Server.waitForAMI(ami, region: region)
|
1358
|
-
MU::Cloud::AWS.ec2(region).modify_image_attribute(
|
1369
|
+
MU::Cloud::AWS::Server.waitForAMI(ami, region: region, credentials: credentials)
|
1370
|
+
MU::Cloud::AWS.ec2(region: region).modify_image_attribute(
|
1359
1371
|
image_id: ami,
|
1360
1372
|
launch_permission: {add: [{group: "all"}]},
|
1361
1373
|
attribute: "launchPermission"
|
@@ -1364,12 +1376,12 @@ module MU
|
|
1364
1376
|
copythreads = []
|
1365
1377
|
if !copy_to_regions.nil? and copy_to_regions.size > 0
|
1366
1378
|
parent_thread_id = Thread.current.object_id
|
1367
|
-
MU::Cloud::AWS::Server.waitForAMI(ami, region: region) if !make_public
|
1379
|
+
MU::Cloud::AWS::Server.waitForAMI(ami, region: region, credentials: credentials) if !make_public
|
1368
1380
|
copy_to_regions.each { |r|
|
1369
1381
|
next if r == region
|
1370
1382
|
copythreads << Thread.new {
|
1371
1383
|
MU.dupGlobals(parent_thread_id)
|
1372
|
-
copy = MU::Cloud::AWS.ec2(r).copy_image(
|
1384
|
+
copy = MU::Cloud::AWS.ec2(region: r).copy_image(
|
1373
1385
|
source_region: region,
|
1374
1386
|
source_image_id: ami,
|
1375
1387
|
name: name,
|
@@ -1378,15 +1390,15 @@ module MU
|
|
1378
1390
|
MU.log "Initiated copy of #{ami} from #{region} to #{r}: #{copy.image_id}"
|
1379
1391
|
|
1380
1392
|
MU::MommaCat.createStandardTags(copy.image_id, region: r)
|
1381
|
-
MU::MommaCat.createTag(copy.image_id, "Name", name, region: r)
|
1393
|
+
MU::MommaCat.createTag(copy.image_id, "Name", name, region: r, credentials: credentials)
|
1382
1394
|
if !tags.nil?
|
1383
1395
|
tags.each { |tag|
|
1384
|
-
MU::MommaCat.createTag(instance.instance_id, tag['key'], tag['value'], region: r)
|
1396
|
+
MU::MommaCat.createTag(instance.instance_id, tag['key'], tag['value'], region: r, credentials: credentials)
|
1385
1397
|
}
|
1386
1398
|
end
|
1387
|
-
MU::Cloud::AWS::Server.waitForAMI(copy.image_id, region: r)
|
1399
|
+
MU::Cloud::AWS::Server.waitForAMI(copy.image_id, region: r, credentials: credentials)
|
1388
1400
|
if make_public
|
1389
|
-
MU::Cloud::AWS.ec2(r).modify_image_attribute(
|
1401
|
+
MU::Cloud::AWS.ec2(region: r).modify_image_attribute(
|
1390
1402
|
image_id: copy.image_id,
|
1391
1403
|
launch_permission: {add: [{group: "all"}]},
|
1392
1404
|
attribute: "launchPermission"
|
@@ -1408,12 +1420,12 @@ module MU
|
|
1408
1420
|
# flagged as ready.
|
1409
1421
|
# @param image_id [String]: The machine image to wait for.
|
1410
1422
|
# @param region [String]: The cloud provider region
|
1411
|
-
def self.waitForAMI(image_id, region: MU.curRegion)
|
1423
|
+
def self.waitForAMI(image_id, region: MU.curRegion, credentials: nil)
|
1412
1424
|
MU.log "Checking to see if AMI #{image_id} is available", MU::DEBUG
|
1413
1425
|
|
1414
1426
|
retries = 0
|
1415
1427
|
begin
|
1416
|
-
images = MU::Cloud::AWS.ec2(region).describe_images(image_ids: [image_id]).images
|
1428
|
+
images = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_images(image_ids: [image_id]).images
|
1417
1429
|
if images.nil? or images.size == 0
|
1418
1430
|
raise MuError, "No such AMI #{image_id} found"
|
1419
1431
|
end
|
@@ -1497,7 +1509,7 @@ module MU
|
|
1497
1509
|
retries = 0
|
1498
1510
|
MU.log "Waiting for Windows instance password to be set by Amazon and flagged as available from the API. Note- if you're using a source AMI that already has its password set, this may fail. You'll want to set use_cloud_provider_windows_password to false if this is the case.", MU::NOTICE
|
1499
1511
|
begin
|
1500
|
-
MU::Cloud::AWS.ec2(@config['region']).wait_until(:password_data_available, instance_id: @cloud_id) do |waiter|
|
1512
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).wait_until(:password_data_available, instance_id: @cloud_id) do |waiter|
|
1501
1513
|
waiter.max_attempts = 60
|
1502
1514
|
waiter.before_attempt do |attempts|
|
1503
1515
|
MU.log "Waiting for Windows password data to be available for node #{@mu_name}", MU::NOTICE if attempts % 5 == 0
|
@@ -1517,7 +1529,7 @@ module MU
|
|
1517
1529
|
end
|
1518
1530
|
end
|
1519
1531
|
|
1520
|
-
resp = MU::Cloud::AWS.ec2(@config['region']).get_password_data(instance_id: @cloud_id)
|
1532
|
+
resp = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).get_password_data(instance_id: @cloud_id)
|
1521
1533
|
encrypted_password = resp.password_data
|
1522
1534
|
|
1523
1535
|
# Note: This is already implemented in the decrypt_windows_password API call
|
@@ -1544,9 +1556,9 @@ module MU
|
|
1544
1556
|
filters << {name: "public-ip", values: [ip]} if ip != nil
|
1545
1557
|
|
1546
1558
|
if filters.size > 0
|
1547
|
-
resp = MU::Cloud::AWS.ec2(region).describe_addresses(filters: filters)
|
1559
|
+
resp = MU::Cloud::AWS.ec2(region: region).describe_addresses(filters: filters)
|
1548
1560
|
else
|
1549
|
-
resp = MU::Cloud::AWS.ec2(region).describe_addresses()
|
1561
|
+
resp = MU::Cloud::AWS.ec2(region: region).describe_addresses()
|
1550
1562
|
end
|
1551
1563
|
resp.addresses.each { |address|
|
1552
1564
|
return address if (address.network_interface_id.nil? || address.network_interface_id.empty?) && !@eips_used.include?(address.public_ip)
|
@@ -1559,10 +1571,10 @@ module MU
|
|
1559
1571
|
end
|
1560
1572
|
end
|
1561
1573
|
if !classic
|
1562
|
-
resp = MU::Cloud::AWS.ec2(region).allocate_address(domain: "vpc")
|
1574
|
+
resp = MU::Cloud::AWS.ec2(region: region).allocate_address(domain: "vpc")
|
1563
1575
|
new_ip = resp.public_ip
|
1564
1576
|
else
|
1565
|
-
new_ip = MU::Cloud::AWS.ec2(region).allocate_address().public_ip
|
1577
|
+
new_ip = MU::Cloud::AWS.ec2(region: region).allocate_address().public_ip
|
1566
1578
|
end
|
1567
1579
|
filters = [{name: "public-ip", values: [new_ip]}]
|
1568
1580
|
if resp.domain
|
@@ -1578,7 +1590,7 @@ module MU
|
|
1578
1590
|
begin
|
1579
1591
|
begin
|
1580
1592
|
sleep 5
|
1581
|
-
resp = MU::Cloud::AWS.ec2(region).describe_addresses(
|
1593
|
+
resp = MU::Cloud::AWS.ec2(region: region).describe_addresses(
|
1582
1594
|
filters: filters
|
1583
1595
|
)
|
1584
1596
|
addr = resp.addresses.first
|
@@ -1602,7 +1614,7 @@ module MU
|
|
1602
1614
|
return true
|
1603
1615
|
end
|
1604
1616
|
az = nil
|
1605
|
-
MU::Cloud::AWS.ec2(@config['region']).describe_instances(
|
1617
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_instances(
|
1606
1618
|
instance_ids: [@cloud_id]
|
1607
1619
|
).reservations.each { |resp|
|
1608
1620
|
if !resp.nil? and !resp.instances.nil?
|
@@ -1618,14 +1630,14 @@ module MU
|
|
1618
1630
|
end
|
1619
1631
|
}
|
1620
1632
|
MU.log "Creating #{size}GB #{type} volume on #{dev} for #{@cloud_id}"
|
1621
|
-
creation = MU::Cloud::AWS.ec2(@config['region']).create_volume(
|
1633
|
+
creation = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_volume(
|
1622
1634
|
availability_zone: az,
|
1623
1635
|
size: size,
|
1624
1636
|
volume_type: type
|
1625
1637
|
)
|
1626
1638
|
begin
|
1627
1639
|
sleep 3
|
1628
|
-
creation = MU::Cloud::AWS.ec2(@config['region']).describe_volumes(volume_ids: [creation.volume_id]).volumes.first
|
1640
|
+
creation = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_volumes(volume_ids: [creation.volume_id]).volumes.first
|
1629
1641
|
if !["creating", "available"].include?(creation.state)
|
1630
1642
|
raise MuError, "Saw state '#{creation.state}' while creating #{size}GB #{type} volume on #{dev} for #{@cloud_id}"
|
1631
1643
|
end
|
@@ -1633,12 +1645,12 @@ module MU
|
|
1633
1645
|
|
1634
1646
|
if @deploy
|
1635
1647
|
MU::MommaCat.listStandardTags.each_pair { |key, value|
|
1636
|
-
MU::MommaCat.createTag(creation.volume_id, key, value, region: @config['region'])
|
1648
|
+
MU::MommaCat.createTag(creation.volume_id, key, value, region: @config['region'], credentials: @config['credentials'])
|
1637
1649
|
}
|
1638
|
-
MU::MommaCat.createTag(creation.volume_id, "Name", "#{MU.deploy_id}-#{@config["name"].upcase}-#{dev.upcase}", region: @config['region'])
|
1650
|
+
MU::MommaCat.createTag(creation.volume_id, "Name", "#{MU.deploy_id}-#{@config["name"].upcase}-#{dev.upcase}", region: @config['region'], credentials: @config['credentials'])
|
1639
1651
|
end
|
1640
1652
|
|
1641
|
-
attachment = MU::Cloud::AWS.ec2(@config['region']).attach_volume(
|
1653
|
+
attachment = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).attach_volume(
|
1642
1654
|
device: dev,
|
1643
1655
|
instance_id: @cloud_id,
|
1644
1656
|
volume_id: creation.volume_id
|
@@ -1646,7 +1658,7 @@ module MU
|
|
1646
1658
|
|
1647
1659
|
begin
|
1648
1660
|
sleep 3
|
1649
|
-
attachment = MU::Cloud::AWS.ec2(@config['region']).describe_volumes(volume_ids: [attachment.volume_id]).volumes.first.attachments.first
|
1661
|
+
attachment = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_volumes(volume_ids: [attachment.volume_id]).volumes.first.attachments.first
|
1650
1662
|
if !["attaching", "attached"].include?(attachment.state)
|
1651
1663
|
raise MuError, "Saw state '#{creation.state}' while creating #{size}GB #{type} volume on #{dev} for #{@cloud_id}"
|
1652
1664
|
end
|
@@ -1662,7 +1674,7 @@ module MU
|
|
1662
1674
|
return true
|
1663
1675
|
end
|
1664
1676
|
begin
|
1665
|
-
MU::Cloud::AWS.ec2(@config['region']).describe_instances(
|
1677
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_instances(
|
1666
1678
|
instance_ids: [@cloud_id]
|
1667
1679
|
).reservations.each { |resp|
|
1668
1680
|
if !resp.nil? and !resp.instances.nil?
|
@@ -1694,7 +1706,7 @@ module MU
|
|
1694
1706
|
@eip_semaphore.synchronize {
|
1695
1707
|
if !ip.nil?
|
1696
1708
|
filters = [{name: "public-ip", values: [ip]}]
|
1697
|
-
resp = MU::Cloud::AWS.ec2(region).describe_addresses(filters: filters)
|
1709
|
+
resp = MU::Cloud::AWS.ec2(region: region).describe_addresses(filters: filters)
|
1698
1710
|
if @eips_used.include?(ip)
|
1699
1711
|
is_free = false
|
1700
1712
|
resp.addresses.each { |address|
|
@@ -1726,12 +1738,12 @@ module MU
|
|
1726
1738
|
attempts = 0
|
1727
1739
|
begin
|
1728
1740
|
if classic
|
1729
|
-
resp = MU::Cloud::AWS.ec2(region).associate_address(
|
1741
|
+
resp = MU::Cloud::AWS.ec2(region: region).associate_address(
|
1730
1742
|
instance_id: instance_id,
|
1731
1743
|
public_ip: elastic_ip.public_ip
|
1732
1744
|
)
|
1733
1745
|
else
|
1734
|
-
resp = MU::Cloud::AWS.ec2(region).associate_address(
|
1746
|
+
resp = MU::Cloud::AWS.ec2(region: region).associate_address(
|
1735
1747
|
instance_id: instance_id,
|
1736
1748
|
allocation_id: elastic_ip.allocation_id,
|
1737
1749
|
allow_reassociation: false
|
@@ -1747,7 +1759,7 @@ module MU
|
|
1747
1759
|
raise MuError "#{e.message} associating #{elastic_ip.allocation_id} with #{instance_id}"
|
1748
1760
|
rescue Aws::EC2::Errors::ResourceAlreadyAssociated => e
|
1749
1761
|
# A previous association attempt may have succeeded, albeit slowly.
|
1750
|
-
resp = MU::Cloud::AWS.ec2(region).describe_addresses(
|
1762
|
+
resp = MU::Cloud::AWS.ec2(region: region).describe_addresses(
|
1751
1763
|
allocation_ids: [elastic_ip.allocation_id]
|
1752
1764
|
)
|
1753
1765
|
first_addr = resp.addresses.first
|
@@ -1759,14 +1771,14 @@ module MU
|
|
1759
1771
|
end
|
1760
1772
|
end
|
1761
1773
|
|
1762
|
-
instance = MU::Cloud::AWS.ec2(region).describe_instances(instance_ids: [instance_id]).reservations.first.instances.first
|
1774
|
+
instance = MU::Cloud::AWS.ec2(region: region).describe_instances(instance_ids: [instance_id]).reservations.first.instances.first
|
1763
1775
|
waited = false
|
1764
1776
|
if instance.public_ip_address != elastic_ip.public_ip
|
1765
1777
|
waited = true
|
1766
1778
|
begin
|
1767
1779
|
sleep 10
|
1768
1780
|
MU.log "Waiting for Elastic IP association of #{elastic_ip.public_ip} to #{instance_id} to take effect", MU::NOTICE
|
1769
|
-
instance = MU::Cloud::AWS.ec2(region).describe_instances(instance_ids: [instance_id]).reservations.first.instances.first
|
1781
|
+
instance = MU::Cloud::AWS.ec2(region: region).describe_instances(instance_ids: [instance_id]).reservations.first.instances.first
|
1770
1782
|
end while instance.public_ip_address != elastic_ip.public_ip
|
1771
1783
|
end
|
1772
1784
|
|
@@ -1775,12 +1787,21 @@ module MU
|
|
1775
1787
|
return elastic_ip.public_ip
|
1776
1788
|
end
|
1777
1789
|
|
1790
|
+
# Does this resource type exist as a global (cloud-wide) artifact, or
|
1791
|
+
# is it localized to a region/zone?
|
1792
|
+
# @return [Boolean]
|
1793
|
+
def self.isGlobal?
|
1794
|
+
false
|
1795
|
+
end
|
1796
|
+
|
1778
1797
|
# Remove all instances associated with the currently loaded deployment. Also cleans up associated volumes, droppings in the MU master's /etc/hosts and ~/.ssh, and in whatever Groomer was used.
|
1779
1798
|
# @param noop [Boolean]: If true, will only print what would be done
|
1780
1799
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
1781
1800
|
# @param region [String]: The cloud provider region
|
1782
1801
|
# @return [void]
|
1783
|
-
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion,
|
1802
|
+
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
1803
|
+
onlycloud = flags["onlycloud"]
|
1804
|
+
skipsnapshots = flags["skipsnapshots"]
|
1784
1805
|
tagfilters = [
|
1785
1806
|
{name: "tag:MU-ID", values: [MU.deploy_id]}
|
1786
1807
|
]
|
@@ -1794,7 +1815,7 @@ module MU
|
|
1794
1815
|
# Build a list of instances we need to clean up. We guard against
|
1795
1816
|
# accidental deletion here by requiring someone to have hand-terminated
|
1796
1817
|
# these, by default.
|
1797
|
-
resp = MU::Cloud::AWS.ec2(region).describe_instances(
|
1818
|
+
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_instances(
|
1798
1819
|
filters: tagfilters
|
1799
1820
|
)
|
1800
1821
|
|
@@ -1817,18 +1838,18 @@ module MU
|
|
1817
1838
|
threads << Thread.new(instance) { |myinstance|
|
1818
1839
|
MU.dupGlobals(parent_thread_id)
|
1819
1840
|
Thread.abort_on_exception = true
|
1820
|
-
MU::Cloud::AWS::Server.terminateInstance(id: myinstance.instance_id, noop: noop, onlycloud: onlycloud, region: region, deploy_id: MU.deploy_id)
|
1841
|
+
MU::Cloud::AWS::Server.terminateInstance(id: myinstance.instance_id, noop: noop, onlycloud: onlycloud, region: region, deploy_id: MU.deploy_id, credentials: credentials)
|
1821
1842
|
}
|
1822
1843
|
}
|
1823
1844
|
|
1824
|
-
resp = MU::Cloud::AWS.ec2(region).describe_volumes(
|
1845
|
+
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_volumes(
|
1825
1846
|
filters: tagfilters
|
1826
1847
|
)
|
1827
1848
|
resp.data.volumes.each { |volume|
|
1828
1849
|
threads << Thread.new(volume) { |myvolume|
|
1829
1850
|
MU.dupGlobals(parent_thread_id)
|
1830
1851
|
Thread.abort_on_exception = true
|
1831
|
-
MU::Cloud::AWS::Server.delete_volume(myvolume, noop, skipsnapshots)
|
1852
|
+
MU::Cloud::AWS::Server.delete_volume(myvolume, noop, skipsnapshots, credentials: credentials)
|
1832
1853
|
}
|
1833
1854
|
}
|
1834
1855
|
|
@@ -1843,12 +1864,12 @@ module MU
|
|
1843
1864
|
# @param id [String]: The cloud provider's identifier for the instance, to use if the full description is not available.
|
1844
1865
|
# @param region [String]: The cloud provider region
|
1845
1866
|
# @return [void]
|
1846
|
-
def self.terminateInstance(instance: nil, noop: false, id: nil, onlycloud: false, region: MU.curRegion, deploy_id: MU.deploy_id, mu_name: nil)
|
1867
|
+
def self.terminateInstance(instance: nil, noop: false, id: nil, onlycloud: false, region: MU.curRegion, deploy_id: MU.deploy_id, mu_name: nil, credentials: nil)
|
1847
1868
|
ips = Array.new
|
1848
1869
|
if !instance
|
1849
1870
|
if id
|
1850
1871
|
begin
|
1851
|
-
resp = MU::Cloud::AWS.ec2(region).describe_instances(instance_ids: [id])
|
1872
|
+
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_instances(instance_ids: [id])
|
1852
1873
|
rescue Aws::EC2::Errors::InvalidInstanceIDNotFound => e
|
1853
1874
|
MU.log "Instance #{id} no longer exists", MU::WARN
|
1854
1875
|
end
|
@@ -1880,26 +1901,26 @@ module MU
|
|
1880
1901
|
).first
|
1881
1902
|
|
1882
1903
|
begin
|
1883
|
-
MU::Cloud::AWS.ec2(region).describe_instances(instance_ids: [id])
|
1904
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_instances(instance_ids: [id])
|
1884
1905
|
rescue Aws::EC2::Errors::InvalidInstanceIDNotFound => e
|
1885
1906
|
MU.log "Instance #{id} no longer exists", MU::DEBUG
|
1886
1907
|
end
|
1887
1908
|
|
1888
|
-
if !server_obj.nil? and MU::Cloud::AWS.hosted and !MU::Cloud::AWS.isGovCloud?
|
1909
|
+
if !server_obj.nil? and MU::Cloud::AWS.hosted? and !MU::Cloud::AWS.isGovCloud?
|
1889
1910
|
# DNS cleanup is now done in MU::Cloud::DNSZone. Keeping this for now
|
1890
1911
|
cleaned_dns = false
|
1891
1912
|
mu_name = server_obj.mu_name
|
1892
|
-
mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu").values.first
|
1913
|
+
mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", credentials: credentials).values.first
|
1893
1914
|
if !mu_zone.nil?
|
1894
1915
|
zone_rrsets = []
|
1895
|
-
rrsets = MU::Cloud::AWS.route53(
|
1916
|
+
rrsets = MU::Cloud::AWS.route53(credentials: credentials).list_resource_record_sets(hosted_zone_id: mu_zone.id)
|
1896
1917
|
rrsets.resource_record_sets.each{ |record|
|
1897
1918
|
zone_rrsets << record
|
1898
1919
|
}
|
1899
1920
|
|
1900
1921
|
# AWS API returns a maximum of 100 results. DNS zones are likely to have more than 100 records, lets page and make sure we grab all records in a given zone
|
1901
1922
|
while rrsets.next_record_name && rrsets.next_record_type
|
1902
|
-
rrsets = MU::Cloud::AWS.route53(
|
1923
|
+
rrsets = MU::Cloud::AWS.route53(credentials: credentials).list_resource_record_sets(hosted_zone_id: mu_zone.id, start_record_name: rrsets.next_record_name, start_record_type: rrsets.next_record_type)
|
1903
1924
|
rrsets.resource_record_sets.each{ |record|
|
1904
1925
|
zone_rrsets << record
|
1905
1926
|
}
|
@@ -2002,14 +2023,14 @@ module MU
|
|
2002
2023
|
MU.log "Terminating #{instance.instance_id} (#{name}) #{noop}"
|
2003
2024
|
if !noop
|
2004
2025
|
begin
|
2005
|
-
MU::Cloud::AWS.ec2(region).modify_instance_attribute(
|
2026
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).modify_instance_attribute(
|
2006
2027
|
instance_id: instance.instance_id,
|
2007
2028
|
disable_api_termination: {value: false}
|
2008
2029
|
)
|
2009
|
-
MU::Cloud::AWS.ec2(region).terminate_instances(instance_ids: [instance.instance_id])
|
2030
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).terminate_instances(instance_ids: [instance.instance_id])
|
2010
2031
|
# Small race window here with the state changing from under us
|
2011
2032
|
rescue Aws::EC2::Errors::IncorrectInstanceState => e
|
2012
|
-
resp = MU::Cloud::AWS.ec2(region).describe_instances(instance_ids: [id])
|
2033
|
+
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_instances(instance_ids: [id])
|
2013
2034
|
if !resp.nil? and !resp.reservations.nil? and !resp.reservations.first.nil?
|
2014
2035
|
instance = resp.reservations.first.instances.first
|
2015
2036
|
if !instance.nil? and instance.state.name != "terminated" and instance.state.name != "terminating"
|
@@ -2026,7 +2047,7 @@ module MU
|
|
2026
2047
|
end
|
2027
2048
|
while instance.state.name != "terminated" and !noop
|
2028
2049
|
sleep 30
|
2029
|
-
instance_response = MU::Cloud::AWS.ec2(region).describe_instances(instance_ids: [instance.instance_id])
|
2050
|
+
instance_response = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_instances(instance_ids: [instance.instance_id])
|
2030
2051
|
instance = instance_response.reservations.first.instances.first
|
2031
2052
|
end
|
2032
2053
|
MU.log "#{instance.instance_id} (#{name}) terminated" if !noop
|
@@ -2156,6 +2177,7 @@ module MU
|
|
2156
2177
|
else
|
2157
2178
|
role = {
|
2158
2179
|
"name" => server["name"],
|
2180
|
+
"credentials" => server["credentials"],
|
2159
2181
|
"can_assume" => [
|
2160
2182
|
{
|
2161
2183
|
"entity_id" => "ec2.amazonaws.com",
|
@@ -2241,9 +2263,9 @@ module MU
|
|
2241
2263
|
# @param id [String]: The cloud provider's identifier for the volume, to use if the full description is not available.
|
2242
2264
|
# @param region [String]: The cloud provider region
|
2243
2265
|
# @return [void]
|
2244
|
-
def self.delete_volume(volume, noop, skipsnapshots, id: nil, region: MU.curRegion)
|
2266
|
+
def self.delete_volume(volume, noop, skipsnapshots, id: nil, region: MU.curRegion, credentials: nil)
|
2245
2267
|
if !volume.nil?
|
2246
|
-
resp = MU::Cloud::AWS.ec2(region).describe_volumes(volume_ids: [volume.volume_id])
|
2268
|
+
resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_volumes(volume_ids: [volume.volume_id])
|
2247
2269
|
volume = resp.data.volumes.first
|
2248
2270
|
end
|
2249
2271
|
name = ""
|
@@ -2260,15 +2282,25 @@ module MU
|
|
2260
2282
|
desc = "#{MU.deploy_id}-MUfinal"
|
2261
2283
|
end
|
2262
2284
|
|
2263
|
-
|
2285
|
+
begin
|
2286
|
+
MU::Cloud::AWS.ec2(region: region, credentials: credentials).create_snapshot(
|
2264
2287
|
volume_id: volume.volume_id,
|
2265
2288
|
description: desc
|
2266
|
-
|
2289
|
+
)
|
2290
|
+
rescue Aws::EC2::Errors::IncorrectState => e
|
2291
|
+
if e.message.match(/'deleting'/)
|
2292
|
+
MU.log "Cannot snapshot volume '#{name}', is already being deleted", MU::WARN
|
2293
|
+
end
|
2294
|
+
end
|
2267
2295
|
end
|
2268
2296
|
|
2269
2297
|
retries = 0
|
2270
2298
|
begin
|
2271
|
-
MU::Cloud::AWS.ec2(region).delete_volume(volume_id: volume.volume_id)
|
2299
|
+
MU::Cloud::AWS.ec2(region: region, credentials: credentials).delete_volume(volume_id: volume.volume_id)
|
2300
|
+
rescue Aws::EC2::Errors::IncorrectState => e
|
2301
|
+
MU.log "Volume #{volume.volume_id} (#{name}) in incorrect state (#{e.message}), will retry", MU::WARN
|
2302
|
+
sleep 30
|
2303
|
+
retry
|
2272
2304
|
rescue Aws::EC2::Errors::InvalidVolumeNotFound
|
2273
2305
|
MU.log "Volume #{volume.volume_id} (#{name}) disappeared before I could remove it!", MU::WARN
|
2274
2306
|
rescue Aws::EC2::Errors::VolumeInUse
|