google-cloud-storage 1.18.1 → 1.44.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHENTICATION.md +17 -30
  3. data/CHANGELOG.md +312 -0
  4. data/CONTRIBUTING.md +4 -5
  5. data/LOGGING.md +1 -1
  6. data/OVERVIEW.md +37 -5
  7. data/TROUBLESHOOTING.md +2 -8
  8. data/lib/google/cloud/storage/bucket/acl.rb +40 -40
  9. data/lib/google/cloud/storage/bucket/cors.rb +4 -1
  10. data/lib/google/cloud/storage/bucket/lifecycle.rb +259 -44
  11. data/lib/google/cloud/storage/bucket/list.rb +3 -3
  12. data/lib/google/cloud/storage/bucket.rb +1096 -172
  13. data/lib/google/cloud/storage/convert.rb +4 -3
  14. data/lib/google/cloud/storage/credentials.rb +16 -14
  15. data/lib/google/cloud/storage/errors.rb +7 -2
  16. data/lib/google/cloud/storage/file/acl.rb +181 -20
  17. data/lib/google/cloud/storage/file/list.rb +10 -8
  18. data/lib/google/cloud/storage/file/signer_v2.rb +36 -18
  19. data/lib/google/cloud/storage/file/signer_v4.rb +249 -61
  20. data/lib/google/cloud/storage/file/verifier.rb +2 -2
  21. data/lib/google/cloud/storage/file.rb +450 -84
  22. data/lib/google/cloud/storage/hmac_key/list.rb +182 -0
  23. data/lib/google/cloud/storage/hmac_key.rb +316 -0
  24. data/lib/google/cloud/storage/policy/binding.rb +246 -0
  25. data/lib/google/cloud/storage/policy/bindings.rb +196 -0
  26. data/lib/google/cloud/storage/policy/condition.rb +138 -0
  27. data/lib/google/cloud/storage/policy.rb +277 -24
  28. data/lib/google/cloud/storage/post_object.rb +20 -2
  29. data/lib/google/cloud/storage/project.rb +249 -50
  30. data/lib/google/cloud/storage/service.rb +479 -288
  31. data/lib/google/cloud/storage/version.rb +1 -1
  32. data/lib/google/cloud/storage.rb +86 -16
  33. data/lib/google-cloud-storage.rb +54 -7
  34. metadata +74 -27
@@ -109,6 +109,15 @@ module Google
109
109
  @gapi.id
110
110
  end
111
111
 
112
+ ##
113
+ # The autoclass configuration of the bucket
114
+ #
115
+ # @return [Google::Apis::StorageV1::Bucket::Autoclass]
116
+ #
117
+ def autoclass
118
+ @gapi.autoclass
119
+ end
120
+
112
121
  ##
113
122
  # The name of the bucket.
114
123
  #
@@ -234,7 +243,7 @@ module Google
234
243
  # rule.action #=> "SetStorageClass"
235
244
  # rule.storage_class #=> "COLDLINE"
236
245
  # rule.age #=> 10
237
- # rule.matches_storage_class #=> ["MULTI_REGIONAL", "REGIONAL"]
246
+ # rule.matches_storage_class #=> ["STANDARD", "NEARLINE"]
238
247
  #
239
248
  # @example Updating the bucket's lifecycle management rules in a block.
240
249
  # require "google/cloud/storage"
@@ -279,12 +288,42 @@ module Google
279
288
  #
280
289
  # @return [String]
281
290
  #
282
- # @see https://cloud.google.com/storage/docs/concepts-techniques
291
+ # @see https://cloud.google.com/storage/docs/locations
283
292
  #
284
293
  def location
285
294
  @gapi.location
286
295
  end
287
296
 
297
+ ##
298
+ # The bucket's location type. Location type defines the geographic
299
+ # placement of the bucket's data and affects cost, performance, and
300
+ # availability. There are three possible values:
301
+ #
302
+ # * `region` - Lowest latency within a single region
303
+ # * `multi-region` - Highest availability across largest area
304
+ # * `dual-region` - High availability and low latency across 2 regions
305
+ #
306
+ # @return [String] The location type code: "region", "multi-region", or
307
+ # "dual-region"
308
+ #
309
+ def location_type
310
+ @gapi.location_type
311
+ end
312
+
313
+ ##
314
+ # Returns the list of regional locations for custom dual-region buckets.
315
+ #
316
+ # @return [String, nil] Returns nil if the property has not been set before creation,
317
+ # if the bucket's resource has not been loaded from the server,
318
+ # or if the bucket is not a dual-regions bucket.
319
+
320
+ # @see https://cloud.google.com/storage/docs/json_api/v1/buckets and
321
+ # https://cloud.google.com/storage/docs/locations
322
+ #
323
+ def data_locations
324
+ @gapi.custom_placement_config&.data_locations
325
+ end
326
+
288
327
  ##
289
328
  # The destination bucket name for the bucket's logs.
290
329
  #
@@ -293,12 +332,15 @@ module Google
293
332
  # @see https://cloud.google.com/storage/docs/access-logs Access Logs
294
333
  #
295
334
  def logging_bucket
296
- @gapi.logging.log_bucket if @gapi.logging
335
+ @gapi.logging&.log_bucket
297
336
  end
298
337
 
299
338
  ##
300
339
  # Updates the destination bucket for the bucket's logs.
301
340
  #
341
+ # To pass metageneration preconditions, call this method within a
342
+ # block passed to {#update}.
343
+ #
302
344
  # @see https://cloud.google.com/storage/docs/access-logs Access Logs
303
345
  #
304
346
  # @param [String] logging_bucket The bucket to hold the logging output
@@ -317,7 +359,7 @@ module Google
317
359
  # @return [String]
318
360
  #
319
361
  def logging_prefix
320
- @gapi.logging.log_object_prefix if @gapi.logging
362
+ @gapi.logging&.log_object_prefix
321
363
  end
322
364
 
323
365
  ##
@@ -328,6 +370,9 @@ module Google
328
370
  # By default, the object prefix is the name of the bucket for which the
329
371
  # logs are enabled.
330
372
  #
373
+ # To pass metageneration preconditions, call this method within a
374
+ # block passed to {#update}.
375
+ #
331
376
  # @see https://cloud.google.com/storage/docs/access-logs Access Logs
332
377
  #
333
378
  # @param [String] logging_prefix The logging object prefix.
@@ -341,8 +386,9 @@ module Google
341
386
  ##
342
387
  # The bucket's storage class. This defines how objects in the bucket are
343
388
  # stored and determines the SLA and the cost of storage. Values include
344
- # `MULTI_REGIONAL`, `REGIONAL`, `NEARLINE`, `COLDLINE`, and
345
- # `DURABLE_REDUCED_AVAILABILITY`.
389
+ # `STANDARD`, `NEARLINE`, `COLDLINE`, and `ARCHIVE`. `REGIONAL`,`MULTI_REGIONAL`,
390
+ # and `DURABLE_REDUCED_AVAILABILITY` are supported as legacy storage
391
+ # classes.
346
392
  #
347
393
  # @return [String]
348
394
  #
@@ -353,11 +399,16 @@ module Google
353
399
  ##
354
400
  # Updates the bucket's storage class. This defines how objects in the
355
401
  # bucket are stored and determines the SLA and the cost of storage.
356
- # Accepted values include `:multi_regional`, `:regional`, `:nearline`,
357
- # and `:coldline`, as well as the equivalent strings returned by
358
- # {Bucket#storage_class}. For more information, see [Storage
402
+ # Accepted values include `:standard`, `:nearline`, `:coldline`, and
403
+ # `:archive`, as well as the equivalent strings returned by
404
+ # {Bucket#storage_class}. `:multi_regional`, `:regional`, and
405
+ # `durable_reduced_availability` are accepted as legacy storage classes.
406
+ # For more information, see [Storage
359
407
  # Classes](https://cloud.google.com/storage/docs/storage-classes).
360
408
  #
409
+ # To pass metageneration preconditions, call this method within a
410
+ # block passed to {#update}.
411
+ #
361
412
  # @param [Symbol, String] new_storage_class Storage class of the bucket.
362
413
  #
363
414
  def storage_class= new_storage_class
@@ -365,6 +416,43 @@ module Google
365
416
  patch_gapi! :storage_class
366
417
  end
367
418
 
419
+ ##
420
+ # Whether Autoclass is enabled for the bucket.
421
+ #
422
+ # @return [Boolean]
423
+ #
424
+ def autoclass_enabled
425
+ @gapi.autoclass&.enabled?
426
+ end
427
+
428
+ ##
429
+ # Toggle time of the autoclass
430
+ #
431
+ # @return [DateTime]
432
+ #
433
+ def autoclass_toggle_time
434
+ @gapi.autoclass&.toggle_time
435
+ end
436
+
437
+ ##
438
+ # Updates bucket's autoclass configuration. This defines the default class for objects in the
439
+ # bucket and down/up-grades the storage class of objects based on the access patterns.
440
+ # Accepted values are `:false`, and `:true`.
441
+ #
442
+ # For more information, see [Storage
443
+ # Classes](https://cloud.google.com/storage/docs/using-autoclass).
444
+ #
445
+ # Note: Only patch requests that disable autoclass are currently supported.
446
+ # To enable autoclass, you must set it at bucket creation time.
447
+ #
448
+ # @param [Boolean] toggle for autoclass configuration of the bucket.
449
+ #
450
+ def autoclass_enabled= toggle
451
+ @gapi.autoclass ||= API::Bucket::Autoclass.new
452
+ @gapi.autoclass.enabled = toggle
453
+ patch_gapi! :autoclass
454
+ end
455
+
368
456
  ##
369
457
  # Whether [Object
370
458
  # Versioning](https://cloud.google.com/storage/docs/object-versioning)
@@ -373,7 +461,7 @@ module Google
373
461
  # @return [Boolean]
374
462
  #
375
463
  def versioning?
376
- @gapi.versioning.enabled? unless @gapi.versioning.nil?
464
+ @gapi.versioning&.enabled?
377
465
  end
378
466
 
379
467
  ##
@@ -381,6 +469,9 @@ module Google
381
469
  # Versioning](https://cloud.google.com/storage/docs/object-versioning)
382
470
  # is enabled for the bucket.
383
471
  #
472
+ # To pass metageneration preconditions, call this method within a
473
+ # block passed to {#update}.
474
+ #
384
475
  # @param [Boolean] new_versioning true if versioning is to be enabled
385
476
  # for the bucket.
386
477
  #
@@ -403,12 +494,15 @@ module Google
403
494
  # @return [String] The main page suffix.
404
495
  #
405
496
  def website_main
406
- @gapi.website.main_page_suffix if @gapi.website
497
+ @gapi.website&.main_page_suffix
407
498
  end
408
499
 
409
500
  ##
410
501
  # Updates the main page suffix for a static website.
411
502
  #
503
+ # To pass metageneration preconditions, call this method within a
504
+ # block passed to {#update}.
505
+ #
412
506
  # @see https://cloud.google.com/storage/docs/website-configuration#step4
413
507
  # How to Host a Static Website
414
508
  #
@@ -430,7 +524,7 @@ module Google
430
524
  # @return [String]
