cloud-mu 3.1.5 → 3.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +5 -1
  3. data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
  4. data/ansible/roles/mu-windows/files/config.xml +76 -0
  5. data/ansible/roles/mu-windows/tasks/main.yml +16 -0
  6. data/bin/mu-adopt +16 -12
  7. data/bin/mu-azure-tests +57 -0
  8. data/bin/mu-cleanup +2 -4
  9. data/bin/mu-configure +52 -0
  10. data/bin/mu-deploy +3 -3
  11. data/bin/mu-findstray-tests +25 -0
  12. data/bin/mu-gen-docs +2 -4
  13. data/bin/mu-load-config.rb +2 -1
  14. data/bin/mu-node-manage +15 -16
  15. data/bin/mu-run-tests +37 -12
  16. data/cloud-mu.gemspec +3 -3
  17. data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
  18. data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
  19. data/cookbooks/mu-tools/libraries/helper.rb +1 -1
  20. data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
  21. data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
  22. data/cookbooks/mu-tools/recipes/eks.rb +2 -2
  23. data/cookbooks/mu-tools/recipes/windows-client.rb +25 -22
  24. data/extras/clean-stock-amis +25 -19
  25. data/extras/generate-stock-images +1 -0
  26. data/extras/image-generators/AWS/win2k12.yaml +2 -0
  27. data/extras/image-generators/AWS/win2k16.yaml +2 -0
  28. data/extras/image-generators/AWS/win2k19.yaml +2 -0
  29. data/modules/mommacat.ru +1 -1
  30. data/modules/mu.rb +86 -98
  31. data/modules/mu/adoption.rb +373 -58
  32. data/modules/mu/cleanup.rb +214 -303
  33. data/modules/mu/cloud.rb +128 -1733
  34. data/modules/mu/cloud/database.rb +49 -0
  35. data/modules/mu/cloud/dnszone.rb +44 -0
  36. data/modules/mu/cloud/machine_images.rb +212 -0
  37. data/modules/mu/cloud/providers.rb +81 -0
  38. data/modules/mu/cloud/resource_base.rb +929 -0
  39. data/modules/mu/cloud/server.rb +40 -0
  40. data/modules/mu/cloud/server_pool.rb +1 -0
  41. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  42. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  43. data/modules/mu/cloud/wrappers.rb +169 -0
  44. data/modules/mu/config.rb +123 -81
  45. data/modules/mu/config/alarm.rb +2 -6
  46. data/modules/mu/config/bucket.rb +32 -3
  47. data/modules/mu/config/cache_cluster.rb +2 -2
  48. data/modules/mu/config/cdn.rb +100 -0
  49. data/modules/mu/config/collection.rb +1 -1
  50. data/modules/mu/config/container_cluster.rb +7 -2
  51. data/modules/mu/config/database.rb +84 -105
  52. data/modules/mu/config/database.yml +1 -2
  53. data/modules/mu/config/dnszone.rb +5 -4
  54. data/modules/mu/config/doc_helpers.rb +5 -6
  55. data/modules/mu/config/endpoint.rb +2 -1
  56. data/modules/mu/config/firewall_rule.rb +3 -19
  57. data/modules/mu/config/folder.rb +1 -1
  58. data/modules/mu/config/function.rb +17 -8
  59. data/modules/mu/config/group.rb +1 -1
  60. data/modules/mu/config/habitat.rb +1 -1
  61. data/modules/mu/config/job.rb +89 -0
  62. data/modules/mu/config/loadbalancer.rb +57 -11
  63. data/modules/mu/config/log.rb +1 -1
  64. data/modules/mu/config/msg_queue.rb +1 -1
  65. data/modules/mu/config/nosqldb.rb +1 -1
  66. data/modules/mu/config/notifier.rb +8 -19
  67. data/modules/mu/config/ref.rb +92 -14
  68. data/modules/mu/config/role.rb +1 -1
  69. data/modules/mu/config/schema_helpers.rb +38 -37
  70. data/modules/mu/config/search_domain.rb +1 -1
  71. data/modules/mu/config/server.rb +12 -13
  72. data/modules/mu/config/server_pool.rb +3 -7
  73. data/modules/mu/config/storage_pool.rb +1 -1
  74. data/modules/mu/config/tail.rb +11 -0
  75. data/modules/mu/config/user.rb +1 -1
  76. data/modules/mu/config/vpc.rb +27 -23
  77. data/modules/mu/config/vpc.yml +0 -1
  78. data/modules/mu/defaults/AWS.yaml +90 -90
  79. data/modules/mu/defaults/Azure.yaml +1 -0
  80. data/modules/mu/defaults/Google.yaml +1 -0
  81. data/modules/mu/deploy.rb +34 -20
  82. data/modules/mu/groomer.rb +16 -1
  83. data/modules/mu/groomers/ansible.rb +69 -4
  84. data/modules/mu/groomers/chef.rb +51 -4
  85. data/modules/mu/logger.rb +120 -144
  86. data/modules/mu/master.rb +97 -4
  87. data/modules/mu/mommacat.rb +160 -874
  88. data/modules/mu/mommacat/daemon.rb +23 -14
  89. data/modules/mu/mommacat/naming.rb +110 -3
  90. data/modules/mu/mommacat/search.rb +497 -0
  91. data/modules/mu/mommacat/storage.rb +252 -194
  92. data/modules/mu/{clouds → providers}/README.md +1 -1
  93. data/modules/mu/{clouds → providers}/aws.rb +258 -57
  94. data/modules/mu/{clouds → providers}/aws/alarm.rb +3 -3
  95. data/modules/mu/{clouds → providers}/aws/bucket.rb +275 -41
  96. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +14 -50
  97. data/modules/mu/providers/aws/cdn.rb +782 -0
  98. data/modules/mu/{clouds → providers}/aws/collection.rb +5 -5
  99. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +95 -84
  100. data/modules/mu/providers/aws/database.rb +1744 -0
  101. data/modules/mu/{clouds → providers}/aws/dnszone.rb +26 -12
  102. data/modules/mu/providers/aws/endpoint.rb +1072 -0
  103. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +39 -32
  104. data/modules/mu/{clouds → providers}/aws/folder.rb +1 -1
  105. data/modules/mu/{clouds → providers}/aws/function.rb +289 -134
  106. data/modules/mu/{clouds → providers}/aws/group.rb +18 -20
  107. data/modules/mu/{clouds → providers}/aws/habitat.rb +3 -3
  108. data/modules/mu/providers/aws/job.rb +466 -0
  109. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +77 -47
  110. data/modules/mu/{clouds → providers}/aws/log.rb +5 -5
  111. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +14 -11
  112. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +96 -5
  113. data/modules/mu/{clouds → providers}/aws/notifier.rb +135 -63
  114. data/modules/mu/{clouds → providers}/aws/role.rb +76 -48
  115. data/modules/mu/{clouds → providers}/aws/search_domain.rb +172 -41
  116. data/modules/mu/{clouds → providers}/aws/server.rb +66 -98
  117. data/modules/mu/{clouds → providers}/aws/server_pool.rb +42 -60
  118. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +21 -38
  119. data/modules/mu/{clouds → providers}/aws/user.rb +12 -16
  120. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  121. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
  122. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +0 -0
  123. data/modules/mu/{clouds → providers}/aws/vpc.rb +143 -74
  124. data/modules/mu/{clouds → providers}/aws/vpc_subnet.rb +0 -0
  125. data/modules/mu/{clouds → providers}/azure.rb +13 -0
  126. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +1 -5
  127. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +8 -1
  128. data/modules/mu/{clouds → providers}/azure/habitat.rb +0 -0
  129. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +0 -0
  130. data/modules/mu/{clouds → providers}/azure/role.rb +0 -0
  131. data/modules/mu/{clouds → providers}/azure/server.rb +32 -24
  132. data/modules/mu/{clouds → providers}/azure/user.rb +1 -1
  133. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  134. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  135. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  136. data/modules/mu/{clouds → providers}/azure/vpc.rb +4 -6
  137. data/modules/mu/{clouds → providers}/cloudformation.rb +10 -0
  138. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  139. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  140. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  141. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  142. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  143. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  144. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  145. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  146. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  147. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  148. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +3 -3
  149. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  150. data/modules/mu/{clouds → providers}/google.rb +29 -6
  151. data/modules/mu/{clouds → providers}/google/bucket.rb +4 -4
  152. data/modules/mu/{clouds → providers}/google/container_cluster.rb +38 -20
  153. data/modules/mu/{clouds → providers}/google/database.rb +5 -12
  154. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +5 -5
  155. data/modules/mu/{clouds → providers}/google/folder.rb +5 -9
  156. data/modules/mu/{clouds → providers}/google/function.rb +6 -6
  157. data/modules/mu/{clouds → providers}/google/group.rb +9 -17
  158. data/modules/mu/{clouds → providers}/google/habitat.rb +4 -8
  159. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +5 -5
  160. data/modules/mu/{clouds → providers}/google/role.rb +50 -31
  161. data/modules/mu/{clouds → providers}/google/server.rb +41 -24
  162. data/modules/mu/{clouds → providers}/google/server_pool.rb +14 -14
  163. data/modules/mu/{clouds → providers}/google/user.rb +34 -24
  164. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  165. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  166. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  167. data/modules/mu/{clouds → providers}/google/vpc.rb +45 -14
  168. data/modules/tests/aws-jobs-functions.yaml +46 -0
  169. data/modules/tests/centos6.yaml +15 -0
  170. data/modules/tests/centos7.yaml +15 -0
  171. data/modules/tests/centos8.yaml +12 -0
  172. data/modules/tests/ecs.yaml +2 -2
  173. data/modules/tests/eks.yaml +1 -1
  174. data/modules/tests/functions/node-function/lambda_function.js +10 -0
  175. data/modules/tests/functions/python-function/lambda_function.py +12 -0
  176. data/modules/tests/microservice_app.yaml +288 -0
  177. data/modules/tests/rds.yaml +108 -0
  178. data/modules/tests/regrooms/rds.yaml +123 -0
  179. data/modules/tests/server-with-scrub-muisms.yaml +1 -1
  180. data/modules/tests/super_complex_bok.yml +2 -2
  181. data/modules/tests/super_simple_bok.yml +3 -5
  182. data/spec/mu/clouds/azure_spec.rb +2 -2
  183. metadata +122 -92
  184. data/modules/mu/clouds/aws/database.rb +0 -1974
  185. 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/clouds/aws/function.rb`:
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
- begin
778
- # Pricing API isn't widely available, so ask a region we know supports
779
- # it
780
- resp = MU::Cloud::AWS.pricing(region: "us-east-1").get_products(
781
- service_code: "AmazonEC2",
782
- filters: [
783
- {
784
- field: "productFamily",
785
- value: "Compute Instance",
786
- type: "TERM_MATCH"
787
- },
788
- {
789
- field: "tenancy",
790
- value: "Shared",
791
- type: "TERM_MATCH"
792
- },
793
- {
794
- field: "location",
795
- value: human_region,
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
- @@instance_types[region][type]["memory"].sub!(/ GiB/, "")
810
- @@instance_types[region][type]["memory"] = @@instance_types[region][type]["memory"].to_f
811
- @@instance_types[region][type]["vcpu"] = @@instance_types[region][type]["vcpu"].to_f
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
- next_token = resp.next_token
814
- end while resp and next_token
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? and name.empty? and id.nil? and id.empty?
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
- return matches.first
884
+ id = matches.first
852
885
  elsif matches.size == 0
853
- raise MuError, "No IAM or ACM certificate named #{name} was found in #{region}"
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).get_certificate(
899
+ resp = MU::Cloud::AWS.acm(region: region).describe_certificate(
861
900
  certificate_arn: id
862
901
  )
863
- if resp.nil?
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
- return id
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.loadCloudType("AWS", :FirewallRule)
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: MU.curRegion, api: "EC2", credentials: nil)
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
- retval = nil
1428
- if !arguments.nil? and arguments.size == 1
1429
- retval = @api.method(method_sym).call(arguments[0])
1430
- elsif !arguments.nil? and arguments.size > 0
1431
- retval = @api.method(method_sym).call(*arguments)
1432
- else
1433
- retval = @api.method(method_sym).call
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