cloud-mu 3.1.3 → 3.3.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 (212) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +15 -3
  3. data/ansible/roles/mu-windows/README.md +33 -0
  4. data/ansible/roles/mu-windows/defaults/main.yml +2 -0
  5. data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
  6. data/ansible/roles/mu-windows/files/config.xml +76 -0
  7. data/ansible/roles/mu-windows/handlers/main.yml +2 -0
  8. data/ansible/roles/mu-windows/meta/main.yml +53 -0
  9. data/ansible/roles/mu-windows/tasks/main.yml +36 -0
  10. data/ansible/roles/mu-windows/tests/inventory +2 -0
  11. data/ansible/roles/mu-windows/tests/test.yml +5 -0
  12. data/ansible/roles/mu-windows/vars/main.yml +2 -0
  13. data/bin/mu-adopt +21 -13
  14. data/bin/mu-azure-tests +57 -0
  15. data/bin/mu-cleanup +2 -4
  16. data/bin/mu-configure +52 -0
  17. data/bin/mu-deploy +3 -3
  18. data/bin/mu-findstray-tests +25 -0
  19. data/bin/mu-gen-docs +2 -4
  20. data/bin/mu-load-config.rb +4 -4
  21. data/bin/mu-node-manage +15 -16
  22. data/bin/mu-run-tests +147 -37
  23. data/cloud-mu.gemspec +22 -20
  24. data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
  25. data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
  26. data/cookbooks/mu-tools/libraries/helper.rb +3 -2
  27. data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
  28. data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
  29. data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
  30. data/cookbooks/mu-tools/recipes/eks.rb +2 -2
  31. data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
  32. data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
  33. data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
  34. data/cookbooks/mu-tools/resources/disk.rb +1 -1
  35. data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
  36. data/extras/clean-stock-amis +25 -19
  37. data/extras/generate-stock-images +1 -0
  38. data/extras/image-generators/AWS/win2k12.yaml +18 -13
  39. data/extras/image-generators/AWS/win2k16.yaml +18 -13
  40. data/extras/image-generators/AWS/win2k19.yaml +21 -0
  41. data/extras/image-generators/Google/centos6.yaml +1 -0
  42. data/extras/image-generators/Google/centos7.yaml +1 -1
  43. data/modules/mommacat.ru +6 -16
  44. data/modules/mu.rb +158 -111
  45. data/modules/mu/adoption.rb +404 -71
  46. data/modules/mu/cleanup.rb +221 -306
  47. data/modules/mu/cloud.rb +129 -1633
  48. data/modules/mu/cloud/database.rb +49 -0
  49. data/modules/mu/cloud/dnszone.rb +44 -0
  50. data/modules/mu/cloud/machine_images.rb +212 -0
  51. data/modules/mu/cloud/providers.rb +81 -0
  52. data/modules/mu/cloud/resource_base.rb +926 -0
  53. data/modules/mu/cloud/server.rb +40 -0
  54. data/modules/mu/cloud/server_pool.rb +1 -0
  55. data/modules/mu/cloud/ssh_sessions.rb +228 -0
  56. data/modules/mu/cloud/winrm_sessions.rb +237 -0
  57. data/modules/mu/cloud/wrappers.rb +169 -0
  58. data/modules/mu/config.rb +171 -1767
  59. data/modules/mu/config/alarm.rb +2 -6
  60. data/modules/mu/config/bucket.rb +32 -3
  61. data/modules/mu/config/cache_cluster.rb +2 -2
  62. data/modules/mu/config/cdn.rb +100 -0
  63. data/modules/mu/config/collection.rb +4 -4
  64. data/modules/mu/config/container_cluster.rb +9 -4
  65. data/modules/mu/config/database.rb +84 -105
  66. data/modules/mu/config/database.yml +1 -2
  67. data/modules/mu/config/dnszone.rb +10 -9
  68. data/modules/mu/config/doc_helpers.rb +516 -0
  69. data/modules/mu/config/endpoint.rb +5 -4
  70. data/modules/mu/config/firewall_rule.rb +103 -4
  71. data/modules/mu/config/folder.rb +4 -4
  72. data/modules/mu/config/function.rb +19 -10
  73. data/modules/mu/config/group.rb +4 -4
  74. data/modules/mu/config/habitat.rb +4 -4
  75. data/modules/mu/config/job.rb +89 -0
  76. data/modules/mu/config/loadbalancer.rb +60 -14
  77. data/modules/mu/config/log.rb +4 -4
  78. data/modules/mu/config/msg_queue.rb +4 -4
  79. data/modules/mu/config/nosqldb.rb +4 -4
  80. data/modules/mu/config/notifier.rb +10 -21
  81. data/modules/mu/config/ref.rb +411 -0
  82. data/modules/mu/config/role.rb +4 -4
  83. data/modules/mu/config/schema_helpers.rb +509 -0
  84. data/modules/mu/config/search_domain.rb +4 -4
  85. data/modules/mu/config/server.rb +98 -71
  86. data/modules/mu/config/server.yml +1 -0
  87. data/modules/mu/config/server_pool.rb +5 -9
  88. data/modules/mu/config/storage_pool.rb +1 -1
  89. data/modules/mu/config/tail.rb +200 -0
  90. data/modules/mu/config/user.rb +4 -4
  91. data/modules/mu/config/vpc.rb +71 -27
  92. data/modules/mu/config/vpc.yml +0 -1
  93. data/modules/mu/defaults/AWS.yaml +91 -68
  94. data/modules/mu/defaults/Azure.yaml +1 -0
  95. data/modules/mu/defaults/Google.yaml +3 -2
  96. data/modules/mu/deploy.rb +43 -26
  97. data/modules/mu/groomer.rb +17 -2
  98. data/modules/mu/groomers/ansible.rb +188 -41
  99. data/modules/mu/groomers/chef.rb +116 -55
  100. data/modules/mu/logger.rb +127 -148
  101. data/modules/mu/master.rb +410 -2
  102. data/modules/mu/master/chef.rb +3 -4
  103. data/modules/mu/master/ldap.rb +3 -3
  104. data/modules/mu/master/ssl.rb +12 -3
  105. data/modules/mu/mommacat.rb +218 -2612
  106. data/modules/mu/mommacat/daemon.rb +403 -0
  107. data/modules/mu/mommacat/naming.rb +473 -0
  108. data/modules/mu/mommacat/search.rb +495 -0
  109. data/modules/mu/mommacat/storage.rb +722 -0
  110. data/modules/mu/{clouds → providers}/README.md +1 -1
  111. data/modules/mu/{clouds → providers}/aws.rb +380 -122
  112. data/modules/mu/{clouds → providers}/aws/alarm.rb +7 -5
  113. data/modules/mu/{clouds → providers}/aws/bucket.rb +297 -59
  114. data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +37 -71
  115. data/modules/mu/providers/aws/cdn.rb +782 -0
  116. data/modules/mu/{clouds → providers}/aws/collection.rb +26 -25
  117. data/modules/mu/{clouds → providers}/aws/container_cluster.rb +724 -744
  118. data/modules/mu/providers/aws/database.rb +1744 -0
  119. data/modules/mu/{clouds → providers}/aws/dnszone.rb +88 -70
  120. data/modules/mu/providers/aws/endpoint.rb +1072 -0
  121. data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +220 -247
  122. data/modules/mu/{clouds → providers}/aws/folder.rb +8 -8
  123. data/modules/mu/{clouds → providers}/aws/function.rb +300 -142
  124. data/modules/mu/{clouds → providers}/aws/group.rb +31 -29
  125. data/modules/mu/{clouds → providers}/aws/habitat.rb +18 -15
  126. data/modules/mu/providers/aws/job.rb +466 -0
  127. data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +66 -56
  128. data/modules/mu/{clouds → providers}/aws/log.rb +17 -14
  129. data/modules/mu/{clouds → providers}/aws/msg_queue.rb +29 -19
  130. data/modules/mu/{clouds → providers}/aws/nosqldb.rb +114 -16
  131. data/modules/mu/{clouds → providers}/aws/notifier.rb +142 -65
  132. data/modules/mu/{clouds → providers}/aws/role.rb +158 -118
  133. data/modules/mu/{clouds → providers}/aws/search_domain.rb +201 -59
  134. data/modules/mu/{clouds → providers}/aws/server.rb +844 -1139
  135. data/modules/mu/{clouds → providers}/aws/server_pool.rb +74 -65
  136. data/modules/mu/{clouds → providers}/aws/storage_pool.rb +26 -44
  137. data/modules/mu/{clouds → providers}/aws/user.rb +24 -25
  138. data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
  139. data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
  140. data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
  141. data/modules/mu/{clouds → providers}/aws/vpc.rb +525 -931
  142. data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
  143. data/modules/mu/{clouds → providers}/azure.rb +29 -9
  144. data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
  145. data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
  146. data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
  147. data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
  148. data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
  149. data/modules/mu/{clouds → providers}/azure/server.rb +97 -49
  150. data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
  151. data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
  152. data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
  153. data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
  154. data/modules/mu/{clouds → providers}/azure/vpc.rb +16 -21
  155. data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
  156. data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
  157. data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
  158. data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
  159. data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
  160. data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
  161. data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
  162. data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
  163. data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
  164. data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
  165. data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
  166. data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +5 -7
  167. data/modules/mu/{clouds → providers}/docker.rb +0 -0
  168. data/modules/mu/{clouds → providers}/google.rb +68 -30
  169. data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
  170. data/modules/mu/{clouds → providers}/google/container_cluster.rb +85 -78
  171. data/modules/mu/{clouds → providers}/google/database.rb +11 -21
  172. data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
  173. data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
  174. data/modules/mu/{clouds → providers}/google/function.rb +140 -168
  175. data/modules/mu/{clouds → providers}/google/group.rb +29 -34
  176. data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
  177. data/modules/mu/{clouds → providers}/google/loadbalancer.rb +19 -21
  178. data/modules/mu/{clouds → providers}/google/role.rb +94 -58
  179. data/modules/mu/{clouds → providers}/google/server.rb +243 -156
  180. data/modules/mu/{clouds → providers}/google/server_pool.rb +26 -45
  181. data/modules/mu/{clouds → providers}/google/user.rb +95 -31
  182. data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
  183. data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
  184. data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
  185. data/modules/mu/{clouds → providers}/google/vpc.rb +103 -79
  186. data/modules/tests/aws-jobs-functions.yaml +46 -0
  187. data/modules/tests/bucket.yml +4 -0
  188. data/modules/tests/centos6.yaml +15 -0
  189. data/modules/tests/centos7.yaml +15 -0
  190. data/modules/tests/centos8.yaml +12 -0
  191. data/modules/tests/ecs.yaml +23 -0
  192. data/modules/tests/eks.yaml +1 -1
  193. data/modules/tests/functions/node-function/lambda_function.js +10 -0
  194. data/modules/tests/functions/python-function/lambda_function.py +12 -0
  195. data/modules/tests/includes-and-params.yaml +2 -1
  196. data/modules/tests/microservice_app.yaml +288 -0
  197. data/modules/tests/rds.yaml +108 -0
  198. data/modules/tests/regrooms/aws-iam.yaml +201 -0
  199. data/modules/tests/regrooms/bucket.yml +19 -0
  200. data/modules/tests/regrooms/rds.yaml +123 -0
  201. data/modules/tests/server-with-scrub-muisms.yaml +2 -1
  202. data/modules/tests/super_complex_bok.yml +2 -2
  203. data/modules/tests/super_simple_bok.yml +3 -5
  204. data/modules/tests/win2k12.yaml +17 -5
  205. data/modules/tests/win2k16.yaml +25 -0
  206. data/modules/tests/win2k19.yaml +25 -0
  207. data/requirements.txt +1 -0
  208. data/spec/mu/clouds/azure_spec.rb +2 -2
  209. metadata +240 -154
  210. data/extras/image-generators/AWS/windows.yaml +0 -18
  211. data/modules/mu/clouds/aws/database.rb +0 -1985
  212. data/modules/mu/clouds/aws/endpoint.rb +0 -592
