cloud-mu 3.3.0 → 3.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ansible/roles/mu-nat/tasks/main.yml +3 -0
- data/bin/mu-aws-setup +41 -7
- data/bin/mu-azure-setup +36 -2
- data/bin/mu-configure +214 -119
- data/bin/mu-gcp-setup +37 -2
- data/bin/mu-node-manage +3 -0
- data/bin/mu-refresh-ssl +67 -0
- data/bin/mu-run-tests +14 -4
- data/bin/mu-self-update +30 -10
- data/bin/mu-upload-chef-artifacts +30 -26
- data/cloud-mu.gemspec +9 -7
- data/cookbooks/mu-master/attributes/default.rb +5 -1
- data/cookbooks/mu-master/metadata.rb +2 -2
- data/cookbooks/mu-master/recipes/default.rb +81 -26
- data/cookbooks/mu-master/recipes/init.rb +197 -62
- data/cookbooks/mu-master/recipes/update_nagios_only.rb +1 -1
- data/cookbooks/mu-master/recipes/vault.rb +78 -77
- data/cookbooks/mu-master/templates/default/mods/rewrite.conf.erb +1 -0
- data/cookbooks/mu-master/templates/default/nagios.conf.erb +103 -0
- data/cookbooks/mu-master/templates/default/web_app.conf.erb +14 -30
- data/cookbooks/mu-tools/attributes/default.rb +12 -0
- data/cookbooks/mu-tools/files/centos-6/CentOS-Base.repo +47 -0
- data/cookbooks/mu-tools/libraries/helper.rb +98 -4
- data/cookbooks/mu-tools/libraries/monkey.rb +1 -1
- data/cookbooks/mu-tools/recipes/apply_security.rb +31 -9
- data/cookbooks/mu-tools/recipes/aws_api.rb +8 -2
- data/cookbooks/mu-tools/recipes/base_repositories.rb +1 -1
- data/cookbooks/mu-tools/recipes/gcloud.rb +2 -9
- data/cookbooks/mu-tools/recipes/google_api.rb +7 -0
- data/cookbooks/mu-tools/recipes/rsyslog.rb +8 -1
- data/cookbooks/mu-tools/resources/disk.rb +113 -42
- data/cookbooks/mu-tools/resources/mommacat_request.rb +1 -2
- data/cookbooks/mu-tools/templates/centos-8/sshd_config.erb +215 -0
- data/extras/Gemfile.lock.bootstrap +394 -0
- data/extras/bucketstubs/error.html +0 -0
- data/extras/bucketstubs/index.html +0 -0
- data/extras/clean-stock-amis +11 -3
- data/extras/generate-stock-images +6 -3
- data/extras/git_rpm/build.sh +20 -0
- data/extras/git_rpm/mugit.spec +53 -0
- data/extras/image-generators/AWS/centos7.yaml +19 -16
- data/extras/image-generators/AWS/{rhel7.yaml → rhel71.yaml} +0 -0
- data/extras/image-generators/AWS/{win2k12.yaml → win2k12r2.yaml} +0 -0
- data/extras/image-generators/VMWare/centos8.yaml +15 -0
- data/extras/openssl_rpm/build.sh +19 -0
- data/extras/openssl_rpm/mussl.spec +46 -0
- data/extras/python_rpm/muthon.spec +14 -4
- data/extras/ruby_rpm/muby.spec +9 -5
- data/extras/sqlite_rpm/build.sh +19 -0
- data/extras/sqlite_rpm/muqlite.spec +47 -0
- data/install/installer +7 -5
- data/modules/mommacat.ru +2 -2
- data/modules/mu.rb +12 -5
- data/modules/mu/cloud/machine_images.rb +1 -1
- data/modules/mu/cloud/providers.rb +6 -1
- data/modules/mu/cloud/resource_base.rb +7 -4
- data/modules/mu/cloud/ssh_sessions.rb +5 -1
- data/modules/mu/cloud/wrappers.rb +16 -7
- data/modules/mu/config.rb +28 -12
- data/modules/mu/config/database.rb +2 -2
- data/modules/mu/config/firewall_rule.rb +1 -1
- data/modules/mu/config/ref.rb +3 -3
- data/modules/mu/config/schema_helpers.rb +12 -3
- data/modules/mu/config/server.rb +10 -4
- data/modules/mu/config/server_pool.rb +2 -2
- data/modules/mu/config/vpc.rb +10 -10
- data/modules/mu/defaults/AWS.yaml +96 -96
- data/modules/mu/deploy.rb +27 -14
- data/modules/mu/groomers/chef.rb +2 -2
- data/modules/mu/master.rb +49 -3
- data/modules/mu/mommacat.rb +27 -9
- data/modules/mu/mommacat/naming.rb +2 -2
- data/modules/mu/mommacat/search.rb +16 -5
- data/modules/mu/mommacat/storage.rb +67 -32
- data/modules/mu/providers/aws.rb +185 -71
- data/modules/mu/providers/aws/alarm.rb +3 -3
- data/modules/mu/providers/aws/bucket.rb +19 -19
- data/modules/mu/providers/aws/cache_cluster.rb +22 -22
- data/modules/mu/providers/aws/cdn.rb +2 -2
- data/modules/mu/providers/aws/collection.rb +14 -14
- data/modules/mu/providers/aws/container_cluster.rb +27 -27
- data/modules/mu/providers/aws/database.rb +49 -45
- data/modules/mu/providers/aws/dnszone.rb +5 -5
- data/modules/mu/providers/aws/endpoint.rb +35 -35
- data/modules/mu/providers/aws/firewall_rule.rb +26 -23
- data/modules/mu/providers/aws/function.rb +35 -32
- data/modules/mu/providers/aws/group.rb +7 -7
- data/modules/mu/providers/aws/habitat.rb +2 -2
- data/modules/mu/providers/aws/job.rb +35 -32
- data/modules/mu/providers/aws/loadbalancer.rb +58 -37
- data/modules/mu/providers/aws/log.rb +14 -14
- data/modules/mu/providers/aws/msg_queue.rb +10 -10
- data/modules/mu/providers/aws/nosqldb.rb +8 -8
- data/modules/mu/providers/aws/notifier.rb +7 -7
- data/modules/mu/providers/aws/role.rb +69 -47
- data/modules/mu/providers/aws/search_domain.rb +10 -10
- data/modules/mu/providers/aws/server.rb +198 -110
- data/modules/mu/providers/aws/server_pool.rb +71 -119
- data/modules/mu/providers/aws/storage_pool.rb +17 -9
- data/modules/mu/providers/aws/user.rb +1 -1
- data/modules/mu/providers/aws/vpc.rb +106 -51
- data/modules/mu/providers/aws/vpc_subnet.rb +43 -39
- data/modules/mu/providers/azure.rb +82 -16
- data/modules/mu/providers/azure/server.rb +18 -3
- data/modules/mu/providers/cloudformation/server.rb +1 -1
- data/modules/mu/providers/google.rb +20 -5
- data/modules/mu/providers/google/folder.rb +6 -2
- data/modules/mu/providers/google/function.rb +65 -30
- data/modules/mu/providers/google/role.rb +2 -1
- data/modules/mu/providers/google/vpc.rb +27 -2
- data/modules/tests/aws-servers-with-handrolled-iam.yaml +37 -0
- data/modules/tests/k8s.yaml +1 -1
- metadata +32 -15
@@ -36,7 +36,7 @@ module MU
|
|
36
36
|
|
37
37
|
MU.log "Creating ElasticSearch domain #{@config['domain_name']}", details: params
|
38
38
|
@cloud_id = @config['domain_name']
|
39
|
-
MU::Cloud::AWS.elasticsearch(region: @
|
39
|
+
MU::Cloud::AWS.elasticsearch(region: @region, credentials: @credentials).create_elasticsearch_domain(params).domain_status
|
40
40
|
|
41
41
|
tagDomain
|
42
42
|
|
@@ -52,7 +52,7 @@ module MU
|
|
52
52
|
waitWhileProcessing # wait until the create finishes, if still going
|
53
53
|
|
54
54
|
MU.log "Updating ElasticSearch domain #{@config['domain_name']}", MU::NOTICE, details: params
|
55
|
-
MU::Cloud::AWS.elasticsearch(region: @
|
55
|
+
MU::Cloud::AWS.elasticsearch(region: @region, credentials: @credentials).update_elasticsearch_domain_config(params)
|
56
56
|
end
|
57
57
|
|
58
58
|
waitWhileProcessing # don't return until creation/updating is complete
|
@@ -68,7 +68,7 @@ module MU
|
|
68
68
|
@cloud_id ||= @config['domain_name']
|
69
69
|
return nil if !@cloud_id
|
70
70
|
MU.retrier([::Aws::ElasticsearchService::Errors::ResourceNotFoundException], wait: 10, max: 12) {
|
71
|
-
@cloud_desc_cache = MU::Cloud::AWS.elasticsearch(region: @
|
71
|
+
@cloud_desc_cache = MU::Cloud::AWS.elasticsearch(region: @region, credentials: @credentials).describe_elasticsearch_domain(
|
72
72
|
domain_name: @cloud_id
|
73
73
|
).domain_status
|
74
74
|
}
|
@@ -88,7 +88,7 @@ module MU
|
|
88
88
|
def notify
|
89
89
|
return nil if !cloud_desc(use_cache: false)
|
90
90
|
deploy_struct = MU.structToHash(cloud_desc, stringify_keys: true)
|
91
|
-
tags = MU::Cloud::AWS.elasticsearch(region: @
|
91
|
+
tags = MU::Cloud::AWS.elasticsearch(region: @region, credentials: @credentials).list_tags(arn: arn).tag_list
|
92
92
|
deploy_struct['tags'] = tags.map { |t| { t.key => t.value } }
|
93
93
|
if deploy_struct['endpoint']
|
94
94
|
deploy_struct['kibana'] = deploy_struct['endpoint']+"/_plugin/kibana/"
|
@@ -200,7 +200,7 @@ module MU
|
|
200
200
|
"cloud" => "AWS",
|
201
201
|
"credentials" => @credentials,
|
202
202
|
"cloud_id" => @cloud_id,
|
203
|
-
"region" => @
|
203
|
+
"region" => @region
|
204
204
|
}
|
205
205
|
|
206
206
|
if !cloud_desc
|
@@ -241,7 +241,7 @@ module MU
|
|
241
241
|
bok['identity_pool_id'] = cloud_desc.cognito_options.identity_pool_id
|
242
242
|
end
|
243
243
|
|
244
|
-
tags = MU::Cloud::AWS.elasticsearch(region: @
|
244
|
+
tags = MU::Cloud::AWS.elasticsearch(region: @region, credentials: @credentials).list_tags(arn: cloud_desc.arn).tag_list
|
245
245
|
if tags and !tags.empty?
|
246
246
|
bok['tags'] = MU.structToHash(tags)
|
247
247
|
end
|
@@ -252,7 +252,7 @@ module MU
|
|
252
252
|
cloud: "AWS",
|
253
253
|
credentials: @credentials,
|
254
254
|
type: "vpcs",
|
255
|
-
region: @
|
255
|
+
region: @region,
|
256
256
|
subnets: cloud_desc.vpc_options.subnet_ids.map { |s| { "subnet_id" => s } }
|
257
257
|
)
|
258
258
|
if cloud_desc.vpc_options.security_group_ids and
|
@@ -262,7 +262,7 @@ module MU
|
|
262
262
|
id: sg,
|
263
263
|
cloud: "AWS",
|
264
264
|
credentials: @credentials,
|
265
|
-
region: @
|
265
|
+
region: @region,
|
266
266
|
type: "firewall_rules",
|
267
267
|
)
|
268
268
|
}
|
@@ -683,7 +683,7 @@ module MU
|
|
683
683
|
params[:log_publishing_options]["SEARCH_SLOW_LOGS"] = {}
|
684
684
|
params[:log_publishing_options]["SEARCH_SLOW_LOGS"][:enabled] = true
|
685
685
|
params[:log_publishing_options]["SEARCH_SLOW_LOGS"][:cloud_watch_logs_log_group_arn] = arn
|
686
|
-
MU::Cloud.resourceClass("AWS", "Log").allowService("es.amazonaws.com", arn, @
|
686
|
+
MU::Cloud.resourceClass("AWS", "Log").allowService("es.amazonaws.com", arn, @region)
|
687
687
|
end
|
688
688
|
end
|
689
689
|
|
@@ -813,7 +813,7 @@ module MU
|
|
813
813
|
raise MU::MuError, "Can't tag ElasticSearch domain, cloud descriptor came back without an ARN"
|
814
814
|
end
|
815
815
|
|
816
|
-
MU::Cloud::AWS.elasticsearch(region: @
|
816
|
+
MU::Cloud::AWS.elasticsearch(region: @region, credentials: @credentials).add_tags(
|
817
817
|
arn: domain.arn,
|
818
818
|
tag_list: tags
|
819
819
|
)
|
@@ -85,7 +85,7 @@ module MU
|
|
85
85
|
MU::Cloud.fetchUserdata(
|
86
86
|
platform: @config["platform"],
|
87
87
|
cloud: "AWS",
|
88
|
-
credentials: @
|
88
|
+
credentials: @credentials,
|
89
89
|
template_variables: {
|
90
90
|
"deployKey" => Base64.urlsafe_encode64(@deploy.public_key),
|
91
91
|
"deploySSHKey" => @deploy.ssh_public_key,
|
@@ -242,8 +242,8 @@ module MU
|
|
242
242
|
else
|
243
243
|
MU::Cloud::AWS.createStandardTags(
|
244
244
|
instance.instance_id,
|
245
|
-
region: @
|
246
|
-
credentials: @
|
245
|
+
region: @region,
|
246
|
+
credentials: @credentials,
|
247
247
|
optional: @config['optional_tags'],
|
248
248
|
nametag: @mu_name,
|
249
249
|
othertags: @config['tags']
|
@@ -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, region: @
|
261
|
+
MU::Cloud::AWS::Server.cleanup(noop: false, ignoremaster: false, region: @region, credentials: @credentials, flags: { "skipsnapshots" => true } )
|
262
262
|
}
|
263
263
|
end
|
264
264
|
end
|
@@ -307,9 +307,9 @@ module MU
|
|
307
307
|
instance_descriptor[:user_data] = Base64.encode64(@userdata)
|
308
308
|
end
|
309
309
|
|
310
|
-
MU::Cloud::AWS::Server.waitForAMI(@config["image_id"], region: @
|
310
|
+
MU::Cloud::AWS::Server.waitForAMI(@config["image_id"], region: @region, credentials: @credentials)
|
311
311
|
|
312
|
-
instance_descriptor[:block_device_mappings] = MU::Cloud::AWS::Server.configureBlockDevices(image_id: @config["image_id"], storage: @config['storage'], region: @
|
312
|
+
instance_descriptor[:block_device_mappings] = MU::Cloud::AWS::Server.configureBlockDevices(image_id: @config["image_id"], storage: @config['storage'], region: @region, credentials: @credentials)
|
313
313
|
|
314
314
|
instance_descriptor[:monitoring] = {enabled: @config['monitoring']}
|
315
315
|
|
@@ -330,10 +330,26 @@ module MU
|
|
330
330
|
resp.nil? or resp.instances.nil? or instance.nil?
|
331
331
|
}
|
332
332
|
|
333
|
+
bad_subnets = []
|
334
|
+
mysubnet_ids = if mySubnets
|
335
|
+
mySubnets.map { |s| s.cloud_id }
|
336
|
+
end
|
333
337
|
begin
|
334
338
|
MU.retrier([Aws::EC2::Errors::InvalidGroupNotFound, Aws::EC2::Errors::InvalidSubnetIDNotFound, Aws::EC2::Errors::InvalidParameterValue], loop_if: loop_if, loop_msg: "Waiting for run_instances to return #{@mu_name}") {
|
335
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
339
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).run_instances(instance_descriptor)
|
336
340
|
}
|
341
|
+
rescue Aws::EC2::Errors::Unsupported => e
|
342
|
+
bad_subnets << instance_descriptor[:subnet_id]
|
343
|
+
better_subnet = (mysubnet_ids - bad_subnets).sample
|
344
|
+
if e.message !~ /is not supported in your requested Availability Zone/ and
|
345
|
+
(mysubnet_ids.nil? or mysubnet_ids.empty? or
|
346
|
+
mysubnet_ids.size == bad_subnets.size or
|
347
|
+
better_subnet.nil? or better_subnet == "")
|
348
|
+
raise MuError.new e.message, details: mysubnet_ids
|
349
|
+
end
|
350
|
+
instance_descriptor[:subnet_id] = (mysubnet_ids - bad_subnets).sample
|
351
|
+
MU.log "One or more subnets does not support this instance type, attempting with #{instance_descriptor[:subnet_id]} instead", MU::WARN, details: bad_subnets
|
352
|
+
retry
|
337
353
|
rescue Aws::EC2::Errors::InvalidRequest => e
|
338
354
|
MU.log e.message, MU::ERR, details: instance_descriptor
|
339
355
|
raise e
|
@@ -351,12 +367,12 @@ module MU
|
|
351
367
|
if hard
|
352
368
|
groupname = nil
|
353
369
|
if !@config['basis'].nil?
|
354
|
-
resp = MU::Cloud::AWS.autoscale(region: @
|
370
|
+
resp = MU::Cloud::AWS.autoscale(region: @region, credentials: @credentials).describe_auto_scaling_instances(
|
355
371
|
instance_ids: [@cloud_id]
|
356
372
|
)
|
357
373
|
groupname = resp.auto_scaling_instances.first.auto_scaling_group_name
|
358
374
|
MU.log "Pausing Autoscale processes in #{groupname}", MU::NOTICE
|
359
|
-
MU::Cloud::AWS.autoscale(region: @
|
375
|
+
MU::Cloud::AWS.autoscale(region: @region, credentials: @credentials).suspend_processes(
|
360
376
|
auto_scaling_group_name: groupname,
|
361
377
|
scaling_processes: [
|
362
378
|
"Terminate",
|
@@ -365,22 +381,22 @@ module MU
|
|
365
381
|
end
|
366
382
|
begin
|
367
383
|
MU.log "Stopping #{@mu_name} (#{@cloud_id})", MU::NOTICE
|
368
|
-
MU::Cloud::AWS.ec2(region: @
|
384
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).stop_instances(
|
369
385
|
instance_ids: [@cloud_id]
|
370
386
|
)
|
371
|
-
MU::Cloud::AWS.ec2(region: @
|
387
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).wait_until(:instance_stopped, instance_ids: [@cloud_id]) do |waiter|
|
372
388
|
waiter.before_attempt do
|
373
389
|
MU.log "Waiting for #{@mu_name} to stop for hard reboot"
|
374
390
|
end
|
375
391
|
end
|
376
392
|
MU.log "Starting #{@mu_name} (#{@cloud_id})"
|
377
|
-
MU::Cloud::AWS.ec2(region: @
|
393
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).start_instances(
|
378
394
|
instance_ids: [@cloud_id]
|
379
395
|
)
|
380
396
|
ensure
|
381
397
|
if !groupname.nil?
|
382
398
|
MU.log "Resuming Autoscale processes in #{groupname}", MU::NOTICE
|
383
|
-
MU::Cloud::AWS.autoscale(region: @
|
399
|
+
MU::Cloud::AWS.autoscale(region: @region, credentials: @credentials).resume_processes(
|
384
400
|
auto_scaling_group_name: groupname,
|
385
401
|
scaling_processes: [
|
386
402
|
"Terminate",
|
@@ -390,7 +406,7 @@ module MU
|
|
390
406
|
end
|
391
407
|
else
|
392
408
|
MU.log "Rebooting #{@mu_name} (#{@cloud_id})"
|
393
|
-
MU::Cloud::AWS.ec2(region: @
|
409
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).reboot_instances(
|
394
410
|
instance_ids: [@cloud_id]
|
395
411
|
)
|
396
412
|
end
|
@@ -405,7 +421,7 @@ module MU
|
|
405
421
|
return nil if @config.nil? or @deploy.nil?
|
406
422
|
|
407
423
|
nat_ssh_key = nat_ssh_user = nat_ssh_host = nil
|
408
|
-
if !@config["vpc"].nil? and !MU::Cloud.resourceClass("AWS", "VPC").haveRouteToInstance?(cloud_desc, region: @
|
424
|
+
if !@config["vpc"].nil? and !MU::Cloud.resourceClass("AWS", "VPC").haveRouteToInstance?(cloud_desc, region: @region, credentials: @credentials)
|
409
425
|
if !@nat.nil?
|
410
426
|
if @nat.is_a?(Struct) && @nat.nat_gateway_id && @nat.nat_gateway_id.start_with?("nat-")
|
411
427
|
raise MuError, "Configured to use NAT Gateway, but I have no route to instance. Either use Bastion, or configure VPC peering"
|
@@ -449,6 +465,9 @@ module MU
|
|
449
465
|
raise MuError, "Couldn't find instance #{@mu_name} (#{@cloud_id})" if !cloud_desc
|
450
466
|
return false if !MU::MommaCat.lock(@cloud_id+"-orchestrate", true)
|
451
467
|
return false if !MU::MommaCat.lock(@cloud_id+"-groom", true)
|
468
|
+
|
469
|
+
getIAMProfile
|
470
|
+
|
452
471
|
finish = Proc.new { |status|
|
453
472
|
MU::MommaCat.unlock(@cloud_id+"-orchestrate")
|
454
473
|
MU::MommaCat.unlock(@cloud_id+"-groom")
|
@@ -457,8 +476,8 @@ module MU
|
|
457
476
|
|
458
477
|
MU::Cloud::AWS.createStandardTags(
|
459
478
|
@cloud_id,
|
460
|
-
region: @
|
461
|
-
credentials: @
|
479
|
+
region: @region,
|
480
|
+
credentials: @credentials,
|
462
481
|
optional: @config['optional_tags'],
|
463
482
|
nametag: @mu_name,
|
464
483
|
othertags: @config['tags']
|
@@ -474,7 +493,15 @@ module MU
|
|
474
493
|
}
|
475
494
|
MU.retrier([Aws::EC2::Errors::ServiceError], max: 30, wait: 40, loop_if: loop_if) { |retries, _wait|
|
476
495
|
if cloud_desc and cloud_desc.state.name == "terminated"
|
477
|
-
|
496
|
+
logs = if !@config['basis'].nil?
|
497
|
+
pool = @deploy.findLitterMate(type: "server_pools", name: @config["name"])
|
498
|
+
if pool
|
499
|
+
MU::Cloud::AWS.autoscale(region: @region, credentials: @credentials).describe_scaling_activities(auto_scaling_group_name: pool.cloud_id).activities
|
500
|
+
else
|
501
|
+
nil
|
502
|
+
end
|
503
|
+
end
|
504
|
+
raise MuError.new, "#{@cloud_id} appears to have been terminated mid-bootstrap!", details: logs
|
478
505
|
end
|
479
506
|
if retries % 3 == 0
|
480
507
|
MU.log "Waiting for EC2 instance #{@mu_name} (#{@cloud_id}) to be ready...", MU::NOTICE
|
@@ -495,7 +522,7 @@ module MU
|
|
495
522
|
|
496
523
|
if !@config['src_dst_check'] and !@config["vpc"].nil?
|
497
524
|
MU.log "Disabling source_dest_check #{@mu_name} (making it NAT-worthy)"
|
498
|
-
MU::Cloud::AWS.ec2(region: @
|
525
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).modify_instance_attribute(
|
499
526
|
instance_id: @cloud_id,
|
500
527
|
source_dest_check: { value: false }
|
501
528
|
)
|
@@ -503,7 +530,7 @@ module MU
|
|
503
530
|
|
504
531
|
# Set console termination protection. Autoscale nodes won't set this
|
505
532
|
# by default.
|
506
|
-
MU::Cloud::AWS.ec2(region: @
|
533
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).modify_instance_attribute(
|
507
534
|
instance_id: @cloud_id,
|
508
535
|
disable_api_termination: { value: true}
|
509
536
|
)
|
@@ -516,7 +543,6 @@ module MU
|
|
516
543
|
notify
|
517
544
|
end
|
518
545
|
|
519
|
-
getIAMProfile
|
520
546
|
finish.call(false) if !bootstrapGroomer
|
521
547
|
|
522
548
|
# Make sure we got our name written everywhere applicable
|
@@ -574,7 +600,7 @@ module MU
|
|
574
600
|
regions.each { |r|
|
575
601
|
searches.each { |search|
|
576
602
|
search_threads << Thread.new(search) { |params|
|
577
|
-
MU.retrier([
|
603
|
+
MU.retrier([], wait: 5, max: 5, ignoreme: [Aws::EC2::Errors::InvalidInstanceIDNotFound]) {
|
578
604
|
MU::Cloud::AWS.ec2(region: r, credentials: args[:credentials]).describe_instances(params).reservations.each { |resp|
|
579
605
|
next if resp.nil? or resp.instances.nil?
|
580
606
|
resp.instances.each { |i|
|
@@ -604,9 +630,9 @@ module MU
|
|
604
630
|
def toKitten(**_args)
|
605
631
|
bok = {
|
606
632
|
"cloud" => "AWS",
|
607
|
-
"credentials" => @
|
633
|
+
"credentials" => @credentials,
|
608
634
|
"cloud_id" => @cloud_id,
|
609
|
-
"region" => @
|
635
|
+
"region" => @region
|
610
636
|
}
|
611
637
|
|
612
638
|
if !cloud_desc
|
@@ -616,7 +642,7 @@ module MU
|
|
616
642
|
|
617
643
|
asgs = MU::Cloud.resourceClass("AWS", "ServerPool").find(
|
618
644
|
instance_id: @cloud_id,
|
619
|
-
region: @
|
645
|
+
region: @region,
|
620
646
|
credentials: @credentials
|
621
647
|
)
|
622
648
|
if asgs.size > 0
|
@@ -651,7 +677,7 @@ module MU
|
|
651
677
|
|
652
678
|
bok['image_id'] = cloud_desc.image_id
|
653
679
|
|
654
|
-
ami = MU::Cloud::AWS.ec2(region: @
|
680
|
+
ami = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_images(image_ids: [bok['image_id']]).images.first
|
655
681
|
|
656
682
|
if ami.nil? or ami.empty?
|
657
683
|
MU.log "#{@mu_name} source image #{bok['image_id']} no longer exists", MU::WARN
|
@@ -660,7 +686,7 @@ module MU
|
|
660
686
|
|
661
687
|
if cloud_desc.block_device_mappings and !cloud_desc.block_device_mappings.empty?
|
662
688
|
vol_map = {}
|
663
|
-
MU::Cloud::AWS.ec2(region: @
|
689
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_volumes(
|
664
690
|
volume_ids: cloud_desc.block_device_mappings.map { |d| d.ebs.volume_id if d.ebs }
|
665
691
|
).volumes.each { |vol|
|
666
692
|
vol_map[vol.volume_id] = vol
|
@@ -696,7 +722,7 @@ module MU
|
|
696
722
|
id: int.vpc_id,
|
697
723
|
cloud: "AWS",
|
698
724
|
credentials: @credentials,
|
699
|
-
region: @
|
725
|
+
region: @region,
|
700
726
|
subnet_id: int.subnet_id,
|
701
727
|
habitat: MU::Config::Ref.get(
|
702
728
|
id: int.owner_id,
|
@@ -725,11 +751,11 @@ module MU
|
|
725
751
|
if int.groups.size > 0
|
726
752
|
|
727
753
|
require 'mu/providers/aws/firewall_rule'
|
728
|
-
ifaces = MU::Cloud.resourceClass("AWS", "FirewallRule").getAssociatedInterfaces(int.groups.map { |sg| sg.group_id }, credentials: @credentials, region: @
|
754
|
+
ifaces = MU::Cloud.resourceClass("AWS", "FirewallRule").getAssociatedInterfaces(int.groups.map { |sg| sg.group_id }, credentials: @credentials, region: @region)
|
729
755
|
done_local_rules = false
|
730
756
|
int.groups.each { |sg|
|
731
757
|
if !done_local_rules and ifaces[sg.group_id].size == 1
|
732
|
-
sg_desc = MU::Cloud.resourceClass("AWS", "FirewallRule").find(cloud_id: sg.group_id, credentials: @credentials, region: @
|
758
|
+
sg_desc = MU::Cloud.resourceClass("AWS", "FirewallRule").find(cloud_id: sg.group_id, credentials: @credentials, region: @region).values.first
|
733
759
|
if sg_desc
|
734
760
|
bok["ingress_rules"] = MU::Cloud.resourceClass("AWS", "FirewallRule").rulesToBoK(sg_desc.ip_permissions)
|
735
761
|
bok["ingress_rules"].concat(MU::Cloud.resourceClass("AWS", "FirewallRule").rulesToBoK(sg_desc.ip_permissions_egress, egress: true))
|
@@ -743,7 +769,7 @@ module MU
|
|
743
769
|
cloud: "AWS",
|
744
770
|
credentials: @credentials,
|
745
771
|
type: "firewall_rules",
|
746
|
-
region: @
|
772
|
+
region: @region
|
747
773
|
)
|
748
774
|
}
|
749
775
|
end
|
@@ -799,7 +825,7 @@ module MU
|
|
799
825
|
if !@config['chef_data'].nil?
|
800
826
|
deploydata.merge!(@config['chef_data'])
|
801
827
|
end
|
802
|
-
deploydata["region"] = @
|
828
|
+
deploydata["region"] = @region if !@region.nil?
|
803
829
|
if !@named
|
804
830
|
MU::MommaCat.nameKitten(self, no_dns: true)
|
805
831
|
@named = true
|
@@ -883,7 +909,7 @@ module MU
|
|
883
909
|
# Canonical Amazon Resource Number for this resource
|
884
910
|
# @return [String]
|
885
911
|
def arn
|
886
|
-
"arn:"+(MU::Cloud::AWS.isGovCloud?(@
|
912
|
+
"arn:"+(MU::Cloud::AWS.isGovCloud?(@region) ? "aws-us-gov" : "aws")+":ec2:"+@region+":"+MU::Cloud::AWS.credToAcct(@credentials)+":instance/"+@cloud_id
|
887
913
|
end
|
888
914
|
|
889
915
|
@cloud_desc_cache = nil
|
@@ -896,7 +922,7 @@ module MU
|
|
896
922
|
retries = 0
|
897
923
|
if !@cloud_id.nil?
|
898
924
|
begin
|
899
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
925
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_instances(instance_ids: [@cloud_id])
|
900
926
|
if resp and resp.reservations and resp.reservations.first and
|
901
927
|
resp.reservations.first.instances and
|
902
928
|
resp.reservations.first.instances.first
|
@@ -943,7 +969,7 @@ module MU
|
|
943
969
|
# Our deploydata gets corrupted often with server pools, this will cause us to use the wrong IP to identify a node
|
944
970
|
# which will cause us to create certificates, DNS records and other artifacts with incorrect information which will cause our deploy to fail.
|
945
971
|
# The cloud_id is always correct so lets use 'cloud_desc' to get the correct IPs
|
946
|
-
if MU::Cloud.resourceClass("AWS", "VPC").haveRouteToInstance?(cloud_desc, region: @
|
972
|
+
if MU::Cloud.resourceClass("AWS", "VPC").haveRouteToInstance?(cloud_desc, region: @region, credentials: @credentials) or @deploydata["public_ip_address"].nil?
|
947
973
|
@config['canonical_ip'] = cloud_desc.private_ip_address
|
948
974
|
@deploydata["private_ip_address"] = cloud_desc.private_ip_address
|
949
975
|
return cloud_desc.private_ip_address
|
@@ -1170,7 +1196,7 @@ module MU
|
|
1170
1196
|
retries = 0
|
1171
1197
|
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
|
1172
1198
|
begin
|
1173
|
-
MU::Cloud::AWS.ec2(region: @
|
1199
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).wait_until(:password_data_available, instance_id: @cloud_id) do |waiter|
|
1174
1200
|
waiter.max_attempts = 60
|
1175
1201
|
waiter.before_attempt do |attempts|
|
1176
1202
|
MU.log "Waiting for Windows password data to be available for node #{@mu_name}", MU::NOTICE if attempts % 5 == 0
|
@@ -1182,15 +1208,15 @@ module MU
|
|
1182
1208
|
rescue Aws::Waiters::Errors::TooManyAttemptsError => e
|
1183
1209
|
if retries < 2
|
1184
1210
|
retries = retries + 1
|
1185
|
-
MU.log "wait_until(:password_data_available, instance_id: #{@cloud_id}) in #{@
|
1211
|
+
MU.log "wait_until(:password_data_available, instance_id: #{@cloud_id}) in #{@region} never got a good response, retrying (#{retries}/2)", MU::WARN, details: e.inspect
|
1186
1212
|
retry
|
1187
1213
|
else
|
1188
|
-
MU.log "wait_until(:password_data_available, instance_id: #{@cloud_id}) in #{@
|
1214
|
+
MU.log "wait_until(:password_data_available, instance_id: #{@cloud_id}) in #{@region} never returned- this image may not be configured to have its password set by AWS.", MU::ERR
|
1189
1215
|
return nil
|
1190
1216
|
end
|
1191
1217
|
end
|
1192
1218
|
|
1193
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
1219
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).get_password_data(instance_id: @cloud_id)
|
1194
1220
|
encrypted_password = resp.password_data
|
1195
1221
|
|
1196
1222
|
# Note: This is already implemented in the decrypt_windows_password API call
|
@@ -1209,7 +1235,7 @@ module MU
|
|
1209
1235
|
# instead of VPC.
|
1210
1236
|
# @param ip [String]: Request a specific IP address.
|
1211
1237
|
# @param region [String]: The cloud provider region
|
1212
|
-
def self.findFreeElasticIp(classic: false, ip: nil, region: MU.curRegion)
|
1238
|
+
def self.findFreeElasticIp(classic: false, ip: nil, region: MU.curRegion, credentials: nil)
|
1213
1239
|
filters = Array.new
|
1214
1240
|
if !classic
|
1215
1241
|
filters << {name: "domain", values: ["vpc"]}
|
@@ -1219,25 +1245,22 @@ module MU
|
|
1219
1245
|
filters << {name: "public-ip", values: [ip]} if ip != nil
|
1220
1246
|
|
1221
1247
|
if filters.size > 0
|
1222
|
-
resp = MU::Cloud::AWS.ec2(region: region).describe_addresses(filters: filters)
|
1248
|
+
resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_addresses(filters: filters)
|
1223
1249
|
else
|
1224
|
-
resp = MU::Cloud::AWS.ec2(region: region).describe_addresses
|
1250
|
+
resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_addresses
|
1225
1251
|
end
|
1226
1252
|
resp.addresses.each { |address|
|
1227
|
-
return address if (address.network_interface_id.nil?
|
1253
|
+
return address if (address.network_interface_id.nil? or address.network_interface_id.empty?) or !@eips_used.include?(address.public_ip)
|
1228
1254
|
}
|
1229
|
-
if ip
|
1230
|
-
|
1231
|
-
|
1232
|
-
else
|
1233
|
-
raise MuError, "Requested EIP #{ip}, but no such IP exists or is available in EC2 Classic"
|
1234
|
-
end
|
1255
|
+
if !ip.nil?
|
1256
|
+
mode = classic ? "EC2 Classic" : "VPC"
|
1257
|
+
raise MuError.new "Requested EIP #{ip}, but no such IP exists or is available in #{mode} mode#{credentials ? " with credentials #{credentials}" : ""}", details: { "describe_address filters" => filters, "describe_address response" => resp }
|
1235
1258
|
end
|
1236
1259
|
if !classic
|
1237
|
-
resp = MU::Cloud::AWS.ec2(region: region).allocate_address(domain: "vpc")
|
1260
|
+
resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).allocate_address(domain: "vpc")
|
1238
1261
|
new_ip = resp.public_ip
|
1239
1262
|
else
|
1240
|
-
new_ip = MU::Cloud::AWS.ec2(region: region).allocate_address().public_ip
|
1263
|
+
new_ip = MU::Cloud::AWS.ec2(region: region, credentials: credentials).allocate_address().public_ip
|
1241
1264
|
end
|
1242
1265
|
filters = [{name: "public-ip", values: [new_ip]}]
|
1243
1266
|
if resp.domain
|
@@ -1253,8 +1276,8 @@ module MU
|
|
1253
1276
|
begin
|
1254
1277
|
begin
|
1255
1278
|
sleep 5
|
1256
|
-
resp = MU::Cloud::AWS.ec2(region: region).describe_addresses(
|
1257
|
-
|
1279
|
+
resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_addresses(
|
1280
|
+
filters: filters
|
1258
1281
|
)
|
1259
1282
|
addr = resp.addresses.first
|
1260
1283
|
end while resp.addresses.size < 1 or addr.public_ip.nil?
|
@@ -1275,19 +1298,19 @@ module MU
|
|
1275
1298
|
def addVolume(dev, size, type: "gp2", delete_on_termination: false)
|
1276
1299
|
|
1277
1300
|
if setDeleteOntermination(dev, delete_on_termination)
|
1278
|
-
MU.log "A volume #{
|
1301
|
+
MU.log "A volume #{dev} already attached to #{self}, skipping", MU::NOTICE
|
1279
1302
|
return
|
1280
1303
|
end
|
1281
1304
|
|
1282
1305
|
MU.log "Creating #{size}GB #{type} volume on #{dev} for #{@cloud_id}"
|
1283
|
-
creation = MU::Cloud::AWS.ec2(region: @
|
1306
|
+
creation = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_volume(
|
1284
1307
|
availability_zone: cloud_desc.placement.availability_zone,
|
1285
1308
|
size: size,
|
1286
1309
|
volume_type: type
|
1287
1310
|
)
|
1288
1311
|
|
1289
1312
|
MU.retrier(wait: 3, loop_if: Proc.new {
|
1290
|
-
creation = MU::Cloud::AWS.ec2(region: @
|
1313
|
+
creation = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_volumes(volume_ids: [creation.volume_id]).volumes.first
|
1291
1314
|
if !["creating", "available"].include?(creation.state)
|
1292
1315
|
raise MuError, "Saw state '#{creation.state}' while creating #{size}GB #{type} volume on #{dev} for #{@cloud_id}"
|
1293
1316
|
end
|
@@ -1298,27 +1321,35 @@ module MU
|
|
1298
1321
|
if @deploy
|
1299
1322
|
MU::Cloud::AWS.createStandardTags(
|
1300
1323
|
creation.volume_id,
|
1301
|
-
region: @
|
1302
|
-
credentials: @
|
1324
|
+
region: @region,
|
1325
|
+
credentials: @credentials,
|
1303
1326
|
optional: @config['optional_tags'],
|
1304
1327
|
nametag: @mu_name+"-"+dev.upcase,
|
1305
1328
|
othertags: @config['tags']
|
1306
1329
|
)
|
1307
1330
|
end
|
1308
1331
|
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1332
|
+
MU.log "Attaching #{creation.volume_id} as #{dev} to #{@cloud_id} in #{@region} (credentials #{@credentials})"
|
1333
|
+
attachment = nil
|
1334
|
+
MU.retrier([Aws::EC2::Errors::IncorrectState], wait: 15, max: 4) {
|
1335
|
+
attachment = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).attach_volume(
|
1336
|
+
device: dev,
|
1337
|
+
instance_id: @cloud_id,
|
1338
|
+
volume_id: creation.volume_id
|
1339
|
+
)
|
1340
|
+
}
|
1314
1341
|
|
1315
1342
|
begin
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1343
|
+
att_resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_volumes(volume_ids: [attachment.volume_id])
|
1344
|
+
if att_resp and att_resp.volumes and !att_resp.volumes.empty? and
|
1345
|
+
att_resp.volumes.first.attachments and
|
1346
|
+
!att_resp.volumes.first.attachments.empty?
|
1347
|
+
attachment = att_resp.volumes.first.attachments.first
|
1348
|
+
if !attachment.nil? and !["attaching", "attached"].include?(attachment.state)
|
1349
|
+
raise MuError, "Saw state '#{creation.state}' while creating #{size}GB #{type} volume on #{dev} for #{@cloud_id}"
|
1350
|
+
end
|
1320
1351
|
end
|
1321
|
-
end while attachment.state != "attached"
|
1352
|
+
end while attachment.nil? or attachment.state != "attached"
|
1322
1353
|
|
1323
1354
|
# Set delete_on_termination, which for some reason is an instance
|
1324
1355
|
# attribute and not on the attachment
|
@@ -1334,7 +1365,7 @@ module MU
|
|
1334
1365
|
return true
|
1335
1366
|
end
|
1336
1367
|
begin
|
1337
|
-
MU::Cloud::AWS.ec2(region: @
|
1368
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_instances(
|
1338
1369
|
instance_ids: [@cloud_id]
|
1339
1370
|
).reservations.each { |resp|
|
1340
1371
|
if !resp.nil? and !resp.instances.nil?
|
@@ -1385,7 +1416,7 @@ module MU
|
|
1385
1416
|
}
|
1386
1417
|
end
|
1387
1418
|
end
|
1388
|
-
elastic_ip = findFreeElasticIp(classic: classic, ip: ip)
|
1419
|
+
elastic_ip = findFreeElasticIp(classic: classic, ip: ip, credentials: credentials)
|
1389
1420
|
if !ip.nil? and (elastic_ip.nil? or ip != elastic_ip.public_ip)
|
1390
1421
|
raise MuError, "Requested EIP #{ip}, but this IP does not exist or is not available"
|
1391
1422
|
end
|
@@ -1737,6 +1768,7 @@ module MU
|
|
1737
1768
|
return size
|
1738
1769
|
end
|
1739
1770
|
|
1771
|
+
|
1740
1772
|
return size if types.has_key?(size)
|
1741
1773
|
|
1742
1774
|
if size.nil? or !types.has_key?(size)
|
@@ -1782,7 +1814,8 @@ module MU
|
|
1782
1814
|
def self.generateStandardRole(server, configurator)
|
1783
1815
|
role = {
|
1784
1816
|
"name" => server["name"],
|
1785
|
-
"
|
1817
|
+
"bare_policies" => !server['generate_iam_role'],
|
1818
|
+
"strip_path" => server["role_strip_path"],
|
1786
1819
|
"can_assume" => [
|
1787
1820
|
{
|
1788
1821
|
"entity_id" => "ec2.amazonaws.com",
|
@@ -1801,6 +1834,7 @@ module MU
|
|
1801
1834
|
}
|
1802
1835
|
]
|
1803
1836
|
}
|
1837
|
+
role["credentials"] = server["credentials"] if server["credentials"]
|
1804
1838
|
if server['iam_policies']
|
1805
1839
|
role['iam_policies'] = server['iam_policies'].dup
|
1806
1840
|
end
|
@@ -1834,9 +1868,10 @@ module MU
|
|
1834
1868
|
MU.log "Cannot mix iam_policies with generate_iam_role set to false", MU::ERR
|
1835
1869
|
ok = false
|
1836
1870
|
end
|
1837
|
-
else
|
1838
|
-
generateStandardRole(server, configurator)
|
1839
1871
|
end
|
1872
|
+
|
1873
|
+
generateStandardRole(server, configurator)
|
1874
|
+
|
1840
1875
|
if !server['create_image'].nil?
|
1841
1876
|
if server['create_image'].has_key?('copy_to_regions') and
|
1842
1877
|
(server['create_image']['copy_to_regions'].nil? or
|
@@ -2085,7 +2120,7 @@ module MU
|
|
2085
2120
|
def haveElasticIP?
|
2086
2121
|
if !cloud_desc.public_ip_address.nil?
|
2087
2122
|
begin
|
2088
|
-
resp = MU::Cloud::AWS.ec2(region: @
|
2123
|
+
resp = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_addresses(public_ips: [cloud_desc.public_ip_address])
|
2089
2124
|
if resp.addresses.size > 0 and resp.addresses.first.instance_id == @cloud_id
|
2090
2125
|
return true
|
2091
2126
|
end
|
@@ -2100,9 +2135,9 @@ module MU
|
|
2100
2135
|
def configureNetworking
|
2101
2136
|
if !@config['static_ip'].nil?
|
2102
2137
|
if !@config['static_ip']['ip'].nil?
|
2103
|
-
MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: @vpc.nil?, ip: @config['static_ip']['ip'])
|
2138
|
+
MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: @vpc.nil?, ip: @config['static_ip']['ip'], credentials: @credentials)
|
2104
2139
|
elsif !haveElasticIP?
|
2105
|
-
MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: @vpc.nil
|
2140
|
+
MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: @vpc.nil?, credentials: @credentials)
|
2106
2141
|
end
|
2107
2142
|
end
|
2108
2143
|
|
@@ -2110,7 +2145,7 @@ module MU
|
|
2110
2145
|
subnet = @vpc.getSubnet(cloud_id: cloud_desc.subnet_id)
|
2111
2146
|
|
2112
2147
|
_nat_ssh_key, _nat_ssh_user, nat_ssh_host, _canonical_ip, _ssh_user, _ssh_key_name = getSSHConfig
|
2113
|
-
if subnet.private? and !nat_ssh_host and !MU::Cloud.resourceClass("AWS", "VPC").haveRouteToInstance?(cloud_desc, region: @
|
2148
|
+
if subnet.private? and !nat_ssh_host and !MU::Cloud.resourceClass("AWS", "VPC").haveRouteToInstance?(cloud_desc, region: @region, credentials: @credentials)
|
2114
2149
|
raise MuError, "#{@mu_name} is in a private subnet (#{subnet}), but has no bastion host configured, and I have no other route to it"
|
2115
2150
|
end
|
2116
2151
|
|
@@ -2127,17 +2162,17 @@ module MU
|
|
2127
2162
|
next
|
2128
2163
|
end
|
2129
2164
|
MU.log "Adding network interface on subnet #{s.cloud_id} for #{@mu_name}"
|
2130
|
-
iface = MU::Cloud::AWS.ec2(region: @
|
2165
|
+
iface = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_network_interface(subnet_id: s.cloud_id).network_interface
|
2131
2166
|
MU::Cloud::AWS.createStandardTags(
|
2132
2167
|
iface.network_interface_id,
|
2133
|
-
region: @
|
2134
|
-
credentials: @
|
2168
|
+
region: @region,
|
2169
|
+
credentials: @credentials,
|
2135
2170
|
optional: @config['optional_tags'],
|
2136
2171
|
nametag: @mu_name+"-ETH"+device_index.to_s,
|
2137
2172
|
othertags: @config['tags']
|
2138
2173
|
)
|
2139
2174
|
|
2140
|
-
MU::Cloud::AWS.ec2(region: @
|
2175
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).attach_network_interface(
|
2141
2176
|
network_interface_id: iface.network_interface_id,
|
2142
2177
|
instance_id: cloud_desc.instance_id,
|
2143
2178
|
device_index: device_index
|
@@ -2156,7 +2191,7 @@ module MU
|
|
2156
2191
|
cloud_desc.network_interfaces.each { |int|
|
2157
2192
|
if int.private_ip_address == cloud_desc.private_ip_address and int.private_ip_addresses.size < (@config['add_private_ips'] + 1)
|
2158
2193
|
MU.log "Adding #{@config['add_private_ips']} extra private IP addresses to #{cloud_desc.instance_id}"
|
2159
|
-
MU::Cloud::AWS.ec2(region: @
|
2194
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).assign_private_ip_addresses(
|
2160
2195
|
network_interface_id: int.network_interface_id,
|
2161
2196
|
secondary_private_ip_address_count: @config['add_private_ips'],
|
2162
2197
|
allow_reassignment: false
|
@@ -2167,14 +2202,14 @@ module MU
|
|
2167
2202
|
end
|
2168
2203
|
|
2169
2204
|
def tagVolumes
|
2170
|
-
volumes = MU::Cloud::AWS.ec2(region: @
|
2205
|
+
volumes = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_volumes(filters: [name: "attachment.instance-id", values: [@cloud_id]])
|
2171
2206
|
volumes.each { |vol|
|
2172
2207
|
vol.volumes.each { |volume|
|
2173
2208
|
volume.attachments.each { |attachment|
|
2174
2209
|
MU::Cloud::AWS.createStandardTags(
|
2175
2210
|
attachment.volume_id,
|
2176
|
-
region: @
|
2177
|
-
credentials: @
|
2211
|
+
region: @region,
|
2212
|
+
credentials: @credentials,
|
2178
2213
|
optional: @config['optional_tags'],
|
2179
2214
|
nametag: ["/dev/sda", "/dev/sda1"].include?(attachment.device) ? "ROOT-"+@mu_name : @mu_name+"-"+attachment.device.upcase,
|
2180
2215
|
othertags: @config['tags']
|
@@ -2195,7 +2230,7 @@ module MU
|
|
2195
2230
|
alarm_obj = MU::MommaCat.findStray(
|
2196
2231
|
"AWS",
|
2197
2232
|
"alarms",
|
2198
|
-
region: @
|
2233
|
+
region: @region,
|
2199
2234
|
deploy_id: @deploy.deploy_id,
|
2200
2235
|
name: alarm['name']
|
2201
2236
|
).first
|
@@ -2204,8 +2239,8 @@ module MU
|
|
2204
2239
|
if alarm["enable_notifications"]
|
2205
2240
|
# XXX vile, this should be a sibling resource generated by the
|
2206
2241
|
# parser
|
2207
|
-
topic_arn = MU::Cloud.resourceClass("AWS", "Notification").createTopic(alarm["notification_group"], region: @
|
2208
|
-
MU::Cloud.resourceClass("AWS", "Notification").subscribe(topic_arn, alarm["notification_endpoint"], alarm["notification_type"], region: @
|
2242
|
+
topic_arn = MU::Cloud.resourceClass("AWS", "Notification").createTopic(alarm["notification_group"], region: @region, credentials: @credentials)
|
2243
|
+
MU::Cloud.resourceClass("AWS", "Notification").subscribe(topic_arn, alarm["notification_endpoint"], alarm["notification_type"], region: @region, credentials: @credentials)
|
2209
2244
|
alarm["alarm_actions"] = [topic_arn]
|
2210
2245
|
alarm["ok_actions"] = [topic_arn]
|
2211
2246
|
end
|
@@ -2226,36 +2261,88 @@ module MU
|
|
2226
2261
|
evaluation_periods: alarm["evaluation_periods"],
|
2227
2262
|
threshold: alarm["threshold"],
|
2228
2263
|
comparison_operator: alarm["comparison_operator"],
|
2229
|
-
region: @
|
2230
|
-
credentials: @
|
2264
|
+
region: @region,
|
2265
|
+
credentials: @credentials
|
2231
2266
|
)
|
2232
2267
|
}
|
2233
2268
|
end
|
2234
2269
|
end
|
2235
2270
|
|
2236
|
-
# We have issues sometimes where our dns_records are pointing at the wrong node name and IP address.
|
2237
|
-
|
2238
2271
|
def getIAMProfile
|
2239
|
-
|
2240
|
-
|
2241
|
-
|
2242
|
-
|
2272
|
+
self.class.getIAMProfile(
|
2273
|
+
@config['name'],
|
2274
|
+
@deploy,
|
2275
|
+
generated: @config['generate_iam_role'],
|
2276
|
+
role_name: @config['iam_role'],
|
2277
|
+
region: @region,
|
2278
|
+
credentials: @credentials,
|
2279
|
+
want_arn: true
|
2280
|
+
)
|
2281
|
+
end
|
2282
|
+
|
2283
|
+
# XXX move to public section
|
2284
|
+
def self.getIAMProfile(myname, deploy, generated: true, role_name: nil, region: nil, credentials: nil, want_arn: false)
|
2285
|
+
|
2286
|
+
arn = if generated
|
2287
|
+
role = deploy.findLitterMate(name: myname, type: "roles", debug: true)
|
2288
|
+
if !role
|
2289
|
+
raise MuError, "Failed to find a role matching #{myname}"
|
2290
|
+
end
|
2291
|
+
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|
|
2292
|
+
'arn:'+(MU::Cloud::AWS.isGovCloud?(region) ? "aws-us-gov" : "aws")+':s3:::'+MU::Cloud::AWS.adminBucketName(credentials)+'/'+file
|
2243
2293
|
}
|
2244
|
-
MU.log "Adding S3 read permissions to #{
|
2294
|
+
MU.log "Adding S3 read permissions to #{myname}'s IAM profile", MU::NOTICE, details: s3_objs
|
2245
2295
|
role.cloudobj.injectPolicyTargets("MuSecrets", s3_objs)
|
2246
2296
|
|
2247
|
-
|
2297
|
+
role_name = role.mu_name
|
2248
2298
|
role.cloudobj.createInstanceProfile
|
2249
2299
|
|
2250
|
-
elsif
|
2251
|
-
raise MuError, "#{
|
2300
|
+
elsif role_name.nil?
|
2301
|
+
raise MuError, "#{myname} has generate_iam_role set to false, but no iam_role assigned."
|
2302
|
+
else
|
2303
|
+
begin
|
2304
|
+
ext_prof = MU::Cloud::AWS.iam(credentials: credentials).get_instance_profile(instance_profile_name: role_name)
|
2305
|
+
role_name = ext_prof.instance_profile.instance_profile_name
|
2306
|
+
ext_prof.instance_profile.arn
|
2307
|
+
rescue Aws::IAM::Errors::NoSuchEntity
|
2308
|
+
role = MU::MommaCat.findStray("AWS", "role", cloud_id: role_name, dummy_ok: true, credentials: credentials).first
|
2309
|
+
if !role
|
2310
|
+
raise MuError, "#{myname} specified iam_role '#{role_name}', but I can't find a role with that name to use when creating an instance profile"
|
2311
|
+
end
|
2312
|
+
role.cloudobj.createInstanceProfile
|
2313
|
+
end
|
2252
2314
|
end
|
2253
2315
|
|
2254
|
-
|
2255
|
-
|
2316
|
+
role_or_policy = deploy.findLitterMate(name: myname, type: "roles")
|
2317
|
+
|
2318
|
+
# Make sure our permissions to read our identity secrets are set
|
2319
|
+
s3_objs = [
|
2320
|
+
"#{deploy.deploy_id}-secret",
|
2321
|
+
"#{role_or_policy.mu_name}.pfx",
|
2322
|
+
"#{role_or_policy.mu_name}.crt",
|
2323
|
+
"#{role_or_policy.mu_name}.key",
|
2324
|
+
"#{role_or_policy.mu_name}-winrm.crt",
|
2325
|
+
"#{role_or_policy.mu_name}-winrm.key"].map { |file|
|
2326
|
+
'arn:'+(MU::Cloud::AWS.isGovCloud?(region) ? "aws-us-gov" : "aws")+':s3:::'+MU::Cloud::AWS.adminBucketName(credentials)+'/'+file
|
2327
|
+
}
|
2328
|
+
if generated
|
2329
|
+
role_or_policy.injectPolicyTargets("MuSecrets", s3_objs)
|
2330
|
+
elsif role_name
|
2331
|
+
realrole = MU::MommaCat.findStray("AWS", "role", cloud_id: role_name, dummy_ok: true, credentials: credentials).first
|
2332
|
+
if !role_or_policy
|
2333
|
+
raise MuError, "I should have a bare policy littermate named #{name} but I can't find it"
|
2334
|
+
end
|
2335
|
+
if realrole
|
2336
|
+
role_or_policy.bindTo("role", realrole.cloud_id)
|
2337
|
+
realrole.injectPolicyTargets(role_or_policy.mu_name+"-MUSECRETS", s3_objs)
|
2338
|
+
end
|
2339
|
+
end
|
2340
|
+
|
2341
|
+
if !role_name.nil?
|
2342
|
+
if arn and want_arn
|
2256
2343
|
return {arn: arn}
|
2257
2344
|
else
|
2258
|
-
return {name:
|
2345
|
+
return {name: role_name}
|
2259
2346
|
end
|
2260
2347
|
end
|
2261
2348
|
|
@@ -2272,8 +2359,8 @@ module MU
|
|
2272
2359
|
if vol[:device_name] == device
|
2273
2360
|
if vol[:ebs][:delete_on_termination] != delete_on_termination
|
2274
2361
|
vol[:ebs][:delete_on_termination] = delete_on_termination
|
2275
|
-
MU.log "Setting delete_on_termination flag to #{delete_on_termination.to_s} on #{@mu_name}'s #{
|
2276
|
-
MU::Cloud::AWS.ec2(region: @
|
2362
|
+
MU.log "Setting delete_on_termination flag to #{delete_on_termination.to_s} on #{@mu_name}'s #{device}"
|
2363
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).modify_instance_attribute(
|
2277
2364
|
instance_id: @cloud_id,
|
2278
2365
|
block_device_mappings: mappings
|
2279
2366
|
)
|
@@ -2317,16 +2404,17 @@ module MU
|
|
2317
2404
|
exclude_storage: img_cfg['image_exclude_storage'],
|
2318
2405
|
copy_to_regions: img_cfg['copy_to_regions'],
|
2319
2406
|
make_public: img_cfg['public'],
|
2320
|
-
region: @
|
2407
|
+
region: @region,
|
2321
2408
|
tags: @config['tags'],
|
2322
|
-
credentials: @
|
2409
|
+
credentials: @credentials
|
2323
2410
|
)
|
2411
|
+
|
2324
2412
|
@deploy.notify("images", @config['name'], ami_ids)
|
2325
2413
|
@config['image_created'] = true
|
2326
2414
|
if img_cfg['image_then_destroy']
|
2327
|
-
MU::Cloud::AWS::Server.waitForAMI(ami_ids[@
|
2328
|
-
MU.log "AMI #{ami_ids[@
|
2329
|
-
MU::Cloud::AWS::Server.terminateInstance(id: @cloud_id, region: @
|
2415
|
+
MU::Cloud::AWS::Server.waitForAMI(ami_ids[@region], region: @region, credentials: @credentials)
|
2416
|
+
MU.log "AMI #{ami_ids[@region]} ready, removing source node #{@mu_name}"
|
2417
|
+
MU::Cloud::AWS::Server.terminateInstance(id: @cloud_id, region: @region, deploy_id: @deploy.deploy_id, mu_name: @mu_name, credentials: @credentials)
|
2330
2418
|
destroy
|
2331
2419
|
end
|
2332
2420
|
end
|