431
525
  #
432
526
  def website_404
433
- @gapi.website.not_found_page if @gapi.website
527
+ @gapi.website&.not_found_page
434
528
  end
435
529
 
436
530
  ##
@@ -448,6 +542,9 @@ module Google
448
542
  ##
449
543
  # Updates the hash of user-provided labels.
450
544
  #
545
+ # To pass metageneration preconditions, call this method within a
546
+ # block passed to {#update}.
547
+ #
451
548
  # @param [Hash(String => String)] labels The user-provided labels.
452
549
  #
453
550
  def labels= labels
@@ -459,6 +556,9 @@ module Google
459
556
  # Updates the page returned from a static website served from the bucket
460
557
  # when a site visitor requests a resource that does not exist.
461
558
  #
559
+ # To pass metageneration preconditions, call this method within a
560
+ # block passed to {#update}.
561
+ #
462
562
  # @see https://cloud.google.com/storage/docs/website-configuration#step4
463
563
  # How to Host a Static Website
464
564
  #
@@ -479,7 +579,7 @@ module Google
479
579
  # the bucket.
480
580
  #
481
581
  def requester_pays
482
- @gapi.billing.requester_pays if @gapi.billing
582
+ @gapi.billing&.requester_pays
483
583
  end
484
584
  alias requester_pays? requester_pays
485
585
 
@@ -490,6 +590,9 @@ module Google
490
590
  # {Project#bucket} and {Project#buckets} to indicate the project to
491
591
  # which the access costs should be billed.
492
592
  #
593
+ # To pass metageneration preconditions, call this method within a
594
+ # block passed to {#update}.
595
+ #
493
596
  # @param [Boolean] new_requester_pays When set to `true`, requester pays
494
597
  # is enabled for the bucket.
495
598
  #
@@ -531,14 +634,18 @@ module Google
531
634
  # bucket.default_kms_key #=> kms_key_name
532
635
  #
533
636
  def default_kms_key
534
- @gapi.encryption && @gapi.encryption.default_kms_key_name
637
+ @gapi.encryption&.default_kms_key_name
535
638
  end
536
639
 
537
640
  ##
538
641
  # Set the Cloud KMS encryption key that will be used to protect files.
539
642
  # For example: `projects/a/locations/b/keyRings/c/cryptoKeys/d`
540
643
  #
541
- # @param [String] new_default_kms_key New Cloud KMS key name.
644
+ # To pass metageneration preconditions, call this method within a
645
+ # block passed to {#update}.
646
+ #
647
+ # @param [String, nil] new_default_kms_key New Cloud KMS key name, or
648
+ # `nil` to delete the Cloud KMS encryption key.
542
649
  #
543
650
  # @example
544
651
  # require "google/cloud/storage"
@@ -552,6 +659,15 @@ module Google
552
659
  #
553
660
  # bucket.default_kms_key = kms_key_name
554
661
  #
662
+ # @example Delete the default Cloud KMS encryption key:
663
+ # require "google/cloud/storage"
664
+ #
665
+ # storage = Google::Cloud::Storage.new
666
+ #
667
+ # bucket = storage.bucket "my-bucket"
668
+ #
669
+ # bucket.default_kms_key = nil
670
+ #
555
671
  def default_kms_key= new_default_kms_key
556
672
  @gapi.encryption = API::Bucket::Encryption.new \
557
673
  default_kms_key_name: new_default_kms_key
@@ -570,7 +686,7 @@ module Google
570
686
  # retention policy exists for the bucket.
571
687
  #
572
688
  def retention_period
573
- @gapi.retention_policy && @gapi.retention_policy.retention_period
689
+ @gapi.retention_policy&.retention_period
574
690
  end
575
691
 
576
692
  ##
@@ -588,6 +704,9 @@ module Google
588
704
  # See also: {#lock_retention_policy!}, {#retention_period},
589
705
  # {#retention_effective_at}, and {#retention_policy_locked?}.
590
706
  #
707
+ # To pass metageneration preconditions, call this method within a
708
+ # block passed to {#update}.
709
+ #
591
710
  # @param [Integer, nil] new_retention_period The retention period
592
711
  # defined in seconds. The value must be between 0 and 100 years (in
593
712
  # seconds), or `nil`.
@@ -629,7 +748,7 @@ module Google
629
748
  # policy, if a policy exists.
630
749
  #
631
750
  def retention_effective_at
632
- @gapi.retention_policy && @gapi.retention_policy.effective_time
751
+ @gapi.retention_policy&.effective_time
633
752
  end
634
753
 
635
754
  ##
@@ -686,6 +805,9 @@ module Google
686
805
  #
687
806
  # See {File#event_based_hold?} and {File#set_event_based_hold!}.
688
807
  #
808
+ # To pass metageneration preconditions, call this method within a
809
+ # block passed to {#update}.
810
+ #
689
811
  # @param [Boolean] new_default_event_based_hold The default event-based
690
812
  # hold field for the bucket.
691
813
  #
@@ -761,20 +883,12 @@ module Google
761
883
  end
762
884
 
763
885
  ##
764
- # Whether the bucket's file IAM configuration enables Bucket Policy
765
- # Only. The default is false. This value can be modified by calling
766
- # {Bucket#policy_only=}.
767
- #
768
- # If true, access checks only use bucket-level IAM policies or above,
769
- # all object ACLs within the bucket are no longer evaluated, and
770
- # access-control is configured solely through the bucket's IAM policy.
771
- # Any requests which attempt to use the ACL API to view or manipulate
772
- # ACLs will fail with 400 errors.
886
+ # Whether the bucket's file IAM configuration enables uniform bucket-level access. The default is false. This
887
+ # value can be modified by calling {Bucket#uniform_bucket_level_access=}.
773
888
  #
774
- # @return [Boolean] Returns `false` if the bucket has no IAM
775
- # configuration or if Bucket Policy Only is not enabled in the IAM
776
- # configuration. Returns `true` if Bucket Policy Only is enabled in
777
- # the IAM configuration.
889
+ # @return [Boolean] Returns `false` if the bucket has no IAM configuration or if uniform bucket-level access is
890
+ # not enabled in the IAM configuration. Returns `true` if uniform bucket-level access is enabled in the IAM
891
+ # configuration.
778
892
  #
779
893
  # @example
780
894
  # require "google/cloud/storage"
@@ -783,30 +897,30 @@ module Google
783
897
  #
784
898
  # bucket = storage.bucket "my-bucket"
785
899
  #
786
- # bucket.policy_only = true
787
- # bucket.policy_only? # true
900
+ # bucket.uniform_bucket_level_access = true
901
+ # bucket.uniform_bucket_level_access? # true
788
902
  #
789
- def policy_only?
790
- return false unless @gapi.iam_configuration &&
791
- @gapi.iam_configuration.bucket_policy_only
792
- !@gapi.iam_configuration.bucket_policy_only.enabled.nil? &&
793
- @gapi.iam_configuration.bucket_policy_only.enabled
903
+ def uniform_bucket_level_access?
904
+ return false unless @gapi.iam_configuration&.uniform_bucket_level_access
905
+ !@gapi.iam_configuration.uniform_bucket_level_access.enabled.nil? &&
906
+ @gapi.iam_configuration.uniform_bucket_level_access.enabled
794
907
  end
795
908
 
796
909
  ##
797
- # If enabled, access checks only use bucket-level IAM policies or above,
798
- # all object ACLs within the bucket are no longer evaluated, and
799
- # access-control is configured solely through the bucket's IAM policy.
800
- # Any requests which attempt to use the ACL API to view or manipulate
801
- # ACLs will fail with 400 errors.
910
+ # Sets whether uniform bucket-level access is enabled for this bucket. When this is enabled, access to the
911
+ # bucket will be configured through IAM, and legacy ACL policies will not work. When it is first enabled,
912
+ # {#uniform_bucket_level_access_locked_at} will be set by the API automatically. The uniform bucket-level access
913
+ # can then be disabled until the time specified, after which it will become immutable and calls to change it
914
+ # will fail. If uniform bucket-level access is enabled, calls to access legacy ACL information will fail.
802
915
  #
803
- # Before enabling Bucket Policy Only please review [feature
804
- # documentation](https://cloud.google.com/storage/docs/bucket-policy-only),
805
- # as well as [Should you use Bucket Policy
806
- # Only?](https://cloud.google.com/storage/docs/bucket-policy-only#should-you-use).
916
+ # Before enabling uniform bucket-level access please review [uniform bucket-level
917
+ # access](https://cloud.google.com/storage/docs/uniform-bucket-level-access).
807
918
  #
808
- # @param [Boolean] new_policy_only When set to `true`, Bucket Policy
809
- # Only is enabled in the bucket's IAM configuration.
919
+ # To pass metageneration preconditions, call this method within a
920
+ # block passed to {#update}.
921
+ #
922
+ # @param [Boolean] new_uniform_bucket_level_access When set to `true`, uniform bucket-level access is enabled in
923
+ # the bucket's IAM configuration.
810
924
  #
811
925
  # @example
812
926
  # require "google/cloud/storage"
@@ -815,31 +929,29 @@ module Google
815
929
  #
816
930
  # bucket = storage.bucket "my-bucket"
817
931
  #
818
- # bucket.policy_only = true
819
- # bucket.policy_only? # true
932
+ # bucket.uniform_bucket_level_access = true
933
+ # bucket.uniform_bucket_level_access? # true
820
934
  #
821
935
  # bucket.default_acl.public! # Google::Cloud::InvalidArgumentError
822
936
  #
823
- # # The deadline for disabling Bucket Policy Only.
824
- # puts bucket.policy_only_locked_at
937
+ # # The deadline for disabling uniform bucket-level access.
938
+ # puts bucket.uniform_bucket_level_access_locked_at
825
939
  #
826
- def policy_only= new_policy_only
827
- @gapi.iam_configuration ||= API::Bucket::IamConfiguration.new \
828
- bucket_policy_only: \
829
- API::Bucket::IamConfiguration::BucketPolicyOnly.new
830
- @gapi.iam_configuration.bucket_policy_only.enabled = new_policy_only
940
+ def uniform_bucket_level_access= new_uniform_bucket_level_access
941
+ @gapi.iam_configuration ||= API::Bucket::IamConfiguration.new
942
+ @gapi.iam_configuration.uniform_bucket_level_access ||= \
943
+ API::Bucket::IamConfiguration::UniformBucketLevelAccess.new
944
+ @gapi.iam_configuration.uniform_bucket_level_access.enabled = new_uniform_bucket_level_access
831
945
  patch_gapi! :iam_configuration
832
946
  end
833
947
 
834
948
  ##
835
- # The deadline time for disabling Bucket Policy Only by calling
836
- # {Bucket#policy_only=}. After the locked time the Bucket Policy Only
837
- # setting cannot be changed from true to false. Corresponds to the
838
- # property `locked_time`.
949
+ # The deadline time for disabling uniform bucket-level access by calling {Bucket#uniform_bucket_level_access=}.
950
+ # After the locked time the uniform bucket-level access setting cannot be changed from true to false.
951
+ # Corresponds to the property `locked_time`.
839
952
  #
