google-cloud-storage 1.18.1 → 1.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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