cloud-mu 3.1.3 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
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 = []