840
- # @return [DateTime, nil] The deadline time for changing
841
- # {Bucket#policy_only=} from true to false, or `nil` if
842
- # {Bucket#policy_only?} is false.
953
+ # @return [DateTime, nil] The deadline time for changing {Bucket#uniform_bucket_level_access=} from true to
954
+ # false, or `nil` if {Bucket#uniform_bucket_level_access?} is false.
843
955
  #
844
956
  # @example
845
957
  # require "google/cloud/storage"
@@ -848,15 +960,195 @@ module Google
848
960
  #
849
961
  # bucket = storage.bucket "my-bucket"
850
962
  #
851
- # bucket.policy_only = true
963
+ # bucket.uniform_bucket_level_access = true
964
+ #
965
+ # # The deadline for disabling uniform bucket-level access.
966
+ # puts bucket.uniform_bucket_level_access_locked_at
852
967
  #
853
- # # The deadline for disabling Bucket Policy Only.
854
- # puts bucket.policy_only_locked_at
968
+ def uniform_bucket_level_access_locked_at
969
+ return nil unless @gapi.iam_configuration&.uniform_bucket_level_access
970
+ @gapi.iam_configuration.uniform_bucket_level_access.locked_time
971
+ end
972
+
973
+ ##
974
+ # @deprecated Use {#uniform_bucket_level_access?} instead.
975
+ #
976
+ def policy_only?
977
+ uniform_bucket_level_access?
978
+ end
979
+
980
+ ##
981
+ # @deprecated Use {#uniform_bucket_level_access=} instead.
982
+ #
983
+ def policy_only= new_policy_only
984
+ self.uniform_bucket_level_access = new_policy_only
985
+ end
986
+
987
+ ##
988
+ # @deprecated Use {#uniform_bucket_level_access_locked_at} instead.
855
989
  #
856
990
  def policy_only_locked_at
857
- return nil unless @gapi.iam_configuration &&
858
- @gapi.iam_configuration.bucket_policy_only
859
- @gapi.iam_configuration.bucket_policy_only.locked_time
991
+ uniform_bucket_level_access_locked_at
992
+ end
993
+
994
+ ##
995
+ # The value for Public Access Prevention in the bucket's IAM configuration. Currently, `inherited` and
996
+ # `enforced` are supported. When set to `enforced`, Public Access Prevention is enforced in the bucket's IAM
997
+ # configuration. This value can be modified by calling {#public_access_prevention=}.
998
+ #
999
+ # @return [String, nil] Currently, `inherited` and `enforced` are supported. Returns `nil` if the bucket has
1000
+ # no IAM configuration.
1001
+ #
1002
+ # @example
1003
+ # require "google/cloud/storage"
1004
+ #
1005
+ # storage = Google::Cloud::Storage.new
1006
+ #
1007
+ # bucket = storage.bucket "my-bucket"
1008
+ #
1009
+ # bucket.public_access_prevention = :enforced
1010
+ # bucket.public_access_prevention #=> "enforced"
1011
+ #
1012
+ def public_access_prevention
1013
+ @gapi.iam_configuration&.public_access_prevention
1014
+ end
1015
+
1016
+ ##
1017
+ # Sets the value for Public Access Prevention in the bucket's IAM configuration. This value can be queried by
1018
+ # calling {#public_access_prevention}.
1019
+ #
1020
+ # @param [Symbol, String] new_public_access_prevention The bucket's new Public Access Prevention configuration.
1021
+ # Currently, `inherited` and `enforced` are supported. When set to `enforced`, Public Access
1022
+ # Prevention is enforced in the bucket's IAM configuration.
1023
+ #
1024
+ # @example Set Public Access Prevention to enforced:
1025
+ # require "google/cloud/storage"
1026
+ #
1027
+ # storage = Google::Cloud::Storage.new
1028
+ #
1029
+ # bucket = storage.bucket "my-bucket"
1030
+ #
1031
+ # bucket.public_access_prevention = :enforced
1032
+ # bucket.public_access_prevention #=> "enforced"
1033
+ #
1034
+ # @example Set Public Access Prevention to inherited:
1035
+ # require "google/cloud/storage"
1036
+ #
1037
+ # storage = Google::Cloud::Storage.new
1038
+ #
1039
+ # bucket = storage.bucket "my-bucket"
1040
+ #
1041
+ # bucket.public_access_prevention = :inherited
1042
+ # bucket.public_access_prevention #=> "inherited"
1043
+ #
1044
+ def public_access_prevention= new_public_access_prevention
1045
+ @gapi.iam_configuration ||= API::Bucket::IamConfiguration.new
1046
+ @gapi.iam_configuration.public_access_prevention = new_public_access_prevention.to_s
1047
+ patch_gapi! :iam_configuration
1048
+ end
1049
+
1050
+ ##
1051
+ # Whether the bucket's file IAM configuration enforces Public Access Prevention. The default is `false`. This
1052
+ # value can be modified by calling {Bucket#public_access_prevention=}.
1053
+ #
1054
+ # @return [Boolean] Returns `false` if the bucket has no IAM configuration or if Public Access Prevention is
1055
+ # not `enforced` in the IAM configuration. Returns `true` if Public Access Prevention is `enforced` in the IAM
1056
+ # configuration.
1057
+ #
1058
+ # @example
1059
+ # require "google/cloud/storage"
1060
+ #
1061
+ # storage = Google::Cloud::Storage.new
1062
+ #
1063
+ # bucket = storage.bucket "my-bucket"
1064
+ #
1065
+ # bucket.public_access_prevention = :enforced
1066
+ # bucket.public_access_prevention_enforced? # true
1067
+ #
1068
+ def public_access_prevention_enforced?
1069
+ return false unless @gapi.iam_configuration&.public_access_prevention
1070
+ @gapi.iam_configuration.public_access_prevention.to_s == "enforced"
1071
+ end
1072
+
1073
+ ##
1074
+ # Whether the value for Public Access Prevention in the bucket's IAM configuration is `inherited`. The default
1075
+ # is `false`. This value can be modified by calling {Bucket#public_access_prevention=}.
1076
+ #
1077
+ # @return [Boolean] Returns `false` if the bucket has no IAM configuration or if Public Access Prevention is
1078
+ # not `inherited` in the IAM configuration. Returns `true` if Public Access Prevention is `inherited` in
1079
+ # the IAM configuration.
1080
+ #
1081
+ # @example
1082
+ # require "google/cloud/storage"
1083
+ #
1084
+ # storage = Google::Cloud::Storage.new
1085
+ #
1086
+ # bucket = storage.bucket "my-bucket"
1087
+ #
1088
+ # bucket.public_access_prevention = :inherited
1089
+ # bucket.public_access_prevention_inherited? # true
1090
+ #
1091
+ def public_access_prevention_inherited?
1092
+ return false unless @gapi.iam_configuration&.public_access_prevention
1093
+ ["inherited", "unspecified"].include? @gapi.iam_configuration.public_access_prevention.to_s
1094
+ end
1095
+
1096
+ alias public_access_prevention_unspecified? public_access_prevention_inherited?
1097
+
1098
+ ##
1099
+ # Recovery Point Objective (RPO) is another attribute of a bucket, it measures how long it takes for a set of
1100
+ # updates to be asynchronously copied to the other region.
1101
+ # Currently, `DEFAULT` and `ASYNC_TURBO` are supported. When set to `ASYNC_TURBO`, Turbo Replication is enabled
1102
+ # for a bucket. `DEFAULT` is used to reset rpo on an existing bucket with rpo set to `ASYNC_TURBO`.
1103
+ # This value can be modified by calling {#rpo=}.
1104
+ #
1105
+ # @return [String, nil] Currently, `DEFAULT` and `ASYNC_TURBO` are supported. Returns `nil` if the bucket has
1106
+ # no RPO.
1107
+ #
1108
+ # @example
1109
+ # require "google/cloud/storage"
1110
+ #
1111
+ # storage = Google::Cloud::Storage.new
1112
+ #
1113
+ # bucket = storage.bucket "my-bucket"
1114
+ #
1115
+ # bucket.rpo = :DEFAULT
1116
+ # bucket.rpo #=> "DEFAULT"
1117
+ #
1118
+ def rpo
1119
+ @gapi.rpo
1120
+ end
1121
+
1122
+ ##
1123
+ # Sets the value for Recovery Point Objective (RPO) in the bucket. This value can be queried by calling {#rpo}.
1124
+ #
1125
+ # @param [Symbol, String] new_rpo The bucket's new Recovery Point Objective metadata.
1126
+ # Currently, `DEFAULT` and `ASYNC_TURBO` are supported. When set to `ASYNC_TURBO`, Turbo Replication
1127
+ # is enabled for a bucket.
1128
+ #
1129
+ # @example Set RPO to DEFAULT:
1130
+ # require "google/cloud/storage"
1131
+ #
1132
+ # storage = Google::Cloud::Storage.new
1133
+ #
1134
+ # bucket = storage.bucket "my-bucket"
1135
+ #
1136
+ # bucket.rpo = :DEFAULT
1137
+ # bucket.rpo #=> "DEFAULT"
1138
+ #
1139
+ # @example Set RPO to ASYNC_TURBO:
1140
+ # require "google/cloud/storage"
1141
+ #
1142
+ # storage = Google::Cloud::Storage.new
1143
+ #
1144
+ # bucket = storage.bucket "my-bucket"
1145
+ #
1146
+ # bucket.rpo = :ASYNC_TURBO
1147
+ # bucket.rpo #=> "ASYNC_TURBO"
1148
+ #
1149
+ def rpo= new_rpo
1150
+ @gapi.rpo = new_rpo&.to_s
1151
+ patch_gapi! :rpo
860
1152
  end
861
1153
 
862
1154
  ##
@@ -869,6 +1161,12 @@ module Google
869
1161
  # completely mutable and will be included in the request. (See
870
1162
  # {Bucket::Cors})
871
1163
  #
1164
+ # @param [Integer] if_metageneration_match Makes the operation conditional
1165
+ # on whether the bucket's current metageneration matches the given value.
1166
+ # @param [Integer] if_metageneration_not_match Makes the operation
1167
+ # conditional on whether the bucket's current metageneration does not
1168
+ # match the given value.
1169
+ #
872
1170
  # @yield [bucket] a block yielding a delegate object for updating the
873
1171
  # file
874
1172
  #
@@ -900,14 +1198,27 @@ module Google
900
1198
  # end
901
1199
  # end
902
1200
  #
903
- def update
1201
+ # @example With a `if_metageneration_match` precondition:
1202
+ # require "google/cloud/storage"
1203
+ #
1204
+ # storage = Google::Cloud::Storage.new
1205
+ #
1206
+ # bucket = storage.bucket "my-todo-app"
1207
+ # bucket.update if_metageneration_match: 6 do |b|
1208
+ # b.website_main = "index.html"
1209
+ # end
1210
+ #
1211
+ def update if_metageneration_match: nil, if_metageneration_not_match: nil
904
1212
  updater = Updater.new @gapi
905
1213
  yield updater
906
1214
  # Add check for mutable cors
907
1215
  updater.check_for_changed_labels!
908
1216
  updater.check_for_mutable_cors!
909
1217
  updater.check_for_mutable_lifecycle!
