gcloud 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG.md +15 -0
  3. data/OVERVIEW.md +38 -5
  4. data/lib/gcloud.rb +55 -4
  5. data/lib/gcloud/bigquery/data.rb +2 -0
  6. data/lib/gcloud/bigquery/dataset.rb +1 -1
  7. data/lib/gcloud/bigquery/dataset/list.rb +2 -0
  8. data/lib/gcloud/bigquery/job/list.rb +2 -0
  9. data/lib/gcloud/bigquery/project.rb +2 -9
  10. data/lib/gcloud/bigquery/table/list.rb +2 -0
  11. data/lib/gcloud/datastore.rb +23 -28
  12. data/lib/gcloud/datastore/connection.rb +3 -1
  13. data/lib/gcloud/datastore/dataset.rb +167 -22
  14. data/lib/gcloud/datastore/dataset/lookup_results.rb +2 -0
  15. data/lib/gcloud/datastore/dataset/query_results.rb +2 -0
  16. data/lib/gcloud/datastore/entity.rb +11 -11
  17. data/lib/gcloud/datastore/key.rb +33 -16
  18. data/lib/gcloud/dns/change/list.rb +2 -0
  19. data/lib/gcloud/dns/project.rb +1 -1
  20. data/lib/gcloud/dns/record/list.rb +2 -0
  21. data/lib/gcloud/dns/zone.rb +2 -2
  22. data/lib/gcloud/dns/zone/list.rb +2 -0
  23. data/lib/gcloud/gce.rb +0 -5
  24. data/lib/gcloud/pubsub.rb +65 -62
  25. data/lib/gcloud/pubsub/connection.rb +20 -2
  26. data/lib/gcloud/pubsub/project.rb +233 -72
  27. data/lib/gcloud/pubsub/subscription.rb +45 -13
  28. data/lib/gcloud/pubsub/subscription/list.rb +2 -0
  29. data/lib/gcloud/pubsub/topic.rb +66 -85
  30. data/lib/gcloud/pubsub/topic/list.rb +2 -0
  31. data/lib/gcloud/resource_manager.rb +244 -0
  32. data/lib/gcloud/resource_manager/connection.rb +124 -0
  33. data/lib/gcloud/resource_manager/credentials.rb +30 -0
  34. data/lib/gcloud/resource_manager/errors.rb +64 -0
  35. data/lib/gcloud/resource_manager/manager.rb +319 -0
  36. data/lib/gcloud/resource_manager/project.rb +529 -0
  37. data/lib/gcloud/resource_manager/project/list.rb +91 -0
  38. data/lib/gcloud/resource_manager/project/updater.rb +137 -0
  39. data/lib/gcloud/storage/bucket.rb +1 -1
  40. data/lib/gcloud/storage/bucket/cors.rb +2 -0
  41. data/lib/gcloud/storage/bucket/list.rb +2 -0
  42. data/lib/gcloud/storage/file/list.rb +2 -0
  43. data/lib/gcloud/storage/project.rb +1 -1
  44. data/lib/gcloud/version.rb +1 -1
  45. metadata +10 -2
