cloud-mu 3.1.5 → 3.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Dockerfile +5 -1
- 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/tasks/main.yml +16 -0
- data/bin/mu-adopt +16 -12
- 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 -1
- data/bin/mu-node-manage +15 -16
- data/bin/mu-run-tests +37 -12
- data/cloud-mu.gemspec +3 -3
- 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 +1 -1
- 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/windows-client.rb +25 -22
- data/extras/clean-stock-amis +25 -19
- data/extras/generate-stock-images +1 -0
- data/extras/image-generators/AWS/win2k12.yaml +2 -0
- data/extras/image-generators/AWS/win2k16.yaml +2 -0
- data/extras/image-generators/AWS/win2k19.yaml +2 -0
- data/modules/mommacat.ru +1 -1
- data/modules/mu.rb +86 -98
- data/modules/mu/adoption.rb +373 -58
- data/modules/mu/cleanup.rb +214 -303
- data/modules/mu/cloud.rb +128 -1733
- data/modules/mu/cloud/database.rb +49 -0
- data/modules/mu/cloud/dnszone.rb +44 -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 +929 -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 +169 -0
- data/modules/mu/config.rb +123 -81
- data/modules/mu/config/alarm.rb +2 -6
- data/modules/mu/config/bucket.rb +32 -3
- data/modules/mu/config/cache_cluster.rb +2 -2
- data/modules/mu/config/cdn.rb +100 -0
- data/modules/mu/config/collection.rb +1 -1
- data/modules/mu/config/container_cluster.rb +7 -2
- data/modules/mu/config/database.rb +84 -105
- data/modules/mu/config/database.yml +1 -2
- data/modules/mu/config/dnszone.rb +5 -4
- data/modules/mu/config/doc_helpers.rb +5 -6
- data/modules/mu/config/endpoint.rb +2 -1
- data/modules/mu/config/firewall_rule.rb +3 -19
- data/modules/mu/config/folder.rb +1 -1
- data/modules/mu/config/function.rb +17 -8
- data/modules/mu/config/group.rb +1 -1
- data/modules/mu/config/habitat.rb +1 -1
- data/modules/mu/config/job.rb +89 -0
- data/modules/mu/config/loadbalancer.rb +57 -11
- data/modules/mu/config/log.rb +1 -1
- data/modules/mu/config/msg_queue.rb +1 -1
- data/modules/mu/config/nosqldb.rb +1 -1
- data/modules/mu/config/notifier.rb +8 -19
- data/modules/mu/config/ref.rb +92 -14
- data/modules/mu/config/role.rb +1 -1
- data/modules/mu/config/schema_helpers.rb +38 -37
- data/modules/mu/config/search_domain.rb +1 -1
- data/modules/mu/config/server.rb +12 -13
- data/modules/mu/config/server_pool.rb +3 -7
- data/modules/mu/config/storage_pool.rb +1 -1
- data/modules/mu/config/tail.rb +11 -0
- data/modules/mu/config/user.rb +1 -1
- data/modules/mu/config/vpc.rb +27 -23
- data/modules/mu/config/vpc.yml +0 -1
- data/modules/mu/defaults/AWS.yaml +90 -90
- data/modules/mu/defaults/Azure.yaml +1 -0
- data/modules/mu/defaults/Google.yaml +1 -0
- data/modules/mu/deploy.rb +34 -20
- data/modules/mu/groomer.rb +16 -1
- data/modules/mu/groomers/ansible.rb +69 -4
- data/modules/mu/groomers/chef.rb +51 -4
- data/modules/mu/logger.rb +120 -144
- data/modules/mu/master.rb +97 -4
- data/modules/mu/mommacat.rb +160 -874
- data/modules/mu/mommacat/daemon.rb +23 -14
- data/modules/mu/mommacat/naming.rb +110 -3
- data/modules/mu/mommacat/search.rb +497 -0
- data/modules/mu/mommacat/storage.rb +252 -194
- data/modules/mu/{clouds → providers}/README.md +1 -1
- data/modules/mu/{clouds → providers}/aws.rb +258 -57
- data/modules/mu/{clouds → providers}/aws/alarm.rb +3 -3
- data/modules/mu/{clouds → providers}/aws/bucket.rb +275 -41
- data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +14 -50
- data/modules/mu/providers/aws/cdn.rb +782 -0
- data/modules/mu/{clouds → providers}/aws/collection.rb +5 -5
- data/modules/mu/{clouds → providers}/aws/container_cluster.rb +95 -84
- data/modules/mu/providers/aws/database.rb +1744 -0
- data/modules/mu/{clouds → providers}/aws/dnszone.rb +26 -12
- data/modules/mu/providers/aws/endpoint.rb +1072 -0
- data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +39 -32
- data/modules/mu/{clouds → providers}/aws/folder.rb +1 -1
- data/modules/mu/{clouds → providers}/aws/function.rb +289 -134
- data/modules/mu/{clouds → providers}/aws/group.rb +18 -20
- data/modules/mu/{clouds → providers}/aws/habitat.rb +3 -3
- data/modules/mu/providers/aws/job.rb +466 -0
- data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +77 -47
- data/modules/mu/{clouds → providers}/aws/log.rb +5 -5
- data/modules/mu/{clouds → providers}/aws/msg_queue.rb +14 -11
- data/modules/mu/{clouds → providers}/aws/nosqldb.rb +96 -5
- data/modules/mu/{clouds → providers}/aws/notifier.rb +135 -63
- data/modules/mu/{clouds → providers}/aws/role.rb +76 -48
- data/modules/mu/{clouds → providers}/aws/search_domain.rb +172 -41
- data/modules/mu/{clouds → providers}/aws/server.rb +66 -98
- data/modules/mu/{clouds → providers}/aws/server_pool.rb +42 -60
- data/modules/mu/{clouds → providers}/aws/storage_pool.rb +21 -38
- data/modules/mu/{clouds → providers}/aws/user.rb +12 -16
- data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
- data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/aws/vpc.rb +143 -74
- data/modules/mu/{clouds → providers}/aws/vpc_subnet.rb +0 -0
- data/modules/mu/{clouds → providers}/azure.rb +13 -0
- data/modules/mu/{clouds → providers}/azure/container_cluster.rb +1 -5
- data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +8 -1
- data/modules/mu/{clouds → providers}/azure/habitat.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/role.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/server.rb +32 -24
- data/modules/mu/{clouds → providers}/azure/user.rb +1 -1
- 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 +4 -6
- data/modules/mu/{clouds → providers}/cloudformation.rb +10 -0
- 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 +3 -3
- data/modules/mu/{clouds → providers}/docker.rb +0 -0
- data/modules/mu/{clouds → providers}/google.rb +29 -6
- data/modules/mu/{clouds → providers}/google/bucket.rb +4 -4
- data/modules/mu/{clouds → providers}/google/container_cluster.rb +38 -20
- data/modules/mu/{clouds → providers}/google/database.rb +5 -12
- data/modules/mu/{clouds → providers}/google/firewall_rule.rb +5 -5
- data/modules/mu/{clouds → providers}/google/folder.rb +5 -9
- data/modules/mu/{clouds → providers}/google/function.rb +6 -6
- data/modules/mu/{clouds → providers}/google/group.rb +9 -17
- data/modules/mu/{clouds → providers}/google/habitat.rb +4 -8
- data/modules/mu/{clouds → providers}/google/loadbalancer.rb +5 -5
- data/modules/mu/{clouds → providers}/google/role.rb +50 -31
- data/modules/mu/{clouds → providers}/google/server.rb +41 -24
- data/modules/mu/{clouds → providers}/google/server_pool.rb +14 -14
- data/modules/mu/{clouds → providers}/google/user.rb +34 -24
- 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 +45 -14
- data/modules/tests/aws-jobs-functions.yaml +46 -0
- data/modules/tests/centos6.yaml +15 -0
- data/modules/tests/centos7.yaml +15 -0
- data/modules/tests/centos8.yaml +12 -0
- data/modules/tests/ecs.yaml +2 -2
- data/modules/tests/eks.yaml +1 -1
- data/modules/tests/functions/node-function/lambda_function.js +10 -0
- data/modules/tests/functions/python-function/lambda_function.py +12 -0
- data/modules/tests/microservice_app.yaml +288 -0
- data/modules/tests/rds.yaml +108 -0
- data/modules/tests/regrooms/rds.yaml +123 -0
- data/modules/tests/server-with-scrub-muisms.yaml +1 -1
- data/modules/tests/super_complex_bok.yml +2 -2
- data/modules/tests/super_simple_bok.yml +3 -5
- data/spec/mu/clouds/azure_spec.rb +2 -2
- metadata +122 -92
- data/modules/mu/clouds/aws/database.rb +0 -1974
- data/modules/mu/clouds/aws/endpoint.rb +0 -596
|
@@ -89,7 +89,7 @@ Looking elsewhere in `cloud.rb` let's see what all we have to do:
|
|
|
89
89
|
generic_instance_methods = [:create, :notify, :mu_name, :cloud_id, :config]
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
Just the basics, for now. Here's what that will look like in the AWS layer, in the file `modules/mu/
|
|
92
|
+
Just the basics, for now. Here's what that will look like in the AWS layer, in the file `modules/mu/providers/aws/function.rb`:
|
|
93
93
|
|
|
94
94
|
```
|
|
95
95
|
module MU
|
|
@@ -33,6 +33,18 @@ module MU
|
|
|
33
33
|
module AdditionalResourceMethods
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
# Is this a "real" cloud provider, or a stub like CloudFormation?
|
|
37
|
+
def self.virtual?
|
|
38
|
+
false
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# List all AWS projects available to our credentials
|
|
42
|
+
def self.listHabitats(credentials = nil, use_cache: true)
|
|
43
|
+
cfg = credConfig(credentials)
|
|
44
|
+
return [] if !cfg or !cfg['account_number']
|
|
45
|
+
[cfg['account_number']]
|
|
46
|
+
end
|
|
47
|
+
|
|
36
48
|
# A hook that is always called just before any of the instance method of
|
|
37
49
|
# our resource implementations gets invoked, so that we can ensure that
|
|
38
50
|
# repetitive setup tasks (like resolving +:resource_group+ for Azure
|
|
@@ -344,6 +356,27 @@ end
|
|
|
344
356
|
# etc)
|
|
345
357
|
# @param deploy_id [MU::MommaCat]
|
|
346
358
|
def self.cleanDeploy(deploy_id, credentials: nil, noop: false)
|
|
359
|
+
|
|
360
|
+
if !noop
|
|
361
|
+
MU.log "Deleting s3://#{adminBucketName(credentials)}/#{deploy_id}-secret"
|
|
362
|
+
MU::Cloud::AWS.s3(credentials: credentials).delete_object(
|
|
363
|
+
bucket: adminBucketName(credentials),
|
|
364
|
+
key: "#{deploy_id}-secret"
|
|
365
|
+
)
|
|
366
|
+
listRegions(credentials: credentials).each { |r|
|
|
367
|
+
resp = MU::Cloud::AWS.ec2(region: r, credentials: credentials).describe_key_pairs(
|
|
368
|
+
filters: [{name: "key-name", values: ["deploy-#{MU.deploy_id}"]}]
|
|
369
|
+
)
|
|
370
|
+
resp.data.key_pairs.each { |keypair|
|
|
371
|
+
MU.log "Deleting key pair #{keypair.key_name} from #{r}"
|
|
372
|
+
MU::Cloud::AWS.ec2(region: r, credentials: credentials).delete_key_pair(key_name: keypair.key_name) if !noop
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
end
|
|
377
|
+
if hosted?
|
|
378
|
+
MU::Cloud::AWS.openFirewallForClients
|
|
379
|
+
end
|
|
347
380
|
end
|
|
348
381
|
|
|
349
382
|
# Plant a Mu deploy secret into a storage bucket somewhere for so our kittens can consume it
|
|
@@ -772,50 +805,47 @@ end
|
|
|
772
805
|
|
|
773
806
|
@@instance_types ||= {}
|
|
774
807
|
@@instance_types[region] ||= {}
|
|
775
|
-
next_token = nil
|
|
776
808
|
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
type: "TERM_MATCH"
|
|
797
|
-
}
|
|
798
|
-
],
|
|
799
|
-
next_token: next_token
|
|
800
|
-
)
|
|
801
|
-
resp.price_list.each { |pricing|
|
|
802
|
-
data = JSON.parse(pricing)
|
|
803
|
-
type = data["product"]["attributes"]["instanceType"]
|
|
804
|
-
next if @@instance_types[region].has_key?(type)
|
|
805
|
-
@@instance_types[region][type] = {}
|
|
806
|
-
["ecu", "vcpu", "memory", "storage"].each { |a|
|
|
807
|
-
@@instance_types[region][type][a] = data["product"]["attributes"][a]
|
|
809
|
+
# Pricing API isn't widely available, so ask a region we know supports
|
|
810
|
+
# it
|
|
811
|
+
resp = MU::Cloud::AWS.pricing(region: "us-east-1").get_products(
|
|
812
|
+
service_code: "AmazonEC2",
|
|
813
|
+
filters: [
|
|
814
|
+
{
|
|
815
|
+
field: "productFamily",
|
|
816
|
+
value: "Compute Instance",
|
|
817
|
+
type: "TERM_MATCH"
|
|
818
|
+
},
|
|
819
|
+
{
|
|
820
|
+
field: "tenancy",
|
|
821
|
+
value: "Shared",
|
|
822
|
+
type: "TERM_MATCH"
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
field: "location",
|
|
826
|
+
value: human_region,
|
|
827
|
+
type: "TERM_MATCH"
|
|
808
828
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
829
|
+
]
|
|
830
|
+
)
|
|
831
|
+
resp.price_list.each { |pricing|
|
|
832
|
+
data = JSON.parse(pricing)
|
|
833
|
+
type = data["product"]["attributes"]["instanceType"]
|
|
834
|
+
next if @@instance_types[region].has_key?(type)
|
|
835
|
+
@@instance_types[region][type] = {}
|
|
836
|
+
["ecu", "vcpu", "memory", "storage"].each { |a|
|
|
837
|
+
@@instance_types[region][type][a] = data["product"]["attributes"][a]
|
|
812
838
|
}
|
|
813
|
-
|
|
814
|
-
|
|
839
|
+
@@instance_types[region][type]["memory"].sub!(/ GiB/, "")
|
|
840
|
+
@@instance_types[region][type]["memory"] = @@instance_types[region][type]["memory"].to_f
|
|
841
|
+
@@instance_types[region][type]["vcpu"] = @@instance_types[region][type]["vcpu"].to_f
|
|
842
|
+
}
|
|
815
843
|
|
|
816
844
|
@@instance_types
|
|
817
845
|
end
|
|
818
846
|
|
|
847
|
+
@@certificates = {}
|
|
848
|
+
|
|
819
849
|
# AWS can stash API-available certificates in Amazon Certificate Manager
|
|
820
850
|
# or in IAM. Rather than make people crazy trying to get the syntax
|
|
821
851
|
# correct in our Baskets of Kittens, let's have a helper that tries to do
|
|
@@ -824,21 +854,24 @@ end
|
|
|
824
854
|
# @param name [String]: The name of the cert. For IAM certs this can be any IAM name; for ACM, it's usually the domain name. If multiple matches are found, or no matches, an exception is raised.
|
|
825
855
|
# @param id [String]: The ARN of a known certificate. We just validate that it exists. This is ignored if a name parameter is supplied.
|
|
826
856
|
# @return [String]: The ARN of a matching certificate that is known to exist. If it is an ACM certificate, we also know that it is not expired.
|
|
827
|
-
def self.findSSLCertificate(name: nil, id: nil, region: myRegion)
|
|
828
|
-
if name.nil?
|
|
857
|
+
def self.findSSLCertificate(name: nil, id: nil, region: myRegion, credentials: nil, raise_on_missing: true)
|
|
858
|
+
if (name.nil? or name.empty?) and (id.nil? or id.empty?)
|
|
829
859
|
raise MuError, "Can't call findSSLCertificate without specifying either a name or an id"
|
|
830
860
|
end
|
|
861
|
+
if id and @@certificates[id]
|
|
862
|
+
return [id, @@certificates[id]]
|
|
863
|
+
end
|
|
831
864
|
|
|
832
865
|
if !name.nil? and !name.empty?
|
|
833
866
|
matches = []
|
|
834
|
-
acmcerts = MU::Cloud::AWS.acm(region: region).list_certificates(
|
|
867
|
+
acmcerts = MU::Cloud::AWS.acm(region: region, credentials: credentials).list_certificates(
|
|
835
868
|
certificate_statuses: ["ISSUED"]
|
|
836
869
|
)
|
|
837
870
|
acmcerts.certificate_summary_list.each { |cert|
|
|
838
871
|
matches << cert.certificate_arn if cert.domain_name == name
|
|
839
872
|
}
|
|
840
873
|
begin
|
|
841
|
-
iamcert = MU::Cloud::AWS.iam.get_server_certificate(
|
|
874
|
+
iamcert = MU::Cloud::AWS.iam(credentials: credentials).get_server_certificate(
|
|
842
875
|
server_certificate_name: name
|
|
843
876
|
)
|
|
844
877
|
rescue Aws::IAM::Errors::ValidationError, Aws::IAM::Errors::NoSuchEntity
|
|
@@ -848,32 +881,45 @@ end
|
|
|
848
881
|
matches << iamcert.server_certificate.server_certificate_metadata.arn
|
|
849
882
|
end
|
|
850
883
|
if matches.size == 1
|
|
851
|
-
|
|
884
|
+
id = matches.first
|
|
852
885
|
elsif matches.size == 0
|
|
853
|
-
|
|
886
|
+
if raise_on_missing
|
|
887
|
+
raise MuError, "No IAM or ACM certificate named #{name} was found in #{region}"
|
|
888
|
+
else
|
|
889
|
+
return nil
|
|
890
|
+
end
|
|
854
891
|
elsif matches.size > 1
|
|
855
892
|
raise MuError, "Multiple certificates named #{name} were found in #{region}. Remove extras or use ssl_certificate_id to supply the exact ARN of the one you want to use."
|
|
856
893
|
end
|
|
857
894
|
end
|
|
858
895
|
|
|
896
|
+
domains = []
|
|
897
|
+
|
|
859
898
|
if id.match(/^arn:aws(?:-us-gov)?:acm/)
|
|
860
|
-
resp = MU::Cloud::AWS.acm(region: region).
|
|
899
|
+
resp = MU::Cloud::AWS.acm(region: region).describe_certificate(
|
|
861
900
|
certificate_arn: id
|
|
862
901
|
)
|
|
863
|
-
|
|
902
|
+
|
|
903
|
+
if resp.nil? or resp.certificate.nil?
|
|
864
904
|
raise MuError, "No such ACM certificate '#{id}'"
|
|
865
905
|
end
|
|
906
|
+
domains << resp.certificate.domain_name
|
|
907
|
+
if resp.certificate.subject_alternative_names
|
|
908
|
+
domains.concat(resp.certificate.subject_alternative_names)
|
|
909
|
+
end
|
|
866
910
|
elsif id.match(/^arn:aws(?:-us-gov)?:iam/)
|
|
867
911
|
resp = MU::Cloud::AWS.iam.list_server_certificates
|
|
868
912
|
if resp.nil?
|
|
869
913
|
raise MuError, "No such IAM certificate '#{id}'"
|
|
870
914
|
end
|
|
871
915
|
resp.server_certificate_metadata_list.each { |cert|
|
|
916
|
+
|
|
872
917
|
if cert.arn == id
|
|
873
918
|
if cert.expiration < Time.now
|
|
874
919
|
MU.log "IAM SSL certificate #{cert.server_certificate_name} (#{id}) is EXPIRED", MU::WARN
|
|
875
920
|
end
|
|
876
|
-
|
|
921
|
+
@@certificates[id] = [cert.server_certificate_name]
|
|
922
|
+
return [id, [cert.server_certificate_name]]
|
|
877
923
|
end
|
|
878
924
|
}
|
|
879
925
|
raise MuError, "No such IAM certificate '#{id}'"
|
|
@@ -881,7 +927,56 @@ end
|
|
|
881
927
|
raise MuError, "The format of '#{id}' doesn't look like an ARN for either Amazon Certificate Manager or IAM"
|
|
882
928
|
end
|
|
883
929
|
|
|
884
|
-
id
|
|
930
|
+
@@certificates[id] = domains.uniq
|
|
931
|
+
[id, domains.uniq]
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
# Given a domain name and an ACM or IAM certificate identifier, sort out
|
|
935
|
+
# whether the domain name is "covered" by the certificate
|
|
936
|
+
# @param name [String]
|
|
937
|
+
# @param cert_id [String]
|
|
938
|
+
# @return [Boolean]
|
|
939
|
+
def self.nameMatchesCertificate(name, cert_id)
|
|
940
|
+
_id, domains = findSSLCertificate(id: cert_id)
|
|
941
|
+
return false if !domains
|
|
942
|
+
domains.each { |dom|
|
|
943
|
+
if dom == name or
|
|
944
|
+
(dom =~ /^\*/ and name =~ /.*#{Regexp.quote(dom[1..-1])}/)
|
|
945
|
+
return true
|
|
946
|
+
end
|
|
947
|
+
}
|
|
948
|
+
false
|
|
949
|
+
end
|
|
950
|
+
|
|
951
|
+
# Given a {MU::Config::Ref} block for an IAM or ACM SSL certificate,
|
|
952
|
+
# look up and validate the specified certificate. This is intended to be
|
|
953
|
+
# invoked from resource implementations' +validateConfig+ methods.
|
|
954
|
+
# @param certblock [Hash,MU::Config::Ref]:
|
|
955
|
+
# @param region [String]: Default region to use when looking up the certificate, if its configuration block does not specify any
|
|
956
|
+
# @param credentials [String]: Default credentials to use when looking up the certificate, if its configuration block does not specify any
|
|
957
|
+
# @return [Boolean]
|
|
958
|
+
def self.resolveSSLCertificate(certblock, region: nil, credentials: nil)
|
|
959
|
+
return false if !certblock
|
|
960
|
+
ok = true
|
|
961
|
+
|
|
962
|
+
certblock['region'] ||= region if !certblock['id']
|
|
963
|
+
certblock['credentials'] ||= credentials
|
|
964
|
+
cert_arn, cert_domains = MU::Cloud::AWS.findSSLCertificate(
|
|
965
|
+
name: certblock["name"],
|
|
966
|
+
id: certblock["id"],
|
|
967
|
+
region: certblock['region'],
|
|
968
|
+
credentials: certblock['credentials']
|
|
969
|
+
)
|
|
970
|
+
|
|
971
|
+
if cert_arn
|
|
972
|
+
certblock['id'] ||= cert_arn
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
['region', 'credentials'].each { |field|
|
|
976
|
+
certblock.delete(field) if certblock[field].nil?
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
[cert_arn, cert_domains]
|
|
885
980
|
end
|
|
886
981
|
|
|
887
982
|
# Amazon Certificate Manager API
|
|
@@ -1001,6 +1096,14 @@ end
|
|
|
1001
1096
|
@@cloudwatchlogs_api[credentials][region]
|
|
1002
1097
|
end
|
|
1003
1098
|
|
|
1099
|
+
# Amazon's CloudWatchEvents API
|
|
1100
|
+
def self.cloudwatchevents(region: MU.curRegion, credentials: nil)
|
|
1101
|
+
region ||= myRegion
|
|
1102
|
+
@@cloudwatchevents_api[credentials] ||= {}
|
|
1103
|
+
@@cloudwatchevents_api[credentials][region] ||= MU::Cloud::AWS::AmazonEndpoint.new(api: "CloudWatchEvents", region: region, credentials: credentials)
|
|
1104
|
+
@@cloudwatchevents_api[credentials][region]
|
|
1105
|
+
end
|
|
1106
|
+
|
|
1004
1107
|
# Amazon's CloudFront API
|
|
1005
1108
|
def self.cloudfront(region: MU.curRegion, credentials: nil)
|
|
1006
1109
|
region ||= myRegion
|
|
@@ -1089,6 +1192,14 @@ end
|
|
|
1089
1192
|
@@dynamo_api[credentials][region]
|
|
1090
1193
|
end
|
|
1091
1194
|
|
|
1195
|
+
# Amazon's DynamoStream API
|
|
1196
|
+
def self.dynamostream(region: MU.curRegion, credentials: nil)
|
|
1197
|
+
region ||= myRegion
|
|
1198
|
+
@@dynamostream_api[credentials] ||= {}
|
|
1199
|
+
@@dynamostream_api[credentials][region] ||= MU::Cloud::AWS::AmazonEndpoint.new(api: "DynamoDBStreams", region: region, credentials: credentials)
|
|
1200
|
+
@@dynamostream_api[credentials][region]
|
|
1201
|
+
end
|
|
1202
|
+
|
|
1092
1203
|
# Amazon's Pricing API
|
|
1093
1204
|
def self.pricing(region: MU.curRegion, credentials: nil)
|
|
1094
1205
|
region ||= myRegion
|
|
@@ -1137,6 +1248,14 @@ end
|
|
|
1137
1248
|
@@kms_api[credentials][region]
|
|
1138
1249
|
end
|
|
1139
1250
|
|
|
1251
|
+
# Amazon's CloudFront API
|
|
1252
|
+
def self.cloudfront(region: MU.curRegion, credentials: nil)
|
|
1253
|
+
region ||= myRegion
|
|
1254
|
+
@@cloudfront_api[credentials] ||= {}
|
|
1255
|
+
@@cloudfront_api[credentials][region] ||= MU::Cloud::AWS::AmazonEndpoint.new(api: "CloudFront", region: region, credentials: credentials)
|
|
1256
|
+
@@cloudfront_api[credentials][region]
|
|
1257
|
+
end
|
|
1258
|
+
|
|
1140
1259
|
# Amazon's Organizations API
|
|
1141
1260
|
def self.orgs(credentials: nil)
|
|
1142
1261
|
@@organizations_api ||= {}
|
|
@@ -1218,7 +1337,7 @@ end
|
|
|
1218
1337
|
# Mu Master, if we're in AWS.
|
|
1219
1338
|
# @return [void]
|
|
1220
1339
|
def self.openFirewallForClients
|
|
1221
|
-
MU::Cloud.
|
|
1340
|
+
MU::Cloud.resourceClass("AWS", :FirewallRule)
|
|
1222
1341
|
begin
|
|
1223
1342
|
if File.exist?(Etc.getpwuid(Process.uid).dir+"/.chef/knife.rb")
|
|
1224
1343
|
::Chef::Config.from_file(Etc.getpwuid(Process.uid).dir+"/.chef/knife.rb")
|
|
@@ -1394,7 +1513,7 @@ end
|
|
|
1394
1513
|
# Create an AWS API client
|
|
1395
1514
|
# @param region [String]: Amazon region so we know what endpoint to use
|
|
1396
1515
|
# @param api [String]: Which API are we wrapping?
|
|
1397
|
-
def initialize(region:
|
|
1516
|
+
def initialize(region: nil, api: "EC2", credentials: nil)
|
|
1398
1517
|
@cred_obj = MU::Cloud::AWS.loadCredentials(credentials)
|
|
1399
1518
|
@credentials = MU::Cloud::AWS.credConfig(credentials, name_only: true)
|
|
1400
1519
|
|
|
@@ -1403,6 +1522,8 @@ end
|
|
|
1403
1522
|
end
|
|
1404
1523
|
|
|
1405
1524
|
params = {}
|
|
1525
|
+
region ||= MU::Cloud::AWS.credConfig(credentials)['region']
|
|
1526
|
+
region ||= MU.myRegion
|
|
1406
1527
|
|
|
1407
1528
|
if region
|
|
1408
1529
|
@region = region
|
|
@@ -1419,21 +1540,98 @@ end
|
|
|
1419
1540
|
# Catch-all for AWS client methods. Essentially a pass-through with some
|
|
1420
1541
|
# rescues for known silly endpoint behavior.
|
|
1421
1542
|
def method_missing(method_sym, *arguments)
|
|
1543
|
+
# make sure error symbols are loaded for our exception handling later
|
|
1422
1544
|
require "aws-sdk-core"
|
|
1545
|
+
require "aws-sdk-core/rds"
|
|
1546
|
+
require "aws-sdk-core/ec2"
|
|
1547
|
+
require "aws-sdk-core/route53"
|
|
1548
|
+
require "aws-sdk-core/iam"
|
|
1549
|
+
require "aws-sdk-core/efs"
|
|
1550
|
+
require "aws-sdk-core/pricing"
|
|
1551
|
+
require "aws-sdk-core/apigateway"
|
|
1552
|
+
require "aws-sdk-core/ecs"
|
|
1553
|
+
require "aws-sdk-core/eks"
|
|
1554
|
+
require "aws-sdk-core/cloudwatchlogs"
|
|
1555
|
+
require "aws-sdk-core/cloudwatchevents"
|
|
1556
|
+
require "aws-sdk-core/elasticloadbalancing"
|
|
1557
|
+
require "aws-sdk-core/elasticloadbalancingv2"
|
|
1558
|
+
require "aws-sdk-core/autoscaling"
|
|
1559
|
+
require "aws-sdk-core/client_waiters"
|
|
1560
|
+
require "aws-sdk-core/waiters/errors"
|
|
1423
1561
|
|
|
1424
1562
|
retries = 0
|
|
1425
1563
|
begin
|
|
1426
1564
|
MU.log "Calling #{method_sym} in #{@region}", MU::DEBUG, details: arguments
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1565
|
+
|
|
1566
|
+
retval = if !arguments.nil? and arguments.size == 1
|
|
1567
|
+
@api.method(method_sym).call(arguments[0])
|
|
1568
|
+
elsif !arguments.nil? and arguments.size > 0
|
|
1569
|
+
@api.method(method_sym).call(*arguments)
|
|
1570
|
+
else
|
|
1571
|
+
@api.method(method_sym).call
|
|
1572
|
+
end
|
|
1573
|
+
|
|
1574
|
+
if !retval.nil?
|
|
1575
|
+
begin
|
|
1576
|
+
page_markers = {
|
|
1577
|
+
:marker => :marker,
|
|
1578
|
+
:next_token => :next_token,
|
|
1579
|
+
:next_marker => :marker
|
|
1580
|
+
}
|
|
1581
|
+
paginator = nil
|
|
1582
|
+
new_page = nil
|
|
1583
|
+
page_markers.each_key { |m|
|
|
1584
|
+
if !retval.nil? and retval.respond_to?(m)
|
|
1585
|
+
paginator = m
|
|
1586
|
+
new_page = retval.send(m)
|
|
1587
|
+
break
|
|
1588
|
+
end
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
if paginator and new_page and !new_page.empty?
|
|
1592
|
+
resp = retval.respond_to?(:__getobj__) ? retval.__getobj__ : retval
|
|
1593
|
+
concat_to = resp.class.instance_methods(false).reject { |m|
|
|
1594
|
+
m.to_s.match(/=$/) or m == paginator or resp.send(m).nil? or !resp.send(m).is_a?(Array)
|
|
1595
|
+
}
|
|
1596
|
+
if concat_to.size != 1
|
|
1597
|
+
MU.log "Tried to figure out where I might append paginated results for a #{resp.class.name}, but failed", MU::DEBUG, details: concat_to
|
|
1598
|
+
else
|
|
1599
|
+
concat_to = concat_to.first
|
|
1600
|
+
new_args = arguments ? arguments.dup : [{}]
|
|
1601
|
+
begin
|
|
1602
|
+
if new_args.is_a?(Array)
|
|
1603
|
+
new_args << {} if new_args.empty?
|
|
1604
|
+
if new_args.size == 1 and new_args.first.is_a?(Hash)
|
|
1605
|
+
new_args[0][page_markers[paginator]] = new_page
|
|
1606
|
+
else
|
|
1607
|
+
MU.log "I don't know how to insert a #{paginator} into these arguments for #{method_sym}", MU::WARN, details: new_args
|
|
1608
|
+
end
|
|
1609
|
+
elsif new_args.is_a?(Hash)
|
|
1610
|
+
new_args[page_markers[paginator]] = new_page
|
|
1611
|
+
end
|
|
1612
|
+
|
|
1613
|
+
MU.log "Attempting magic pagination for #{method_sym}", MU::DEBUG, details: new_args
|
|
1614
|
+
|
|
1615
|
+
# resp = if !arguments.nil? and arguments.size == 1
|
|
1616
|
+
# @api.method(method_sym).call(new_args[0])
|
|
1617
|
+
# elsif !arguments.nil? and arguments.size > 0
|
|
1618
|
+
resp = @api.method(method_sym).call(*new_args)
|
|
1619
|
+
# end
|
|
1620
|
+
break if resp.nil?
|
|
1621
|
+
resp = resp.__getobj__ if resp.respond_to?(:__getobj__)
|
|
1622
|
+
retval.send(concat_to).concat(resp.send(concat_to))
|
|
1623
|
+
new_page = resp.send(paginator) if !resp.nil?
|
|
1624
|
+
end while !resp.nil? and !new_page.nil? and !new_page.empty?
|
|
1625
|
+
end
|
|
1626
|
+
end
|
|
1627
|
+
rescue StandardError => e
|
|
1628
|
+
MU.log "Made a good-faith effort to auto-paginate API call to #{method_sym} and failed with #{e.message}", MU::DEBUG, details: arguments
|
|
1629
|
+
raise e
|
|
1630
|
+
end
|
|
1434
1631
|
end
|
|
1632
|
+
|
|
1435
1633
|
return retval
|
|
1436
|
-
rescue Aws::EC2::Errors::InternalError, Aws::EC2::Errors::RequestLimitExceeded, Aws::EC2::Errors::Unavailable, Aws::Route53::Errors::Throttling, Aws::ElasticLoadBalancing::Errors::HttpFailureException, Aws::EC2::Errors::Http503Error, Aws::AutoScaling::Errors::Http503Error, Aws::AutoScaling::Errors::InternalFailure, Aws::AutoScaling::Errors::ServiceUnavailable, Aws::Route53::Errors::ServiceUnavailable, Aws::ElasticLoadBalancing::Errors::Throttling, Aws::RDS::Errors::ClientUnavailable, Aws::Waiters::Errors::UnexpectedError, Aws::ElasticLoadBalancing::Errors::ServiceUnavailable, Aws::ElasticLoadBalancingV2::Errors::Throttling, Seahorse::Client::NetworkingError, Aws::IAM::Errors::Throttling, Aws::EFS::Errors::ThrottlingException, Aws::Pricing::Errors::ThrottlingException, Aws::APIGateway::Errors::TooManyRequestsException, Aws::ECS::Errors::ThrottlingException, Net::ReadTimeout, Faraday::TimeoutError, Aws::CloudWatchLogs::Errors::ThrottlingException => e
|
|
1634
|
+
rescue Aws::Lambda::Errors::TooManyRequestsException, Aws::RDS::Errors::Throttling, Aws::EC2::Errors::InternalError, Aws::EC2::Errors::RequestLimitExceeded, Aws::EC2::Errors::Unavailable, Aws::Route53::Errors::Throttling, Aws::ElasticLoadBalancing::Errors::HttpFailureException, Aws::EC2::Errors::Http503Error, Aws::AutoScaling::Errors::Http503Error, Aws::AutoScaling::Errors::InternalFailure, Aws::AutoScaling::Errors::ServiceUnavailable, Aws::Route53::Errors::ServiceUnavailable, Aws::ElasticLoadBalancing::Errors::Throttling, Aws::RDS::Errors::ClientUnavailable, Aws::Waiters::Errors::UnexpectedError, Aws::ElasticLoadBalancing::Errors::ServiceUnavailable, Aws::ElasticLoadBalancingV2::Errors::Throttling, Seahorse::Client::NetworkingError, Aws::IAM::Errors::Throttling, Aws::EFS::Errors::ThrottlingException, Aws::Pricing::Errors::ThrottlingException, Aws::APIGateway::Errors::TooManyRequestsException, Aws::ECS::Errors::ThrottlingException, Net::ReadTimeout, Faraday::TimeoutError, Aws::CloudWatchLogs::Errors::ThrottlingException => e
|
|
1437
1635
|
if e.class.name == "Seahorse::Client::NetworkingError" and e.message.match(/Name or service not known/)
|
|
1438
1636
|
MU.log e.inspect, MU::ERR
|
|
1439
1637
|
raise e
|
|
@@ -1475,6 +1673,7 @@ end
|
|
|
1475
1673
|
@@wafglobal = {}
|
|
1476
1674
|
@@waf = {}
|
|
1477
1675
|
@@cloudwatchlogs_api = {}
|
|
1676
|
+
@@cloudwatchevents_api = {}
|
|
1478
1677
|
@@cloudfront_api = {}
|
|
1479
1678
|
@@elasticache_api = {}
|
|
1480
1679
|
@@sns_api = {}
|
|
@@ -1493,6 +1692,8 @@ end
|
|
|
1493
1692
|
@@kms_api ={}
|
|
1494
1693
|
@@organization_api ={}
|
|
1495
1694
|
@@dynamo_api ={}
|
|
1695
|
+
@@dynamostream_api ={}
|
|
1696
|
+
@@cloudfront_api ={}
|
|
1496
1697
|
end
|
|
1497
1698
|
end
|
|
1498
1699
|
end
|