cloud-mu 3.1.3 → 3.1.4

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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +10 -2
  3. data/bin/mu-adopt +5 -1
  4. data/bin/mu-load-config.rb +2 -3
  5. data/bin/mu-run-tests +112 -27
  6. data/cloud-mu.gemspec +20 -20
  7. data/cookbooks/mu-tools/libraries/helper.rb +2 -1
  8. data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
  9. data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
  10. data/cookbooks/mu-tools/resources/disk.rb +1 -1
  11. data/extras/image-generators/Google/centos6.yaml +1 -0
  12. data/extras/image-generators/Google/centos7.yaml +1 -1
  13. data/modules/mommacat.ru +5 -15
  14. data/modules/mu.rb +10 -14
  15. data/modules/mu/adoption.rb +20 -14
  16. data/modules/mu/cleanup.rb +13 -9
  17. data/modules/mu/cloud.rb +26 -26
  18. data/modules/mu/clouds/aws.rb +100 -59
  19. data/modules/mu/clouds/aws/alarm.rb +4 -2
  20. data/modules/mu/clouds/aws/bucket.rb +25 -21
  21. data/modules/mu/clouds/aws/cache_cluster.rb +25 -23
  22. data/modules/mu/clouds/aws/collection.rb +21 -20
  23. data/modules/mu/clouds/aws/container_cluster.rb +47 -26
  24. data/modules/mu/clouds/aws/database.rb +57 -68
  25. data/modules/mu/clouds/aws/dnszone.rb +14 -14
  26. data/modules/mu/clouds/aws/endpoint.rb +20 -16
  27. data/modules/mu/clouds/aws/firewall_rule.rb +19 -16
  28. data/modules/mu/clouds/aws/folder.rb +7 -7
  29. data/modules/mu/clouds/aws/function.rb +15 -12
  30. data/modules/mu/clouds/aws/group.rb +14 -10
  31. data/modules/mu/clouds/aws/habitat.rb +16 -13
  32. data/modules/mu/clouds/aws/loadbalancer.rb +16 -15
  33. data/modules/mu/clouds/aws/log.rb +13 -10
  34. data/modules/mu/clouds/aws/msg_queue.rb +15 -8
  35. data/modules/mu/clouds/aws/nosqldb.rb +18 -11
  36. data/modules/mu/clouds/aws/notifier.rb +11 -6
  37. data/modules/mu/clouds/aws/role.rb +87 -70
  38. data/modules/mu/clouds/aws/search_domain.rb +30 -19
  39. data/modules/mu/clouds/aws/server.rb +102 -72
  40. data/modules/mu/clouds/aws/server_pool.rb +47 -28
  41. data/modules/mu/clouds/aws/storage_pool.rb +5 -6
  42. data/modules/mu/clouds/aws/user.rb +13 -10
  43. data/modules/mu/clouds/aws/vpc.rb +135 -121
  44. data/modules/mu/clouds/azure.rb +16 -9
  45. data/modules/mu/clouds/azure/container_cluster.rb +2 -3
  46. data/modules/mu/clouds/azure/firewall_rule.rb +10 -10
  47. data/modules/mu/clouds/azure/habitat.rb +8 -6
  48. data/modules/mu/clouds/azure/loadbalancer.rb +5 -5
  49. data/modules/mu/clouds/azure/role.rb +8 -10
  50. data/modules/mu/clouds/azure/server.rb +65 -25
  51. data/modules/mu/clouds/azure/user.rb +5 -7
  52. data/modules/mu/clouds/azure/vpc.rb +12 -15
  53. data/modules/mu/clouds/cloudformation.rb +8 -7
  54. data/modules/mu/clouds/cloudformation/vpc.rb +2 -4
  55. data/modules/mu/clouds/google.rb +39 -24
  56. data/modules/mu/clouds/google/bucket.rb +9 -11
  57. data/modules/mu/clouds/google/container_cluster.rb +27 -42
  58. data/modules/mu/clouds/google/database.rb +6 -9
  59. data/modules/mu/clouds/google/firewall_rule.rb +11 -10
  60. data/modules/mu/clouds/google/folder.rb +16 -9
  61. data/modules/mu/clouds/google/function.rb +127 -161
  62. data/modules/mu/clouds/google/group.rb +21 -18
  63. data/modules/mu/clouds/google/habitat.rb +18 -15
  64. data/modules/mu/clouds/google/loadbalancer.rb +14 -16
  65. data/modules/mu/clouds/google/role.rb +48 -31
  66. data/modules/mu/clouds/google/server.rb +105 -105
  67. data/modules/mu/clouds/google/server_pool.rb +12 -31
  68. data/modules/mu/clouds/google/user.rb +67 -13
  69. data/modules/mu/clouds/google/vpc.rb +58 -65
  70. data/modules/mu/config.rb +89 -1738
  71. data/modules/mu/config/bucket.rb +3 -3
  72. data/modules/mu/config/collection.rb +3 -3
  73. data/modules/mu/config/container_cluster.rb +2 -2
  74. data/modules/mu/config/dnszone.rb +5 -5
  75. data/modules/mu/config/doc_helpers.rb +517 -0
  76. data/modules/mu/config/endpoint.rb +3 -3
  77. data/modules/mu/config/firewall_rule.rb +118 -3
  78. data/modules/mu/config/folder.rb +3 -3
  79. data/modules/mu/config/function.rb +2 -2
  80. data/modules/mu/config/group.rb +3 -3
  81. data/modules/mu/config/habitat.rb +3 -3
  82. data/modules/mu/config/loadbalancer.rb +3 -3
  83. data/modules/mu/config/log.rb +3 -3
  84. data/modules/mu/config/msg_queue.rb +3 -3
  85. data/modules/mu/config/nosqldb.rb +3 -3
  86. data/modules/mu/config/notifier.rb +2 -2
  87. data/modules/mu/config/ref.rb +333 -0
  88. data/modules/mu/config/role.rb +3 -3
  89. data/modules/mu/config/schema_helpers.rb +508 -0
  90. data/modules/mu/config/search_domain.rb +3 -3
  91. data/modules/mu/config/server.rb +86 -58
  92. data/modules/mu/config/server_pool.rb +2 -2
  93. data/modules/mu/config/tail.rb +189 -0
  94. data/modules/mu/config/user.rb +3 -3
  95. data/modules/mu/config/vpc.rb +44 -4
  96. data/modules/mu/defaults/Google.yaml +2 -2
  97. data/modules/mu/deploy.rb +13 -10
  98. data/modules/mu/groomer.rb +1 -1
  99. data/modules/mu/groomers/ansible.rb +69 -24
  100. data/modules/mu/groomers/chef.rb +52 -44
  101. data/modules/mu/logger.rb +17 -14
  102. data/modules/mu/master.rb +317 -2
  103. data/modules/mu/master/chef.rb +3 -4
  104. data/modules/mu/master/ldap.rb +3 -3
  105. data/modules/mu/master/ssl.rb +12 -2
  106. data/modules/mu/mommacat.rb +85 -1766
  107. data/modules/mu/mommacat/daemon.rb +394 -0
  108. data/modules/mu/mommacat/naming.rb +366 -0
  109. data/modules/mu/mommacat/storage.rb +689 -0
  110. data/modules/tests/bucket.yml +4 -0
  111. data/modules/tests/{win2k12.yaml → needwork/win2k12.yaml} +0 -0
  112. data/modules/tests/regrooms/aws-iam.yaml +201 -0
  113. data/modules/tests/regrooms/bucket.yml +19 -0
  114. metadata +112 -102