910
- patch_gapi! updater.updates unless updater.updates.empty?
1218
+ return if updater.updates.empty?
1219
+ update_gapi! updater.updates,
1220
+ if_metageneration_match: if_metageneration_match,
1221
+ if_metageneration_not_match: if_metageneration_not_match
911
1222
  end
912
1223
 
913
1224
  ##
@@ -917,6 +1228,12 @@ module Google
917
1228
  # The API call to delete the bucket may be retried under certain
918
1229
  # conditions. See {Google::Cloud#storage} to control this behavior.
919
1230
  #
1231
+ # @param [Integer] if_metageneration_match Makes the operation conditional
1232
+ # on whether the bucket's current metageneration matches the given value.
1233
+ # @param [Integer] if_metageneration_not_match Makes the operation
1234
+ # conditional on whether the bucket's current metageneration does not
1235
+ # match the given value.
1236
+ #
920
1237
  # @return [Boolean] Returns `true` if the bucket was deleted.
921
1238
  #
922
1239
  # @example
@@ -927,10 +1244,12 @@ module Google
927
1244
  # bucket = storage.bucket "my-bucket"
928
1245
  # bucket.delete
929
1246
  #
930
- def delete
1247
+ def delete if_metageneration_match: nil, if_metageneration_not_match: nil
931
1248
  ensure_service!
932
- service.delete_bucket name, user_project: user_project
933
- true
1249
+ service.delete_bucket name,
1250
+ if_metageneration_match: if_metageneration_match,
1251
+ if_metageneration_not_match: if_metageneration_not_match,
1252
+ user_project: user_project
934
1253
  end
935
1254
 
936
1255
  ##
@@ -1004,6 +1323,19 @@ module Google
1004
1323
  # @param [String] path Name (path) of the file.
1005
1324
  # @param [Integer] generation When present, selects a specific revision
1006
1325
  # of this object. Default is the latest version.
1326
+ # @param [Integer] if_generation_match Makes the operation conditional
1327
+ # on whether the file's current generation matches the given value.
1328
+ # Setting to 0 makes the operation succeed only if there are no live
1329
+ # versions of the file.
1330
+ # @param [Integer] if_generation_not_match Makes the operation conditional
1331
+ # on whether the file's current generation does not match the given
1332
+ # value. If no live file exists, the precondition fails. Setting to 0
1333
+ # makes the operation succeed only if there is a live version of the file.
1334
+ # @param [Integer] if_metageneration_match Makes the operation conditional
1335
+ # on whether the file's current metageneration matches the given value.
1336
+ # @param [Integer] if_metageneration_not_match Makes the operation
1337
+ # conditional on whether the file's current metageneration does not
1338
+ # match the given value.
1007
1339
  # @param [Boolean] skip_lookup Optionally create a Bucket object
1008
1340
  # without verifying the bucket resource exists on the Storage service.
1009
1341
  # Calls made on this object will raise errors if the bucket resource
@@ -1025,7 +1357,14 @@ module Google
1025
1357
  # file = bucket.file "path/to/my-file.ext"
1026
1358
  # puts file.name
1027
1359
  #
1028
- def file path, generation: nil, skip_lookup: nil, encryption_key: nil
1360
+ def file path,
1361
+ generation: nil,
1362
+ if_generation_match: nil,
1363
+ if_generation_not_match: nil,
1364
+ if_metageneration_match: nil,
1365
+ if_metageneration_not_match: nil,
1366
+ skip_lookup: nil,
1367
+ encryption_key: nil
1029
1368
  ensure_service!
1030
1369
  if skip_lookup
1031
1370
  return File.new_lazy name, path, service,
@@ -1033,6 +1372,10 @@ module Google
1033
1372
  user_project: user_project
1034
1373
  end
1035
1374
  gapi = service.get_file name, path, generation: generation,
1375
+ if_generation_match: if_generation_match,
1376
+ if_generation_not_match: if_generation_not_match,
1377
+ if_metageneration_match: if_metageneration_match,
1378
+ if_metageneration_not_match: if_metageneration_not_match,
1036
1379
  key: encryption_key,
1037
1380
  user_project: user_project
1038
1381
  File.from_gapi gapi, service, user_project: user_project
@@ -1102,16 +1445,39 @@ module Google
1102
1445
  # @param [String] content_type The
1103
1446
  # [Content-Type](https://tools.ietf.org/html/rfc2616#section-14.17)
1104
1447
  # response header to be returned when the file is downloaded.
1448
+ # @param [DateTime] custom_time A custom time specified by the user for
1449
+ # the file. Once set, custom_time can't be unset, and it can only be
1450
+ # changed to a time in the future. If custom_time must be unset, you
1451
+ # must either perform a rewrite operation, or upload the data again
1452
+ # and create a new file.
1453
+ # @param [Symbol, nil] checksum The type of checksum for the client to
1454
+ # automatically calculate and send with the create request to verify
1455
+ # the integrity of the object. If provided, Cloud Storage will only
1456
+ # create the file if the value calculated by the client matches the
1457
+ # value calculated by the service.
1458
+ #
1459
+ # Acceptable values are:
1460
+ #
1461
+ # * `md5` - Calculate and provide a checksum using the MD5 hash.
1462
+ # * `crc32c` - Calculate and provide a checksum using the CRC32c hash.
1463
+ # * `all` - Calculate and provide checksums for all available verifications.
1464
+ #
1465
+ # Optional. The default is `nil`. Do not provide if also providing a
1466
+ # corresponding `crc32c` or `md5` argument. See
1467
+ # [Validation](https://cloud.google.com/storage/docs/hashes-etags)
1468
+ # for more information.
1105
1469
  # @param [String] crc32c The CRC32c checksum of the file data, as
1106
1470
  # described in [RFC 4960, Appendix
1107
1471
  # B](http://tools.ietf.org/html/rfc4960#appendix-B).
1108
1472
  # If provided, Cloud Storage will only create the file if the value
1109
- # matches the value calculated by the service. See
1473
+ # matches the value calculated by the service. Do not provide if also
1474
+ # providing a `checksum: :crc32c` or `checksum: :all` argument. See
1110
1475
  # [Validation](https://cloud.google.com/storage/docs/hashes-etags)
1111
1476
  # for more information.
1112
1477
  # @param [String] md5 The MD5 hash of the file data. If provided, Cloud
1113
1478
  # Storage will only create the file if the value matches the value
1114
- # calculated by the service. See
1479
+ # calculated by the service. Do not provide if also providing a
1480
+ # `checksum: :md5` or `checksum: :all` argument. See
1115
1481
  # [Validation](https://cloud.google.com/storage/docs/hashes-etags) for
1116
1482
  # more information.
1117
1483
  # @param [Hash] metadata A hash of custom, user-provided web-safe keys
@@ -1119,10 +1485,12 @@ module Google
1119
1485
  # file as "x-goog-meta-" response headers.
1120
1486
  # @param [Symbol, String] storage_class Storage class of the file.
1121
1487
  # Determines how the file is stored and determines the SLA and the
1122
- # cost of storage. Accepted values include `:multi_regional`,
1123
- # `:regional`, `:nearline`, and `:coldline`, as well as the equivalent
1124
- # strings returned by {#storage_class}. For more information, see
1125
- # [Storage Classes](https://cloud.google.com/storage/docs/storage-classes)
1488
+ # cost of storage. Accepted values include `:standard`, `:nearline`,
1489
+ # `:coldline`, and `:archive`, as well as the equivalent strings
1490
+ # returned by {#storage_class}. `:multi_regional`, `:regional`, and
1491
+ # `durable_reduced_availability` are accepted legacy storage classes.
1492
+ # For more information, see [Storage
1493
+ # Classes](https://cloud.google.com/storage/docs/storage-classes)
1126
1494
  # and [Per-Object Storage
1127
1495
  # Class](https://cloud.google.com/storage/docs/per-object-storage-class).
1128
1496
  # The default value is the default storage class for the bucket.
@@ -1136,6 +1504,19 @@ module Google
1136
1504
  # the same location as the bucket.The Service Account associated with
1137
1505
  # your project requires access to this encryption key. Do not provide
1138
1506
  # if `encryption_key` is used.
1507
+ # @param [Integer] if_generation_match Makes the operation conditional
1508
+ # on whether the file's current generation matches the given value.
1509
+ # Setting to 0 makes the operation succeed only if there are no live
1510
+ # versions of the file.
1511
+ # @param [Integer] if_generation_not_match Makes the operation conditional
1512
+ # on whether the file's current generation does not match the given
1513
+ # value. If no live file exists, the precondition fails. Setting to 0
1514
+ # makes the operation succeed only if there is a live version of the file.
1515
+ # @param [Integer] if_metageneration_match Makes the operation conditional
1516
+ # on whether the file's current metageneration matches the given value.
1517
+ # @param [Integer] if_metageneration_not_match Makes the operation
1518
+ # conditional on whether the file's current metageneration does not
1519
+ # match the given value.
1139
1520
  #
1140
1521
  # @return [Google::Cloud::Storage::File]
1141
1522
  #
@@ -1219,29 +1600,59 @@ module Google
1219
1600
  # file.download "path/to/downloaded/gzipped.txt",
1220
1601
  # skip_decompress: true
1221
1602
  #
1222
- def create_file file, path = nil, acl: nil, cache_control: nil,
1223
- content_disposition: nil, content_encoding: nil,
1224
- content_language: nil, content_type: nil,
1225
- crc32c: nil, md5: nil, metadata: nil,
1226
- storage_class: nil, encryption_key: nil, kms_key: nil,
1227
- temporary_hold: nil, event_based_hold: nil
1603
+ def create_file file,
1604
+ path = nil,
1605
+ acl: nil,
1606
+ cache_control: nil,
1607
+ content_disposition: nil,
1608
+ content_encoding: nil,
1609
+ content_language: nil,
1610
+ content_type: nil,
1611
+ custom_time: nil,
1612
+ checksum: nil,
1613
+ crc32c: nil,
1614
+ md5: nil,
1615
+ metadata: nil,
1616
+ storage_class: nil,
1617
+ encryption_key: nil,
1618
+ kms_key: nil,
1619
+ temporary_hold: nil,
1620
+ event_based_hold: nil,
1621
+ if_generation_match: nil,
1622
+ if_generation_not_match: nil,
1623
+ if_metageneration_match: nil,
1624
+ if_metageneration_not_match: nil
1228
1625
  ensure_service!
1229
- options = { acl: File::Acl.predefined_rule_for(acl), md5: md5,
1230
- cache_control: cache_control, content_type: content_type,
1231
- content_disposition: content_disposition, crc32c: crc32c,
1232
- content_encoding: content_encoding, metadata: metadata,
1233
- content_language: content_language, key: encryption_key,
1234
- kms_key: kms_key,
1235
- storage_class: storage_class_for(storage_class),
1236
- temporary_hold: temporary_hold,
1237
- event_based_hold: event_based_hold,
1238
- user_project: user_project }
1239
1626
  ensure_io_or_file_exists! file
1240
1627
  path ||= file.path if file.respond_to? :path
1241
1628
  path ||= file if file.is_a? String
