cloud-mu 3.1.2 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +15 -3
- data/ansible/roles/mu-windows/README.md +33 -0
- data/ansible/roles/mu-windows/defaults/main.yml +2 -0
- data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
- data/ansible/roles/mu-windows/files/config.xml +76 -0
- data/ansible/roles/mu-windows/handlers/main.yml +2 -0
- data/ansible/roles/mu-windows/meta/main.yml +53 -0
- data/ansible/roles/mu-windows/tasks/main.yml +36 -0
- data/ansible/roles/mu-windows/tests/inventory +2 -0
- data/ansible/roles/mu-windows/tests/test.yml +5 -0
- data/ansible/roles/mu-windows/vars/main.yml +2 -0
- data/bin/mu-adopt +10 -13
- data/bin/mu-azure-tests +57 -0
- data/bin/mu-cleanup +2 -4
- data/bin/mu-configure +52 -0
- data/bin/mu-deploy +3 -3
- data/bin/mu-findstray-tests +25 -0
- data/bin/mu-gen-docs +2 -4
- data/bin/mu-load-config.rb +2 -3
- data/bin/mu-node-manage +15 -16
- data/bin/mu-run-tests +135 -37
- data/cloud-mu.gemspec +22 -20
- data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
- data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
- data/cookbooks/mu-tools/libraries/helper.rb +3 -2
- data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
- data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
- data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
- data/cookbooks/mu-tools/recipes/eks.rb +2 -2
- data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
- data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
- data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
- data/cookbooks/mu-tools/resources/disk.rb +1 -1
- data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
- data/extras/clean-stock-amis +25 -19
- data/extras/generate-stock-images +1 -0
- data/extras/image-generators/AWS/win2k12.yaml +18 -13
- data/extras/image-generators/AWS/win2k16.yaml +18 -13
- data/extras/image-generators/AWS/win2k19.yaml +21 -0
- data/extras/image-generators/Google/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +1 -1
- data/modules/mommacat.ru +6 -16
- data/modules/mu.rb +165 -111
- data/modules/mu/adoption.rb +401 -68
- data/modules/mu/cleanup.rb +199 -306
- data/modules/mu/cloud.rb +100 -1632
- data/modules/mu/cloud/database.rb +49 -0
- data/modules/mu/cloud/dnszone.rb +46 -0
- data/modules/mu/cloud/machine_images.rb +212 -0
- data/modules/mu/cloud/providers.rb +81 -0
- data/modules/mu/cloud/resource_base.rb +920 -0
- data/modules/mu/cloud/server.rb +40 -0
- data/modules/mu/cloud/server_pool.rb +1 -0
- data/modules/mu/cloud/ssh_sessions.rb +228 -0
- data/modules/mu/cloud/winrm_sessions.rb +237 -0
- data/modules/mu/cloud/wrappers.rb +165 -0
- data/modules/mu/config.rb +171 -1767
- data/modules/mu/config/alarm.rb +2 -6
- data/modules/mu/config/bucket.rb +4 -4
- data/modules/mu/config/cache_cluster.rb +1 -1
- data/modules/mu/config/collection.rb +4 -4
- data/modules/mu/config/container_cluster.rb +9 -4
- data/modules/mu/config/database.rb +83 -104
- data/modules/mu/config/database.yml +1 -2
- data/modules/mu/config/dnszone.rb +6 -6
- data/modules/mu/config/doc_helpers.rb +516 -0
- data/modules/mu/config/endpoint.rb +4 -4
- data/modules/mu/config/firewall_rule.rb +103 -4
- data/modules/mu/config/folder.rb +4 -4
- data/modules/mu/config/function.rb +3 -3
- data/modules/mu/config/group.rb +4 -4
- data/modules/mu/config/habitat.rb +4 -4
- data/modules/mu/config/loadbalancer.rb +60 -14
- data/modules/mu/config/log.rb +4 -4
- data/modules/mu/config/msg_queue.rb +4 -4
- data/modules/mu/config/nosqldb.rb +4 -4
- data/modules/mu/config/notifier.rb +3 -3
- data/modules/mu/config/ref.rb +365 -0
- data/modules/mu/config/role.rb +4 -4
- data/modules/mu/config/schema_helpers.rb +509 -0
- data/modules/mu/config/search_domain.rb +4 -4
- data/modules/mu/config/server.rb +97 -70
- data/modules/mu/config/server.yml +1 -0
- data/modules/mu/config/server_pool.rb +5 -9
- data/modules/mu/config/storage_pool.rb +1 -1
- data/modules/mu/config/tail.rb +200 -0
- data/modules/mu/config/user.rb +4 -4
- data/modules/mu/config/vpc.rb +70 -27
- data/modules/mu/config/vpc.yml +0 -1
- data/modules/mu/defaults/AWS.yaml +83 -60
- data/modules/mu/defaults/Azure.yaml +1 -0
- data/modules/mu/defaults/Google.yaml +3 -2
- data/modules/mu/deploy.rb +30 -26
- data/modules/mu/groomer.rb +17 -2
- data/modules/mu/groomers/ansible.rb +188 -41
- data/modules/mu/groomers/chef.rb +116 -55
- data/modules/mu/logger.rb +127 -148
- data/modules/mu/master.rb +389 -2
- data/modules/mu/master/chef.rb +3 -4
- data/modules/mu/master/ldap.rb +3 -3
- data/modules/mu/master/ssl.rb +12 -3
- data/modules/mu/mommacat.rb +217 -2612
- data/modules/mu/mommacat/daemon.rb +397 -0
- data/modules/mu/mommacat/naming.rb +473 -0
- data/modules/mu/mommacat/search.rb +495 -0
- data/modules/mu/mommacat/storage.rb +722 -0
- data/modules/mu/{clouds → providers}/README.md +1 -1
- data/modules/mu/{clouds → providers}/aws.rb +271 -112
- data/modules/mu/{clouds → providers}/aws/alarm.rb +5 -3
- data/modules/mu/{clouds → providers}/aws/bucket.rb +26 -22
- data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +33 -67
- data/modules/mu/{clouds → providers}/aws/collection.rb +24 -23
- data/modules/mu/{clouds → providers}/aws/container_cluster.rb +681 -721
- data/modules/mu/providers/aws/database.rb +1744 -0
- data/modules/mu/{clouds → providers}/aws/dnszone.rb +64 -63
- data/modules/mu/{clouds → providers}/aws/endpoint.rb +22 -27
- data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +214 -244
- data/modules/mu/{clouds → providers}/aws/folder.rb +7 -7
- data/modules/mu/{clouds → providers}/aws/function.rb +17 -22
- data/modules/mu/{clouds → providers}/aws/group.rb +23 -23
- data/modules/mu/{clouds → providers}/aws/habitat.rb +17 -14
- data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +57 -48
- data/modules/mu/{clouds → providers}/aws/log.rb +15 -12
- data/modules/mu/{clouds → providers}/aws/msg_queue.rb +17 -16
- data/modules/mu/{clouds → providers}/aws/nosqldb.rb +18 -11
- data/modules/mu/{clouds → providers}/aws/notifier.rb +11 -6
- data/modules/mu/{clouds → providers}/aws/role.rb +112 -86
- data/modules/mu/{clouds → providers}/aws/search_domain.rb +39 -33
- data/modules/mu/{clouds → providers}/aws/server.rb +835 -1133
- data/modules/mu/{clouds → providers}/aws/server_pool.rb +56 -60
- data/modules/mu/{clouds → providers}/aws/storage_pool.rb +24 -42
- data/modules/mu/{clouds → providers}/aws/user.rb +21 -22
- data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
- data/modules/mu/{clouds → providers}/aws/vpc.rb +523 -929
- data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
- data/modules/mu/{clouds → providers}/azure.rb +29 -9
- data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
- data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
- data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
- data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
- data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
- data/modules/mu/{clouds → providers}/azure/server.rb +95 -48
- data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
- data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/vpc.rb +16 -21
- data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
- data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
- data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
- data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
- data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +5 -7
- data/modules/mu/{clouds → providers}/docker.rb +0 -0
- data/modules/mu/{clouds → providers}/google.rb +67 -30
- data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
- data/modules/mu/{clouds → providers}/google/container_cluster.rb +84 -77
- data/modules/mu/{clouds → providers}/google/database.rb +10 -20
- data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
- data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
- data/modules/mu/{clouds → providers}/google/function.rb +139 -167
- data/modules/mu/{clouds → providers}/google/group.rb +29 -34
- data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
- data/modules/mu/{clouds → providers}/google/loadbalancer.rb +18 -20
- data/modules/mu/{clouds → providers}/google/role.rb +92 -58
- data/modules/mu/{clouds → providers}/google/server.rb +242 -155
- data/modules/mu/{clouds → providers}/google/server_pool.rb +25 -44
- data/modules/mu/{clouds → providers}/google/user.rb +95 -31
- data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/google/vpc.rb +103 -79
- data/modules/tests/bucket.yml +4 -0
- data/modules/tests/centos6.yaml +11 -0
- data/modules/tests/centos7.yaml +11 -0
- data/modules/tests/centos8.yaml +12 -0
- data/modules/tests/ecs.yaml +23 -0
- data/modules/tests/includes-and-params.yaml +2 -1
- data/modules/tests/rds.yaml +108 -0
- data/modules/tests/regrooms/aws-iam.yaml +201 -0
- data/modules/tests/regrooms/bucket.yml +19 -0
- data/modules/tests/regrooms/rds.yaml +123 -0
- data/modules/tests/server-with-scrub-muisms.yaml +1 -0
- data/modules/tests/super_simple_bok.yml +1 -3
- data/modules/tests/win2k12.yaml +17 -5
- data/modules/tests/win2k16.yaml +25 -0
- data/modules/tests/win2k19.yaml +25 -0
- data/requirements.txt +1 -0
- data/spec/mu/clouds/azure_spec.rb +2 -2
- metadata +232 -154
- data/extras/image-generators/AWS/windows.yaml +0 -18
- data/modules/mu/clouds/aws/database.rb +0 -1985
@@ -344,8 +344,8 @@ module MU
|
|
344
344
|
)
|
345
345
|
rescue Aws::Route53::Errors::LastVPCAssociation => e
|
346
346
|
MU.log e.inspect, MU::WARN
|
347
|
-
rescue Aws::Route53::Errors::VPCAssociationNotFound
|
348
|
-
MU.log "VPC #{vpc_id} access to zone #{id} already revoked", MU::
|
347
|
+
rescue Aws::Route53::Errors::VPCAssociationNotFound
|
348
|
+
MU.log "VPC #{vpc_id} access to zone #{id} already revoked", MU::NOTICE
|
349
349
|
end
|
350
350
|
end
|
351
351
|
end
|
@@ -366,10 +366,10 @@ module MU
|
|
366
366
|
# @param location [Hash<String>]: A parsed Hash of {MU::Config::BasketofKittens::dnszones::records::geo_location}.
|
367
367
|
# @param set_identifier [String]: A unique string to differentiate otherwise-similar records. Normally auto-generated, should not need to specify.
|
368
368
|
# @param alias_zone [String]: Zone ID of the target's hosted zone, when creating an alias (type R53ALIAS)
|
369
|
-
def self.manageRecord(id, name, type, targets: nil,
|
369
|
+
def self.manageRecord(id, name, type, targets: nil,
|
370
370
|
ttl: 7200, delete: false, sync_wait: true, failover: nil,
|
371
371
|
healthcheck: nil, region: nil, weight: nil, overwrite: true,
|
372
|
-
location: nil, set_identifier: nil, alias_zone: nil)
|
372
|
+
location: nil, set_identifier: nil, alias_zone: nil, noop: false)
|
373
373
|
|
374
374
|
MU.setVar("curRegion", region) if !region.nil?
|
375
375
|
zone = MU::Cloud::DNSZone.find(cloud_id: id).values.first
|
@@ -380,6 +380,11 @@ module MU
|
|
380
380
|
action = "UPSERT" if overwrite
|
381
381
|
action = "DELETE" if delete
|
382
382
|
|
383
|
+
record_sets = MU::Cloud::AWS.route53.list_resource_record_sets(
|
384
|
+
hosted_zone_id: id,
|
385
|
+
start_record_name: name
|
386
|
+
).resource_record_sets if delete
|
387
|
+
|
383
388
|
if type == "R53ALIAS"
|
384
389
|
target_zone = id
|
385
390
|
target_name = targets[0].downcase
|
@@ -413,7 +418,15 @@ module MU
|
|
413
418
|
}
|
414
419
|
else
|
415
420
|
rrsets = []
|
416
|
-
if
|
421
|
+
if delete
|
422
|
+
record_sets.each { |r|
|
423
|
+
if r.name == name and r.type == type
|
424
|
+
rrsets = MU.structToHash(r.resource_records)
|
425
|
+
end
|
426
|
+
}
|
427
|
+
end
|
428
|
+
|
429
|
+
if !targets.nil? and (!delete or rrsets.empty?)
|
417
430
|
targets.each { |target|
|
418
431
|
rrsets << {value: target}
|
419
432
|
}
|
@@ -426,6 +439,7 @@ module MU
|
|
426
439
|
resource_records: rrsets
|
427
440
|
}
|
428
441
|
|
442
|
+
|
429
443
|
if !healthcheck.nil?
|
430
444
|
base_rrset[:health_check_id] = healthcheck
|
431
445
|
end
|
@@ -445,12 +459,13 @@ module MU
|
|
445
459
|
|
446
460
|
# Doing an UPSERT with a new set_identifier will fail with a record already exist error, so lets try and get it from an existing record.
|
447
461
|
# This can be an issue with multiple secondary failover records
|
448
|
-
if (location || failover || region || weight)
|
449
|
-
record_sets
|
462
|
+
if (location || failover || region || weight) and set_identifier.nil?
|
463
|
+
record_sets ||= MU::Cloud::AWS.route53.list_resource_record_sets(
|
450
464
|
hosted_zone_id: id,
|
451
465
|
start_record_name: name
|
452
466
|
).resource_record_sets
|
453
467
|
|
468
|
+
|
454
469
|
record_sets.each { |r|
|
455
470
|
if r.name == name
|
456
471
|
if location && location == r.location
|
@@ -497,18 +512,23 @@ module MU
|
|
497
512
|
MU.log "Adding DNS record #{name} => #{targets} (#{type}) to #{id}", details: params
|
498
513
|
end
|
499
514
|
|
500
|
-
|
515
|
+
return if noop
|
516
|
+
|
517
|
+
on_retry = Proc.new { |e|
|
518
|
+
if (delete and e.message.match(/but it was not found/)) or
|
519
|
+
(!delete and e.message.match(/(it|name) already exists/))
|
520
|
+
MU.log e.message, MU::DEBUG, details: params
|
521
|
+
return
|
522
|
+
elsif e.class == Aws::Route53::Errors::InvalidChangeBatch
|
523
|
+
MU.log "Problem managing entry for #{name}", MU::ERR, details: params
|
524
|
+
raise MuError, e.inspect
|
525
|
+
end
|
526
|
+
}
|
527
|
+
|
528
|
+
change_id = nil
|
529
|
+
MU.retrier([Aws::Route53::Errors::PriorRequestNotComplete, Aws::Route53::Errors::InvalidChangeBatch], wait: 15, max: 10, on_retry: on_retry) {
|
501
530
|
change_id = MU::Cloud::AWS.route53.change_resource_record_sets(params).change_info.id
|
502
|
-
|
503
|
-
sleep 10
|
504
|
-
retry
|
505
|
-
rescue Aws::Route53::Errors::InvalidChangeBatch, Aws::Route53::Errors::InvalidInput, Exception => e
|
506
|
-
return if e.message.match(/ but it already exists/) and !delete
|
507
|
-
MU.log "Failed to change DNS records, #{e.inspect}", MU::ERR, details: params
|
508
|
-
raise e if !delete
|
509
|
-
MU.log "Record #{name} (#{type}) in #{id} can't be deleted. Already removed? #{e.inspect}", MU::WARN, details: params if delete
|
510
|
-
return
|
511
|
-
end
|
531
|
+
}
|
512
532
|
|
513
533
|
if sync_wait
|
514
534
|
attempts = 0
|
@@ -535,23 +555,27 @@ module MU
|
|
535
555
|
# @param delete [Boolean]: Remove this entry instead of creating it.
|
536
556
|
# @param cloudclass [Object]: The resource's Mu class.
|
537
557
|
# @param sync_wait [Boolean]: Wait for DNS entry to propagate across zone.
|
538
|
-
def self.genericMuDNSEntry(name: nil, target: nil, cloudclass: nil, noop: false, delete: false, sync_wait: true)
|
539
|
-
return nil if name.nil? or
|
540
|
-
|
558
|
+
def self.genericMuDNSEntry(name: nil, target: nil, cloudclass: nil, noop: false, delete: false, sync_wait: true, credentials: nil)
|
559
|
+
return nil if name.nil? or cloudclass.nil?
|
560
|
+
return nil if target.nil? and !delete
|
561
|
+
mu_zone = MU::Cloud::DNSZone.find(cloud_id: "platform-mu", credentials: credentials).values.first
|
541
562
|
raise MuError, "Couldn't isolate platform-mu DNS zone" if mu_zone.nil?
|
542
563
|
|
543
564
|
if !mu_zone.nil? and !MU.myVPC.nil?
|
544
565
|
subdomain = cloudclass.cfg_name
|
545
566
|
dns_name = name.downcase+"."+subdomain
|
546
567
|
dns_name += "."+MU.myInstanceId if MU.myInstanceId
|
568
|
+
|
547
569
|
record_type = "CNAME"
|
548
570
|
record_type = "A" if target.match(/^\d+\.\d+\.\d+\.\d+/)
|
549
571
|
ip = nil
|
550
572
|
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
573
|
+
records = []
|
574
|
+
lookup = MU::Cloud::AWS.route53(credentials: credentials).list_resource_record_sets(
|
575
|
+
hosted_zone_id: mu_zone.id,
|
576
|
+
start_record_name: "#{dns_name}.platform-mu",
|
577
|
+
start_record_type: record_type,
|
578
|
+
max_items: 1
|
555
579
|
).resource_record_sets
|
556
580
|
|
557
581
|
lookup.each { |record|
|
@@ -572,34 +596,14 @@ module MU
|
|
572
596
|
# MU.log "'#{dns_name}.platform-mu' does not resolve.", MU::DEBUG, details: e.inspect
|
573
597
|
# end
|
574
598
|
|
575
|
-
if ip == target
|
576
|
-
return "#{dns_name}.platform-mu"
|
577
|
-
elsif noop
|
578
|
-
return nil
|
599
|
+
if ip == target and !delete
|
600
|
+
return "#{dns_name}.platform-mu"
|
579
601
|
end
|
580
602
|
|
581
603
|
sync_wait = false if delete
|
582
604
|
|
583
605
|
record_type = "R53ALIAS" if cloudclass == MU::Cloud::AWS::LoadBalancer
|
584
|
-
|
585
|
-
begin
|
586
|
-
MU::Cloud::AWS::DNSZone.manageRecord(mu_zone.id, dns_name, record_type, targets: [target], delete: delete, sync_wait: sync_wait)
|
587
|
-
rescue Aws::Route53::Errors::PriorRequestNotComplete => e
|
588
|
-
MU.log "Route53 was still processing a request, waiting", MU::WARN, details: e
|
589
|
-
sleep 15
|
590
|
-
retry
|
591
|
-
rescue Aws::Route53::Errors::InvalidChangeBatch => e
|
592
|
-
if e.inspect.match(/alias target name does not lie within the target zone/) and attempts < 5
|
593
|
-
MU.log e.inspect, MU::WARN
|
594
|
-
sleep 15
|
595
|
-
attempts = attempts + 1
|
596
|
-
retry
|
597
|
-
elsif !e.inspect.match(/(it|name) already exists/)
|
598
|
-
raise MuError, "Problem managing entry for #{dns_name} -> #{target}: #{e.inspect}"
|
599
|
-
else
|
600
|
-
MU.log "#{dns_name} already exists", MU::DEBUG, details: e.inspect
|
601
|
-
end
|
602
|
-
end
|
606
|
+
MU::Cloud::AWS::DNSZone.manageRecord(mu_zone.id, dns_name, record_type, targets: [target], delete: delete, sync_wait: sync_wait, noop: noop)
|
603
607
|
return "#{dns_name}.platform-mu"
|
604
608
|
else
|
605
609
|
return nil
|
@@ -663,7 +667,8 @@ module MU
|
|
663
667
|
# Called by {MU::Cleanup}. Locates resources that were created by the
|
664
668
|
# currently-loaded deployment, and purges them.
|
665
669
|
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
666
|
-
|
670
|
+
MU.log "AWS::DNSZone.cleanup: need to support flags['known']", MU::DEBUG, details: flags
|
671
|
+
|
667
672
|
threads = []
|
668
673
|
MU::Cloud::AWS.route53(credentials: credentials).list_health_checks.health_checks.each { |check|
|
669
674
|
begin
|
@@ -692,19 +697,19 @@ module MU
|
|
692
697
|
threads << Thread.new(check) { |mycheck|
|
693
698
|
MU.dupGlobals(parent_thread_id)
|
694
699
|
Thread.abort_on_exception = true
|
695
|
-
MU.log "Removing health check #{
|
700
|
+
MU.log "Removing health check #{mycheck.id}"
|
696
701
|
retries = 5
|
697
702
|
begin
|
698
|
-
MU::Cloud::AWS.route53(credentials: credentials).delete_health_check(
|
703
|
+
MU::Cloud::AWS.route53(credentials: credentials).delete_health_check(health_mycheck_id: mycheck.id) if !noop
|
699
704
|
rescue Aws::Route53::Errors::NoSuchHealthCheck => e
|
700
|
-
MU.log "Health Check '#{
|
705
|
+
MU.log "Health Check '#{mycheck.id}' disappeared before I could remove it", MU::WARN, details: e.inspect
|
701
706
|
rescue Aws::Route53::Errors::InvalidInput => e
|
702
707
|
if e.message.match(/is still referenced from parent health check/) && retries <= 5
|
703
708
|
sleep 5
|
704
709
|
retries += 1
|
705
710
|
retry
|
706
711
|
else
|
707
|
-
MU.log "Health Check #{
|
712
|
+
MU.log "Health Check #{mycheck.id} still has a parent health check associated with it, skipping", MU::WARN, details: e.inspect
|
708
713
|
end
|
709
714
|
end
|
710
715
|
}
|
@@ -719,7 +724,7 @@ module MU
|
|
719
724
|
}
|
720
725
|
|
721
726
|
zones = MU::Cloud::DNSZone.find(deploy_id: MU.deploy_id, region: region)
|
722
|
-
zones.
|
727
|
+
zones.values.each { |zone|
|
723
728
|
MU.log "Purging DNS Zone '#{zone.name}' (#{zone.id})"
|
724
729
|
if !noop
|
725
730
|
begin
|
@@ -727,7 +732,6 @@ module MU
|
|
727
732
|
rrsets = MU::Cloud::AWS.route53(credentials: credentials).list_resource_record_sets(hosted_zone_id: zone.id)
|
728
733
|
rrsets.resource_record_sets.each { |rrset|
|
729
734
|
next if zone.name == rrset.name and (rrset.type == "NS" or rrset.type == "SOA")
|
730
|
-
records = []
|
731
735
|
MU::Cloud::AWS.route53(credentials: credentials).change_resource_record_sets(
|
732
736
|
hosted_zone_id: zone.id,
|
733
737
|
change_batch: {
|
@@ -791,9 +795,9 @@ module MU
|
|
791
795
|
end
|
792
796
|
|
793
797
|
# Cloud-specific configuration properties.
|
794
|
-
# @param
|
798
|
+
# @param _config [MU::Config]: The calling MU::Config object
|
795
799
|
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
796
|
-
def self.schema(
|
800
|
+
def self.schema(_config)
|
797
801
|
toplevel_required = []
|
798
802
|
schema = {}
|
799
803
|
[toplevel_required, schema]
|
@@ -801,9 +805,9 @@ module MU
|
|
801
805
|
|
802
806
|
# Cloud-specific pre-processing of {MU::Config::BasketofKittens::dnszones}, bare and unvalidated.
|
803
807
|
# @param zone [Hash]: The resource to process and validate
|
804
|
-
# @param
|
808
|
+
# @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
805
809
|
# @return [Boolean]: True if validation succeeded, False otherwise
|
806
|
-
def self.validateConfig(zone,
|
810
|
+
def self.validateConfig(zone, _configurator)
|
807
811
|
ok = true
|
808
812
|
|
809
813
|
if !zone["records"].nil?
|
@@ -821,10 +825,7 @@ module MU
|
|
821
825
|
end
|
822
826
|
|
823
827
|
if !record['mu_type'].nil?
|
824
|
-
zone[
|
825
|
-
"type" => record['mu_type'],
|
826
|
-
"name" => record['target']
|
827
|
-
}
|
828
|
+
MU::Config.addDependency(zone, record['target'], record['mu_type'])
|
828
829
|
end
|
829
830
|
|
830
831
|
if record.has_key?('healthchecks') && !record['healthchecks'].empty?
|
@@ -116,15 +116,15 @@ MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials
|
|
116
116
|
end
|
117
117
|
|
118
118
|
if m['integrate_with']
|
119
|
-
role_arn = if m['iam_role']
|
120
|
-
if m['iam_role'].match(/^arn:/)
|
121
|
-
m['iam_role']
|
122
|
-
else
|
123
|
-
sib_role = @deploy.findLitterMate(name: m['iam_role'], type: "roles")
|
124
|
-
sib_role.cloudobj.arn
|
119
|
+
# role_arn = if m['iam_role']
|
120
|
+
# if m['iam_role'].match(/^arn:/)
|
121
|
+
# m['iam_role']
|
122
|
+
# else
|
123
|
+
# sib_role = @deploy.findLitterMate(name: m['iam_role'], type: "roles")
|
124
|
+
# sib_role.cloudobj.arn
|
125
125
|
# XXX make this more like get_role_arn in Function, or just use Role.find?
|
126
|
-
end
|
127
|
-
end
|
126
|
+
# end
|
127
|
+
# end
|
128
128
|
|
129
129
|
function_obj = nil
|
130
130
|
|
@@ -198,13 +198,12 @@ MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials
|
|
198
198
|
generate_methods
|
199
199
|
|
200
200
|
MU.log "Deploying API Gateway #{@config['name']} to #{@config['deploy_to']}"
|
201
|
-
|
201
|
+
MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).create_deployment(
|
202
202
|
rest_api_id: @cloud_id,
|
203
203
|
stage_name: @config['deploy_to']
|
204
204
|
# cache_cluster_enabled: false,
|
205
205
|
# cache_cluster_size: 0.5,
|
206
206
|
)
|
207
|
-
deployment_id = resp.id
|
208
207
|
# this automatically creates a stage with the same name, so we don't
|
209
208
|
# have to deal with that
|
210
209
|
|
@@ -220,11 +219,14 @@ MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials
|
|
220
219
|
|
221
220
|
end
|
222
221
|
|
222
|
+
@cloud_desc_cache = nil
|
223
223
|
# @return [Struct]
|
224
|
-
def cloud_desc
|
225
|
-
|
224
|
+
def cloud_desc(use_cache: true)
|
225
|
+
return @cloud_desc_cache if @cloud_desc_cache and use_cache
|
226
|
+
@cloud_desc_cache = MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials']).get_rest_api(
|
226
227
|
rest_api_id: @cloud_id
|
227
228
|
)
|
229
|
+
@cloud_desc_cache
|
228
230
|
end
|
229
231
|
|
230
232
|
# Return the metadata for this API
|
@@ -241,6 +243,9 @@ MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials
|
|
241
243
|
# @param region [String]: The cloud provider region
|
242
244
|
# @return [void]
|
243
245
|
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
246
|
+
MU.log "AWS::Endpoint.cleanup: need to support flags['known']", MU::DEBUG, details: flags
|
247
|
+
MU.log "Placeholder: AWS Endpoint artifacts do not support tags, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: ignoremaster
|
248
|
+
|
244
249
|
resp = MU::Cloud::AWS.apig(region: region, credentials: credentials).get_rest_apis
|
245
250
|
if resp and resp.items
|
246
251
|
resp.items.each { |api|
|
@@ -279,9 +284,9 @@ MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials
|
|
279
284
|
end
|
280
285
|
|
281
286
|
# Cloud-specific configuration properties.
|
282
|
-
# @param
|
287
|
+
# @param _config [MU::Config]: The calling MU::Config object
|
283
288
|
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
284
|
-
def self.schema(
|
289
|
+
def self.schema(_config)
|
285
290
|
toplevel_required = []
|
286
291
|
schema = {
|
287
292
|
"deploy_to" => {
|
@@ -467,11 +472,7 @@ MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials
|
|
467
472
|
endpoint['methods'].each { |m|
|
468
473
|
if m['integrate_with'] and m['integrate_with']['name']
|
469
474
|
if m['integrate_with']['type'] != "aws_generic"
|
470
|
-
endpoint['
|
471
|
-
endpoint['dependencies'] << {
|
472
|
-
"type" => m['integrate_with']['type'],
|
473
|
-
"name" => m['integrate_with']['name']
|
474
|
-
}
|
475
|
+
MU::Config.addDependency(endpoint, m['integrate_with']['name'], m['integrate_with']['type'])
|
475
476
|
end
|
476
477
|
|
477
478
|
m['integrate_with']['backend_http_method'] ||= m['type']
|
@@ -520,13 +521,8 @@ MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials
|
|
520
521
|
end
|
521
522
|
configurator.insertKitten(roledesc, "roles")
|
522
523
|
|
523
|
-
endpoint['dependencies'] ||= []
|
524
524
|
m['iam_role'] = endpoint['name']+"-"+m['integrate_with']['name']
|
525
|
-
|
526
|
-
endpoint['dependencies'] << {
|
527
|
-
"type" => "role",
|
528
|
-
"name" => endpoint['name']+"-"+m['integrate_with']['name']
|
529
|
-
}
|
525
|
+
MU::Config.addDependency(endpoint, m['iam_role'], "role")
|
530
526
|
end
|
531
527
|
end
|
532
528
|
}
|
@@ -538,8 +534,6 @@ MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials
|
|
538
534
|
ok
|
539
535
|
end
|
540
536
|
|
541
|
-
private
|
542
|
-
|
543
537
|
def self.cors_option_integrations(path)
|
544
538
|
{
|
545
539
|
"type" => "OPTIONS",
|
@@ -585,6 +579,7 @@ MU::Cloud::AWS.apig(region: @config['region'], credentials: @config['credentials
|
|
585
579
|
}
|
586
580
|
}
|
587
581
|
end
|
582
|
+
private_class_method :cors_option_integrations
|
588
583
|
|
589
584
|
end
|
590
585
|
end
|
@@ -18,7 +18,7 @@ module MU
|
|
18
18
|
class AWS
|
19
19
|
# A firewall ruleset as configured in {MU::Config::BasketofKittens::firewall_rules}
|
20
20
|
class FirewallRule < MU::Cloud::FirewallRule
|
21
|
-
require "mu/
|
21
|
+
require "mu/providers/aws/vpc"
|
22
22
|
|
23
23
|
@admin_sgs = Hash.new
|
24
24
|
@admin_sg_semaphore = Mutex.new
|
@@ -54,13 +54,12 @@ module MU
|
|
54
54
|
|
55
55
|
secgroup = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).create_security_group(sg_struct)
|
56
56
|
@cloud_id = secgroup.group_id
|
57
|
-
rescue Aws::EC2::Errors::InvalidGroupDuplicate
|
57
|
+
rescue Aws::EC2::Errors::InvalidGroupDuplicate
|
58
58
|
MU.log "EC2 Security Group #{groupname} already exists, using it", MU::NOTICE
|
59
59
|
filters = [{name: "group-name", values: [groupname]}]
|
60
60
|
filters << {name: "vpc-id", values: [vpc_id]} if !vpc_id.nil?
|
61
61
|
|
62
62
|
secgroup = MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_security_groups(filters: filters).security_groups.first
|
63
|
-
deploy_id = @deploy.deploy_id if !@deploy_id.nil?
|
64
63
|
if secgroup.nil?
|
65
64
|
raise MuError, "Failed to locate security group named #{groupname}, even though EC2 says it already exists", caller
|
66
65
|
end
|
@@ -69,24 +68,24 @@ module MU
|
|
69
68
|
|
70
69
|
begin
|
71
70
|
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).describe_security_groups(group_ids: [secgroup.group_id])
|
72
|
-
rescue Aws::EC2::Errors::InvalidGroupNotFound
|
71
|
+
rescue Aws::EC2::Errors::InvalidGroupNotFound
|
73
72
|
MU.log "#{secgroup.group_id} not yet ready, waiting...", MU::NOTICE
|
74
73
|
sleep 10
|
75
74
|
retry
|
76
75
|
end
|
77
76
|
|
78
77
|
MU::Cloud::AWS.createStandardTags(secgroup.group_id, region: @config['region'], credentials: @config['credentials'])
|
79
|
-
MU::
|
78
|
+
MU::Cloud::AWS.createTag(secgroup.group_id, "Name", groupname, region: @config['region'], credentials: @config['credentials'])
|
80
79
|
|
81
80
|
if @config['optional_tags']
|
82
81
|
MU::MommaCat.listOptionalTags.each { |key, value|
|
83
|
-
MU::
|
82
|
+
MU::Cloud::AWS.createTag(secgroup.group_id, key, value, region: @config['region'], credentials: @config['credentials'])
|
84
83
|
}
|
85
84
|
end
|
86
85
|
|
87
86
|
if @config['tags']
|
88
87
|
@config['tags'].each { |tag|
|
89
|
-
MU::
|
88
|
+
MU::Cloud::AWS.createTag(secgroup.group_id, tag['key'], tag['value'], region: @config['region'], credentials: @config['credentials'])
|
90
89
|
}
|
91
90
|
end
|
92
91
|
|
@@ -180,7 +179,7 @@ module MU
|
|
180
179
|
ip_permissions: ec2_rule
|
181
180
|
)
|
182
181
|
end
|
183
|
-
rescue Aws::EC2::Errors::InvalidPermissionDuplicate
|
182
|
+
rescue Aws::EC2::Errors::InvalidPermissionDuplicate
|
184
183
|
MU.log "Attempt to add duplicate rule to #{@cloud_id}", MU::DEBUG, details: ec2_rule
|
185
184
|
# Ensure that, at least, the description field gets updated on
|
186
185
|
# existing rules
|
@@ -246,7 +245,7 @@ module MU
|
|
246
245
|
# Reverse-map our cloud description into a runnable config hash.
|
247
246
|
# We assume that any values we have in +@config+ are placeholders, and
|
248
247
|
# calculate our own accordingly based on what's live in the cloud.
|
249
|
-
def toKitten(
|
248
|
+
def toKitten(**_args)
|
250
249
|
bok = {
|
251
250
|
"cloud" => "AWS",
|
252
251
|
"credentials" => @config['credentials'],
|
@@ -383,9 +382,8 @@ module MU
|
|
383
382
|
# @param region [String]: The cloud provider region
|
384
383
|
# @return [void]
|
385
384
|
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
386
|
-
filters =
|
387
|
-
|
388
|
-
filters = [
|
385
|
+
filters = if flags and flags["vpc_id"]
|
386
|
+
[
|
389
387
|
{name: "vpc-id", values: [flags["vpc_id"]]}
|
390
388
|
]
|
391
389
|
else
|
@@ -395,11 +393,12 @@ module MU
|
|
395
393
|
if !ignoremaster
|
396
394
|
filters << {name: "tag:MU-MASTER-IP", values: [MU.mu_public_ip]}
|
397
395
|
end
|
396
|
+
filters
|
398
397
|
end
|
399
398
|
|
400
399
|
# Some services create sneaky rogue ENIs which then block removal of
|
401
400
|
# associated security groups. Find them and fry them.
|
402
|
-
MU::Cloud
|
401
|
+
MU::Cloud.resourceClass("AWS", "VPC").purge_interfaces(noop, filters, region: region, credentials: credentials)
|
403
402
|
|
404
403
|
resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_security_groups(
|
405
404
|
filters: filters
|
@@ -409,75 +408,8 @@ module MU
|
|
409
408
|
MU.log "Revoking rules in EC2 Security Group #{sg.group_name} (#{sg.group_id})"
|
410
409
|
|
411
410
|
if !noop
|
412
|
-
|
413
|
-
|
414
|
-
sg.ip_permissions.each { |hole|
|
415
|
-
ingress_to_revoke << MU.structToHash(hole)
|
416
|
-
ingress_to_revoke.each { |rule|
|
417
|
-
if !rule[:user_id_group_pairs].nil? and rule[:user_id_group_pairs] .size == 0
|
418
|
-
rule.delete(:user_id_group_pairs)
|
419
|
-
elsif !rule[:user_id_group_pairs].nil?
|
420
|
-
rule[:user_id_group_pairs].each { |group_ref|
|
421
|
-
group_ref = MU.structToHash(group_ref)
|
422
|
-
group_ref.delete(:group_name) if group_ref[:group_id]
|
423
|
-
}
|
424
|
-
end
|
425
|
-
|
426
|
-
if !rule[:ip_ranges].nil? and rule[:ip_ranges].size == 0
|
427
|
-
rule.delete(:ip_ranges)
|
428
|
-
end
|
429
|
-
|
430
|
-
if !rule[:prefix_list_ids].nil? and rule[:prefix_list_ids].size == 0
|
431
|
-
rule.delete(:prefix_list_ids)
|
432
|
-
end
|
433
|
-
|
434
|
-
if !rule[:ipv_6_ranges].nil? and rule[:ipv_6_ranges].size == 0
|
435
|
-
rule.delete(:ipv_6_ranges)
|
436
|
-
end
|
437
|
-
}
|
438
|
-
}
|
439
|
-
sg.ip_permissions_egress.each { |hole|
|
440
|
-
egress_to_revoke << MU.structToHash(hole)
|
441
|
-
egress_to_revoke.each { |rule|
|
442
|
-
if !rule[:user_id_group_pairs].nil? and rule[:user_id_group_pairs].size == 0
|
443
|
-
rule.delete(:user_id_group_pairs)
|
444
|
-
elsif !rule[:user_id_group_pairs].nil?
|
445
|
-
rule[:user_id_group_pairs].each { |group_ref|
|
446
|
-
group_ref = MU.structToHash(group_ref)
|
447
|
-
group_ref.delete(:group_name) if group_ref[:group_id]
|
448
|
-
}
|
449
|
-
end
|
450
|
-
|
451
|
-
if !rule[:ip_ranges].nil? and rule[:ip_ranges].size == 0
|
452
|
-
rule.delete(:ip_ranges)
|
453
|
-
end
|
454
|
-
|
455
|
-
if !rule[:prefix_list_ids].nil? and rule[:prefix_list_ids].size == 0
|
456
|
-
rule.delete(:prefix_list_ids)
|
457
|
-
end
|
458
|
-
|
459
|
-
if !rule[:ipv_6_ranges].nil? and rule[:ipv_6_ranges].size == 0
|
460
|
-
rule.delete(:ipv_6_ranges)
|
461
|
-
end
|
462
|
-
}
|
463
|
-
}
|
464
|
-
begin
|
465
|
-
|
466
|
-
if ingress_to_revoke.size > 0
|
467
|
-
MU::Cloud::AWS.ec2(credentials: credentials, region: region).revoke_security_group_ingress(
|
468
|
-
group_id: sg.group_id,
|
469
|
-
ip_permissions: ingress_to_revoke
|
470
|
-
)
|
471
|
-
end
|
472
|
-
if egress_to_revoke.size > 0
|
473
|
-
MU::Cloud::AWS.ec2(credentials: credentials, region: region).revoke_security_group_egress(
|
474
|
-
group_id: sg.group_id,
|
475
|
-
ip_permissions: egress_to_revoke
|
476
|
-
)
|
477
|
-
end
|
478
|
-
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
479
|
-
MU.log "Rule in #{sg.group_id} disappeared before I could remove it", MU::WARN
|
480
|
-
end
|
411
|
+
revoke_rules(sg, region: region, credentials: credentials)
|
412
|
+
revoke_rules(sg, egress: true, region: region, credentials: credentials)
|
481
413
|
end
|
482
414
|
}
|
483
415
|
|
@@ -485,61 +417,132 @@ module MU
|
|
485
417
|
next if sg.group_name == "default"
|
486
418
|
MU.log "Removing EC2 Security Group #{sg.group_name}"
|
487
419
|
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
{ name: "vpc-id", values: [sg.vpc_id] }
|
506
|
-
]
|
507
|
-
).security_groups
|
508
|
-
if default_resp and default_resp.size == 1
|
509
|
-
default_sg = default_resp.first.group_id
|
510
|
-
eni_resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_network_interfaces(
|
511
|
-
filters: [ {name: "group-id", values: [sg.group_id]} ]
|
512
|
-
)
|
513
|
-
if eni_resp and eni_resp.data and
|
514
|
-
eni_resp.data.network_interfaces
|
515
|
-
eni_resp.data.network_interfaces.each { |iface|
|
516
|
-
iface_groups = iface.groups.map { |sg| sg.group_id }
|
517
|
-
iface_groups.delete(sg.group_id)
|
518
|
-
iface_groups << default_sg if iface_groups.empty?
|
519
|
-
MU.log "Attempting to remove #{sg.group_id} from ENI #{iface.network_interface_id}"
|
420
|
+
on_retry = Proc.new {
|
421
|
+
# try to get out from under loose network interfaces with which
|
422
|
+
# we're associated
|
423
|
+
if sg.vpc_id
|
424
|
+
default_sg = MU::Cloud.resourceClass("AWS", "VPC").getDefaultSg(sg.vpc_id, region: region, credentials: credentials)
|
425
|
+
if default_sg
|
426
|
+
eni_resp = MU::Cloud::AWS.ec2(credentials: credentials, region: region).describe_network_interfaces(
|
427
|
+
filters: [ {name: "group-id", values: [sg.group_id]} ]
|
428
|
+
)
|
429
|
+
if eni_resp and eni_resp.data and
|
430
|
+
eni_resp.data.network_interfaces
|
431
|
+
eni_resp.data.network_interfaces.each { |iface|
|
432
|
+
iface_groups = iface.groups.map { |if_sg| if_sg.group_id }
|
433
|
+
iface_groups.delete(sg.group_id)
|
434
|
+
iface_groups << default_sg if iface_groups.empty?
|
435
|
+
MU.log "Attempting to remove #{sg.group_id} (#{sg.group_name}) from ENI #{iface.network_interface_id}"
|
436
|
+
begin
|
520
437
|
MU::Cloud::AWS.ec2(credentials: credentials, region: region).modify_network_interface_attribute(
|
521
438
|
network_interface_id: iface.network_interface_id,
|
522
439
|
groups: iface_groups
|
523
440
|
)
|
524
|
-
|
525
|
-
|
441
|
+
rescue ::Aws::EC2::Errors::InvalidNetworkInterfaceIDNotFound
|
442
|
+
# fine by me
|
443
|
+
rescue ::Aws::EC2::Errors::AuthFailure
|
444
|
+
MU.log "Permission denied attempting to trim Security Group list for #{iface.network_interface_id}", MU::WARN, details: iface.groups.map { |g| g.group_name }.join(",")+" => default"
|
445
|
+
end
|
446
|
+
}
|
526
447
|
end
|
527
448
|
end
|
449
|
+
end
|
450
|
+
}
|
528
451
|
|
529
|
-
|
530
|
-
|
531
|
-
|
452
|
+
if !noop
|
453
|
+
MU.retrier([Aws::EC2::Errors::DependencyViolation, Aws::EC2::Errors::InvalidGroupInUse], ignoreme: [Aws::EC2::Errors::InvalidGroupNotFound], max: 10, wait: 10, on_retry: on_retry) {
|
454
|
+
begin
|
455
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).delete_security_group(group_id: sg.group_id)
|
456
|
+
rescue Aws::EC2::Errors::CannotDelete => e
|
457
|
+
MU.log e.message, MU::WARN
|
458
|
+
end
|
459
|
+
}
|
460
|
+
end
|
461
|
+
|
462
|
+
}
|
463
|
+
end
|
464
|
+
|
465
|
+
def self.revoke_rules(sg, egress: false, region: MU.myregion, credentials: nil)
|
466
|
+
holes = sg.send(egress ? :ip_permissions_egress : :ip_permissions)
|
467
|
+
|
468
|
+
to_revoke = []
|
469
|
+
|
470
|
+
holes.each { |hole|
|
471
|
+
to_revoke << MU.structToHash(hole)
|
472
|
+
to_revoke.each { |rule|
|
473
|
+
if !rule[:user_id_group_pairs].nil? and rule[:user_id_group_pairs].size == 0
|
474
|
+
rule.delete(:user_id_group_pairs)
|
475
|
+
elsif !rule[:user_id_group_pairs].nil?
|
476
|
+
rule[:user_id_group_pairs].each { |group_ref|
|
477
|
+
group_ref = MU.structToHash(group_ref)
|
478
|
+
group_ref.delete(:group_name) if group_ref[:group_id]
|
479
|
+
}
|
480
|
+
end
|
481
|
+
|
482
|
+
if !rule[:ip_ranges].nil? and rule[:ip_ranges].size == 0
|
483
|
+
rule.delete(:ip_ranges)
|
484
|
+
end
|
485
|
+
|
486
|
+
if !rule[:prefix_list_ids].nil? and rule[:prefix_list_ids].size == 0
|
487
|
+
rule.delete(:prefix_list_ids)
|
488
|
+
end
|
489
|
+
|
490
|
+
if !rule[:ipv_6_ranges].nil? and rule[:ipv_6_ranges].size == 0
|
491
|
+
rule.delete(:ipv_6_ranges)
|
492
|
+
end
|
493
|
+
}
|
494
|
+
}
|
495
|
+
|
496
|
+
if to_revoke.size > 0
|
497
|
+
begin
|
498
|
+
if egress
|
499
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).revoke_security_group_egress(
|
500
|
+
group_id: sg.group_id,
|
501
|
+
ip_permissions: to_revoke
|
502
|
+
)
|
532
503
|
else
|
533
|
-
MU.
|
504
|
+
MU::Cloud::AWS.ec2(credentials: credentials, region: region).revoke_security_group_ingress(
|
505
|
+
group_id: sg.group_id,
|
506
|
+
ip_permissions: to_revoke
|
507
|
+
)
|
534
508
|
end
|
509
|
+
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
510
|
+
MU.log "Rule in #{sg.group_id} disappeared before I could remove it", MU::WARN
|
535
511
|
end
|
512
|
+
end
|
513
|
+
|
514
|
+
end
|
515
|
+
private_class_method :revoke_rules
|
516
|
+
|
517
|
+
# Return an AWS-specific chunk of schema commonly used in the +ingress_rules+ parameter of other resource types.
|
518
|
+
# @return [Hash]
|
519
|
+
def self.ingressRuleAddtlSchema
|
520
|
+
{
|
521
|
+
"items" => {
|
522
|
+
"properties" => {
|
523
|
+
"sgs" => {
|
524
|
+
"type" => "array",
|
525
|
+
"items" => {
|
526
|
+
"description" => "Other AWS Security Groups; resources that are associated with this group will have this rule applied to their traffic",
|
527
|
+
"type" => "string"
|
528
|
+
}
|
529
|
+
},
|
530
|
+
"lbs" => {
|
531
|
+
"type" => "array",
|
532
|
+
"items" => {
|
533
|
+
"description" => "AWS Load Balancers which will have this rule applied to their traffic",
|
534
|
+
"type" => "string"
|
535
|
+
}
|
536
|
+
}
|
537
|
+
}
|
538
|
+
}
|
536
539
|
}
|
537
540
|
end
|
538
541
|
|
539
542
|
# Cloud-specific configuration properties.
|
540
|
-
# @param
|
543
|
+
# @param _config [MU::Config]: The calling MU::Config object
|
541
544
|
# @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
|
542
|
-
def self.schema(
|
545
|
+
def self.schema(_config)
|
543
546
|
toplevel_required = []
|
544
547
|
schema = {
|
545
548
|
"rules" => {
|
@@ -645,36 +648,16 @@ module MU
|
|
645
648
|
|
646
649
|
if rule['firewall_rules']
|
647
650
|
rule['firewall_rules'].each { |sg|
|
648
|
-
if sg
|
649
|
-
|
650
|
-
"type" => "firewall_rule",
|
651
|
-
"name" => sg.name,
|
652
|
-
"no_create_wait" => true
|
653
|
-
}
|
654
|
-
elsif sg['name'] and !sg['deploy_id']
|
655
|
-
acl["dependencies"] << {
|
656
|
-
"type" => "firewall_rule",
|
657
|
-
"name" => sg['name'],
|
658
|
-
"no_create_wait" => true
|
659
|
-
}
|
651
|
+
if sg['name'] and !sg['deploy_id']
|
652
|
+
MU::Config.addDependency(acl, sg['name'], "firewall_rule", no_create_wait: true)
|
660
653
|
end
|
661
654
|
}
|
662
655
|
end
|
663
656
|
|
664
657
|
if rule['loadbalancers']
|
665
658
|
rule['loadbalancers'].each { |lb|
|
666
|
-
if lb
|
667
|
-
|
668
|
-
"type" => "loadbalancer",
|
669
|
-
"name" => lb.name,
|
670
|
-
"phase" => "groom"
|
671
|
-
}
|
672
|
-
elsif lb['name'] and !lb['deploy_id']
|
673
|
-
acl["dependencies"] << {
|
674
|
-
"type" => "loadbalancer",
|
675
|
-
"name" => lb['name'],
|
676
|
-
"phase" => "groom"
|
677
|
-
}
|
659
|
+
if lb['name'] and !lb['deploy_id']
|
660
|
+
MU::Config.addDependency(acl, lb['name'], "loadbalancer", phase: "groom")
|
678
661
|
end
|
679
662
|
}
|
680
663
|
end
|
@@ -716,32 +699,7 @@ module MU
|
|
716
699
|
|
717
700
|
private
|
718
701
|
|
719
|
-
|
720
|
-
# Manufacture an EC2 security group. The second parameter, rules, is an
|
721
|
-
# "ingress_rules" structure parsed and validated by MU::Config.
|
722
|
-
#########################################################################
|
723
|
-
def setRules(rules, add_to_self: false, ingress: true, egress: false)
|
724
|
-
describe
|
725
|
-
# XXX warn about attempt to set rules before we exist
|
726
|
-
return if rules.nil? or rules.size == 0 or !@cloud_id
|
727
|
-
|
728
|
-
# add_to_self means that this security is a "member" of its own rules
|
729
|
-
# (which is to say, objects that have this SG are allowed in my these
|
730
|
-
# rules)
|
731
|
-
if add_to_self
|
732
|
-
rules.each { |rule|
|
733
|
-
if rule['sgs'].nil? or !rule['sgs'].include?(@cloud_id)
|
734
|
-
new_rule = rule.clone
|
735
|
-
new_rule.delete('hosts')
|
736
|
-
rule['sgs'] = Array.new if rule['sgs'].nil?
|
737
|
-
rule['sgs'] << @cloud_id
|
738
|
-
end
|
739
|
-
}
|
740
|
-
end
|
741
|
-
|
742
|
-
ec2_rules = convertToEc2(rules)
|
743
|
-
ext_permissions = MU.structToHash(cloud_desc.ip_permissions)
|
744
|
-
|
702
|
+
def purge_extraneous_rules(ec2_rules, ext_permissions)
|
745
703
|
# Purge any old rules that we're sure we created (check the comment)
|
746
704
|
# but which are no longer configured.
|
747
705
|
ext_permissions.each { |ext_rule|
|
@@ -778,97 +736,109 @@ module MU
|
|
778
736
|
ip_permissions: [ext_rule]
|
779
737
|
)
|
780
738
|
end
|
781
|
-
|
782
739
|
}
|
740
|
+
end
|
783
741
|
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
}
|
803
|
-
break
|
804
|
-
end
|
805
|
-
}
|
806
|
-
if haverule and !different
|
807
|
-
MU.log "Security Group rule already up-to-date in #{@mu_name}", MU::DEBUG, details: rule
|
808
|
-
next
|
742
|
+
#########################################################################
|
743
|
+
# Manufacture an EC2 security group. The second parameter, rules, is an
|
744
|
+
# "ingress_rules" structure parsed and validated by MU::Config.
|
745
|
+
#########################################################################
|
746
|
+
def setRules(rules, add_to_self: false, ingress: true, egress: false)
|
747
|
+
# XXX warn about attempt to set rules before we exist
|
748
|
+
return if rules.nil? or rules.size == 0 or !@cloud_id
|
749
|
+
|
750
|
+
# add_to_self means that this security is a "member" of its own rules
|
751
|
+
# (which is to say, objects that have this SG are allowed in my these
|
752
|
+
# rules)
|
753
|
+
if add_to_self
|
754
|
+
rules.each { |rule|
|
755
|
+
if rule['sgs'].nil? or !rule['sgs'].include?(@cloud_id)
|
756
|
+
new_rule = rule.clone
|
757
|
+
new_rule.delete('hosts')
|
758
|
+
rule['sgs'] = Array.new if rule['sgs'].nil?
|
759
|
+
rule['sgs'] << @cloud_id
|
809
760
|
end
|
761
|
+
}
|
762
|
+
end
|
810
763
|
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
764
|
+
ec2_rules = convertToEc2(rules)
|
765
|
+
return if ec2_rules.nil?
|
766
|
+
|
767
|
+
ext_permissions = MU.structToHash(cloud_desc(use_cache: false).ip_permissions)
|
768
|
+
|
769
|
+
purge_extraneous_rules(ec2_rules, ext_permissions)
|
770
|
+
|
771
|
+
ec2_rules.uniq!
|
772
|
+
ec2_rules.each { |rule|
|
773
|
+
haverule = nil
|
774
|
+
different = false
|
775
|
+
ext_permissions.each { |ext_rule|
|
776
|
+
if rule[:from_port] == ext_rule[:from_port] and
|
777
|
+
rule[:to_port] == ext_rule[:to_port] and
|
778
|
+
rule[:ip_protocol] == ext_rule[:ip_protocol]
|
779
|
+
haverule = ext_rule
|
780
|
+
ext_rule.keys.each { |k|
|
781
|
+
if ext_rule[k].nil? or ext_rule[k] == []
|
782
|
+
haverule.delete(k)
|
823
783
|
end
|
784
|
+
different = true if rule[k] != ext_rule[k]
|
785
|
+
}
|
786
|
+
break
|
787
|
+
end
|
788
|
+
}
|
789
|
+
if haverule and !different
|
790
|
+
MU.log "Security Group rule already up-to-date in #{@mu_name}", MU::DEBUG, details: rule
|
791
|
+
next
|
792
|
+
end
|
793
|
+
|
794
|
+
MU.log "Setting #{ingress ? "ingress" : "egress"} rule in Security Group #{@mu_name} (#{@cloud_id})", MU::NOTICE, details: rule
|
795
|
+
|
796
|
+
MU.retrier([Aws::EC2::Errors::InvalidGroupNotFound], max: 10, wait: 10, ignoreme: [Aws::EC2::Errors::InvalidPermissionDuplicate]) {
|
797
|
+
if ingress
|
798
|
+
if haverule
|
824
799
|
begin
|
825
|
-
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).
|
800
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).revoke_security_group_ingress(
|
826
801
|
group_id: @cloud_id,
|
827
|
-
ip_permissions: [
|
802
|
+
ip_permissions: [haverule]
|
828
803
|
)
|
829
|
-
rescue Aws::EC2::Errors::
|
830
|
-
MU.log "FirewallRule #{@mu_name} had a bogus rule: #{e.message}", MU::ERR, details: rule
|
831
|
-
raise e
|
804
|
+
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
832
805
|
end
|
833
806
|
end
|
834
|
-
|
835
|
-
|
836
|
-
if haverule
|
837
|
-
begin
|
838
|
-
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).revoke_security_group_egress(
|
839
|
-
group_id: @cloud_id,
|
840
|
-
ip_permissions: [haverule]
|
841
|
-
)
|
842
|
-
rescue Aws::EC2::Errors::InvalidPermissionNotFound => e
|
843
|
-
end
|
844
|
-
end
|
845
|
-
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).authorize_security_group_egress(
|
807
|
+
begin
|
808
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).authorize_security_group_ingress(
|
846
809
|
group_id: @cloud_id,
|
847
810
|
ip_permissions: [rule]
|
848
811
|
)
|
812
|
+
rescue Aws::EC2::Errors::InvalidParameterCombination => e
|
813
|
+
MU.log "FirewallRule #{@mu_name} had a bogus rule: #{e.message}", MU::ERR, details: rule
|
814
|
+
raise e
|
849
815
|
end
|
816
|
+
end
|
850
817
|
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
818
|
+
if egress
|
819
|
+
if haverule
|
820
|
+
begin
|
821
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).revoke_security_group_egress(
|
822
|
+
group_id: @cloud_id,
|
823
|
+
ip_permissions: [haverule]
|
824
|
+
)
|
825
|
+
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
826
|
+
end
|
859
827
|
end
|
860
|
-
|
861
|
-
|
828
|
+
MU::Cloud::AWS.ec2(region: @config['region'], credentials: @config['credentials']).authorize_security_group_egress(
|
829
|
+
group_id: @cloud_id,
|
830
|
+
ip_permissions: [rule]
|
831
|
+
)
|
862
832
|
end
|
863
833
|
}
|
864
|
-
|
834
|
+
}
|
865
835
|
|
866
836
|
end
|
867
837
|
|
868
|
-
|
869
|
-
# Convert our config languages description of firewall rules into
|
870
|
-
#
|
871
|
-
|
838
|
+
#######################################################################
|
839
|
+
# Convert our config languages description of firewall rules into
|
840
|
+
# Amazon's. Our rule structure is as defined in MU::Config.
|
841
|
+
#######################################################################
|
872
842
|
def convertToEc2(rules)
|
873
843
|
ec2_rules = []
|
874
844
|
if rules != nil
|
@@ -992,8 +962,8 @@ module MU
|
|
992
962
|
ec2_rules << ec2_rule
|
993
963
|
}
|
994
964
|
end
|
995
|
-
|
996
|
-
|
965
|
+
|
966
|
+
ec2_rules.uniq
|
997
967
|
end
|
998
968
|
|
999
969
|
end #class
|