@@ -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, 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
@@ -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,15 +213,15 @@ 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
- }
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
+ # }
220
225
  group_roles = MU::Cloud::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
@@ -227,9 +232,9 @@ module MU
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" => {
@@ -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
@@ -360,8 +365,6 @@ If we are binding (rather than creating) a group and no roles are specified, we
360
365
  ok
361
366
  end
362
367
 
363
- private
364
-
365
368
  end
366
369
  end
367
370
  end
@@ -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, 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
@@ -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" => {
@@ -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
@@ -149,6 +149,11 @@ module MU
149
149
  def self.cleanup(noop: false, ignoremaster: false, region: nil, credentials: nil, flags: {})
150
150
  flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
151
151
  return if !MU::Cloud::Google::Habitat.isLive?(flags["project"], 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|
@@ -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
@@ -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
 
@@ -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, 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?
@@ -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
@@ -626,15 +631,17 @@ module MU
626
631
  }
627
632
  end
628
633
 
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
- }
634
+ if my_org
635
+ resp = begin
636
+ MU::Cloud::Google.iam(credentials: args[:credentials]).list_organization_roles(my_org.name)
637
+ rescue ::Google::Apis::ClientError => e
638
+ raise e if !e.message.match(/forbidden: /)
639
+ end
640
+ if resp and resp.roles
641
+ resp.roles.each { |role|
642
+ found[role.name] = role
643
+ }
644
+ end
638
645
  end
639
646
  end
640
647
 
@@ -644,7 +651,8 @@ module MU
644
651
  # Reverse-map our cloud description into a runnable config hash.
645
652
  # We assume that any values we have in +@config+ are placeholders, and
646
653
  # calculate our own accordingly based on what's live in the cloud.