1242
1629
  raise ArgumentError, "must provide path" if path.nil?
1243
-
1244
- gapi = service.insert_file name, file, path, options
1630
+ crc32c = crc32c_for file, checksum, crc32c
1631
+ md5 = md5_for file, checksum, md5
1632
+
1633
+ gapi = service.insert_file name,
1634
+ file,
1635
+ path,
1636
+ acl: File::Acl.predefined_rule_for(acl),
1637
+ md5: md5,
1638
+ cache_control: cache_control,
1639
+ content_type: content_type,
1640
+ custom_time: custom_time,
1641
+ content_disposition: content_disposition,
1642
+ crc32c: crc32c,
1643
+ content_encoding: content_encoding,
1644
+ metadata: metadata,
1645
+ content_language: content_language,
1646
+ key: encryption_key,
1647
+ kms_key: kms_key,
1648
+ storage_class: storage_class_for(storage_class),
1649
+ temporary_hold: temporary_hold,
1650
+ event_based_hold: event_based_hold,
1651
+ if_generation_match: if_generation_match,
1652
+ if_generation_not_match: if_generation_not_match,
1653
+ if_metageneration_match: if_metageneration_match,
1654
+ if_metageneration_not_match: if_metageneration_not_match,
1655
+ user_project: user_project
1245
1656
  File.from_gapi gapi, service, user_project: user_project
1246
1657
  end
1247
1658
  alias upload_file create_file
@@ -1285,6 +1696,16 @@ module Google
1285
1696
  # used. All source files must have been encrypted with the same key,
1286
1697
  # and the resulting destination file will also be encrypted with the
1287
1698
  # key.
1699
+ # @param [Array<Integer>] if_source_generation_match Makes the operation
1700
+ # conditional on whether the source files' current generations match the
1701
+ # given values. The list must match `sources` item-to-item.
1702
+ # @param [Integer] if_generation_match Makes the operation conditional
1703
+ # on whether the destination file's current generation matches the
1704
+ # given value. Setting to 0 makes the operation succeed only if there
1705
+ # are no live versions of the file.
1706
+ # @param [Integer] if_metageneration_match Makes the operation conditional
1707
+ # on whether the destination file's current metageneration matches the
1708
+ # given value.
1288
1709
  #
1289
1710
  # @yield [file] A block yielding a delegate file object for setting the
1290
1711
  # properties of the destination file.
@@ -1333,16 +1754,19 @@ module Google
1333
1754
  #
1334
1755
  # new_file = bucket.compose [file_1, file_2], "path/to/new-file.ext"
1335
1756
  #
1336
- def compose sources, destination, acl: nil, encryption_key: nil
1757
+ def compose sources,
1758
+ destination,
1759
+ acl: nil,
1760
+ encryption_key: nil,
1761
+ if_source_generation_match: nil,
1762
+ if_generation_match: nil,
1763
+ if_metageneration_match: nil
1337
1764
  ensure_service!
1338
1765
  sources = Array sources
1339
1766
  if sources.size < 2
1340
1767
  raise ArgumentError, "must provide at least two source files"
1341
1768
  end
1342
1769
 
1343
- options = { acl: File::Acl.predefined_rule_for(acl),
1344
- key: encryption_key,
1345
- user_project: user_project }
1346
1770
  destination_gapi = nil
1347
1771
  if block_given?
1348
1772
  destination_gapi = API::Object.new
@@ -1350,8 +1774,18 @@ module Google
1350
1774
  yield updater
1351
1775
  updater.check_for_changed_metadata!
1352
1776
  end
1353
- gapi = service.compose_file name, sources, destination,
1354
- destination_gapi, options
1777
+
1778
+ acl_rule = File::Acl.predefined_rule_for acl
1779
+ gapi = service.compose_file name,
1780
+ sources,
1781
+ destination,
1782
+ destination_gapi,
1783
+ acl: acl_rule,
1784
+ key: encryption_key,
1785
+ if_source_generation_match: if_source_generation_match,
1786
+ if_generation_match: if_generation_match,
1787
+ if_metageneration_match: if_metageneration_match,
1788
+ user_project: user_project
1355
1789
  File.from_gapi gapi, service, user_project: user_project
1356
1790
  end
1357
1791
  alias compose_file compose
@@ -1373,7 +1807,7 @@ module Google
1373
1807
  # A {SignedUrlUnavailable} is raised if the service account credentials
1374
1808
  # are missing. Service account credentials are acquired by following the
1375
1809
  # steps in [Service Account Authentication](
1376
- # https://cloud.google.com/storage/docs/authentication#service_accounts).
1810
+ # https://cloud.google.com/iam/docs/service-accounts).
1377
1811
  #
1378
1812
  # @see https://cloud.google.com/storage/docs/access-control/signed-urls
1379
1813
  # Signed URLs guide
@@ -1400,10 +1834,22 @@ module Google
1400
1834
  # use the signed URL.
1401
1835
  # @param [String] issuer Service Account's Client Email.
1402
1836
  # @param [String] client_email Service Account's Client Email.
1403
- # @param [OpenSSL::PKey::RSA, String] signing_key Service Account's
1404
- # Private Key.
1405
- # @param [OpenSSL::PKey::RSA, String] private_key Service Account's
1406
- # Private Key.
1837
+ # @param [OpenSSL::PKey::RSA, String, Proc] signing_key Service Account's
1838
+ # Private Key or a Proc that accepts a single String parameter and returns a
1839
+ # RSA SHA256 signature using a valid Google Service Account Private Key.
1840
+ # @param [OpenSSL::PKey::RSA, String, Proc] private_key Service Account's
1841
+ # Private Key or a Proc that accepts a single String parameter and returns a
1842
+ # RSA SHA256 signature using a valid Google Service Account Private Key.
1843
+ # @param [OpenSSL::PKey::RSA, String, Proc] signer Service Account's
1844
+ # Private Key or a Proc that accepts a single String parameter and returns a
1845
+ # RSA SHA256 signature using a valid Google Service Account Private Key.
1846
+ #
1847
+ # When using this method in environments such as GAE Flexible Environment,
1848
+ # GKE, or Cloud Functions where the private key is unavailable, it may be
1849
+ # necessary to provide a Proc (or lambda) via the signer parameter. This
1850
+ # Proc should return a signature created using a RPC call to the
1851
+ # [Service Account Credentials signBlob](https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob)
1852
+ # method as shown in the example below.
1407
1853
  # @param [Hash] query Query string parameters to include in the signed
1408
1854
  # URL. The given parameters are not verified by the signature.
1409
1855
  #
@@ -1412,11 +1858,29 @@ module Google
1412
1858
  # using the URL, but only when the file resource is missing the
1413
1859
  # corresponding values. (These values can be permanently set using
1414
1860
  # {File#content_disposition=} and {File#content_type=}.)
1861
+ # @param [String] scheme The URL scheme. The default value is `HTTPS`.
1862
+ # @param [Boolean] virtual_hosted_style Whether to use a virtual hosted-style
1863
+ # hostname, which adds the bucket into the host portion of the URI rather
1864
+ # than the path, e.g. `https://mybucket.storage.googleapis.com/...`.
1865
+ # For V4 signing, this also sets the `host` header in the canonicalized
1866
+ # extension headers to the virtual hosted-style host, unless that header is
1867
+ # supplied via the `headers` param. The default value of `false` uses the
1868
+ # form of `https://storage.googleapis.com/mybucket`.
1869
+ # @param [String] bucket_bound_hostname Use a bucket-bound hostname, which
1870
+ # replaces the `storage.googleapis.com` host with the name of a `CNAME`
1871
+ # bucket, e.g. a bucket named `gcs-subdomain.my.domain.tld`, or a Google
1872
+ # Cloud Load Balancer which routes to a bucket you own, e.g.
1873
+ # `my-load-balancer-domain.tld`.
1415
1874
  # @param [Symbol, String] version The version of the signed credential
1416
1875
  # to create. Must be one of `:v2` or `:v4`. The default value is
1417
1876
  # `:v2`.
1418
1877
  #
1419
- # @return [String]
1878
+ # @return [String] The signed URL.
1879
+ #
1880
+ # @raise [SignedUrlUnavailable] If the service account credentials
1881
+ # are missing. Service account credentials are acquired by following the
1882
+ # steps in [Service Account Authentication](
1883
+ # https://cloud.google.com/iam/docs/service-accounts).
1420
1884
  #
1421
1885
  # @example
1422
1886
  # require "google/cloud/storage"
@@ -1447,6 +1911,40 @@ module Google
1447
1911
  # issuer: "service-account@gcloud.com",
1448
1912
  # signing_key: key
1449
1913
  #
1914
+ # @example Using Cloud IAMCredentials signBlob to create the signature:
1915
+ # require "google/cloud/storage"
1916
+ # require "google/apis/iamcredentials_v1"
1917
+ # require "googleauth"
1918
+ #
1919
+ # # Issuer is the service account email that the Signed URL will be signed with
1920
+ # # and any permission granted in the Signed URL must be granted to the
1921
+ # # Google Service Account.
1922
+ # issuer = "service-account@project-id.iam.gserviceaccount.com"
1923
+ #
1924
+ # # Create a lambda that accepts the string_to_sign
1925
+ # signer = lambda do |string_to_sign|
1926
+ # IAMCredentials = Google::Apis::IamcredentialsV1
1927
+ # iam_client = IAMCredentials::IAMCredentialsService.new
1928
+ #
1929
+ # # Get the environment configured authorization
1930
+ # scopes = ["https://www.googleapis.com/auth/iam"]
1931
+ # iam_client.authorization = Google::Auth.get_application_default scopes
1932
+ #
1933
+ # request = Google::Apis::IamcredentialsV1::SignBlobRequest.new(
1934
+ # payload: string_to_sign
1935
+ # )
1936
+ # resource = "projects/-/serviceAccounts/#{issuer}"
1937
+ # response = iam_client.sign_service_account_blob resource, request
1938
+ # response.signed_blob
1939
+ # end
1940
+ #
1941
+ # storage = Google::Cloud::Storage.new
1942
+ #
1943
+ # bucket_name = "my-todo-app"
1944
+ # file_path = "avatars/heidi/400x400.png"
1945
+ # url = storage.signed_url bucket_name, file_path,
1946
+ # method: "GET", issuer: issuer,
1947
+ # signer: signer
1450
1948
  # @example Using the `headers` option:
1451
1949
  # require "google/cloud/storage"
1452
1950
  #
@@ -1482,36 +1980,60 @@ module Google
1482
1980
  # bucket = storage.bucket "my-todo-app"
1483
1981
  # list_files_url = bucket.signed_url version: :v4
1484
1982
  #
1485
- def signed_url path = nil, method: nil, expires: nil, content_type: nil,
1486
- content_md5: nil, headers: nil, issuer: nil,
1487
- client_email: nil, signing_key: nil, private_key: nil,
1488
- query: nil, version: nil
1983
+ def signed_url path = nil,
1984
+ method: "GET",
1985
+ expires: nil,
1986
+ content_type: nil,
1987
+ content_md5: nil,
1988
+ headers: nil,
1989
+ issuer: nil,
1990
+ client_email: nil,
1991
+ signing_key: nil,
1992
+ private_key: nil,
1993
+ signer: nil,
1994
+ query: nil,
1995
+ scheme: "HTTPS",
1996
+ virtual_hosted_style: nil,
1997
+ bucket_bound_hostname: nil,
1998
+ version: nil
1489
1999
  ensure_service!
