cloud-mu 3.1.6 → 3.4.0

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.
Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/bin/mu-adopt +15 -12
  4. data/bin/mu-azure-tests +57 -0
  5. data/bin/mu-cleanup +2 -4
  6. data/bin/mu-configure +37 -1
  7. data/bin/mu-deploy +3 -3
  8. data/bin/mu-findstray-tests +25 -0
  9. data/bin/mu-gen-docs +2 -4
  10. data/bin/mu-load-config.rb +2 -1
  11. data/bin/mu-run-tests +37 -12
  12. data/cloud-mu.gemspec +4 -4
  13. data/cookbooks/mu-tools/attributes/default.rb +7 -0
  14. data/cookbooks/mu-tools/libraries/helper.rb +87 -3
  15. data/cookbooks/mu-tools/recipes/apply_security.rb +39 -23
  16. data/cookbooks/mu-tools/recipes/aws_api.rb +13 -0
  17. data/cookbooks/mu-tools/recipes/google_api.rb +4 -0
  18. data/cookbooks/mu-tools/recipes/rsyslog.rb +8 -1
  19. data/cookbooks/mu-tools/resources/disk.rb +33 -12
  20. data/cookbooks/mu-tools/resources/mommacat_request.rb +1 -2
  21. data/cookbooks/mu-tools/templates/centos-8/sshd_config.erb +215 -0
  22. data/extras/clean-stock-amis +10 -2
  23. data/extras/generate-stock-images +7 -3
  24. data/extras/image-generators/AWS/centos7.yaml +19 -16
  25. data/extras/image-generators/AWS/{rhel7.yaml → rhel71.yaml} +0 -0
  26. data/extras/image-generators/AWS/{win2k12.yaml → win2k12r2.yaml} +0 -0
  27. data/modules/mommacat.ru +2 -2
  28. data/modules/mu.rb +84 -97
  29. data/modules/mu/adoption.rb +359 -59
  30. data/modules/mu/cleanup.rb +67 -44
  31. data/modules/mu/cloud.rb +108 -1754
  32. data/modules/mu/cloud/database.rb +49 -0
  33. data/modules/mu/cloud/dnszone.rb +44 -0
  34. data/modules/mu/cloud/machine_images.rb +212 -0
  35. data/modules/mu/cloud/providers.rb +81 -0
  36. data/modules/mu/cloud/resource_base.rb +929 -0
  37. data/modules/mu/cloud/server.rb +40 -0
  38. data/modules/mu/cloud/server_pool.rb +1 -0
  39. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  40. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  41. data/modules/mu/cloud/wrappers.rb +178 -0
  42. data/modules/mu/config.rb +122 -80
  43. data/modules/mu/config/alarm.rb +2 -6
  44. data/modules/mu/config/bucket.rb +32 -3
  45. data/modules/mu/config/cache_cluster.rb +2 -2
  46. data/modules/mu/config/cdn.rb +100 -0
  47. data/modules/mu/config/collection.rb +1 -1
  48. data/modules/mu/config/container_cluster.rb +2 -2
  49. data/modules/mu/config/database.rb +84 -105
  50. data/modules/mu/config/database.yml +1 -2
  51. data/modules/mu/config/dnszone.rb +5 -4
  52. data/modules/mu/config/doc_helpers.rb +4 -5
  53. data/modules/mu/config/endpoint.rb +2 -1
  54. data/modules/mu/config/firewall_rule.rb +3 -19
  55. data/modules/mu/config/folder.rb +1 -1
  56. data/modules/mu/config/function.rb +17 -8
  57. data/modules/mu/config/group.rb +1 -1
  58. data/modules/mu/config/habitat.rb +1 -1
  59. data/modules/mu/config/job.rb +89 -0
  60. data/modules/mu/config/loadbalancer.rb +57 -11
  61. data/modules/mu/config/log.rb +1 -1
  62. data/modules/mu/config/msg_queue.rb +1 -1
  63. data/modules/mu/config/nosqldb.rb +1 -1
  64. data/modules/mu/config/notifier.rb +8 -19
  65. data/modules/mu/config/ref.rb +81 -9
  66. data/modules/mu/config/role.rb +1 -1
  67. data/modules/mu/config/schema_helpers.rb +30 -34
  68. data/modules/mu/config/search_domain.rb +1 -1
  69. data/modules/mu/config/server.rb +5 -13
  70. data/modules/mu/config/server_pool.rb +3 -7
  71. data/modules/mu/config/storage_pool.rb +1 -1
  72. data/modules/mu/config/tail.rb +10 -0
  73. data/modules/mu/config/user.rb +1 -1
  74. data/modules/mu/config/vpc.rb +13 -17
  75. data/modules/mu/defaults/AWS.yaml +106 -106
  76. data/modules/mu/defaults/Azure.yaml +1 -0
  77. data/modules/mu/defaults/Google.yaml +1 -0
  78. data/modules/mu/deploy.rb +33 -19
  79. data/modules/mu/groomer.rb +15 -0
  80. data/modules/mu/groomers/chef.rb +3 -0
  81. data/modules/mu/logger.rb +120 -144
  82. data/modules/mu/master.rb +22 -1
  83. data/modules/mu/mommacat.rb +71 -26
  84. data/modules/mu/mommacat/daemon.rb +23 -14
  85. data/modules/mu/mommacat/naming.rb +82 -3
  86. data/modules/mu/mommacat/search.rb +59 -16
  87. data/modules/mu/mommacat/storage.rb +119 -48
  88. data/modules/mu/{clouds → providers}/README.md +1 -1
  89. data/modules/mu/{clouds → providers}/aws.rb +248 -62
  90. data/modules/mu/{clouds → providers}/aws/alarm.rb +3 -3
  91. data/modules/mu/{clouds → providers}/aws/bucket.rb +275 -41
  92. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +14 -50
  93. data/modules/mu/providers/aws/cdn.rb +782 -0
  94. data/modules/mu/{clouds → providers}/aws/collection.rb +5 -5
  95. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +65 -63
  96. data/modules/mu/providers/aws/database.rb +1747 -0
  97. data/modules/mu/{clouds → providers}/aws/dnszone.rb +26 -12
  98. data/modules/mu/providers/aws/endpoint.rb +1072 -0
  99. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +39 -32
  100. data/modules/mu/{clouds → providers}/aws/folder.rb +1 -1
  101. data/modules/mu/{clouds → providers}/aws/function.rb +291 -133
  102. data/modules/mu/{clouds → providers}/aws/group.rb +18 -20
  103. data/modules/mu/{clouds → providers}/aws/habitat.rb +3 -3
  104. data/modules/mu/providers/aws/job.rb +469 -0
  105. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +77 -47
  106. data/modules/mu/{clouds → providers}/aws/log.rb +5 -5
  107. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +14 -11
  108. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +96 -5
  109. data/modules/mu/{clouds → providers}/aws/notifier.rb +135 -63
  110. data/modules/mu/{clouds → providers}/aws/role.rb +112 -78
  111. data/modules/mu/{clouds → providers}/aws/search_domain.rb +172 -41
  112. data/modules/mu/{clouds → providers}/aws/server.rb +120 -145
  113. data/modules/mu/{clouds → providers}/aws/server_pool.rb +42 -60
  114. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +21 -38
  115. data/modules/mu/{clouds → providers}/aws/user.rb +12 -16
  116. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  117. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
  118. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +0 -0
  119. data/modules/mu/{clouds → providers}/aws/vpc.rb +141 -73
  120. data/modules/mu/{clouds → providers}/aws/vpc_subnet.rb +0 -0
  121. data/modules/mu/{clouds → providers}/azure.rb +4 -1
  122. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +1 -5
  123. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +8 -1
  124. data/modules/mu/{clouds → providers}/azure/habitat.rb +0 -0
  125. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +0 -0
  126. data/modules/mu/{clouds → providers}/azure/role.rb +0 -0
  127. data/modules/mu/{clouds → providers}/azure/server.rb +32 -24
  128. data/modules/mu/{clouds → providers}/azure/user.rb +1 -1
  129. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  130. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  131. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  132. data/modules/mu/{clouds → providers}/azure/vpc.rb +4 -6
  133. data/modules/mu/{clouds → providers}/cloudformation.rb +1 -1
  134. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  135. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  136. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  137. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  138. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  139. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  140. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  141. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  142. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  143. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  144. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +3 -3
  145. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  146. data/modules/mu/{clouds → providers}/google.rb +15 -6
  147. data/modules/mu/{clouds → providers}/google/bucket.rb +2 -2
  148. data/modules/mu/{clouds → providers}/google/container_cluster.rb +29 -14
  149. data/modules/mu/{clouds → providers}/google/database.rb +2 -9
  150. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +3 -3
  151. data/modules/mu/{clouds → providers}/google/folder.rb +5 -9
  152. data/modules/mu/{clouds → providers}/google/function.rb +4 -4
  153. data/modules/mu/{clouds → providers}/google/group.rb +9 -17
  154. data/modules/mu/{clouds → providers}/google/habitat.rb +4 -8
  155. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +2 -2
  156. data/modules/mu/{clouds → providers}/google/role.rb +46 -35
  157. data/modules/mu/{clouds → providers}/google/server.rb +26 -11
  158. data/modules/mu/{clouds → providers}/google/server_pool.rb +11 -11
  159. data/modules/mu/{clouds → providers}/google/user.rb +32 -22
  160. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  161. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  162. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  163. data/modules/mu/{clouds → providers}/google/vpc.rb +38 -3
  164. data/modules/tests/aws-jobs-functions.yaml +46 -0
  165. data/modules/tests/centos6.yaml +15 -0
  166. data/modules/tests/centos7.yaml +15 -0
  167. data/modules/tests/centos8.yaml +12 -0
  168. data/modules/tests/ecs.yaml +2 -2
  169. data/modules/tests/eks.yaml +1 -1
  170. data/modules/tests/functions/node-function/lambda_function.js +10 -0
  171. data/modules/tests/functions/python-function/lambda_function.py +12 -0
  172. data/modules/tests/microservice_app.yaml +288 -0
  173. data/modules/tests/rds.yaml +108 -0
  174. data/modules/tests/regrooms/rds.yaml +123 -0
  175. data/modules/tests/server-with-scrub-muisms.yaml +1 -1
  176. data/modules/tests/super_complex_bok.yml +2 -2
  177. data/modules/tests/super_simple_bok.yml +2 -2
  178. data/spec/mu/clouds/azure_spec.rb +2 -2
  179. metadata +126 -98
  180. data/modules/mu/clouds/aws/database.rb +0 -1974
  181. data/modules/mu/clouds/aws/endpoint.rb +0 -596