@@ -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 = []
@@ -139,12 +139,17 @@ module MU
139
139
  # Remove all groups associated with the currently loaded deployment.
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
- # @param region [String]: The cloud provider region
143
142
  # @return [void]
144
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
145
- my_domains = MU::Cloud::Google.getDomains(credentials)
143
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
144
+ MU::Cloud::Google.getDomains(credentials)
146
145
  my_org = MU::Cloud::Google.getOrg(credentials)
147
146
 
147
+ filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
148
+ if !ignoremaster and MU.mu_public_ip
149
+ filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
150
+ end
151
+ MU.log "Placeholder: Google Group artifacts do not support labels, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: filter
152
+
148
153
  if my_org
149
154
  groups = MU::Cloud::Google.admin_directory(credentials: credentials).list_groups(customer: MU::Cloud::Google.customerID(credentials)).groups
150
155
  if groups
@@ -161,7 +166,7 @@ module MU
161
166
 
162
167
  if flags['known']
163
168
  flags['known'].each { |group|
164
- MU::Cloud::Google::Role.removeBindings("group", group, credentials: credentials, noop: noop)
169
+ MU::Cloud.resourceClass("Google", "Role").removeBindings("group", group, credentials: credentials, noop: noop)
165
170
  }
166
171
  end