1490
2000
  version ||= :v2
1491
2001
  case version.to_sym
1492
2002
  when :v2
1493
- signer = File::SignerV2.from_bucket self, path
1494
- signer.signed_url method: method, expires: expires,
1495
- headers: headers, content_type: content_type,
1496
- content_md5: content_md5, issuer: issuer,
1497
- client_email: client_email,
1498
- signing_key: signing_key,
1499
- private_key: private_key, query: query
2003
+ sign = File::SignerV2.from_bucket self, path
2004
+ sign.signed_url method: method,
2005
+ expires: expires,
2006
+ headers: headers,
2007
+ content_type: content_type,
2008
+ content_md5: content_md5,
2009
+ issuer: issuer,
2010
+ client_email: client_email,
2011
+ signing_key: signing_key,
2012
+ private_key: private_key,
2013
+ signer: signer,
2014
+ query: query
1500
2015
  when :v4
1501
- signer = File::SignerV4.from_bucket self, path
1502
- signer.signed_url method: method, expires: expires,
1503
- headers: headers, issuer: issuer,
1504
- client_email: client_email,
1505
- signing_key: signing_key,
1506
- private_key: private_key, query: query
2016
+ sign = File::SignerV4.from_bucket self, path
2017
+ sign.signed_url method: method,
2018
+ expires: expires,
2019
+ headers: headers,
2020
+ issuer: issuer,
2021
+ client_email: client_email,
2022
+ signing_key: signing_key,
2023
+ private_key: private_key,
2024
+ signer: signer,
2025
+ query: query,
2026
+ scheme: scheme,
2027
+ virtual_hosted_style: virtual_hosted_style,
2028
+ bucket_bound_hostname: bucket_bound_hostname
1507
2029
  else
1508
2030
  raise ArgumentError, "version '#{version}' not supported"
1509
2031
  end
1510
2032
  end
1511
2033
 
1512
2034
  ##
1513
- # Generate a PostObject that includes the fields and url to
1514
- # upload objects via html forms.
2035
+ # Generate a PostObject that includes the fields and URL to
2036
+ # upload objects via HTML forms.
1515
2037
  #
1516
2038
  # Generating a PostObject requires service account credentials,
1517
2039
  # either by connecting with a service account when calling
@@ -1524,28 +2046,45 @@ module Google
1524
2046
  # A {SignedUrlUnavailable} is raised if the service account credentials
1525
2047
  # are missing. Service account credentials are acquired by following the
1526
2048
  # steps in [Service Account Authentication](
1527
- # https://cloud.google.com/storage/docs/authentication#service_accounts).
2049
+ # https://cloud.google.com/iam/docs/service-accounts).
1528
2050
  #
1529
2051
  # @see https://cloud.google.com/storage/docs/xml-api/post-object
1530
2052
  #
1531
2053
  # @param [String] path Path to the file in Google Cloud Storage.
1532
2054
  # @param [Hash] policy The security policy that describes what
1533
- # can and cannot be uploaded in the form. When provided,
1534
- # the PostObject fields will include a Signature based on the JSON
1535
- # representation of this Hash and the same policy in Base64 format.
2055
+ # can and cannot be uploaded in the form. When provided, the PostObject
2056
+ # fields will include a signature based on the JSON representation of
2057
+ # this hash and the same policy in Base64 format.
2058
+ #
1536
2059
  # If you do not provide a security policy, requests are considered
1537
2060
  # to be anonymous and will only work with buckets that have granted
1538
- # WRITE or FULL_CONTROL permission to anonymous users.
2061
+ # `WRITE` or `FULL_CONTROL` permission to anonymous users.
1539
2062
  # See [Policy Document](https://cloud.google.com/storage/docs/xml-api/post-object#policydocument)
1540
2063
  # for more information.
1541
2064
  # @param [String] issuer Service Account's Client Email.
1542
2065
  # @param [String] client_email Service Account's Client Email.
1543
- # @param [OpenSSL::PKey::RSA, String] signing_key Service Account's
1544
- # Private Key.
1545
- # @param [OpenSSL::PKey::RSA, String] private_key Service Account's
1546
- # Private Key.
1547
- #
1548
- # @return [PostObject]
2066
+ # @param [OpenSSL::PKey::RSA, String, Proc] signing_key Service Account's
2067
+ # Private Key or a Proc that accepts a single String parameter and returns a
2068
+ # RSA SHA256 signature using a valid Google Service Account Private Key.
2069
+ # @param [OpenSSL::PKey::RSA, String, Proc] private_key Service Account's
2070
+ # Private Key or a Proc that accepts a single String parameter and returns a
2071
+ # RSA SHA256 signature using a valid Google Service Account Private Key.
2072
+ # @param [OpenSSL::PKey::RSA, String, Proc] signer Service Account's
2073
+ # Private Key or a Proc that accepts a single String parameter and returns a
2074
+ # RSA SHA256 signature using a valid Google Service Account Private Key.
2075
+ #
2076
+ # When using this method in environments such as GAE Flexible Environment,
2077
+ # GKE, or Cloud Functions where the private key is unavailable, it may be
2078
+ # necessary to provide a Proc (or lambda) via the signer parameter. This
2079
+ # Proc should return a signature created using a RPC call to the
2080
+ # [Service Account Credentials signBlob](https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob)
2081
+ # method as shown in the example below.
2082
+ # @return [PostObject] An object containing the URL, fields, and values needed to upload files via HTML forms.
2083
+ #
2084
+ # @raise [SignedUrlUnavailable] If the service account credentials
2085
+ # are missing. Service account credentials are acquired by following the
2086
+ # steps in [Service Account Authentication](
2087
+ # https://cloud.google.com/iam/docs/service-accounts).
1549
2088
  #
1550
2089
  # @example
1551
2090
  # require "google/cloud/storage"
@@ -1605,15 +2144,226 @@ module Google
1605
2144
  # post.fields[:signature] #=> "ABC...XYZ="
1606
2145
  # post.fields[:policy] #=> "ABC...XYZ="
1607
2146
  #
1608
- def post_object path, policy: nil, issuer: nil,
1609
- client_email: nil, signing_key: nil,
1610
- private_key: nil
2147
+ # @example Using Cloud IAMCredentials signBlob to create the signature:
2148
+ # require "google/cloud/storage"
2149
+ # require "google/apis/iamcredentials_v1"
2150
+ # require "googleauth"
2151
+ #
2152
+ # # Issuer is the service account email that the Signed URL will be signed with
2153
+ # # and any permission granted in the Signed URL must be granted to the
2154
+ # # Google Service Account.
2155
+ # issuer = "service-account@project-id.iam.gserviceaccount.com"
2156
+ #
2157
+ # # Create a lambda that accepts the string_to_sign
2158
+ # signer = lambda do |string_to_sign|
2159
+ # IAMCredentials = Google::Apis::IamcredentialsV1
2160
+ # iam_client = IAMCredentials::IAMCredentialsService.new
2161
+ #
2162
+ # # Get the environment configured authorization
2163
+ # scopes = ["https://www.googleapis.com/auth/iam"]
2164
+ # iam_client.authorization = Google::Auth.get_application_default scopes
2165
+ #
2166
+ # request = Google::Apis::IamcredentialsV1::SignBlobRequest.new(
2167
+ # payload: string_to_sign
2168
+ # )
2169
+ # resource = "projects/-/serviceAccounts/#{issuer}"
2170
+ # response = iam_client.sign_service_account_blob resource, request
2171
+ # response.signed_blob
2172
+ # end
2173
+ #
2174
+ # storage = Google::Cloud::Storage.new
2175
+ #
2176
+ # bucket = storage.bucket "my-todo-app"
2177
+ # post = bucket.post_object "avatars/heidi/400x400.png",
2178
+ # issuer: issuer,
2179
+ # signer: signer
2180
+ #
2181
+ # post.url #=> "https://storage.googleapis.com"
2182
+ # post.fields[:key] #=> "my-todo-app/avatars/heidi/400x400.png"
2183
+ # post.fields[:GoogleAccessId] #=> "0123456789@gserviceaccount.com"
2184
+ # post.fields[:signature] #=> "ABC...XYZ="
2185
+ # post.fields[:policy] #=> "ABC...XYZ="
2186
+ #
2187
+ def post_object path,
2188
+ policy: nil,
2189
+ issuer: nil,
2190
+ client_email: nil,
2191
+ signing_key: nil,
2192
+ private_key: nil,
2193
+ signer: nil
1611
2194
  ensure_service!
2195
+ sign = File::SignerV2.from_bucket self, path
2196
+ sign.post_object issuer: issuer,
2197
+ client_email: client_email,
2198
+ signing_key: signing_key,
2199
+ private_key: private_key,
2200
+ signer: signer,
2201
+ policy: policy
2202
+ end
1612
2203
 