@@ -144,7 +144,7 @@ module MU
144
144
  # @param noop [Boolean]: If true, will only print what would be done
145
145
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
146
146
  # @return [void]
147
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
147
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
148
148
  flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
149
149
 
150
150
  resp = MU::Cloud::Google.storage(credentials: credentials).list_buckets(flags['habitat'])
@@ -243,7 +243,7 @@ module MU
243
243
  grantees[binding.role] << { "id" => grantee }
244
244
  elsif grantee.match(/^serviceAccount:(.*)/)
245
245
  sa_name = Regexp.last_match[1]
246
- if MU::Cloud::Google::User.cannedServiceAcctName?(sa_name)
246
+ if MU::Cloud.resourceClass("Google", "User").cannedServiceAcctName?(sa_name)
247
247
  grantees[binding.role] << { "id" => grantee }
248
248
  else
249
249
  grantees[binding.role] << MU::Config::Ref.get(
@@ -657,7 +657,7 @@ module MU
657
657
  end
658
658
 
659
659
  if bok['service_account']
660
- found = MU::Cloud::Google::User.find(
660
+ found = MU::Cloud.resourceClass("Google", "User").find(
661
661
  credentials: bok['credentials'],
662
662
  project: bok['project'],
663
663
  cloud_id: bok['service_account']
@@ -744,10 +744,10 @@ module MU
744
744
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
745
745
  # @param region [String]: The cloud provider region in which to operate
746
746
  # @return [void]
747
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
747
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
748
748
 
749
749
  flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
750
- return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
750
+ return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
751
751
  clusters = []
752
752
 
753
753
  # Make sure we catch regional *and* zone clusters
@@ -817,10 +817,10 @@ module MU
817
817
  "type" => "integer",
818
818
  "description" => "The number of local SSD disks to be attached to workers. See https://cloud.google.com/compute/docs/disks/local-ssd#local_ssd_limits"
819
819
  },
820
- "ssh_user" => MU::Cloud::Google::Server.schema(config)[1]["ssh_user"],
821
- "metadata" => MU::Cloud::Google::Server.schema(config)[1]["metadata"],
822
- "service_account" => MU::Cloud::Google::Server.schema(config)[1]["service_account"],
823
- "scopes" => MU::Cloud::Google::Server.schema(config)[1]["scopes"],
820
+ "ssh_user" => MU::Cloud.resourceClass("Google", "Server").schema(config)[1]["ssh_user"],
821
+ "metadata" => MU::Cloud.resourceClass("Google", "Server").schema(config)[1]["metadata"],
822
+ "service_account" => MU::Cloud.resourceClass("Google", "Server").schema(config)[1]["service_account"],
823
+ "scopes" => MU::Cloud.resourceClass("Google", "Server").schema(config)[1]["scopes"],
824
824
  "private_cluster" => {
825
825
  "description" => "Set a GKE cluster to be private, that is segregated into its own hidden VPC.",
826
826
  "type" => "object",
@@ -1021,6 +1021,25 @@ module MU
1021
1021
  cluster['ip_aliases'] = true
1022
1022
  end
1023
1023
 
1024
+ # try to stake out some nice /21s for our networking config
1025
+ if cluster['ip_aliases'] and cluster["vpc"] and cluster["vpc"]["id"]
1026
+ habarg = if cluster["vpc"]["habitat"] and cluster["vpc"]["habitat"]["id"]
1027
+ cluster["vpc"]["habitat"]["id"]
1028
+ else
1029
+ cluster["project"]
1030
+ end
1031
+ found = MU::MommaCat.findStray("Google", "vpcs", cloud_id: cluster["vpc"]["id"], credentials: cluster["credentials"], habitats: [habarg], dummy_ok: true)
1032
+ if found and found.size == 1
1033
+ myvpc = found.first
1034
+ # XXX this might not make sense with custom_subnet
1035
+ cluster['pod_ip_block'] ||= myvpc.getUnusedAddressBlock(max_bits: 21)
1036
+ cluster['services_ip_block'] ||= myvpc.getUnusedAddressBlock(exclude: [cluster['pod_ip_block']], max_bits: 21)
1037
+ if cluster['tpu']
1038
+ cluster['tpu_ip_block'] ||= myvpc.getUnusedAddressBlock(exclude: [cluster['pod_ip_block'], cluster['services_ip_block']], max_bits: 21)
1039
+ end
1040
+ end
1041
+ end
1042
+
1024
1043
  if cluster['service_account']
1025
1044
  cluster['service_account']['cloud'] = "Google"
1026
1045
  cluster['service_account']['habitat'] ||= MU::Config::Ref.get(
@@ -1032,11 +1051,7 @@ module MU
1032
1051
  if cluster['service_account']['name'] and
1033
1052
  !cluster['service_account']['id'] and
1034
1053
  !cluster['service_account']['deploy_id']
1035
- cluster['dependencies'] ||= []
1036
- cluster['dependencies'] << {
1037
- "type" => "user",
1038
- "name" => cluster['service_account']['name']
1039
- }
1054
+ MU::Config.addDependency(cluster, cluster['service_account']['name'], "user")
1040
1055
  end
1041
1056
  found = MU::Config::Ref.get(cluster['service_account'])
1042
1057
  # XXX verify that found.kitten fails when it's supposed to
@@ -1045,7 +1060,7 @@ module MU
1045
1060
  ok = false
1046
1061
  end
1047
1062
  else
1048
- cluster = MU::Cloud::Google::User.genericServiceAccount(cluster, configurator)
1063
+ cluster = MU::Cloud.resourceClass("Google", "User").genericServiceAccount(cluster, configurator)
1049
1064
  end
1050
1065
 
1051
1066
  if cluster['dependencies']
@@ -1141,7 +1156,7 @@ module MU
1141
1156
  end
1142
1157
  end
1143
1158
 
1144
- cluster['instance_type'] = MU::Cloud::Google::Server.validateInstanceType(cluster["instance_type"], cluster["region"], project: cluster['project'], credentials: cluster['credentials'])
1159
+ cluster['instance_type'] = MU::Cloud.resourceClass("Google", "Server").validateInstanceType(cluster["instance_type"], cluster["region"], project: cluster['project'], credentials: cluster['credentials'])
1145
1160
  ok = false if cluster['instance_type'].nil?
1146
1161
 
1147
1162
  if !MU::Master.kubectl
@@ -25,14 +25,7 @@ module MU
25
25
  @config["groomer"] = MU::Config.defaultGroomer unless @config["groomer"]
26
26
  @groomclass = MU::Groomer.loadGroomer(@config["groomer"])
27
27
 
28
- @mu_name ||=
29
- if @config and @config['engine'] and @config["engine"].match(/^sqlserver/)
30
- @deploy.getResourceName(@config["name"], max_length: 15)
31
- else
32
- @deploy.getResourceName(@config["name"], max_length: 63)
33
- end
34
-
35
- @mu_name.gsub(/(--|-$)/i, "").gsub(/(_)/, "-").gsub!(/^[^a-z]/i, "")
28
+ @mu_name ||= @deploy.getResourceName(@config["name"], max_length: 63)
36
29
  end
37
30
 
38
31
  # Called automatically by {MU::Deploy#createResources}
@@ -107,7 +100,7 @@ module MU
107
100
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
108
101
  # @param region [String]: The cloud provider region in which to operate
109
102
  # @return [void]
110
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
103
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
111
104
  flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
112
105
 
113
106
  # instances = MU::Cloud::Google.sql(credentials: credentials).list_instances(flags['habitat'], filter: %Q{userLabels.mu-id:"#{MU.deploy_id.downcase}"})
@@ -207,9 +207,9 @@ end
207
207
  # @param noop [Boolean]: If true, will only print what would be done
208
208
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
209
209
  # @return [void]
210
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
210
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
211
211
  flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
212
- return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
212
+ return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
213
213
  filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
214
214
  if !ignoremaster and MU.mu_public_ip
215
215
  filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
@@ -440,7 +440,7 @@ end
440
440
  elsif acl['vpc']['habitat'] and acl['vpc']['habitat']['name']
441
441
  acl['vpc']['project'] = acl['vpc']['habitat']['name']
442
442
  end
443
- correct_vpc = MU::Cloud::Google::VPC.pickVPC(
443
+ correct_vpc = MU::Cloud.resourceClass("Google", "VPC").pickVPC(
444
444
  acl['vpc'],
445
445
  acl,
446
446
  "firewall_rule",
@@ -138,7 +138,7 @@ module MU
138
138
  # Return the metadata for this folders's configuration
139
139
  # @return [Hash]
140
140
  def notify
141
- desc = MU.structToHash(MU::Cloud::Google.folder(credentials: @config['credentials']).get_folder("folders/"+@cloud_id))
141
+ desc = MU.structToHash(cloud_desc)
142
142
  desc["mu_name"] = @mu_name
143
143
  desc["parent"] = @parent
144
144
  desc["cloud_id"] = @cloud_id
@@ -162,7 +162,7 @@ module MU
162
162
  # @param noop [Boolean]: If true, will only print what would be done
163
163
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
164
164
  # @return [void]
165
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
165
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
166
166
  filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
167
167
  if !ignoremaster and MU.mu_public_ip
168
168
  filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
@@ -236,10 +236,10 @@ module MU
236
236
  # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching resources
237
237
  def self.find(**args)
238
238
  found = {}
239
-
240
239
  # Recursively search a GCP folder hierarchy for a folder matching our
241
240
  # supplied name or identifier.
242
241
  def self.find_matching_folder(parent, name: nil, id: nil, credentials: nil)
242
+
243
243
  resp = MU::Cloud::Google.folder(credentials: credentials).list_folders(parent: parent)
244
244
  if resp and resp.folders
245
245
  resp.folders.each { |f|
@@ -278,6 +278,7 @@ module MU
278
278
  end
279
279
  else
280
280
  resp = MU::Cloud::Google.folder(credentials: args[:credentials]).list_folders(parent: parent)
281
+
281
282
  if resp and resp.folders
282
283
  resp.folders.each { |folder|
283
284
  next if folder.lifecycle_state == "DELETE_REQUESTED"
@@ -310,7 +311,6 @@ module MU
310
311
  bok['cloud_id'] = cloud_desc.name
311
312
  bok['name'] = cloud_desc.display_name#+bok['cloud_id'] # only way to guarantee uniqueness
312
313
  if cloud_desc.parent.match(/^folders\/(.*)/)
313
- MU.log bok['display_name']+" generating reference", MU::NOTICE, details: cloud_desc.parent
314
314
  bok['parent'] = MU::Config::Ref.get(
315
315
  id: cloud_desc.parent,
316
316
  cloud: "Google",
@@ -355,11 +355,7 @@ MU.log bok['display_name']+" generating reference", MU::NOTICE, details: cloud_d
355
355
  end
356
356
 
357
357
  if folder['parent'] and folder['parent']['name'] and !folder['parent']['deploy_id'] and configurator.haveLitterMate?(folder['parent']['name'], "folders")
358
- folder["dependencies"] ||= []
359
- folder["dependencies"] << {
360
- "type" => "folder",
361
- "name" => folder['parent']['name']
362
- }
358
+ MU::Config.addDependency(folder, folder['parent']['name'], "folder")
363
359
  end
364
360
 
365
361
  ok
@@ -233,9 +233,9 @@ module example.com/cloudfunction
233
233
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
234
234
  # @param region [String]: The cloud provider region
235
235
  # @return [void]
236
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
236
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
237
237
  flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
238
- return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
238
+ return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
239
239
  # Make sure we catch regional *and* zone functions
240
240
  found = MU::Cloud::Google::Function.find(credentials: credentials, region: region, project: flags["habitat"])
241
241
  found.each_pair { |cloud_id, desc|
@@ -373,7 +373,7 @@ module example.com/cloudfunction
373
373
  }
374
374
  }
375
375
  },
376
- "service_account" => MU::Cloud::Google::Server.schema(config)[1]["service_account"],
376
+ "service_account" => MU::Cloud.resourceClass("Google", "Server").schema(config)[1]["service_account"],
377
377
  "runtime" => {
378
378
  "type" => "string",
379
379
  "enum" => %w{nodejs go python nodejs8 nodejs10 python37 go111 go113},
@@ -524,7 +524,7 @@ module example.com/cloudfunction
524
524
  ok = false
525
525
  end
526
526
  else
527
- function = MU::Cloud::Google::User.genericServiceAccount(function, configurator)
527
+ function = MU::Cloud.resourceClass("Google", "User").genericServiceAccount(function, configurator)
528
528
  end
529
529
 
530
530
  # siblings = configurator.haveLitterMate?(nil, "vpcs", has_multiple: true)
@@ -44,7 +44,7 @@ module MU
44
44
  resp = MU::Cloud::Google.admin_directory(credentials: @credentials).insert_group(group_obj)
45
45
  @cloud_id = resp.email
46
46
 
47
- MU::Cloud::Google::Role.bindFromConfig("group", @cloud_id, @config['roles'], credentials: @config['credentials'])
47
+ MU::Cloud.resourceClass("Google", "Role").bindFromConfig("group", @cloud_id, @config['roles'], credentials: @config['credentials'])
48
48
  else
49
49
  @cloud_id = @config['name'].sub(/@.*/, "")+"@"+@config['domain']
50
50
  end
@@ -52,7 +52,7 @@ module MU
52
52
 
53
53
  # Called automatically by {MU::Deploy#createResources}
54
54
  def groom
55
- MU::Cloud::Google::Role.bindFromConfig("group", @cloud_id, @config['roles'], credentials: @config['credentials'], debug: true)
55
+ MU::Cloud.resourceClass("Google", "Role").bindFromConfig("group", @cloud_id, @config['roles'], credentials: @config['credentials'], debug: true)
56
56
 
57
57
  if @config['members']
58
58
  resolved_desired = []
@@ -140,7 +140,7 @@ module MU
140
140
  # @param noop [Boolean]: If true, will only print what would be done
141
141
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
142
142
  # @return [void]
143
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
143
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
144
144
  MU::Cloud::Google.getDomains(credentials)
145
145
  my_org = MU::Cloud::Google.getOrg(credentials)
146
146
 
@@ -166,7 +166,7 @@ module MU
166
166
 
167
167
  if flags['known']
168
168
  flags['known'].each { |group|
169
- MU::Cloud::Google::Role.removeBindings("group", group, credentials: credentials, noop: noop)
169
+ MU::Cloud.resourceClass("Google", "Role").removeBindings("group", group, credentials: credentials, noop: noop)
170
170
  }
171
171
  end
172
172
  end
@@ -222,10 +222,10 @@ module MU
222
222
  # type: "users"
223
223
  # )
224
224
  # }
225
- group_roles = MU::Cloud::Google::Role.getAllBindings(@config['credentials'])["by_entity"]
225
+ group_roles = MU::Cloud.resourceClass("Google", "Role").getAllBindings(@config['credentials'])["by_entity"]
226
226
  if group_roles["group"] and group_roles["group"][bok['cloud_id']] and
227
227
  group_roles["group"][bok['cloud_id']].size > 0
228
- bok['roles'] = MU::Cloud::Google::Role.entityBindingsToSchema(group_roles["group"][bok['cloud_id']], credentials: @config['credentials'])
228
+ bok['roles'] = MU::Cloud.resourceClass("Google", "Role").entityBindingsToSchema(group_roles["group"][bok['cloud_id']], credentials: @config['credentials'])
229
229
  end
230
230
 
231
231
  bok
@@ -264,7 +264,7 @@ If we are binding (rather than creating) a group and no roles are specified, we
264
264
 
265
265
  "roles" => {
266
266
  "type" => "array",
267
- "items" => MU::Cloud::Google::Role.ref_schema
267
+ "items" => MU::Cloud.resourceClass("Google", "Role").ref_schema
268
268
  }
269
269
  }
270
270
  [toplevel_required, schema]
@@ -340,11 +340,7 @@ If we are binding (rather than creating) a group and no roles are specified, we
340
340
  if group['members']
341
341
  group['members'].each { |m|
342
342
  if configurator.haveLitterMate?(m, "users")
343
- group['dependencies'] ||= []
344
- group['dependencies'] << {
345
- "name" => m,
346
- "type" => "user"
347
- }
343
+ MU::Config.addDependency(group, m, "user")
348
344
  end
349
345
  }
350
346
  end
@@ -353,11 +349,7 @@ If we are binding (rather than creating) a group and no roles are specified, we
353
349
  group['roles'].each { |r|
354
350
  if r['role'] and r['role']['name'] and
355
351
  (!r['role']['deploy_id'] and !r['role']['id'])
356
- group['dependencies'] ||= []
357
- group['dependencies'] << {
358
- "type" => "role",
359
- "name" => r['role']['name']
360
- }
352
+ MU::Config.addDependency(group, r['role']['name'], "role")
361
353
  end
362
354
  }
363
355
  end
@@ -61,7 +61,7 @@ module MU
61
61
  if @config['parent']['name'] and !@config['parent']['id']
62
62
  @config['parent']['deploy_id'] = @deploy.deploy_id
63
63
  end
64
- parent = MU::Cloud::Google::Folder.resolveParent(@config['parent'], credentials: @config['credentials'])
64
+ parent = MU::Cloud.resourceClass("Google", "Folder").resolveParent(@config['parent'], credentials: @config['credentials'])
65
65
  if !parent
66
66
  MU.log "Unable to resolve parent resource of Google Project #{@config['name']}", MU::ERR, details: @config['parent']
67
67
  raise "Unable to resolve parent resource of Google Project #{@config['name']}"
@@ -222,7 +222,7 @@ module MU
222
222
  # @param noop [Boolean]: If true, will only print what would be done
223
223
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
224
224
  # @return [void]
225
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
225
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
226
226
  resp = MU::Cloud::Google.resource_manager(credentials: credentials).list_projects
227
227
 
228
228
  if resp and resp.projects
@@ -285,7 +285,7 @@ module MU
285
285
  next if p.lifecycle_state == "DELETE_REQUESTED"
286
286
  found[p.project_id] = p
287
287
  }
288
- @@list_projects_cache = found
288
+ @@list_projects_cache = found.clone
289
289
  end
290
290
 
291
291
  found
@@ -376,11 +376,7 @@ module MU
376
376
  end
377
377
 
378
378
  if habitat['parent'] and habitat['parent']['name'] and !habitat['parent']['deploy_id'] and configurator.haveLitterMate?(habitat['parent']['name'], "folders")
379
- habitat["dependencies"] ||= []
380
- habitat["dependencies"] << {
381
- "type" => "folder",
382
- "name" => habitat['parent']['name']
383
- }
379
+ MU::Config.addDependency(habitat, habitat['parent']['name'], "folder")
384
380
  end
385
381
 
386
382
  ok
@@ -146,9 +146,9 @@ module MU
146
146
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
147
147
  # @param region [String]: The cloud provider region
148
148
  # @return [void]
149
- def self.cleanup(noop: false, ignoremaster: false, region: nil, credentials: nil, flags: {})
149
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: nil, credentials: nil, flags: {})
150
150
  flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
151
- return if !MU::Cloud::Google::Habitat.isLive?(flags["habitat"], credentials)
151
+ return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
152
152
  filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
153
153
  if !ignoremaster and MU.mu_public_ip
154
154
  filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
@@ -271,13 +271,13 @@ module MU
271
271
  my_org = MU::Cloud::Google.getOrg(credentials)
272
272
  if my_org
273
273
  scopes["organizations"] = [my_org.name]
274
- folders = MU::Cloud::Google::Folder.find(credentials: credentials)
274
+ folders = MU::Cloud.resourceClass("Google", "Folder").find(credentials: credentials)
275
275
  if folders and folders.size > 0
276
276
  scopes["folders"] = folders.keys
277
277
  end
278
278
  end
279
279
 
280
- projects = MU::Cloud::Google::Habitat.find(credentials: credentials)
280
+ projects = MU::Cloud.resourceClass("Google", "Habitat").find(credentials: credentials)
281
281
  if projects and projects.size > 0
282
282
  scopes["projects"] = projects.keys
283
283
  end
@@ -407,12 +407,12 @@ module MU
407
407
  # email field (which is the "real" id most of the time)
408
408
  real_id = nil
409
409
  if entity_type == "group"
410
- found = MU::Cloud::Google::Group.find(cloud_id: entity_id, credentials: credentials)
410
+ found = MU::Cloud.resourceClass("Google", "Group").find(cloud_id: entity_id, credentials: credentials)
411
411
  if found[entity_id]
412
412
  real_id = found[entity_id].id
413
413
  end
414
414
  elsif entity_type == "user"
415
- found = MU::Cloud::Google::User.find(cloud_id: entity_id, credentials: credentials)
415
+ found = MU::Cloud.resourceClass("Google", "User").find(cloud_id: entity_id, credentials: credentials)
416
416
  if found[entity_id]
417
417
  real_id = found[entity_id].id
418
418
  end
@@ -465,7 +465,7 @@ module MU
465
465
  # @param noop [Boolean]: If true, will only print what would be done
466
466
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
467
467
  # @return [void]
468
- def self.cleanup(noop: false, ignoremaster: false, credentials: nil, flags: {})
468
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
469
469
  customer = MU::Cloud::Google.customerID(credentials)
470
470
  my_org = MU::Cloud::Google.getOrg(credentials)
471
471
 
@@ -563,7 +563,7 @@ module MU
563
563
  if args[:project]
564
564
  canned = Hash[MU::Cloud::Google.iam(credentials: args[:credentials]).list_roles.roles.map { |r| [r.name, r] }]
565
565
  begin
566
- MU::Cloud::Google::Habitat.bindings(args[:project], credentials: args[:credentials]).each { |binding|
566
+ MU::Cloud.resourceClass("Google", "Habitat").bindings(args[:project], credentials: args[:credentials]).each { |binding|
567
567
  found[binding.role] = canned[binding.role]
568
568
  }
569
569
  rescue ::Google::Apis::ClientError => e
@@ -591,10 +591,15 @@ module MU
591
591
  bindings['by_scope']['projects'][args[:project]]
592
592
  bindings['by_scope']['projects'][args[:project]].keys.each { |r|
593
593
  if r.match(/^roles\//)
594
- role = MU::Cloud::Google.iam(credentials: args[:credentials]).get_role(r)
595
- found[role.name] = role
594
+ begin
595
+ role = MU::Cloud::Google.iam(credentials: args[:credentials]).get_role(r)
596
+ found[role.name] = role
597
+ rescue ::Google::Apis::ClientError => e
598
+ raise e if !e.message.match(/(?:forbidden|notFound): /)
599
+ MU.log "Failed MU::Cloud::Google.iam(credentials: #{args[:credentials]}).get_role(#{r})", MU::WARN, details: e.message
600
+ end
596
601
  elsif !found[r]
597
- MU.log "NEED TO GET #{r}", MU::WARN
602
+ # MU.log "NEED TO GET #{r}", MU::WARN
598
603
  end
599
604
  }
600
605
  end
@@ -688,7 +693,7 @@ module MU
688
693
  ids, _names, _privs = MU::Cloud::Google::Role.privilege_service_to_name(@config['credentials'])
689
694
  cloud_desc.role_privileges.each { |priv|
690
695
  if !ids[priv.service_id]
691
- MU.log "Role privilege defined for a service id with no name I can find, writing with raw id", MU::WARN, details: priv
696
+ MU.log "Role privilege defined for a service id with no name I can find, writing with raw id", MU::DEBUG, details: priv
692
697
  bok["import"] << priv.service_id+"/"+priv.privilege_name
693
698
  else
694
699
  bok["import"] << ids[priv.service_id]+"/"+priv.privilege_name
@@ -740,25 +745,36 @@ module MU
740
745
  end
741
746
 
742
747
  entity_types.each_pair { |entity_type, entities|
748
+ next if entity_type == "deleted"
743
749
  mu_entitytype = (entity_type == "serviceAccount" ? "user" : entity_type)+"s"
744
750
  entities.each { |entity|
751
+ next if entity.nil?
745
752
  foreign = if entity_type == "serviceAccount" and entity.match(/@(.*?)\.iam\.gserviceaccount\.com/)
746
753
  !MU::Cloud::Google.listHabitats(@credentials).include?(Regexp.last_match[1])
747
754
  end
755
+
748
756
  entity_ref = if entity_type == "organizations"
749
757
  { "id" => ((org == my_org.name and @config['credentials']) ? @config['credentials'] : org) }
750
758
  elsif entity_type == "domain"
751
759
  { "id" => entity }
752
760
  else
753
- if foreign
754
- { "id" => entity }
755
- else
756
- MU::Config::Ref.get(
757
- id: entity,
758
- cloud: "Google",
759
- type: mu_entitytype
760
- )
761
+ shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(mu_entitytype)
762
+ if args[:types].include?(shortclass) and
763
+ !(entity_type == "serviceAccount" and
764
+ MU::Cloud::Google::User.cannedServiceAcctName?(entity))
765
+ MU.log "Role #{@cloud_id}: Skipping #{shortclass} binding for #{entity}; we are adopting that type and will set bindings from that resource", MU::DEBUG
766
+ next
761
767
  end
768
+
769
+ MU::Config::Ref.get(
770
+ id: entity,
771
+ cloud: "Google",
772
+ type: mu_entitytype
773
+ )
774
+ end
775
+ if entity_ref.nil?
776
+ MU.log "I somehow ended up with a nil entity reference for #{entity_type} #{entity}", MU::ERR, details: [ bok, bindings ]
777
+ next
762
778
  end
763
779
  refmap ||= {}
764
780
  refmap[entity_ref] ||= {}
@@ -778,6 +794,7 @@ module MU
778
794
  }
779
795
  }
780
796
  }
797
+
781
798
  bok["bindings"] ||= []
782
799
  refmap.each_pair { |entity, scopes|
783
800
  newbinding = { "entity" => entity }
@@ -900,7 +917,7 @@ module MU
900
917
  end
901
918
 
902
919
  role = MU::Cloud::Google.admin_directory(credentials: credentials).get_role(MU::Cloud::Google.customerID(credentials), binding.role_id)
903
- MU.log "Failed to find entity #{binding.assigned_to} referenced in GSuite/Cloud Identity binding to role #{role.role_name}", MU::WARN, details: role
920
+ MU.log "Failed to find entity #{binding.assigned_to} referenced in GSuite/Cloud Identity binding to role #{role.role_name}", MU::DEBUG, details: role
904
921
  }
905
922
 
906
923
  resp = MU::Cloud::Google.resource_manager(credentials: credentials).get_organization_iam_policy(my_org.name)
@@ -908,15 +925,17 @@ module MU
908
925
  insertBinding("organizations", my_org.name, binding)
909
926
  }
910
927
 
911
- MU::Cloud::Google::Folder.find(credentials: credentials).keys.each { |folder|
912
- MU::Cloud::Google::Folder.bindings(folder, credentials: credentials).each { |binding|
928
+ MU::Cloud.resourceClass("Google", "Folder").find(credentials: credentials).keys.each { |folder|
929
+ folder_bindings = MU::Cloud.resourceClass("Google", "Folder").bindings(folder, credentials: credentials)
930
+ next if !folder_bindings
931
+ folder_bindings.each { |binding|
913
932
  insertBinding("folders", folder, binding)
914
933
  }
915
934
  }
916
935
  end
917
- MU::Cloud::Google::Habitat.find(credentials: credentials).keys.each { |project|
936
+ MU::Cloud::Google.listHabitats(credentials).each { |project|
918
937
  begin
919
- MU::Cloud::Google::Habitat.bindings(project, credentials: credentials).each { |binding|
938
+ MU::Cloud.resourceClass("Google", "Habitat").bindings(project, credentials: credentials).each { |binding|
920
939
  insertBinding("projects", project, binding)
921
940
  }
922
941
  rescue ::Google::Apis::ClientError => e
@@ -1099,7 +1118,7 @@ If this value is not specified, and the role name matches the name of an existin
1099
1118
  MU.log "None of the directory service privileges available to credentials #{role['credentials']} map to the ones declared for role #{role['name']}", MU::ERR, details: role['import'].sort
1100
1119
  ok = false
1101
1120
  elsif missing.size > 0
1102
- MU.log "Some directory service privileges declared for role #{role['name']} aren't available to credentials #{role['credentials']}, will skip", MU::WARN, details: missing
1121
+ MU.log "Some directory service privileges declared for role #{role['name']} aren't available to credentials #{role['credentials']}, will skip", MU::DEBUG, details: missing
1103
1122
  end
1104
1123
  end
1105
1124
  end
@@ -1114,11 +1133,7 @@ If this value is not specified, and the role name matches the name of an existin
1114
1133
  if role['role_source'] == "project"
1115
1134
  role['project'] ||= MU::Cloud::Google.defaultProject(role['credentials'])
1116
1135
  if configurator.haveLitterMate?(role['project'], "habitats")
1117
- role['dependencies'] ||= []
1118
- role['dependencies'] << {
1119
- "type" => "habitat",
1120
- "name" => role['project']
1121
- }
1136
+ MU::Config.addDependency(role, role['project'], "habitat")
1122
1137
  end
1123
1138
  end
1124
1139
 
@@ -1126,14 +1141,10 @@ If this value is not specified, and the role name matches the name of an existin
1126
1141
  role['bindings'].each { |binding|
1127
1142
  if binding['entity'] and binding['entity']['name'] and
1128
1143
  configurator.haveLitterMate?(binding['entity']['name'], binding['entity']['type'])
1129
- role['dependencies'] ||= []
1130
- role['dependencies'] << {
1131
- "type" => binding['entity']['type'].sub(/s$/, ''),
1132
- "name" => binding['entity']['name']
1133
- }
1134
-
1144
+ MU::Config.addDependency(role, binding['entity']['name'], binding['entity']['type'])
1135
1145
  end
1136
1146
  }
1147
+ role['bindings'].uniq!
1137
1148
  end
1138
1149
 
1139
1150
  ok