@@ -0,0 +1,529 @@
1
+ #--
2
+ # Copyright 2015 Google Inc. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "time"
17
+ require "gcloud/resource_manager/errors"
18
+ require "gcloud/resource_manager/project/list"
19
+ require "gcloud/resource_manager/project/updater"
20
+
21
+ module Gcloud
22
+ module ResourceManager
23
+ ##
24
+ # = Project
25
+ #
26
+ # Project is a high-level Google Cloud Platform entity. It is a container
27
+ # for ACLs, APIs, AppEngine Apps, VMs, and other Google Cloud Platform
28
+ # resources.
29
+ #
30
+ # require "gcloud"
31
+ #
32
+ # gcloud = Gcloud.new
33
+ # resource_manager = gcloud.resource_manager
34
+ # project = resource_manager.project "tokyo-rain-123"
35
+ # project.update do |p|
36
+ # p.name = "My Project"
37
+ # p.labels["env"] = "production"
38
+ # end
39
+ #
40
+ class Project
41
+ ##
42
+ # The Connection object.
43
+ attr_accessor :connection #:nodoc:
44
+
45
+ ##
46
+ # The Google API Client object.
47
+ attr_accessor :gapi #:nodoc:
48
+
49
+ ##
50
+ # Create an empty Project object.
51
+ def initialize #:nodoc:
52
+ @connection = nil
53
+ @gapi = {}
54
+ end
55
+
56
+ ##
57
+ # The unique, user-assigned ID of the project. It must be 6 to 30
58
+ # lowercase letters, digits, or hyphens. It must start with a letter.
59
+ # Trailing hyphens are prohibited. e.g. tokyo-rain-123
60
+ #
61
+ def project_id
62
+ @gapi["projectId"]
63
+ end
64
+
65
+ ##
66
+ # The number uniquely identifying the project. e.g. 415104041262
67
+ #
68
+ def project_number
69
+ @gapi["projectNumber"]
70
+ end
71
+
72
+ ##
73
+ # The user-assigned name of the project.
74
+ #
75
+ def name
76
+ @gapi["name"]
77
+ end
78
+
79
+ ##
80
+ # Updates the user-assigned name of the project. This field is optional
81
+ # and can remain unset.
82
+ #
83
+ # Allowed characters are: lowercase and uppercase letters, numbers,
84
+ # hyphen, single-quote, double-quote, space, and exclamation point.
85
+ #
86
+ # === Example
87
+ #
88
+ # require "gcloud"
89
+ #
90
+ # gcloud = Gcloud.new
91
+ # resource_manager = gcloud.resource_manager
92
+ # project = resource_manager.project "tokyo-rain-123"
93
+ # project.name = "My Project"
94
+ #
95
+ def name= new_name
96
+ ensure_connection!
97
+ @gapi["name"] = new_name
98
+ resp = connection.update_project @gapi
99
+ if resp.success?
100
+ @gapi = resp.data
101
+ else
102
+ fail ApiError.from_response(resp)
103
+ end
104
+ end
105
+
106
+ ##
107
+ # The labels associated with this project.
108
+ #
109
+ # Label keys must be between 1 and 63 characters long and must conform to
110
+ # the regular expression <code>[a-z]([-a-z0-9]*[a-z0-9])?</code>.
111
+ #
112
+ # Label values must be between 0 and 63 characters long and must conform
113
+ # to the regular expression <code>([a-z]([-a-z0-9]*[a-z0-9])?)?</code>.
114
+ #
115
+ # No more than 256 labels can be associated with a given resource.
116
+ # (+Hash+)
117
+ #
118
+ # === Examples
119
+ #
120
+ # Labels are read-only and cannot be changed by direct assignment.
121
+ #
122
+ # require "gcloud"
123
+ #
124
+ # gcloud = Gcloud.new
125
+ # resource_manager = gcloud.resource_manager
126
+ # project = resource_manager.project "tokyo-rain-123"
127
+ # project.labels["env"] #=> "dev" # read only
128
+ # project.labels["env"] = "production" # raises error
129
+ #
130
+ # Labels can be updated by passing a block, or by calling the #labels=
131
+ # method.
132
+ #
133
+ # require "gcloud"
134
+ #
135
+ # gcloud = Gcloud.new
136
+ # resource_manager = gcloud.resource_manager
137
+ # project = resource_manager.project "tokyo-rain-123"
138
+ # project.labels do |labels|
139
+ # labels["env"] = "production"
140
+ # end
141
+ #
142
+ def labels
143
+ labels = @gapi["labels"]
144
+ labels = labels.to_hash if labels.respond_to? :to_hash
145
+ if block_given?
146
+ yielded_labels = labels.dup
147
+ yield yielded_labels
148
+ self.labels = yielded_labels if yielded_labels != labels # changed
149
+ else
150
+ labels.freeze
151
+ end
152
+ end
153
+
154
+ ##
155
+ # Updates the labels associated with this project.
156
+ #
157
+ # Label keys must be between 1 and 63 characters long and must conform to
158
+ # the regular expression <code>[a-z]([-a-z0-9]*[a-z0-9])?</code>.
159
+ #
160
+ # Label values must be between 0 and 63 characters long and must conform
161
+ # to the regular expression <code>([a-z]([-a-z0-9]*[a-z0-9])?)?</code>.
162
+ #
163
+ # No more than 256 labels can be associated with a given resource.
164
+ # (+Hash+)
165
+ #
166
+ # === Example
167
+ #
168
+ # require "gcloud"
169
+ #
170
+ # gcloud = Gcloud.new
171
+ # resource_manager = gcloud.resource_manager
172
+ # project = resource_manager.project "tokyo-rain-123"
173
+ # project.labels = { "env" => "production" }
174
+ #
175
+ def labels= new_labels
176
+ ensure_connection!
177
+ @gapi["labels"] = new_labels
178
+ resp = connection.update_project @gapi
179
+ if resp.success?
180
+ @gapi = resp.data
181
+ else
182
+ fail ApiError.from_response(resp)
183
+ end
184
+ end
185
+
186
+ ##
187
+ # The time that this project was created.
188
+ #
189
+ def created_at
190
+ Time.parse @gapi["createTime"]
191
+ rescue
192
+ nil
193
+ end
194
+
195
+ ##
196
+ # The project lifecycle state.
197
+ #
198
+ # Possible values are:
199
+ # * +ACTIVE+ - The normal and active state.
200
+ # * +LIFECYCLE_STATE_UNSPECIFIED+ - Unspecified state. This is only
201
+ # used/useful for distinguishing unset values.
202
+ # * +DELETE_REQUESTED+ - The project has been marked for deletion by the
203
+ # user (by invoking DeleteProject) or by the system (Google Cloud
204
+ # Platform). This can generally be reversed by invoking UndeleteProject.
205
+ # * +DELETE_IN_PROGRESS+ - The process of deleting the project has begun.
206
+ # Reversing the deletion is no longer possible.
207
+ #
208
+ def state
209
+ @gapi["lifecycleState"]
210
+ end
211
+
212
+ ##
213
+ # Checks if the state is +ACTIVE+.
214
+ def active?
215
+ return false if state.nil?
216
+ "ACTIVE".casecmp(state).zero?
217
+ end
218
+
219
+ ##
220
+ # Checks if the state is +LIFECYCLE_STATE_UNSPECIFIED+.
221
+ def unspecified?
222
+ return false if state.nil?
223
+ "LIFECYCLE_STATE_UNSPECIFIED".casecmp(state).zero?
224
+ end
225
+
226
+ ##
227
+ # Checks if the state is +DELETE_REQUESTED+.
228
+ def delete_requested?
229
+ return false if state.nil?
230
+ "DELETE_REQUESTED".casecmp(state).zero?
231
+ end
232
+
233
+ ##
234
+ # Checks if the state is +DELETE_IN_PROGRESS+.
235
+ def delete_in_progress?
236
+ return false if state.nil?
237
+ "DELETE_IN_PROGRESS".casecmp(state).zero?
238
+ end
239
+
240
+ ##
241
+ # Updates the project in a single API call. See Project::Updater
242
+ #
243
+ # === Example
244
+ #
245
+ # require "gcloud"
246
+ #
247
+ # gcloud = Gcloud.new
248
+ # resource_manager = gcloud.resource_manager
249
+ # project = resource_manager.project "tokyo-rain-123"
250
+ # project.update do |p|
251
+ # p.name = "My Project"
252
+ # p.labels["env"] = "production"
253
+ # end
254
+ #
255
+ def update
256
+ updater = Updater.from_project self
257
+ yield updater
258
+ resp = connection.update_project updater.gapi
259
+ if resp.success?
260
+ @gapi = resp.data
261
+ else
262
+ fail ApiError.from_response(resp)
263
+ end
264
+ end
265
+
266
+ ##
267
+ # Reloads the project (with updated state) from the Google Cloud Resource
268
+ # Manager service.
269
+ #
270
+ # === Example
271
+ #
272
+ # require "gcloud"
273
+ #
274
+ # gcloud = Gcloud.new
275
+ # resource_manager = gcloud.resource_manager
276
+ # project = resource_manager.project "tokyo-rain-123"
277
+ # project.reload!
278
+ #
279
+ def reload!
280
+ resp = connection.get_project project_id
281
+ if resp.success?
282
+ @gapi = resp.data
283
+ else
284
+ fail ApiError.from_response(resp)
285
+ end
286
+ end
287
+ alias_method :refresh!, :reload!
288
+
289
+ ##
290
+ # Marks the project for deletion. This method will only affect the project
291
+ # if the following criteria are met:
292
+ #
293
+ # * The project does not have a billing account associated with it.
294
+ # * The project has a lifecycle state of +ACTIVE+.
295
+ # * This method changes the project's lifecycle state from +ACTIVE+ to
296
+ # +DELETE_REQUESTED+. The deletion starts at an unspecified time, at
297
+ # which point the lifecycle state changes to +DELETE_IN_PROGRESS+.
298
+ #
299
+ # Until the deletion completes, you can check the lifecycle state by
300
+ # calling #reload!, or by retrieving the project with Manager#project. The
301
+ # project remains visible to Manager#project and Manager#projects, but
302
+ # cannot be updated.
303
+ #
304
+ # After the deletion completes, the project is not retrievable by the
305
+ # Manager#project and Manager#projects methods.
306
+ #
307
+ # The caller must have modify permissions for this project.
308
+ #
309
+ # === Example
310
+ #
311
+ # require "gcloud"
312
+ #
313
+ # gcloud = Gcloud.new
314
+ # resource_manager = gcloud.resource_manager
315
+ # project = resource_manager.project "tokyo-rain-123"
316
+ # project.active? #=> true
317
+ # project.delete
318
+ # project.active? #=> false
319
+ # project.delete_requested? #=> true
320
+ #
321
+ def delete
322
+ resp = connection.delete_project project_id
323
+ if resp.success?
324
+ reload!
325
+ true
326
+ else
327
+ fail ApiError.from_response(resp)
328
+ end
329
+ end
330
+
331
+ ##
332
+ # Restores the project. You can only use this method for a project that
333
+ # has a lifecycle state of +DELETE_REQUESTED+. After deletion starts, as
334
+ # indicated by a lifecycle state of +DELETE_IN_PROGRESS+, the project
335
+ # cannot be restored.
336
+ #
337
+ # The caller must have modify permissions for this project.
338
+ #
339
+ # === Example
340
+ #
341
+ # require "gcloud"
342
+ #
343
+ # gcloud = Gcloud.new
344
+ # resource_manager = gcloud.resource_manager
345
+ # project = resource_manager.project "tokyo-rain-123"
346
+ # project.delete_requested? #=> true
347
+ # project.undelete
348
+ # project.delete_requested? #=> false
349
+ # project.active? #=> true
350
+ #
351
+ def undelete
352
+ resp = connection.undelete_project project_id
353
+ if resp.success?
354
+ reload!
355
+ true
356
+ else
357
+ fail ApiError.from_response(resp)
358
+ end
359
+ end
360
+
361
+ ##
362
+ # Gets the {Cloud IAM}[https://cloud.google.com/iam/] access control
363
+ # policy. See {Managing
364
+ # Policies}[https://cloud.google.com/iam/docs/managing-policies]
365
+ # for more information.
366
+ #
367
+ # === Parameters
368
+ #
369
+ # +options+::
370
+ # An optional Hash for controlling additional behavior. (+Hash+)
371
+ # <code>options[:force]</code>::
372
+ # Force load the latest policy when +true+. Otherwise the policy will be
373
+ # memoized to reduce the number of API calls made. The default is
374
+ # +false+. (+Boolean+)
375
+ #
376
+ # === Returns
377
+ #
378
+ # A hash that conforms to the following structure:
379
+ #
380
+ # {
381
+ # "bindings" => [{
382
+ # "role" => "roles/viewer",
383
+ # "members" => ["serviceAccount:your-service-account"]
384
+ # }],
385
+ # "version" => 0,
386
+ # "etag" => "CAE="
387
+ # }
388
+ #
389
+ # === Examples
390
+ #
391
+ # By default the policy values are memoized to reduce the number of API
392
+ # calls made.
393
+ #
394
+ # require "gcloud"
395
+ #
396
+ # gcloud = Gcloud.new
397
+ # resource_manager = gcloud.resource_manager
398
+ # project = resource_manager.project "tokyo-rain-123"
399
+ # policy = project.policy
400
+ #
401
+ # puts policy["bindings"]
402
+ # puts policy["version"]
403
+ # puts policy["etag"]
404
+ #
405
+ # Use the +force+ option to retrieve the latest policy from the service.
406
+ #
407
+ # require "gcloud"
408
+ #
409
+ # gcloud = Gcloud.new
410
+ # resource_manager = gcloud.resource_manager
411
+ # project = resource_manager.project "tokyo-rain-123"
412
+ # policy = project.policy force: true
413
+ #
414
+ def policy options = {}
415
+ @policy = nil if options[:force]
416
+ @policy ||= begin
417
+ ensure_connection!
418
+ resp = connection.get_policy project_id
419
+ fail ApiError.from_response(resp) unless resp.success?
420
+ policy = resp.data
421
+ policy = policy.to_hash if policy.respond_to? :to_hash
422
+ policy
423
+ end
424
+ end
425
+
426
+ ##
427
+ # Sets the {Cloud IAM}[https://cloud.google.com/iam/] access control
428
+ # policy. See {Managing
429
+ # Policies}[https://cloud.google.com/iam/docs/managing-policies]
430
+ # for more information.
431
+ #
432
+ # === Parameters
433
+ #
434
+ # +new_policy+::
435
+ # A hash that conforms to the following structure:
436
+ #
437
+ # {
438
+ # "bindings" => [{
439
+ # "role" => "roles/viewer",
440
+ # "members" => ["serviceAccount:your-service-account"]
441
+ # }]
442
+ # }
443
+ #
444
+ # === Example
445
+ #
446
+ # require "gcloud"
447
+ #
448
+ # gcloud = Gcloud.new
449
+ # resource_manager = gcloud.resource_manager
450
+ # project = resource_manager.project "tokyo-rain-123"
451
+ #
452
+ # viewer_policy = {
453
+ # "bindings" => [{
454
+ # "role" => "roles/viewer",
455
+ # "members" => ["serviceAccount:your-service-account"]
456
+ # }]
457
+ # }
458
+ # project.policy = viewer_policy
459
+ #
460
+ def policy= new_policy
461
+ ensure_connection!
462
+ resp = connection.set_policy project_id, new_policy
463
+ if resp.success?
464
+ @policy = resp.data
465
+ @policy = @policy.to_hash if @policy.respond_to? :to_hash
466
+ else
467
+ fail ApiError.from_response(resp)
468
+ end
469
+ end
470
+
471
+ ##
472
+ # Tests the specified permissions against the {Cloud
473
+ # IAM}[https://cloud.google.com/iam/] access control policy. See
474
+ # {Managing Policies}[https://cloud.google.com/iam/docs/managing-policies]
475
+ # for more information.
476
+ #
477
+ # === Parameters
478
+ #
479
+ # +permissions+::
480
+ # The set of permissions to check access for. Permissions with wildcards
481
+ # (such as +*+ or +storage.*+) are not allowed.
482
+ # (String or Array of Strings)
483
+ #
484
+ # === Returns
485
+ #
486
+ # The permissions that have access. (Array of Strings)
487
+ #
488
+ # === Example
489
+ #
490
+ # require "gcloud"
491
+ #
492
+ # gcloud = Gcloud.new
493
+ # resource_manager = gcloud.resource_manager
494
+ # project = resource_manager.project "tokyo-rain-123"
495
+ # perms = project.test_permissions "resourcemanager.projects.get",
496
+ # "resourcemanager.projects.delete"
497
+ # perms.include? "resourcemanager.projects.get" #=> true
498
+ # perms.include? "resourcemanager.projects.delete" #=> false
499
+ #
500
+ def test_permissions *permissions
501
+ permissions = Array(permissions).flatten
502
+ ensure_connection!
503
+ resp = connection.test_permissions project_id, permissions
504
+ if resp.success?
505
+ Array(resp.data["permissions"])
506
+ else
507
+ fail ApiError.from_response(resp)
508
+ end
509
+ end
510
+
511
+ ##
512
+ # New Change from a Google API Client object.
513
+ def self.from_gapi gapi, connection #:nodoc:
514
+ new.tap do |p|
515
+ p.gapi = gapi
516
+ p.connection = connection
517
+ end
518
+ end
519
+
520
+ protected
521
+
522
+ ##
523
+ # Raise an error unless an active connection is available.
524
+ def ensure_connection!
525
+ fail "Must have active connection" unless connection
526
+ end
527
+ end
528
+ end
529
+ end