1613
- signer = File::SignerV2.from_bucket self, path
1614
- signer.post_object issuer: issuer, client_email: client_email,
1615
- signing_key: signing_key, private_key: private_key,
1616
- policy: policy
2204
+ ##
2205
+ # Generate a `PostObject` that includes the fields and URL to
2206
+ # upload objects via HTML forms. The resulting `PostObject` is
2207
+ # based on a policy document created from the method arguments.
2208
+ # This policy provides authorization to ensure that the HTML
2209
+ # form can upload files into the bucket. See [Signatures -
2210
+ # Policy document](https://cloud.google.com/storage/docs/authentication/signatures#policy-document).
2211
+ #
2212
+ # Generating a `PostObject` requires service account credentials,
2213
+ # either by connecting with a service account when calling
2214
+ # {Google::Cloud.storage}, or by passing in the service account
2215
+ # `issuer` and `signing_key` values. Although the private key can
2216
+ # be passed as a string for convenience, creating and storing
2217
+ # an instance of `OpenSSL::PKey::RSA` is more efficient
2218
+ # when making multiple calls to `generate_signed_post_policy_v4`.
2219
+ #
2220
+ # A {SignedUrlUnavailable} is raised if the service account credentials
2221
+ # are missing. Service account credentials are acquired by following the
2222
+ # steps in [Service Account Authentication](
2223
+ # https://cloud.google.com/iam/docs/service-accounts).
2224
+ #
2225
+ # @see https://cloud.google.com/storage/docs/authentication/signatures#policy-document Signatures -
2226
+ # Policy document
2227
+ # @see https://cloud.google.com/storage/docs/xml-api/post-object
2228
+ #
2229
+ # @param [String] path Path to the file in Google Cloud Storage.
2230
+ # @param [String] issuer Service Account's Client Email.
2231
+ # @param [String] client_email Service Account's Client Email.
2232
+ # @param [OpenSSL::PKey::RSA, String, Proc] signing_key Service Account's
2233
+ # Private Key or a Proc that accepts a single String parameter and returns a
2234
+ # RSA SHA256 signature using a valid Google Service Account Private Key.
2235
+ # @param [OpenSSL::PKey::RSA, String, Proc] private_key Service Account's
2236
+ # Private Key or a Proc that accepts a single String parameter and returns a
2237
+ # RSA SHA256 signature using a valid Google Service Account Private Key.
2238
+ # @param [OpenSSL::PKey::RSA, String, Proc] signer Service Account's
2239
+ # Private Key or a Proc that accepts a single String parameter and returns a
2240
+ # RSA SHA256 signature using a valid Google Service Account Private Key.
2241
+ #
2242
+ # When using this method in environments such as GAE Flexible Environment,
2243
+ # GKE, or Cloud Functions where the private key is unavailable, it may be
2244
+ # necessary to provide a Proc (or lambda) via the signer parameter. This
2245
+ # Proc should return a signature created using a RPC call to the
2246
+ # [Service Account Credentials signBlob](https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob)
2247
+ # method as shown in the example below.
2248
+ # @param [Integer] expires The number of seconds until the URL expires.
2249
+ # The default is 604800 (7 days).
2250
+ # @param [Hash{String => String}] fields User-supplied form fields such as `acl`,
2251
+ # `cache-control`, `success_action_status`, and `success_action_redirect`.
2252
+ # Optional. See [Upload an object with HTML forms - Form
2253
+ # fields](https://cloud.google.com/storage/docs/xml-api/post-object-forms#form_fields).
2254
+ # @param [Array<Hash{String => String}|Array<String>>] conditions An array of
2255
+ # policy conditions that every upload must satisfy. For example:
2256
+ # `[["eq", "$Content-Type", "image/jpeg"]]`. Optional. See [Signatures - Policy
2257
+ # document](https://cloud.google.com/storage/docs/authentication/signatures#policy-document).
2258
+ # @param [String] scheme The URL scheme. The default value is `HTTPS`.
2259
+ # @param [Boolean] virtual_hosted_style Whether to use a virtual hosted-style
2260
+ # hostname, which adds the bucket into the host portion of the URI rather
2261
+ # than the path, e.g. `https://mybucket.storage.googleapis.com/...`.
2262
+ # The default value of `false` uses the
2263
+ # form of `https://storage.googleapis.com/mybucket`.
2264
+ # @param [String] bucket_bound_hostname Use a bucket-bound hostname, which
2265
+ # replaces the `storage.googleapis.com` host with the name of a `CNAME`
2266
+ # bucket, e.g. a bucket named `gcs-subdomain.my.domain.tld`, or a Google
2267
+ # Cloud Load Balancer which routes to a bucket you own, e.g.
2268
+ # `my-load-balancer-domain.tld`.
2269
+ #
2270
+ # @return [PostObject] An object containing the URL, fields, and values needed to
2271
+ # upload files via HTML forms.
2272
+ #
2273
+ # @raise [SignedUrlUnavailable] If the service account credentials are missing.
2274
+ # Service account credentials are acquired by following the steps in [Service
2275
+ # Account Authentication](https://cloud.google.com/iam/docs/service-accounts).
2276
+ #
2277
+ # @example
2278
+ # require "google/cloud/storage"
2279
+ #
2280
+ # storage = Google::Cloud::Storage.new
2281
+ #
2282
+ # bucket = storage.bucket "my-todo-app"
2283
+ #
2284
+ # conditions = [["starts-with", "$acl","public"]]
2285
+ # post = bucket.generate_signed_post_policy_v4 "avatars/heidi/400x400.png",
2286
+ # expires: 10,
2287
+ # conditions: conditions
2288
+ #
2289
+ # post.url #=> "https://storage.googleapis.com/my-todo-app/"
2290
+ # post.fields["key"] #=> "my-todo-app/avatars/heidi/400x400.png"
2291
+ # post.fields["policy"] #=> "ABC...XYZ"
2292
+ # post.fields["x-goog-algorithm"] #=> "GOOG4-RSA-SHA256"
2293
+ # post.fields["x-goog-credential"] #=> "cred@pid.iam.gserviceaccount.com/20200123/auto/storage/goog4_request"
2294
+ # post.fields["x-goog-date"] #=> "20200128T000000Z"
2295
+ # post.fields["x-goog-signature"] #=> "4893a0e...cd82"
2296
+ #
2297
+ # @example Using Cloud IAMCredentials signBlob to create the signature:
2298
+ # require "google/cloud/storage"
2299
+ # require "google/apis/iamcredentials_v1"
2300
+ # require "googleauth"
2301
+ #
2302
+ # # Issuer is the service account email that the Signed URL will be signed with
2303
+ # # and any permission granted in the Signed URL must be granted to the
2304
+ # # Google Service Account.
2305
+ # issuer = "service-account@project-id.iam.gserviceaccount.com"
2306
+ #
2307
+ # # Create a lambda that accepts the string_to_sign
2308
+ # signer = lambda do |string_to_sign|
2309
+ # IAMCredentials = Google::Apis::IamcredentialsV1
2310
+ # iam_client = IAMCredentials::IAMCredentialsService.new
2311
+ #
2312
+ # # Get the environment configured authorization
2313
+ # scopes = ["https://www.googleapis.com/auth/iam"]
2314
+ # iam_client.authorization = Google::Auth.get_application_default scopes
2315
+ #
2316
+ # request = Google::Apis::IamcredentialsV1::SignBlobRequest.new(
2317
+ # payload: string_to_sign
2318
+ # )
2319
+ # resource = "projects/-/serviceAccounts/#{issuer}"
2320
+ # response = iam_client.sign_service_account_blob resource, request
2321
+ # response.signed_blob
2322
+ # end
2323
+ #
2324
+ # storage = Google::Cloud::Storage.new
2325
+ #
2326
+ # bucket = storage.bucket "my-todo-app"
2327
+ # conditions = [["starts-with", "$acl","public"]]
2328
+ # post = bucket.generate_signed_post_policy_v4 "avatars/heidi/400x400.png",
2329
+ # expires: 10,
2330
+ # conditions: conditions,
2331
+ # issuer: issuer,
2332
+ # signer: signer
2333
+ #
2334
+ # post.url #=> "https://storage.googleapis.com/my-todo-app/"
2335
+ # post.fields["key"] #=> "my-todo-app/avatars/heidi/400x400.png"
2336
+ # post.fields["policy"] #=> "ABC...XYZ"
2337
+ # post.fields["x-goog-algorithm"] #=> "GOOG4-RSA-SHA256"
2338
+ # post.fields["x-goog-credential"] #=> "cred@pid.iam.gserviceaccount.com/20200123/auto/storage/goog4_request"
2339
+ # post.fields["x-goog-date"] #=> "20200128T000000Z"
2340
+ # post.fields["x-goog-signature"] #=> "4893a0e...cd82"
2341
+ #
2342
+ def generate_signed_post_policy_v4 path,
2343
+ issuer: nil,
2344
+ client_email: nil,
2345
+ signing_key: nil,
2346
+ private_key: nil,
2347
+ signer: nil,
2348
+ expires: nil,
2349
+ fields: nil,
2350
+ conditions: nil,
2351
+ scheme: "https",
2352
+ virtual_hosted_style: nil,
2353
+ bucket_bound_hostname: nil
2354
+ ensure_service!
2355
+ sign = File::SignerV4.from_bucket self, path
2356
+ sign.post_object issuer: issuer,
2357
+ client_email: client_email,
2358
+ signing_key: signing_key,
2359
+ private_key: private_key,
2360
+ signer: signer,
2361
+ expires: expires,
2362
+ fields: fields,
2363
+ conditions: conditions,
2364
+ scheme: scheme,
2365
+ virtual_hosted_style: virtual_hosted_style,
2366
+ bucket_bound_hostname: bucket_bound_hostname
1617
2367
  end
1618
2368
 
1619
2369
  ##
@@ -1719,6 +2469,26 @@ module Google
1719
2469
  # @param [Boolean] force [Deprecated] Force the latest policy to be
1720
2470
  # retrieved from the Storage service when `true`. Deprecated because
1721
2471
  # the latest policy is now always retrieved. The default is `nil`.
2472
+ # @param [Integer] requested_policy_version The requested syntax schema
2473
+ # version of the policy. Optional. If `1`, `nil`, or not provided, a
2474
+ # {Google::Cloud::Storage::PolicyV1} object is returned, which
2475
+ # provides {Google::Cloud::Storage::PolicyV1#roles} and related
2476
+ # helpers but does not provide a `bindings` method. If `3` is
2477
+ # provided, a {Google::Cloud::Storage::PolicyV3} object is returned,
2478
+ # which provides {Google::Cloud::Storage::PolicyV3#bindings} but does
2479
+ # not provide a `roles` method or related helpers. A higher version
2480
+ # indicates that the policy contains role bindings with the newer
2481
+ # syntax schema that is unsupported by earlier versions.
2482
+ #
2483
+ # The following requested policy versions are valid:
2484
+ #
2485
+ # * 1 - The first version of Cloud IAM policy schema. Supports binding one
2486
+ # role to one or more members. Does not support conditional bindings.
2487
+ # * 3 - Introduces the condition field in the role binding, which further
2488
+ # constrains the role binding via context-based and attribute-based rules.
2489
+ # See [Understanding policies](https://cloud.google.com/iam/docs/policies)
2490
+ # and [Overview of Cloud IAM Conditions](https://cloud.google.com/iam/docs/conditions-overview)
2491
+ # for more information.
1722
2492
  #
1723
2493
  # @yield [policy] A block for updating the policy. The latest policy
1724
2494
  # will be read from the service and passed to the block. After the
@@ -1728,31 +2498,98 @@ module Google
1728
2498
  #
1729
2499
  # @return [Policy] the current Cloud IAM Policy for this bucket
1730
2500
  #
1731
- # @example
2501
+ # @example Retrieving a Policy that is implicitly version 1:
1732
2502
  # require "google/cloud/storage"
1733
2503
  #
1734
2504
  # storage = Google::Cloud::Storage.new
1735
- #
1736
- # bucket = storage.bucket "my-todo-app"
2505
+ # bucket = storage.bucket "my-bucket"
1737
2506
  #
1738
2507
  # policy = bucket.policy
2508
+ # policy.version # 1
2509
+ # puts policy.roles["roles/storage.objectViewer"]
1739
2510
  #
1740
- # @example Retrieve the latest policy and update it in a block:
2511
+ # @example Retrieving a version 3 Policy using `requested_policy_version`:
1741
2512
  # require "google/cloud/storage"
1742
2513
  #
1743
2514
  # storage = Google::Cloud::Storage.new
2515
+ # bucket = storage.bucket "my-bucket"
1744
2516
  #
1745
- # bucket = storage.bucket "my-todo-app"
2517
+ # policy = bucket.policy requested_policy_version: 3
2518
+ # policy.version # 3
2519
+ # puts policy.bindings.find do |b|
2520
+ # b[:role] == "roles/storage.objectViewer"
2521
+ # end
2522
+ #
2523
+ # @example Updating a Policy that is implicitly version 1:
2524
+ # require "google/cloud/storage"
2525
+ #
2526
+ # storage = Google::Cloud::Storage.new
2527
+ # bucket = storage.bucket "my-bucket"
1746
2528
  #
