gcloud 0.4.1 → 0.5.0

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