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.
- checksums.yaml +4 -4
- data/Dockerfile +10 -2
- data/bin/mu-adopt +5 -1
- data/bin/mu-load-config.rb +2 -3
- data/bin/mu-run-tests +112 -27
- data/cloud-mu.gemspec +20 -20
- data/cookbooks/mu-tools/libraries/helper.rb +2 -1
- data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
- data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
- data/cookbooks/mu-tools/resources/disk.rb +1 -1
- data/extras/image-generators/Google/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +1 -1
- data/modules/mommacat.ru +5 -15
- data/modules/mu.rb +10 -14
- data/modules/mu/adoption.rb +20 -14
- data/modules/mu/cleanup.rb +13 -9
- data/modules/mu/cloud.rb +26 -26
- data/modules/mu/clouds/aws.rb +100 -59
- data/modules/mu/clouds/aws/alarm.rb +4 -2
- data/modules/mu/clouds/aws/bucket.rb +25 -21
- data/modules/mu/clouds/aws/cache_cluster.rb +25 -23
- data/modules/mu/clouds/aws/collection.rb +21 -20
- data/modules/mu/clouds/aws/container_cluster.rb +47 -26
- data/modules/mu/clouds/aws/database.rb +57 -68
- data/modules/mu/clouds/aws/dnszone.rb +14 -14
- data/modules/mu/clouds/aws/endpoint.rb +20 -16
- data/modules/mu/clouds/aws/firewall_rule.rb +19 -16
- data/modules/mu/clouds/aws/folder.rb +7 -7
- data/modules/mu/clouds/aws/function.rb +15 -12
- data/modules/mu/clouds/aws/group.rb +14 -10
- data/modules/mu/clouds/aws/habitat.rb +16 -13
- data/modules/mu/clouds/aws/loadbalancer.rb +16 -15
- data/modules/mu/clouds/aws/log.rb +13 -10
- data/modules/mu/clouds/aws/msg_queue.rb +15 -8
- data/modules/mu/clouds/aws/nosqldb.rb +18 -11
- data/modules/mu/clouds/aws/notifier.rb +11 -6
- data/modules/mu/clouds/aws/role.rb +87 -70
- data/modules/mu/clouds/aws/search_domain.rb +30 -19
- data/modules/mu/clouds/aws/server.rb +102 -72
- data/modules/mu/clouds/aws/server_pool.rb +47 -28
- data/modules/mu/clouds/aws/storage_pool.rb +5 -6
- data/modules/mu/clouds/aws/user.rb +13 -10
- data/modules/mu/clouds/aws/vpc.rb +135 -121
- data/modules/mu/clouds/azure.rb +16 -9
- data/modules/mu/clouds/azure/container_cluster.rb +2 -3
- data/modules/mu/clouds/azure/firewall_rule.rb +10 -10
- data/modules/mu/clouds/azure/habitat.rb +8 -6
- data/modules/mu/clouds/azure/loadbalancer.rb +5 -5
- data/modules/mu/clouds/azure/role.rb +8 -10
- data/modules/mu/clouds/azure/server.rb +65 -25
- data/modules/mu/clouds/azure/user.rb +5 -7
- data/modules/mu/clouds/azure/vpc.rb +12 -15
- data/modules/mu/clouds/cloudformation.rb +8 -7
- data/modules/mu/clouds/cloudformation/vpc.rb +2 -4
- data/modules/mu/clouds/google.rb +39 -24
- data/modules/mu/clouds/google/bucket.rb +9 -11
- data/modules/mu/clouds/google/container_cluster.rb +27 -42
- data/modules/mu/clouds/google/database.rb +6 -9
- data/modules/mu/clouds/google/firewall_rule.rb +11 -10
- data/modules/mu/clouds/google/folder.rb +16 -9
- data/modules/mu/clouds/google/function.rb +127 -161
- data/modules/mu/clouds/google/group.rb +21 -18
- data/modules/mu/clouds/google/habitat.rb +18 -15
- data/modules/mu/clouds/google/loadbalancer.rb +14 -16
- data/modules/mu/clouds/google/role.rb +48 -31
- data/modules/mu/clouds/google/server.rb +105 -105
- data/modules/mu/clouds/google/server_pool.rb +12 -31
- data/modules/mu/clouds/google/user.rb +67 -13
- data/modules/mu/clouds/google/vpc.rb +58 -65
- data/modules/mu/config.rb +89 -1738
- data/modules/mu/config/bucket.rb +3 -3
- data/modules/mu/config/collection.rb +3 -3
- data/modules/mu/config/container_cluster.rb +2 -2
- data/modules/mu/config/dnszone.rb +5 -5
- data/modules/mu/config/doc_helpers.rb +517 -0
- data/modules/mu/config/endpoint.rb +3 -3
- data/modules/mu/config/firewall_rule.rb +118 -3
- data/modules/mu/config/folder.rb +3 -3
- data/modules/mu/config/function.rb +2 -2
- data/modules/mu/config/group.rb +3 -3
- data/modules/mu/config/habitat.rb +3 -3
- data/modules/mu/config/loadbalancer.rb +3 -3
- data/modules/mu/config/log.rb +3 -3
- data/modules/mu/config/msg_queue.rb +3 -3
- data/modules/mu/config/nosqldb.rb +3 -3
- data/modules/mu/config/notifier.rb +2 -2
- data/modules/mu/config/ref.rb +333 -0
- data/modules/mu/config/role.rb +3 -3
- data/modules/mu/config/schema_helpers.rb +508 -0
- data/modules/mu/config/search_domain.rb +3 -3
- data/modules/mu/config/server.rb +86 -58
- data/modules/mu/config/server_pool.rb +2 -2
- data/modules/mu/config/tail.rb +189 -0
- data/modules/mu/config/user.rb +3 -3
- data/modules/mu/config/vpc.rb +44 -4
- data/modules/mu/defaults/Google.yaml +2 -2
- data/modules/mu/deploy.rb +13 -10
- data/modules/mu/groomer.rb +1 -1
- data/modules/mu/groomers/ansible.rb +69 -24
- data/modules/mu/groomers/chef.rb +52 -44
- data/modules/mu/logger.rb +17 -14
- data/modules/mu/master.rb +317 -2
- data/modules/mu/master/chef.rb +3 -4
- data/modules/mu/master/ldap.rb +3 -3
- data/modules/mu/master/ssl.rb +12 -2
- data/modules/mu/mommacat.rb +85 -1766
- data/modules/mu/mommacat/daemon.rb +394 -0
- data/modules/mu/mommacat/naming.rb +366 -0
- data/modules/mu/mommacat/storage.rb +689 -0
- data/modules/tests/bucket.yml +4 -0
- data/modules/tests/{win2k12.yaml → needwork/win2k12.yaml} +0 -0
- data/modules/tests/regrooms/aws-iam.yaml +201 -0
- data/modules/tests/regrooms/bucket.yml +19 -0
- 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,
|
|
145
|
-
|
|
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(
|
|
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'].
|
|
213
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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
|
-
|
|
229
|
-
|
|
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(
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
|
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,
|
|
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
|
-
# @
|
|
290
|
-
|
|
291
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
resp.roles
|
|
636
|
-
|
|
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(
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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 = []
|