1747
2529
  # bucket.policy do |p|
1748
- # p.add "roles/owner", "user:owner@example.com"
2530
+ # p.version # the value is 1
2531
+ # p.remove "roles/storage.admin", "user:owner@example.com"
2532
+ # p.add "roles/storage.admin", "user:newowner@example.com"
2533
+ # p.roles["roles/storage.objectViewer"] = ["allUsers"]
2534
+ # end
2535
+ #
2536
+ # @example Updating a Policy from version 1 to version 3 by adding a condition:
2537
+ # require "google/cloud/storage"
2538
+ #
2539
+ # storage = Google::Cloud::Storage.new
2540
+ # bucket = storage.bucket "my-bucket"
2541
+ #
2542
+ # bucket.uniform_bucket_level_access = true
2543
+ #
2544
+ # bucket.policy requested_policy_version: 3 do |p|
2545
+ # p.version # the value is 1
2546
+ # p.version = 3 # Must be explicitly set to opt-in to support for conditions.
2547
+ #
2548
+ # expr = "resource.name.startsWith(\"projects/_/buckets/bucket-name/objects/prefix-a-\")"
2549
+ # p.bindings.insert({
2550
+ # role: "roles/storage.admin",
2551
+ # members: ["user:owner@example.com"],
2552
+ # condition: {
2553
+ # title: "my-condition",
2554
+ # description: "description of condition",
2555
+ # expression: expr
2556
+ # }
2557
+ # })
2558
+ # end
2559
+ #
2560
+ # @example Updating a version 3 Policy:
2561
+ # require "google/cloud/storage"
2562
+ #
2563
+ # storage = Google::Cloud::Storage.new
2564
+ # bucket = storage.bucket "my-bucket"
2565
+ #
2566
+ # bucket.uniform_bucket_level_access? # true
2567
+ #
2568
+ # bucket.policy requested_policy_version: 3 do |p|
2569
+ # p.version = 3 # Must be explicitly set to opt-in to support for conditions.
2570
+ #
2571
+ # expr = "resource.name.startsWith(\"projects/_/buckets/bucket-name/objects/prefix-a-\")"
2572
+ # p.bindings.insert({
2573
+ # role: "roles/storage.admin",
2574
+ # members: ["user:owner@example.com"],
2575
+ # condition: {
2576
+ # title: "my-condition",
2577
+ # description: "description of condition",
2578
+ # expression: expr
2579
+ # }
2580
+ # })
1749
2581
  # end
1750
2582
  #
1751
- def policy force: nil
2583
+ def policy force: nil, requested_policy_version: nil
1752
2584
  warn "DEPRECATED: 'force' in Bucket#policy" unless force.nil?
1753
2585
  ensure_service!
1754
- gapi = service.get_bucket_policy name, user_project: user_project
1755
- policy = Policy.from_gapi gapi
2586
+ gapi = service.get_bucket_policy name, requested_policy_version: requested_policy_version,
2587
+ user_project: user_project
2588
+ policy = if requested_policy_version.nil? || requested_policy_version == 1
2589
+ PolicyV1.from_gapi gapi
2590
+ else
2591
+ PolicyV3.from_gapi gapi
2592
+ end
1756
2593
  return policy unless block_given?
1757
2594
  yield policy
1758
2595
  update_policy policy
@@ -1777,24 +2614,70 @@ module Google
1777
2614
  #
1778
2615
  # @return [Policy] The policy returned by the API update operation.
1779
2616
  #
1780
- # @example
2617
+ # @example Updating a Policy that is implicitly version 1:
1781
2618
  # require "google/cloud/storage"
1782
2619
  #
1783
2620
  # storage = Google::Cloud::Storage.new
2621
+ # bucket = storage.bucket "my-bucket"
1784
2622
  #
1785
- # bucket = storage.bucket "my-todo-app"
2623
+ # policy = bucket.policy
2624
+ # policy.version # 1
2625
+ # policy.remove "roles/storage.admin", "user:owner@example.com"
2626
+ # policy.add "roles/storage.admin", "user:newowner@example.com"
2627
+ # policy.roles["roles/storage.objectViewer"] = ["allUsers"]
2628
+ #
2629
+ # policy = bucket.update_policy policy
2630
+ #
2631
+ # @example Updating a Policy from version 1 to version 3 by adding a condition:
2632
+ # require "google/cloud/storage"
2633
+ #
2634
+ # storage = Google::Cloud::Storage.new
2635
+ # bucket = storage.bucket "my-bucket"
2636
+ #
2637
+ # policy = bucket.policy requested_policy_version: 3
2638
+ # policy.version # 1
2639
+ # policy.version = 3
2640
+ #
2641
+ # expr = "resource.name.startsWith(\"projects/_/buckets/bucket-name/objects/prefix-a-\")"
2642
+ # policy.bindings.insert({
2643
+ # role: "roles/storage.admin",
2644
+ # members: ["user:owner@example.com"],
2645
+ # condition: {
2646
+ # title: "my-condition",
2647
+ # description: "description of condition",
2648
+ # expression: expr
2649
+ # }
2650
+ # })
2651
+ #
2652
+ # policy = bucket.update_policy policy
2653
+ #
2654
+ # @example Updating a version 3 Policy:
2655
+ # require "google/cloud/storage"
1786
2656
  #
1787
- # policy = bucket.policy # API call
2657
+ # storage = Google::Cloud::Storage.new
2658
+ # bucket = storage.bucket "my-bucket"
1788
2659
  #
1789
- # policy.add "roles/owner", "user:owner@example.com"
2660
+ # policy = bucket.policy requested_policy_version: 3
2661
+ # policy.version # 3 indicates an existing binding with a condition.
2662
+ #
2663
+ # expr = "resource.name.startsWith(\"projects/_/buckets/bucket-name/objects/prefix-a-\")"
2664
+ # policy.bindings.insert({
2665
+ # role: "roles/storage.admin",
2666
+ # members: ["user:owner@example.com"],
2667
+ # condition: {
2668
+ # title: "my-condition",
2669
+ # description: "description of condition",
2670
+ # expression: expr
2671
+ # }
2672
+ # })
1790
2673
  #
1791
- # bucket.update_policy policy # API call
2674
+ # policy = bucket.update_policy policy
1792
2675
  #
1793
2676
  def update_policy new_policy
1794
2677
  ensure_service!
1795
2678
  gapi = service.set_bucket_policy name, new_policy.to_gapi,
1796
2679
  user_project: user_project
1797
- Policy.from_gapi gapi
2680
+ new_policy.class.from_gapi gapi
1798
2681
  end
1799
2682
  alias policy= update_policy
1800
2683
 
@@ -1817,7 +2700,7 @@ module Google
1817
2700
  #
1818
2701
  # storage = Google::Cloud::Storage.new
1819
2702
  #
1820
- # bucket = storage.bucket "my-todo-app"
2703
+ # bucket = storage.bucket "my-bucket"
1821
2704
  #
1822
2705
  # permissions = bucket.test_permissions "storage.buckets.get",
1823
2706
  # "storage.buckets.delete"
@@ -1964,11 +2847,12 @@ module Google
1964
2847
  def create_notification topic, custom_attrs: nil, event_types: nil,
1965
2848
  prefix: nil, payload: nil
1966
2849
  ensure_service!
1967
- options = { custom_attrs: custom_attrs, event_types: event_types,
1968
- prefix: prefix, payload: payload,
1969
- user_project: user_project }
1970
2850
 
1971
- gapi = service.insert_notification name, topic, options
2851
+ gapi = service.insert_notification name, topic, custom_attrs: custom_attrs,
2852
+ event_types: event_types,
2853
+ prefix: prefix,
2854
+ payload: payload,
2855
+ user_project: user_project
1972
2856
  Notification.from_gapi name, gapi, service, user_project: user_project
1973
2857
  end
1974
2858
  alias new_notification create_notification
@@ -2047,20 +2931,46 @@ module Google
2047
2931
  reload!
2048
2932
  end
2049
2933
 
2050
- def patch_gapi! *attributes
2934
+ def patch_gapi! attributes,
2935
+ if_metageneration_match: nil,
2936
+ if_metageneration_not_match: nil
2937
+ attributes = Array(attributes)
2051
2938
  attributes.flatten!
2052
2939
  return if attributes.empty?
2053
2940
  ensure_service!
2054
2941
  patch_args = Hash[attributes.map do |attr|
2055
2942
  [attr, @gapi.send(attr)]
2056
2943
  end]
2057
- patch_gapi = API::Bucket.new patch_args
2058
- @gapi = service.patch_bucket name, patch_gapi,
2944
+ patch_gapi = API::Bucket.new(**patch_args)
2945
+ @gapi = service.patch_bucket name,
2946
+ patch_gapi,
2947
+ if_metageneration_match: if_metageneration_match,
2948
+ if_metageneration_not_match: if_metageneration_not_match,
2059
2949
  user_project: user_project
2060
2950
  @lazy = nil
2061
2951
  self
2062
2952
  end
2063
2953
 
2954
+ def update_gapi! attributes,
2955
+ if_metageneration_match: nil,
2956
+ if_metageneration_not_match: nil
2957
+ attributes = Array(attributes)
2958
+ attributes.flatten!
2959
+ return if attributes.empty?
2960
+ ensure_service!
2961
+ update_args = Hash[attributes.map do |attr|
2962
+ [attr, @gapi.send(attr)]
2963
+ end]
2964
+ update_gapi = API::Bucket.new(**update_args)
2965
+ @gapi = service.update_bucket name,
2966
+ update_gapi,
2967
+ if_metageneration_match: if_metageneration_match,
2968
+ if_metageneration_not_match: if_metageneration_not_match,
2969
+ user_project: user_project
2970
+ @lazy = nil
2971
+ self
2972
+ end
2973
+
2064
2974
  ##
2065
2975
  # Raise an error if the file is not found.
2066
2976
  def ensure_io_or_file_exists! file
@@ -2069,13 +2979,27 @@ module Google
2069
2979
  raise ArgumentError, "cannot find file #{file}"
2070
2980
  end
2071
2981
 
2982
+ def crc32c_for source, checksum, crc32c
2983
+ return crc32c unless [:crc32c, :all].include? checksum
2984
+ raise ArgumentError, "'checksum: :crc32c' or 'checksum: :all' is present with 'crc32c' arg" if crc32c
2985
+ File::Verifier.crc32c_for source
2986
+ end
2987
+
2988
+ def md5_for source, checksum, md5
2989
+ return md5 unless [:md5, :all].include? checksum
2990
+ raise ArgumentError, "'checksum: :md5' or 'checksum: :all' is present with 'md5' arg" if md5
2991
+ File::Verifier.md5_for source
2992
+ end
2993
+
2072
2994
  ##
2073
2995
  # Yielded to a block to accumulate changes for a patch request.
2074
2996
  class Updater < Bucket
2075
2997
  attr_reader :updates
2998
+
2076
2999
  ##
2077
3000
  # Create an Updater object.
2078
3001
  def initialize gapi
3002
+ super()
2079
3003
  @updates = []
2080
3004
  @gapi = gapi
2081
3005
  @labels = @gapi.labels.to_h.dup