167
172
  end
@@ -199,7 +204,7 @@ module MU
199
204
  # Reverse-map our cloud description into a runnable config hash.
200
205
  # We assume that any values we have in +@config+ are placeholders, and
201
206
  # calculate our own accordingly based on what's live in the cloud.
202
- def toKitten(rootparent: nil, billing: nil, habitats: nil)
207
+ def toKitten(**_args)
203
208
 
204
209
  bok = {
205
210
  "cloud" => "Google",
@@ -208,28 +213,28 @@ module MU
208
213
 
209
214
  bok['name'] = cloud_desc.name
210
215
  bok['cloud_id'] = cloud_desc.email
211
- bok['members'] = members
212
- bok['members'].each { |m|
213
- m = MU::Config::Ref.get(
214
- id: m,
215
- cloud: "Google",
216
- credentials: @config['credentials'],
217
- type: "users"
218
- )
219
- }
220
- group_roles = MU::Cloud::Google::Role.getAllBindings(@config['credentials'])["by_entity"]
216
+ bok['members'] = members.dup
217
+ # bok['members'] = members.map { |m|
218
+ # MU::Config::Ref.get(
219
+ # id: m,
220
+ # cloud: "Google",
221
+ # credentials: @config['credentials'],
222
+ # type: "users"
223
+ # )
224
+ # }
225
+ group_roles = MU::Cloud.resourceClass("Google", "Role").getAllBindings(@config['credentials'])["by_entity"]
221
226
  if group_roles["group"] and group_roles["group"][bok['cloud_id']] and
222
227
  group_roles["group"][bok['cloud_id']].size > 0
223
- 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'])
224
229
  end
225
230
 
226
231
  bok
227
232
  end
228
233
 
229
234
  # Cloud-specific configuration properties.
230
- # @param config [MU::Config]: The calling MU::Config object
235
+ # @param _config [MU::Config]: The calling MU::Config object
231
236
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
232
- def self.schema(config)
237
+ def self.schema(_config)
233
238
  toplevel_required = []
234
239
  schema = {
235
240
  "name" => {
@@ -259,7 +264,7 @@ If we are binding (rather than creating) a group and no roles are specified, we
259
264
 
260
265
  "roles" => {
261
266
  "type" => "array",
262
- "items" => MU::Cloud::Google::Role.ref_schema
267
+ "items" => MU::Cloud.resourceClass("Google", "Role").ref_schema
263
268
  }
264
269
  }
265
270
  [toplevel_required, schema]
@@ -322,7 +327,7 @@ If we are binding (rather than creating) a group and no roles are specified, we
322
327
  end
323
328
 
324
329
 
325
- credcfg = MU::Cloud::Google.credConfig(group['credentials'])
330
+ MU::Cloud::Google.credConfig(group['credentials'])
326
331
 
327
332
  if group['external'] and group['members']
328
333
  MU.log "Cannot manage memberships for external group #{group['name']}", MU::ERR
@@ -335,11 +340,7 @@ If we are binding (rather than creating) a group and no roles are specified, we
335
340
  if group['members']
336
341
  group['members'].each { |m|
337
342
  if configurator.haveLitterMate?(m, "users")
338
- group['dependencies'] ||= []
339
- group['dependencies'] << {
340
- "name" => m,
341
- "type" => "user"
342
- }
343
+ MU::Config.addDependency(group, m, "user")
343
344
  end
344
345
  }
345
346
  end
@@ -348,11 +349,7 @@ If we are binding (rather than creating) a group and no roles are specified, we
348
349
  group['roles'].each { |r|
349
350
  if r['role'] and r['role']['name'] and
350
351
  (!r['role']['deploy_id'] and !r['role']['id'])
351
- group['dependencies'] ||= []
352
- group['dependencies'] << {
353
- "type" => "role",
354
- "name" => r['role']['name']
355
- }
352
+ MU::Config.addDependency(group, r['role']['name'], "role")
356
353
  end
357
354
  }
358
355
  end
@@ -360,8 +357,6 @@ If we are binding (rather than creating) a group and no roles are specified, we
360
357
  ok
361
358
  end
362
359
 
363
- private
364
-
365
360
  end
366
361
  end
367
362
  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']}"
@@ -113,7 +113,7 @@ module MU
113
113
  @habitat_id = parent_id
114
114
  begin
115
115
  setProjectBilling
116
- rescue Exception => e
116
+ rescue StandardError => e
117
117
  MU.log "Failed to set billing account #{@config['billing_acct']} on project #{@cloud_id}: #{e.message}", MU::ERR
118
118
  MU::Cloud::Google.resource_manager(credentials: @config['credentials']).delete_project(@cloud_id)
119
119
  raise e
@@ -167,10 +167,12 @@ module MU
167
167
  end
168
168
  end
169
169
 
170
+ @cached_cloud_desc = nil
170
171
  # Return the cloud descriptor for the Habitat
171
172
  # @return [Google::Apis::Core::Hashable]
172
- def cloud_desc
173
- @cached_cloud_desc ||= MU::Cloud::Google::Habitat.find(cloud_id: @cloud_id).values.first
173
+ def cloud_desc(use_cache: true)
174
+ return @cached_cloud_desc if @cached_cloud_desc and use_cache
175
+ @cached_cloud_desc = MU::Cloud::Google::Habitat.find(cloud_id: @cloud_id).values.first
174
176
  if @cached_cloud_desc and @cached_cloud_desc.parent
175
177
  @habitat_id ||= @cached_cloud_desc.parent.id
176
178
  end
@@ -209,7 +211,7 @@ module MU
209
211
  billing.billing_account_name.empty?
210
212
  return false
211
213
  end
212
- rescue ::Google::Apis::ClientError => e
214
+ rescue ::Google::Apis::ClientError
213
215
  return false
214
216
  end
215
217
 
@@ -219,14 +221,15 @@ module MU
219
221
  # Remove all Google projects associated with the currently loaded deployment. Try to, anyway.
220
222
  # @param noop [Boolean]: If true, will only print what would be done
221
223
  # @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
222
- # @param region [String]: The cloud provider region
223
224
  # @return [void]
224
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
225
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
225
226
  resp = MU::Cloud::Google.resource_manager(credentials: credentials).list_projects
227
+
226
228
  if resp and resp.projects
227
229
  resp.projects.each { |p|
228
- if p.labels and p.labels["mu-id"] == MU.deploy_id.downcase and
229
- p.lifecycle_state == "ACTIVE"
230
+ labelmatch = (p.labels and (p.labels["mu-id"] == MU.deploy_id.downcase and (ignoremaster or p.labels["mu-master-ip"] == MU.mu_public_ip.gsub(/\./, "_"))))
231
+ flagmatch = (flags and flags['known'] and flags['known'].include?(p.project_id))
232
+ if (labelmatch or flagmatch) and p.lifecycle_state == "ACTIVE"
230
233
  MU.log "Deleting project #{p.project_id} (#{p.name})", details: p
231
234
  if !noop
232
235
  begin
@@ -282,7 +285,7 @@ module MU
282
285
  next if p.lifecycle_state == "DELETE_REQUESTED"
283
286
  found[p.project_id] = p
284
287
  }
285
- @@list_projects_cache = found
288
+ @@list_projects_cache = found.clone
286
289
  end
287
290
 
288
291
  found
@@ -291,7 +294,7 @@ module MU
291
294
  # Reverse-map our cloud description into a runnable config hash.
292
295
  # We assume that any values we have in +@config+ are placeholders, and
293
296
  # calculate our own accordingly based on what's live in the cloud.
294
- def toKitten(rootparent: nil, billing: nil, habitats: nil)
297
+ def toKitten(**args)
295
298
  bok = {
296
299
  "cloud" => "Google",
297
300
  "credentials" => @config['credentials']
@@ -311,17 +314,17 @@ module MU
311
314
  credentials: @config['credentials'],
312
315
  type: "folders"
313
316
  )
314
- elsif rootparent
317
+ elsif args[:rootparent]
315
318
  bok['parent'] = {
316
- 'id' => rootparent.is_a?(String) ? rootparent : rootparent.cloud_desc.name
319
+ 'id' => args[:rootparent].is_a?(String) ? args[:rootparent] : args[:rootparent].cloud_desc.name
317
320
  }
318
321
  else
319
322
  # org parent is *probably* safe to infer from credentials
320
323
  end
321
324
  end
322
325
 
323
- if billing
324
- bok['billing_acct'] = billing
326
+ if args[:billing]
327
+ bok['billing_acct'] = args[:billing]
325
328
  else
326
329
  cur_billing = MU::Cloud::Google.billing(credentials: @config['credentials']).get_project_billing_info("projects/"+@cloud_id)
327
330
  if cur_billing and cur_billing.billing_account_name
@@ -334,9 +337,9 @@ module MU
334
337
 
335
338
 
336
339
  # Cloud-specific configuration properties.
337
- # @param config [MU::Config]: The calling MU::Config object
340
+ # @param _config [MU::Config]: The calling MU::Config object
338
341
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
339
- def self.schema(config)
342
+ def self.schema(_config)
340
343
  toplevel_required = []
341
344
  schema = {
342
345
  "billing_acct" => {
@@ -373,11 +376,7 @@ module MU
373
376
  end
374
377
 
375
378
  if habitat['parent'] and habitat['parent']['name'] and !habitat['parent']['deploy_id'] and configurator.haveLitterMate?(habitat['parent']['name'], "folders")
376
- habitat["dependencies"] ||= []
377
- habitat["dependencies"] << {
378
- "type" => "folder",
379
- "name" => habitat['parent']['name']
380
- }
379
+ MU::Config.addDependency(habitat, habitat['parent']['name'], "folder")
381
380
  end
382
381
 
383
382
  ok
@@ -79,13 +79,13 @@ module MU
79
79
  end
80
80
  if @config['global']
81
81
  MU.log "Creating Global Forwarding Rule #{@mu_name}", MU::NOTICE, details: ruleobj
82
- resp = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_global_forwarding_rule(
82
+ MU::Cloud::Google.compute(credentials: @config['credentials']).insert_global_forwarding_rule(
83
83
  @project_id,
84
84
  ruleobj
85
85
  )
86
86
  else
87
87
  MU.log "Creating regional Forwarding Rule #{@mu_name} in #{@config['region']}", MU::NOTICE, details: ruleobj
88
- resp = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_forwarding_rule(
88
+ MU::Cloud::Google.compute(credentials: @config['credentials']).insert_forwarding_rule(
89
89
  @project_id,
90
90
  @config['region'],
91
91
  ruleobj
@@ -146,15 +146,20 @@ 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: {})
150
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
151
- return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], credentials)
149
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: nil, credentials: nil, flags: {})
150
+ flags["habitat"] ||= MU::Cloud::Google.defaultProject(credentials)
151
+ return if !MU::Cloud.resourceClass("Google", "Habitat").isLive?(flags["habitat"], credentials)
152
+ filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
153
+ if !ignoremaster and MU.mu_public_ip
154
+ filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
155
+ end
156
+ MU.log "Placeholder: Google LoadBalancer artifacts do not support labels, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: filter
152
157
 
153
158
  if region
154
159
  ["forwarding_rule", "region_backend_service"].each { |type|
155
160
  MU::Cloud::Google.compute(credentials: credentials).delete(
156
161
  type,
157
- flags["project"],
162
+ flags["habitat"],
158
163
  region,
159
164
  noop
160
165
  )
@@ -165,7 +170,7 @@ module MU
165
170
  ["global_forwarding_rule", "target_http_proxy", "target_https_proxy", "url_map", "backend_service", "health_check", "http_health_check", "https_health_check"].each { |type|
166
171
  MU::Cloud::Google.compute(credentials: credentials).delete(
167
172
  type,
168
- flags["project"],
173
+ flags["habitat"],
169
174
  nil,
170
175
  noop
171
176
  )
@@ -174,9 +179,9 @@ module MU
174
179
  end
175
180
 
176
181
  # Cloud-specific configuration properties.
177
- # @param config [MU::Config]: The calling MU::Config object
182
+ # @param _config [MU::Config]: The calling MU::Config object
178
183
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
179
- def self.schema(config)
184
+ def self.schema(_config)
180
185
  toplevel_required = []
181
186
  schema = {
182
187
  "named_ports" => {
@@ -202,9 +207,9 @@ module MU
202
207
 
203
208
  # Cloud-specific pre-processing of {MU::Config::BasketofKittens::loadbalancers}, bare and unvalidated.
204
209
  # @param lb [Hash]: The resource to process and validate
205
- # @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member
210
+ # @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
206
211
  # @return [Boolean]: True if validation succeeded, False otherwise
207
- def self.validateConfig(lb, configurator)
212
+ def self.validateConfig(lb, _configurator)
208
213
  ok = true
209
214
  if lb['classic']
210
215
  MU.log "LoadBalancer 'classic' flag has no meaning in Google Cloud", MU::WARN
@@ -236,7 +241,6 @@ module MU
236
241
  end
237
242
 
238
243
  lb["listeners"].each { |l|
239
- ruleobj = nil
240
244
  if lb["private"] and !["TCP", "UDP"].include?(l['lb_protocol'])
241
245
  MU.log "Only TCP and UDP listeners are valid for private LoadBalancers in Google Cloud", MU::ERR
242
246
  ok = false
@@ -255,7 +259,6 @@ module MU
255
259
  lb["targetgroups"].each { |tg|
256
260
  if tg["healthcheck"]
257
261
  target = tg["healthcheck"]['target'].match(/^([^:]+):(\d+)(.*)/)
258
- proto = target[1]
259
262
  if tg["proto"] != target[1]
260
263
  MU.log "LoadBalancer #{lb['name']} can't mix and match target group and health check protocols in Google Cloud", MU::ERR, details: tg
261
264
  ok = false
@@ -286,14 +289,9 @@ module MU
286
289
  end
287
290
 
288
291
  # Locate an existing LoadBalancer or LoadBalancers and return an array containing matching Google resource descriptors for those that match.
289
- # @param cloud_id [String]: The cloud provider's identifier for this resource.
290
- # @param region [String]: The cloud provider region
291
- # @param tag_key [String]: A tag key to search.
292
- # @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
293
- # @param flags [Hash]: Optional flags
294
- # @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching LoadBalancers
295
- def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, flags: {}, credentials: nil)
296
- flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
292
+ # @return [Hash<String,OpenStruct>]: The cloud provider's complete descriptions of matching LoadBalancers
293
+ def self.find(**args)
294
+ args = MU::Cloud::Google.findLocationArgs(args)
297
295
  end
298
296
 
299
297
  private
@@ -32,6 +32,7 @@ module MU
32
32
  # If we're being reverse-engineered from a cloud descriptor, use that
33
33
  # to determine what sort of account we are.
34
34
  if args[:from_cloud_desc]
35
+ require 'google/apis/admin_directory_v1'
35
36
  @cloud_desc_cache = args[:from_cloud_desc]
36
37
  if args[:from_cloud_desc].class == ::Google::Apis::AdminDirectoryV1::Role
37
38
  @config['role_source'] = "directory"
@@ -87,7 +88,7 @@ module MU
87
88
  resp = if @config['role_source'] == "org"
88
89
  my_org = MU::Cloud::Google.getOrg(@config['credentials'])
89
90
  MU.log "Creating IAM organization role #{@mu_name} in #{my_org.display_name}", details: create_role_obj
90
- resp = MU::Cloud::Google.iam(credentials: @credentials).create_organization_role(my_org.name, create_role_obj)
91
+ MU::Cloud::Google.iam(credentials: @credentials).create_organization_role(my_org.name, create_role_obj)
91
92
  elsif @config['role_source'] == "project"
92
93
  if !@project_id
93
94
  raise MuError, "Role #{@mu_name} is supposed to be in project #{@config['project']}, but no such project was found"
@@ -133,12 +134,13 @@ module MU
133
134
  }
134
135
  end
135
136
 
137
+ @cloud_desc_cache = nil
136
138
  # Return the cloud descriptor for the Role
137
139
  # @return [Google::Apis::Core::Hashable]
138
- def cloud_desc
139
- return @cloud_desc_cache if @cloud_desc_cache
140
+ def cloud_desc(use_cache: true)
141
+ return @cloud_desc_cache if @cloud_desc_cache and use_cache
140
142
 
141
- my_org = MU::Cloud::Google.getOrg(@config['credentials'])
143
+ MU::Cloud::Google.getOrg(@config['credentials'])
142
144
 
143
145
  @cloud_desc_cache = if @config['role_source'] == "directory"
144
146
  MU::Cloud::Google.admin_directory(credentials: @config['credentials']).get_role(@customer, @cloud_id)
@@ -238,7 +240,7 @@ module MU
238
240
  req_obj = MU::Cloud::Google.resource_manager(:SetIamPolicyRequest).new(
239
241
  policy: policy
240
242
  )
241
- policy = if scope_type == "organizations"
243
+ if scope_type == "organizations"
242
244
  MU::Cloud::Google.resource_manager(credentials: credentials).set_organization_iam_policy(
243
245
  scope_id,
244
246
  req_obj
@@ -269,13 +271,13 @@ module MU
269
271
  my_org = MU::Cloud::Google.getOrg(credentials)
270
272
  if my_org
271
273
  scopes["organizations"] = [my_org.name]
272
- folders = MU::Cloud::Google::Folder.find(credentials: credentials)
274
+ folders = MU::Cloud.resourceClass("Google", "Folder").find(credentials: credentials)
273
275
  if folders and folders.size > 0
274
276
  scopes["folders"] = folders.keys
275
277
  end
276
278
  end
277
279
 
278
- projects = MU::Cloud::Google::Habitat.find(credentials: credentials)
280
+ projects = MU::Cloud.resourceClass("Google", "Habitat").find(credentials: credentials)
279
281
  if projects and projects.size > 0
280
282
  scopes["projects"] = projects.keys
281
283
  end
@@ -310,7 +312,7 @@ module MU
310
312
  policy: policy
311
313
  )
312
314
 
313
- policy = if scope_type == "organizations"
315
+ if scope_type == "organizations"
314
316
  MU::Cloud::Google.resource_manager(credentials: credentials).set_organization_iam_policy(
315
317
  scope_id,
316
318
  req_obj
@@ -340,8 +342,6 @@ module MU
340
342
  def self.bindFromConfig(entity_type, entity_id, cfg, credentials: nil, deploy: nil, debug: false)
341
343
  loglevel = debug ? MU::NOTICE : MU::DEBUG
342
344
 
343
- bindings = []
344
-
345
345
  return if !cfg
346
346
  MU.log "Google::Role::bindFromConfig binding called for #{entity_type} #{entity_id}", loglevel, details: cfg
347
347
 
@@ -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
@@ -464,12 +464,17 @@ module MU
464
464
  # Remove all roles associated with the currently loaded deployment.
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
- # @param region [String]: The cloud provider region
468
467
  # @return [void]
469
- def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
468
+ def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, credentials: nil, flags: {})
470
469
  customer = MU::Cloud::Google.customerID(credentials)
471
470
  my_org = MU::Cloud::Google.getOrg(credentials)
472
471
 
472
+ filter = %Q{(labels.mu-id = "#{MU.deploy_id.downcase}")}
473
+ if !ignoremaster and MU.mu_public_ip
474
+ filter += %Q{ AND (labels.mu-master-ip = "#{MU.mu_public_ip.gsub(/\./, "_")}")}
475
+ end
476
+ MU.log "Placeholder: Google Role artifacts do not support labels, so ignoremaster cleanup flag has no effect", MU::DEBUG, details: filter
477
+
473
478
  if flags['known']
474
479
  flags['known'].each { |id|
475
480
  next if id.nil?
@@ -558,7 +563,7 @@ module MU
558
563
  if args[:project]
559
564
  canned = Hash[MU::Cloud::Google.iam(credentials: args[:credentials]).list_roles.roles.map { |r| [r.name, r] }]
560
565
  begin
561
- 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|
562
567
  found[binding.role] = canned[binding.role]
563
568
  }
564
569
  rescue ::Google::Apis::ClientError => e
@@ -576,7 +581,7 @@ module MU
576
581
  }
577
582
  end
578
583
  if args[:cloud_id]
579
- found.reject! { |k, v| k != role.name }
584
+ found.reject! { |k, _v| k != role.name }
580
585
  end
581
586
 
582
587
  # Now go get everything that's bound here
@@ -586,10 +591,15 @@ module MU
586
591
  bindings['by_scope']['projects'][args[:project]]
587
592
  bindings['by_scope']['projects'][args[:project]].keys.each { |r|
588
593
  if r.match(/^roles\//)
589
- role = MU::Cloud::Google.iam(credentials: args[:credentials]).get_role(r)
590
- 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
591
601
  elsif !found[r]
592
- MU.log "NEED TO GET #{r}", MU::WARN
602
+ # MU.log "NEED TO GET #{r}", MU::WARN
593
603
  end
594
604
  }
595
605
  end
@@ -626,15 +636,17 @@ module MU
626
636
  }
627
637
  end
628
638
 
629
- resp = begin
630
- MU::Cloud::Google.iam(credentials: args[:credentials]).list_organization_roles(my_org.name)
631
- rescue ::Google::Apis::ClientError => e
632
- raise e if !e.message.match(/forbidden: /)
633
- end
634
- if resp and resp.roles
635
- resp.roles.each { |role|
636
- found[role.name] = role
637
- }
639
+ if my_org
640
+ resp = begin
641
+ MU::Cloud::Google.iam(credentials: args[:credentials]).list_organization_roles(my_org.name)
642
+ rescue ::Google::Apis::ClientError => e
643
+ raise e if !e.message.match(/forbidden: /)
644
+ end
645
+ if resp and resp.roles
646
+ resp.roles.each { |role|
647
+ found[role.name] = role
648
+ }
649
+ end
638
650
  end
639
651
  end
640
652
 
@@ -644,7 +656,8 @@ module MU
644
656
  # Reverse-map our cloud description into a runnable config hash.
645
657
  # We assume that any values we have in +@config+ are placeholders, and
646
658
  # calculate our own accordingly based on what's live in the cloud.
647
- def toKitten(rootparent: nil, billing: nil, habitats: nil)
659
+ def toKitten(**args)
660
+
648
661
  bok = {
649
662
  "cloud" => "Google",
650
663
  "credentials" => @config['credentials'],
@@ -677,10 +690,10 @@ module MU
677
690
  end
678
691
  if !cloud_desc.role_privileges.nil? and !cloud_desc.role_privileges.empty?
679
692
  bok['import'] = []
680
- ids, names, privs = MU::Cloud::Google::Role.privilege_service_to_name(@config['credentials'])
693
+ ids, _names, _privs = MU::Cloud::Google::Role.privilege_service_to_name(@config['credentials'])
681
694
  cloud_desc.role_privileges.each { |priv|
682
695
  if !ids[priv.service_id]
683
- 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
684
697
  bok["import"] << priv.service_id+"/"+priv.privilege_name
685
698
  else
686
699
  bok["import"] << ids[priv.service_id]+"/"+priv.privilege_name
@@ -696,7 +709,7 @@ module MU
696
709
  bok['name'] = name.gsub(/[^a-z0-9]/i, '-')
697
710
  bok['role_source'] = "canned"
698
711
  elsif cloud_desc.name.match(/^([^\/]+?)\/([^\/]+?)\/roles\/(.*)/)
699
- junk, type, parent, name = Regexp.last_match.to_a
712
+ _junk, type, parent, name = Regexp.last_match.to_a
700
713
  bok['name'] = name.gsub(/[^a-z0-9]/i, '-')
701
714
  bok['role_source'] = type == "organizations" ? "org" : "project"
702
715
  if bok['role_source'] == "project"
@@ -723,25 +736,45 @@ module MU
723
736
  bindings[scopetype].each_pair { |scope_id, entity_types|
724
737
  # If we've been given a habitat filter, skip over bindings
725
738
  # that don't match it.
726
- if scopetype == "projects" and habitats and
727
- !habitats.empty? and !habitats.include?(scope_id)
728
- next
739
+ if scopetype == "projects"
740
+ if (args[:habitats] and !args[:habitats].empty? and
741
+ !args[:habitats].include?(scope_id)) or
742
+ !MU::Cloud::Google.listHabitats(@credentials).include?(scope_id)
743
+ next
744
+ end
729
745
  end
730
746
 
731
747
  entity_types.each_pair { |entity_type, entities|
732
748
  mu_entitytype = (entity_type == "serviceAccount" ? "user" : entity_type)+"s"
733
749
  entities.each { |entity|
750
+ next if entity.nil?
751
+ foreign = if entity_type == "serviceAccount" and entity.match(/@(.*?)\.iam\.gserviceaccount\.com/)
752
+ !MU::Cloud::Google.listHabitats(@credentials).include?(Regexp.last_match[1])
753
+ end
754
+
734
755
  entity_ref = if entity_type == "organizations"
735
756
  { "id" => ((org == my_org.name and @config['credentials']) ? @config['credentials'] : org) }
736
757
  elsif entity_type == "domain"
737
758
  { "id" => entity }
738
759
  else
760
+ shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(mu_entitytype)
761
+ if args[:types].include?(shortclass) and
762
+ !(entity_type == "serviceAccount" and
763
+ MU::Cloud::Google::User.cannedServiceAcctName?(entity))
764
+ MU.log "Role #{@cloud_id}: Skipping #{shortclass} binding for #{entity}; we are adopting that type and will set bindings from that resource", MU::DEBUG
765
+ next
766
+ end
767
+
739
768
  MU::Config::Ref.get(
740
769
  id: entity,
741
770
  cloud: "Google",
742
771
  type: mu_entitytype
743
772
  )
744
773
  end
774
+ if entity_ref.nil?
775
+ MU.log "I somehow ended up with a nil entity reference for #{entity_type} #{entity}", MU::ERR, details: [ bok, bindings ]
776
+ next
777
+ end
745
778
  refmap ||= {}
746
779
  refmap[entity_ref] ||= {}
747
780
  refmap[entity_ref][scopetype] ||= []
@@ -760,6 +793,7 @@ module MU
760
793
  }
761
794
  }
762
795
  }
796
+
763
797
  bok["bindings"] ||= []
764
798
  refmap.each_pair { |entity, scopes|
765
799
  newbinding = { "entity" => entity }
@@ -882,7 +916,7 @@ module MU
882
916
  end
883
917
 
884
918
  role = MU::Cloud::Google.admin_directory(credentials: credentials).get_role(MU::Cloud::Google.customerID(credentials), binding.role_id)
885
- MU.log "Failed to find entity #{binding.assigned_to} referenced in GSuite/Cloud Identity binding to role #{role.role_name}", MU::WARN, details: role
919
+ MU.log "Failed to find entity #{binding.assigned_to} referenced in GSuite/Cloud Identity binding to role #{role.role_name}", MU::DEBUG, details: role
886
920
  }
887
921
 
888
922
  resp = MU::Cloud::Google.resource_manager(credentials: credentials).get_organization_iam_policy(my_org.name)
@@ -890,15 +924,17 @@ module MU
890
924
  insertBinding("organizations", my_org.name, binding)
891
925
  }
892
926
 
893
- MU::Cloud::Google::Folder.find(credentials: credentials).keys.each { |folder|
894
- MU::Cloud::Google::Folder.bindings(folder, credentials: credentials).each { |binding|
927
+ MU::Cloud.resourceClass("Google", "Folder").find(credentials: credentials).keys.each { |folder|
928
+ folder_bindings = MU::Cloud.resourceClass("Google", "Folder").bindings(folder, credentials: credentials)
929
+ next if !folder_bindings
930
+ folder_bindings.each { |binding|
895
931
  insertBinding("folders", folder, binding)
896
932
  }
897
933
  }
898
934
  end
899
- MU::Cloud::Google::Habitat.find(credentials: credentials).keys.each { |project|
935
+ MU::Cloud::Google.listHabitats(credentials).each { |project|
900
936
  begin
901
- MU::Cloud::Google::Habitat.bindings(project, credentials: credentials).each { |binding|
937
+ MU::Cloud.resourceClass("Google", "Habitat").bindings(project, credentials: credentials).each { |binding|
902
938
  insertBinding("projects", project, binding)
903
939
  }
904
940
  rescue ::Google::Apis::ClientError => e
@@ -983,9 +1019,9 @@ module MU
983
1019
  end
984
1020
 
985
1021
  # Cloud-specific configuration properties.
986
- # @param config [MU::Config]: The calling MU::Config object
1022
+ # @param _config [MU::Config]: The calling MU::Config object
987
1023
  # @return [Array<Array,Hash>]: List of required fields, and json-schema Hash of cloud-specific configuration parameters for this resource
988
- def self.schema(config)
1024
+ def self.schema(_config)
989
1025
  toplevel_required = []
990
1026
  schema = {
991
1027
  "name" => {
@@ -1050,7 +1086,7 @@ If this value is not specified, and the role name matches the name of an existin
1050
1086
  def self.validateConfig(role, configurator)
1051
1087
  ok = true
1052
1088
 
1053
- credcfg = MU::Cloud::Google.credConfig(role['credentials'])
1089
+ MU::Cloud::Google.credConfig(role['credentials'])
1054
1090
 
1055
1091
  my_org = MU::Cloud::Google.getOrg(role['credentials'])
1056
1092
  if !role['role_source']
@@ -1059,7 +1095,7 @@ If this value is not specified, and the role name matches the name of an existin
1059
1095
  if !lookup_name.match(/^roles\//)
1060
1096
  lookup_name = "roles/"+lookup_name
1061
1097
  end
1062
- canned = MU::Cloud::Google.iam(credentials: role['credentials']).get_role(lookup_name)
1098
+ MU::Cloud::Google.iam(credentials: role['credentials']).get_role(lookup_name)
1063
1099
  MU.log "Role #{role['name']} appears to be a referenced to canned role #{role.name} (#{role.title})", MU::NOTICE
1064
1100
  role['role_source'] = "canned"
1065
1101
  rescue ::Google::Apis::ClientError
@@ -1081,7 +1117,7 @@ If this value is not specified, and the role name matches the name of an existin
1081
1117
  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
1082
1118
  ok = false
1083
1119
  elsif missing.size > 0
1084
- MU.log "Some directory service privileges declared for role #{role['name']} aren't available to credentials #{role['credentials']}, will skip", MU::WARN, details: missing
1120
+ MU.log "Some directory service privileges declared for role #{role['name']} aren't available to credentials #{role['credentials']}, will skip", MU::DEBUG, details: missing
1085
1121
  end
1086
1122
  end
1087
1123
  end
@@ -1096,11 +1132,7 @@ If this value is not specified, and the role name matches the name of an existin
1096
1132
  if role['role_source'] == "project"
1097
1133
  role['project'] ||= MU::Cloud::Google.defaultProject(role['credentials'])
1098
1134
  if configurator.haveLitterMate?(role['project'], "habitats")
1099
- role['dependencies'] ||= []
1100
- role['dependencies'] << {
1101
- "type" => "habitat",
1102
- "name" => role['project']
1103
- }
1135
+ MU::Config.addDependency(role, role['project'], "habitat")
1104
1136
  end
1105
1137
  end
1106
1138
 
@@ -1108,26 +1140,25 @@ If this value is not specified, and the role name matches the name of an existin
1108
1140
  role['bindings'].each { |binding|
1109
1141
  if binding['entity'] and binding['entity']['name'] and
1110
1142
  configurator.haveLitterMate?(binding['entity']['name'], binding['entity']['type'])
1111
- role['dependencies'] ||= []
1112
- role['dependencies'] << {
1113
- "type" => binding['entity']['type'].sub(/s$/, ''),
1114
- "name" => binding['entity']['name']
1115
- }
1116
-
1143
+ MU::Config.addDependency(role, binding['entity']['name'], binding['entity']['type'])
1117
1144
  end
1118
1145
  }
1146
+ role['bindings'].uniq!
1119
1147
  end
1120
1148
 
1121
1149
  ok
1122
1150
  end
1123
1151
 
1124
- private
1125
-
1126
1152
  @@service_id_to_name = {}
1127
1153
  @@service_id_to_privs = {}
1128
1154
  @@service_name_to_id = {}
1129
1155
  @@service_name_map_semaphore = Mutex.new
1130
1156
 
1157
+ # Generate lookup tables mapping between hex service role identifiers,
1158
+ # human-readable names of services, and the privileges associated with
1159
+ # those roles.
1160
+ # @param credentials [String]
1161
+ # @return [Array<Hash,Hash,Hash>]
1131
1162
  def self.privilege_service_to_name(credentials = nil)
1132
1163
 
1133
1164
  customer = MU::Cloud::Google.customerID(credentials)
@@ -1176,6 +1207,11 @@ If this value is not specified, and the role name matches the name of an existin
1176
1207
  }
1177
1208
  end
1178
1209
 
1210
+ # Convert a list of shorthand GSuite/Cloud Identity privileges into
1211
+ # +RolePrivilege+ objects for consumption by other API calls
1212
+ # @param roles [Array<String>]:
1213
+ # @param credentials [String]:
1214
+ # @return [Array<Google::Apis::AdminDirectoryV1::DirectoryService::Role::RolePrivilege>]
1179
1215
  def self.map_directory_privileges(roles, credentials: nil)
1180
1216
  rolepriv_objs = []
1181
1217
  notfound = []