647
- def toKitten(rootparent: nil, billing: nil, habitats: nil)
654
+ def toKitten(**args)
655
+
648
656
  bok = {
649
657
  "cloud" => "Google",
650
658
  "credentials" => @config['credentials'],
@@ -677,7 +685,7 @@ module MU
677
685
  end
678
686
  if !cloud_desc.role_privileges.nil? and !cloud_desc.role_privileges.empty?
679
687
  bok['import'] = []
680
- ids, names, privs = MU::Cloud::Google::Role.privilege_service_to_name(@config['credentials'])
688
+ ids, _names, _privs = MU::Cloud::Google::Role.privilege_service_to_name(@config['credentials'])
681
689
  cloud_desc.role_privileges.each { |priv|
682
690
  if !ids[priv.service_id]
683
691
  MU.log "Role privilege defined for a service id with no name I can find, writing with raw id", MU::WARN, details: priv
@@ -696,7 +704,7 @@ module MU
696
704
  bok['name'] = name.gsub(/[^a-z0-9]/i, '-')
697
705
  bok['role_source'] = "canned"
698
706
  elsif cloud_desc.name.match(/^([^\/]+?)\/([^\/]+?)\/roles\/(.*)/)
699
- junk, type, parent, name = Regexp.last_match.to_a
707
+ _junk, type, parent, name = Regexp.last_match.to_a
700
708
  bok['name'] = name.gsub(/[^a-z0-9]/i, '-')
701
709
  bok['role_source'] = type == "organizations" ? "org" : "project"
702
710
  if bok['role_source'] == "project"
@@ -723,8 +731,9 @@ module MU
723
731
  bindings[scopetype].each_pair { |scope_id, entity_types|
724
732
  # If we've been given a habitat filter, skip over bindings
725
733
  # that don't match it.
726
- if scopetype == "projects" and habitats and
727
- !habitats.empty? and !habitats.include?(scope_id)
734
+ if scopetype == "projects" and args[:habitats] and
735
+ !args[:habitats].empty? and
736
+ !args[:habitats].include?(scope_id)
728
737
  next
729
738
  end
730
739
 
@@ -983,9 +992,9 @@ module MU
983
992
  end
984
993
 
985
994
  # Cloud-specific configuration properties.
986
- # @param config [MU::Config]: The calling MU::Config object
995
+ # @param _config [MU::Config]: The calling MU::Config object
987
996
  # @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)
997
+ def self.schema(_config)
989
998
  toplevel_required = []
990
999
  schema = {
991
1000
  "name" => {
@@ -1050,7 +1059,7 @@ If this value is not specified, and the role name matches the name of an existin
1050
1059
  def self.validateConfig(role, configurator)
1051
1060
  ok = true
1052
1061
 
1053
- credcfg = MU::Cloud::Google.credConfig(role['credentials'])
1062
+ MU::Cloud::Google.credConfig(role['credentials'])
1054
1063
 
1055
1064
  my_org = MU::Cloud::Google.getOrg(role['credentials'])
1056
1065
  if !role['role_source']
@@ -1059,7 +1068,7 @@ If this value is not specified, and the role name matches the name of an existin
1059
1068
  if !lookup_name.match(/^roles\//)
1060
1069
  lookup_name = "roles/"+lookup_name
1061
1070
  end
1062
- canned = MU::Cloud::Google.iam(credentials: role['credentials']).get_role(lookup_name)
1071
+ MU::Cloud::Google.iam(credentials: role['credentials']).get_role(lookup_name)
1063
1072
  MU.log "Role #{role['name']} appears to be a referenced to canned role #{role.name} (#{role.title})", MU::NOTICE
1064
1073
  role['role_source'] = "canned"
1065
1074
  rescue ::Google::Apis::ClientError
@@ -1121,13 +1130,16 @@ If this value is not specified, and the role name matches the name of an existin
1121
1130
  ok
1122
1131
  end
1123
1132
 
1124
- private
1125
-
1126
1133
  @@service_id_to_name = {}
1127
1134
  @@service_id_to_privs = {}
1128
1135
  @@service_name_to_id = {}
1129
1136
  @@service_name_map_semaphore = Mutex.new
1130
1137
 
1138
+ # Generate lookup tables mapping between hex service role identifiers,
1139
+ # human-readable names of services, and the privileges associated with
1140
+ # those roles.
1141
+ # @param credentials [String]
1142
+ # @return [Array<Hash,Hash,Hash>]
1131
1143
  def self.privilege_service_to_name(credentials = nil)
1132
1144
 
1133
1145
  customer = MU::Cloud::Google.customerID(credentials)
@@ -1176,6 +1188,11 @@ If this value is not specified, and the role name matches the name of an existin
1176
1188
  }
1177
1189
  end
1178
1190
 
1191
+ # Convert a list of shorthand GSuite/Cloud Identity privileges into
1192
+ # +RolePrivilege+ objects for consumption by other API calls
1193
+ # @param roles [Array<String>]:
1194
+ # @param credentials [String]:
1195
+ # @return [Array<Google::Apis::AdminDirectoryV1::DirectoryService::Role::RolePrivilege>]
1179
1196
  def self.map_directory_privileges(roles, credentials: nil)
1180
1197
  rolepriv_objs = []
1181
1198
  notfound = []