google-cloud-resource_manager 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,214 @@
1
+ # Copyright 2016 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require "google/cloud/errors"
17
+ require "google/apis/cloudresourcemanager_v1"
18
+
19
+ module Google
20
+ module Cloud
21
+ module ResourceManager
22
+ ##
23
+ # # Policy
24
+ #
25
+ # Represents a Cloud IAM Policy for the Resource Manager service.
26
+ #
27
+ # A common pattern for updating a resource's metadata, such as its Policy,
28
+ # is to read the current data from the service, update the data locally,
29
+ # and then send the modified data for writing. This pattern may result in
30
+ # a conflict if two or more processes attempt the sequence simultaneously.
31
+ # IAM solves this problem with the
32
+ # {Google::Cloud::ResourceManager::Policy#etag} property, which is used to
33
+ # verify whether the policy has changed since the last request. When you
34
+ # make a request to with an `etag` value, Cloud IAM compares the `etag`
35
+ # value in the request with the existing `etag` value associated with the
36
+ # policy. It writes the policy only if the `etag` values match.
37
+ #
38
+ # When you update a policy, first read the policy (and its current `etag`)
39
+ # from the service, then modify the policy locally, and then write the
40
+ # modified policy to the service. See
41
+ # {Google::Cloud::ResourceManager::Project#policy} and
42
+ # {Google::Cloud::ResourceManager::Project#policy=}.
43
+ #
44
+ # @see https://cloud.google.com/iam/docs/managing-policies Managing
45
+ # policies
46
+ # @see https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects/setIamPolicy
47
+ # projects.setIamPolicy
48
+ #
49
+ # @attr [String] etag Used to verify whether the policy has changed since
50
+ # the last request. The policy will be written only if the `etag` values
51
+ # match.
52
+ # @attr [Hash{String => Array<String>}] roles The bindings that associate
53
+ # roles with an array of members. See [Understanding
54
+ # Roles](https://cloud.google.com/iam/docs/understanding-roles) for a
55
+ # listing of primitive and curated roles. See
56
+ # [Binding](https://cloud.google.com/resource-manager/reference/rpc/google.iam.v1#binding)
57
+ # for a listing of values and patterns for members.
58
+ #
59
+ # @example
60
+ # require "google/cloud"
61
+ #
62
+ # gcloud = Google::Cloud.new
63
+ # resource_manager = gcloud.resource_manager
64
+ # project = resource_manager.project "tokyo-rain-123"
65
+ #
66
+ # policy = project.policy # API call
67
+ #
68
+ # policy.remove "roles/owner", "user:owner@example.com" # Local call
69
+ # policy.add "roles/owner", "user:newowner@example.com" # Local call
70
+ # policy.roles["roles/viewer"] = ["allUsers"] # Local call
71
+ #
72
+ # project.policy = policy # API call
73
+ #
74
+ class Policy
75
+ ##
76
+ # Alias to the Google Client API module
77
+ API = Google::Apis::CloudresourcemanagerV1
78
+
79
+ attr_reader :etag, :roles
80
+
81
+ ##
82
+ # @private Creates a Policy object.
83
+ def initialize etag, roles
84
+ @etag = etag
85
+ @roles = roles
86
+ end
87
+
88
+ ##
89
+ # Convenience method for adding a member to a binding on this policy.
90
+ # See [Understanding
91
+ # Roles](https://cloud.google.com/iam/docs/understanding-roles) for a
92
+ # listing of primitive and curated roles. See
93
+ # [Binding](https://cloud.google.com/resource-manager/reference/rpc/google.iam.v1#binding)
94
+ # for a listing of values and patterns for members.
95
+ #
96
+ # @param [String] role_name A Cloud IAM role, such as `"roles/owner"`.
97
+ # @param [String] member A Cloud IAM identity, such as
98
+ # `"user:owner@example.com"`.
99
+ #
100
+ # @example
101
+ # require "google/cloud"
102
+ #
103
+ # gcloud = Google::Cloud.new
104
+ # resource_manager = gcloud.resource_manager
105
+ # project = resource_manager.project "tokyo-rain-123"
106
+ #
107
+ # policy = project.policy # API call
108
+ #
109
+ # policy.add "roles/owner", "user:newowner@example.com" # Local call
110
+ #
111
+ # project.policy = policy # API call
112
+ #
113
+ def add role_name, member
114
+ role(role_name) << member
115
+ end
116
+
117
+ ##
118
+ # Convenience method for removing a member from a binding on this
119
+ # policy. See [Understanding
120
+ # Roles](https://cloud.google.com/iam/docs/understanding-roles) for a
121
+ # listing of primitive and curated roles. See
122
+ # [Binding](https://cloud.google.com/resource-manager/reference/rpc/google.iam.v1#binding)
123
+ # for a listing of values and patterns for members.
124
+ #
125
+ # @param [String] role_name A Cloud IAM role, such as `"roles/owner"`.
126
+ # @param [String] member A Cloud IAM identity, such as
127
+ # `"user:owner@example.com"`.
128
+ #
129
+ # @example
130
+ # require "google/cloud"
131
+ #
132
+ # gcloud = Google::Cloud.new
133
+ # resource_manager = gcloud.resource_manager
134
+ # project = resource_manager.project "tokyo-rain-123"
135
+ #
136
+ # policy = project.policy # API call
137
+ #
138
+ # policy.remove "roles/owner", "user:owner@example.com" # Local call
139
+ #
140
+ # project.policy = policy # API call
141
+ #
142
+ def remove role_name, member
143
+ role(role_name).delete member
144
+ end
145
+
146
+ ##
147
+ # Convenience method returning the array of members bound to a role in
148
+ # this policy, or an empty array if no value is present for the role in
149
+ # {#roles}. See [Understanding
150
+ # Roles](https://cloud.google.com/iam/docs/understanding-roles) for a
151
+ # listing of primitive and curated roles. See
152
+ # [Binding](https://cloud.google.com/resource-manager/reference/rpc/google.iam.v1#binding)
153
+ # for a listing of values and patterns for members.
154
+ #
155
+ # @return [Array<String>] The members strings, or an empty array.
156
+ #
157
+ # @example
158
+ # require "google/cloud"
159
+ #
160
+ # gcloud = Google::Cloud.new
161
+ # resource_manager = gcloud.resource_manager
162
+ # project = resource_manager.project "tokyo-rain-123"
163
+ #
164
+ # policy = project.policy
165
+ #
166
+ # policy.role("roles/viewer") << "user:viewer@example.com"
167
+ #
168
+ def role role_name
169
+ roles[role_name] ||= []
170
+ end
171
+
172
+ ##
173
+ # Returns a deep copy of the policy.
174
+ #
175
+ # @return [Policy]
176
+ #
177
+ def deep_dup
178
+ dup.tap do |p|
179
+ roles_dup = p.roles.each_with_object({}) do |(k, v), memo|
180
+ memo[k] = v.dup rescue value
181
+ end
182
+ p.instance_variable_set "@roles", roles_dup
183
+ end
184
+ end
185
+
186
+ ##
187
+ # @private Convert the Policy to a
188
+ # Google::Apis::CloudresourcemanagerV1::Policy.
189
+ def to_gapi
190
+ API::Policy.new(
191
+ etag: etag,
192
+ bindings: roles.keys.map do |role_name|
193
+ next if roles[role_name].empty?
194
+ API::Binding.new(
195
+ role: role_name,
196
+ members: roles[role_name]
197
+ )
198
+ end
199
+ )
200
+ end
201
+
202
+ ##
203
+ # @private New Policy from a
204
+ # Google::Apis::CloudresourcemanagerV1::Policy object.
205
+ def self.from_gapi gapi
206
+ roles = gapi.bindings.each_with_object({}) do |binding, memo|
207
+ memo[binding.role] = binding.members.to_a
208
+ end
209
+ new gapi.etag, roles
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,486 @@
1
+ # Copyright 2015 Google Inc. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require "time"
17
+ require "google/cloud/resource_manager/project/list"
18
+ require "google/cloud/resource_manager/project/updater"
19
+ require "google/cloud/resource_manager/policy"
20
+
21
+ module Google
22
+ module Cloud
23
+ module ResourceManager
24
+ ##
25
+ # # Project
26
+ #
27
+ # Project is a high-level Google Cloud Platform entity. It is a container
28
+ # for ACLs, APIs, AppEngine Apps, VMs, and other Google Cloud Platform
29
+ # resources.
30
+ #
31
+ # @example
32
+ # require "google/cloud"
33
+ #
34
+ # gcloud = Google::Cloud.new
35
+ # resource_manager = gcloud.resource_manager
36
+ # project = resource_manager.project "tokyo-rain-123"
37
+ # project.update do |p|
38
+ # p.name = "My Project"
39
+ # p.labels["env"] = "production"
40
+ # end
41
+ #
42
+ class Project
43
+ ##
44
+ # @private The Service object.
45
+ attr_accessor :service
46
+
47
+ ##
48
+ # @private The Google API Client object.
49
+ attr_accessor :gapi
50
+
51
+ ##
52
+ # @private Create an empty Project object.
53
+ def initialize
54
+ @service = nil
55
+ @gapi = Google::Cloud::ResourceManager::Service::API::Project.new
56
+ end
57
+
58
+ ##
59
+ # The unique, user-assigned ID of the project. It must be 6 to 30
60
+ # lowercase letters, digits, or hyphens. It must start with a letter.
61
+ # Trailing hyphens are prohibited. e.g. tokyo-rain-123
62
+ #
63
+ def project_id
64
+ @gapi.project_id
65
+ end
66
+
67
+ ##
68
+ # The number uniquely identifying the project. e.g. 415104041262
69
+ #
70
+ def project_number
71
+ @gapi.project_number
72
+ end
73
+
74
+ ##
75
+ # The user-assigned name of the project.
76
+ #
77
+ def name
78
+ @gapi.name
79
+ end
80
+
81
+ ##
82
+ # Updates the user-assigned name of the project. This field is optional
83
+ # and can remain unset.
84
+ #
85
+ # Allowed characters are: lowercase and uppercase letters, numbers,
86
+ # hyphen, single-quote, double-quote, space, and exclamation point.
87
+ #
88
+ # @example
89
+ # require "google/cloud"
90
+ #
91
+ # gcloud = Google::Cloud.new
92
+ # resource_manager = gcloud.resource_manager
93
+ # project = resource_manager.project "tokyo-rain-123"
94
+ # project.name = "My Project"
95
+ #
96
+ def name= new_name
97
+ ensure_service!
98
+ @gapi.name = new_name
99
+ @gapi = service.update_project @gapi
100
+ end
101
+
102
+ ##
103
+ # The labels associated with this project.
104
+ #
105
+ # Label keys must be between 1 and 63 characters long and must conform
106
+ # to the regular expression <code>[a-z]([-a-z0-9]*[a-z0-9])?</code>.
107
+ #
108
+ # Label values must be between 0 and 63 characters long and must conform
109
+ # to the regular expression <code>([a-z]([-a-z0-9]*[a-z0-9])?)?</code>.
110
+ #
111
+ # No more than 256 labels can be associated with a given resource.
112
+ # (`Hash`)
113
+ #
114
+ # @yield [labels] a block for setting labels
115
+ # @yieldparam [Hash] labels the hash accepting labels
116
+ #
117
+ # @example Labels are read-only and cannot be changed:
118
+ # require "google/cloud"
119
+ #
120
+ # gcloud = Google::Cloud.new
121
+ # resource_manager = gcloud.resource_manager
122
+ # project = resource_manager.project "tokyo-rain-123"
123
+ # project.labels["env"] #=> "dev" # read only
124
+ # project.labels["env"] = "production" # raises error
125
+ #
126
+ # @example Labels can be updated by passing a block, or with {#labels=}:
127
+ # require "google/cloud"
128
+ #
129
+ # gcloud = Google::Cloud.new
130
+ # resource_manager = gcloud.resource_manager
131
+ # project = resource_manager.project "tokyo-rain-123"
132
+ # project.labels do |labels|
133
+ # labels["env"] = "production"
134
+ # end
135
+ #
136
+ def labels
137
+ labels = @gapi.labels.to_h
138
+ if block_given?
139
+ yielded_labels = labels.dup
140
+ yield yielded_labels
141
+ self.labels = yielded_labels if yielded_labels != labels # changed
142
+ else
143
+ labels.freeze
144
+ end
145
+ end
146
+
147
+ ##
148
+ # Updates the labels associated with this project.
149
+ #
150
+ # Label keys must be between 1 and 63 characters long and must conform
151
+ # to the regular expression <code>[a-z]([-a-z0-9]*[a-z0-9])?</code>.
152
+ #
153
+ # Label values must be between 0 and 63 characters long and must conform
154
+ # to the regular expression <code>([a-z]([-a-z0-9]*[a-z0-9])?)?</code>.
155
+ #
156
+ # No more than 256 labels can be associated with a given resource.
157
+ # (`Hash`)
158
+ #
159
+ # @example
160
+ # require "google/cloud"
161
+ #
162
+ # gcloud = Google::Cloud.new
163
+ # resource_manager = gcloud.resource_manager
164
+ # project = resource_manager.project "tokyo-rain-123"
165
+ # project.labels = { "env" => "production" }
166
+ #
167
+ def labels= new_labels
168
+ ensure_service!
169
+ @gapi.labels = new_labels
170
+ @gapi = service.update_project @gapi
171
+ end
172
+
173
+ ##
174
+ # The time that this project was created.
175
+ #
176
+ def created_at
177
+ Time.parse @gapi.create_time
178
+ rescue
179
+ nil
180
+ end
181
+
182
+ ##
183
+ # The project lifecycle state.
184
+ #
185
+ # Possible values are:
186
+ # * `ACTIVE` - The normal and active state.
187
+ # * `DELETE_REQUESTED` - The project has been marked for deletion by the
188
+ # user (by invoking ##delete) or by the system (Google Cloud
189
+ # Platform). This can generally be reversed by invoking {#undelete}.
190
+ # * `DELETE_IN_PROGRESS` - The process of deleting the project has
191
+ # begun. Reversing the deletion is no longer possible.
192
+ # * `LIFECYCLE_STATE_UNSPECIFIED` - Unspecified state. This is only
193
+ # used/useful for distinguishing unset values.
194
+ #
195
+ def state
196
+ @gapi.lifecycle_state
197
+ end
198
+
199
+ ##
200
+ # Checks if the state is `ACTIVE`.
201
+ def active?
202
+ return false if state.nil?
203
+ "ACTIVE".casecmp(state).zero?
204
+ end
205
+
206
+ ##
207
+ # Checks if the state is `LIFECYCLE_STATE_UNSPECIFIED`.
208
+ def unspecified?
209
+ return false if state.nil?
210
+ "LIFECYCLE_STATE_UNSPECIFIED".casecmp(state).zero?
211
+ end
212
+
213
+ ##
214
+ # Checks if the state is `DELETE_REQUESTED`.
215
+ def delete_requested?
216
+ return false if state.nil?
217
+ "DELETE_REQUESTED".casecmp(state).zero?
218
+ end
219
+
220
+ ##
221
+ # Checks if the state is `DELETE_IN_PROGRESS`.
222
+ def delete_in_progress?
223
+ return false if state.nil?
224
+ "DELETE_IN_PROGRESS".casecmp(state).zero?
225
+ end
226
+
227
+ ##
228
+ # Updates the project in a single API call. See {Project::Updater}
229
+ #
230
+ # @yield [project] a block yielding a project delegate
231
+ # @yieldparam [Project::Updater] project the delegate object for
232
+ # updating the project
233
+ #
234
+ # @example
235
+ # require "google/cloud"
236
+ #
237
+ # gcloud = Google::Cloud.new
238
+ # resource_manager = gcloud.resource_manager
239
+ # project = resource_manager.project "tokyo-rain-123"
240
+ # project.update do |p|
241
+ # p.name = "My Project"
242
+ # p.labels["env"] = "production"
243
+ # end
244
+ #
245
+ def update
246
+ updater = Updater.from_project self
247
+ yield updater
248
+ if updater.gapi.to_h != @gapi.to_h # changed
249
+ @gapi = service.update_project updater.gapi
250
+ end
251
+ self
252
+ end
253
+
254
+ ##
255
+ # Reloads the project (with updated state) from the Google Cloud
256
+ # Resource Manager service.
257
+ #
258
+ # @example
259
+ # require "google/cloud"
260
+ #
261
+ # gcloud = Google::Cloud.new
262
+ # resource_manager = gcloud.resource_manager
263
+ # project = resource_manager.project "tokyo-rain-123"
264
+ # project.reload!
265
+ #
266
+ def reload!
267
+ @gapi = service.get_project project_id
268
+ end
269
+ alias_method :refresh!, :reload!
270
+
271
+ ##
272
+ # Marks the project for deletion. This method will only affect the
273
+ # project if the following criteria are met:
274
+ #
275
+ # * The project does not have a billing account associated with it.
276
+ # * The project has a lifecycle state of `ACTIVE`.
277
+ # * This method changes the project's lifecycle state from `ACTIVE` to
278
+ # `DELETE_REQUESTED`. The deletion starts at an unspecified time, at
279
+ # which point the lifecycle state changes to `DELETE_IN_PROGRESS`.
280
+ #
281
+ # Until the deletion completes, you can check the lifecycle state by
282
+ # calling #reload!, or by retrieving the project with Manager#project.
283
+ # The project remains visible to Manager#project and Manager#projects,
284
+ # but cannot be updated.
285
+ #
286
+ # After the deletion completes, the project is not retrievable by the
287
+ # Manager#project and Manager#projects methods.
288
+ #
289
+ # The caller must have modify permissions for this project.
290
+ #
291
+ # @example
292
+ # require "google/cloud"
293
+ #
294
+ # gcloud = Google::Cloud.new
295
+ # resource_manager = gcloud.resource_manager
296
+ # project = resource_manager.project "tokyo-rain-123"
297
+ # project.active? #=> true
298
+ # project.delete
299
+ # project.active? #=> false
300
+ # project.delete_requested? #=> true
301
+ #
302
+ def delete
303
+ service.delete_project project_id
304
+ reload!
305
+ true
306
+ end
307
+
308
+ ##
309
+ # Restores the project. You can only use this method for a project that
310
+ # has a lifecycle state of `DELETE_REQUESTED`. After deletion starts, as
311
+ # indicated by a lifecycle state of `DELETE_IN_PROGRESS`, the project
312
+ # cannot be restored.
313
+ #
314
+ # The caller must have modify permissions for this project.
315
+ #
316
+ # @example
317
+ # require "google/cloud"
318
+ #
319
+ # gcloud = Google::Cloud.new
320
+ # resource_manager = gcloud.resource_manager
321
+ # project = resource_manager.project "tokyo-rain-123"
322
+ # project.delete_requested? #=> true
323
+ # project.undelete
324
+ # project.delete_requested? #=> false
325
+ # project.active? #=> true
326
+ #
327
+ def undelete
328
+ service.undelete_project project_id
329
+ reload!
330
+ true
331
+ end
332
+
333
+ ##
334
+ # Gets and updates the [Cloud IAM](https://cloud.google.com/iam/) access
335
+ # control policy for this project.
336
+ #
337
+ # @see https://cloud.google.com/iam/docs/managing-policies Managing
338
+ # Policies
339
+ # @see https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects/setIamPolicy
340
+ # projects.setIamPolicy
341
+ #
342
+ # @param [Boolean] force Force load the latest policy when `true`.
343
+ # Otherwise the policy will be memoized to reduce the number of API
344
+ # calls made. The default is `false`.
345
+ #
346
+ # @yield [policy] A block for updating the policy. The latest policy
347
+ # will be read from the service and passed to the block. After the
348
+ # block completes, the modified policy will be written to the service.
349
+ # @yieldparam [Policy] policy the current Cloud IAM Policy for this
350
+ # project
351
+ #
352
+ # @return [Policy] the current Cloud IAM Policy for this project
353
+ #
354
+ # @example Policy values are memoized to reduce the number of API calls:
355
+ # require "google/cloud"
356
+ #
357
+ # gcloud = Google::Cloud.new
358
+ # resource_manager = gcloud.resource_manager
359
+ # project = resource_manager.project "tokyo-rain-123"
360
+ #
361
+ # policy = project.policy # API call
362
+ # policy_2 = project.policy # No API call
363
+ #
364
+ # @example Use `force` to retrieve the latest policy from the service:
365
+ # require "google/cloud"
366
+ #
367
+ # gcloud = Google::Cloud.new
368
+ # resource_manager = gcloud.resource_manager
369
+ # project = resource_manager.project "tokyo-rain-123"
370
+ #
371
+ # policy = project.policy force: true # API call
372
+ # policy_2 = project.policy force: true # API call
373
+ #
374
+ # @example Update the policy by passing a block:
375
+ # require "google/cloud"
376
+ #
377
+ # gcloud = Google::Cloud.new
378
+ # resource_manager = gcloud.resource_manager
379
+ # project = resource_manager.project "tokyo-rain-123"
380
+ #
381
+ # policy = project.policy do |p|
382
+ # p.add "roles/owner", "user:owner@example.com"
383
+ # end # 2 API calls
384
+ #
385
+ def policy force: false
386
+ @policy = nil if force || block_given?
387
+ @policy ||= begin
388
+ ensure_service!
389
+ gapi = service.get_policy project_id
390
+ Policy.from_gapi gapi
391
+ end
392
+ return @policy unless block_given?
393
+ p = @policy.deep_dup
394
+ yield p
395
+ self.policy = p
396
+ end
397
+
398
+ ##
399
+ # Updates the [Cloud IAM](https://cloud.google.com/iam/) access control
400
+ # policy for this project. The policy should be read from {#policy}. See
401
+ # {Google::Cloud::ResourceManager::Policy} for an explanation of the
402
+ # policy `etag` property and how to modify policies.
403
+ #
404
+ # You can also update the policy by passing a block to {#policy}, which
405
+ # will call this method internally after the block completes.
406
+ #
407
+ # @see https://cloud.google.com/iam/docs/managing-policies Managing
408
+ # Policies
409
+ # @see https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects/setIamPolicy
410
+ # projects.setIamPolicy
411
+ #
412
+ # @param [Policy] new_policy a new or modified Cloud IAM Policy for this
413
+ # project
414
+ #
415
+ # @example
416
+ # require "google/cloud"
417
+ #
418
+ # gcloud = Google::Cloud.new
419
+ # resource_manager = gcloud.resource_manager
420
+ # project = resource_manager.project "tokyo-rain-123"
421
+ #
422
+ # policy = project.policy # API call
423
+ #
424
+ # policy.add "roles/owner", "user:owner@example.com"
425
+ #
426
+ # project.policy = policy # API call
427
+ #
428
+ def policy= new_policy
429
+ ensure_service!
430
+ gapi = service.set_policy project_id, new_policy.to_gapi
431
+ # Convert symbols to strings for backwards compatibility.
432
+ # This will go away when we add a ResourceManager::Policy class.
433
+ @policy = Policy.from_gapi gapi
434
+ end
435
+
436
+ ##
437
+ # Tests the specified permissions against the [Cloud
438
+ # IAM](https://cloud.google.com/iam/) access control policy.
439
+ #
440
+ # @see https://cloud.google.com/iam/docs/managing-policies Managing
441
+ # Policies
442
+ #
443
+ # @param [String, Array<String>] permissions The set of permissions to
444
+ # check access for. Permissions with wildcards (such as `*` or
445
+ # `storage.*`) are not allowed.
446
+ #
447
+ # @return [Array<String>] The permissions that have access
448
+ #
449
+ # @example
450
+ # require "google/cloud"
451
+ #
452
+ # gcloud = Google::Cloud.new
453
+ # resource_manager = gcloud.resource_manager
454
+ # project = resource_manager.project "tokyo-rain-123"
455
+ # perms = project.test_permissions "resourcemanager.projects.get",
456
+ # "resourcemanager.projects.delete"
457
+ # perms.include? "resourcemanager.projects.get" #=> true
458
+ # perms.include? "resourcemanager.projects.delete" #=> false
459
+ #
460
+ def test_permissions *permissions
461
+ permissions = Array(permissions).flatten
462
+ ensure_service!
463
+ gapi = service.test_permissions project_id, permissions
464
+ gapi.permissions
465
+ end
466
+
467
+ ##
468
+ # @private New Change from a Google API Client object.
469
+ def self.from_gapi gapi, service
470
+ new.tap do |p|
471
+ p.gapi = gapi
472
+ p.service = service
473
+ end
474
+ end
475
+
476
+ protected
477
+
478
+ ##
479
+ # Raise an error unless an active service is available.
480
+ def ensure_service!
481
+ fail "Must have active connection" unless service
482
+ end
483
+ end
484
+ end
485
+ end
486
+ end