]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/cloud.google.com/go/storage/bucket.go
Merge branch 'fix_read_test' of github.com:alexandreFre/terraform-provider-statuscake
[github/fretlink/terraform-provider-statuscake.git] / vendor / cloud.google.com / go / storage / bucket.go
CommitLineData
107c1cdb
ND
1// Copyright 2014 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package storage
16
17import (
18 "context"
19 "fmt"
20 "net/http"
21 "reflect"
22 "time"
23
24 "cloud.google.com/go/internal/optional"
25 "cloud.google.com/go/internal/trace"
26 "google.golang.org/api/googleapi"
27 "google.golang.org/api/iterator"
28 raw "google.golang.org/api/storage/v1"
29)
30
31// BucketHandle provides operations on a Google Cloud Storage bucket.
32// Use Client.Bucket to get a handle.
33type BucketHandle struct {
34 c *Client
35 name string
36 acl ACLHandle
37 defaultObjectACL ACLHandle
38 conds *BucketConditions
39 userProject string // project for Requester Pays buckets
40}
41
42// Bucket returns a BucketHandle, which provides operations on the named bucket.
43// This call does not perform any network operations.
44//
45// The supplied name must contain only lowercase letters, numbers, dashes,
46// underscores, and dots. The full specification for valid bucket names can be
47// found at:
48// https://cloud.google.com/storage/docs/bucket-naming
49func (c *Client) Bucket(name string) *BucketHandle {
50 return &BucketHandle{
51 c: c,
52 name: name,
53 acl: ACLHandle{
54 c: c,
55 bucket: name,
56 },
57 defaultObjectACL: ACLHandle{
58 c: c,
59 bucket: name,
60 isDefault: true,
61 },
62 }
63}
64
65// Create creates the Bucket in the project.
66// If attrs is nil the API defaults will be used.
67func (b *BucketHandle) Create(ctx context.Context, projectID string, attrs *BucketAttrs) (err error) {
68 ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create")
69 defer func() { trace.EndSpan(ctx, err) }()
70
71 var bkt *raw.Bucket
72 if attrs != nil {
73 bkt = attrs.toRawBucket()
74 } else {
75 bkt = &raw.Bucket{}
76 }
77 bkt.Name = b.name
78 // If there is lifecycle information but no location, explicitly set
79 // the location. This is a GCS quirk/bug.
80 if bkt.Location == "" && bkt.Lifecycle != nil {
81 bkt.Location = "US"
82 }
83 req := b.c.raw.Buckets.Insert(projectID, bkt)
84 setClientHeader(req.Header())
85 if attrs != nil && attrs.PredefinedACL != "" {
86 req.PredefinedAcl(attrs.PredefinedACL)
87 }
88 if attrs != nil && attrs.PredefinedDefaultObjectACL != "" {
89 req.PredefinedDefaultObjectAcl(attrs.PredefinedDefaultObjectACL)
90 }
91 return runWithRetry(ctx, func() error { _, err := req.Context(ctx).Do(); return err })
92}
93
94// Delete deletes the Bucket.
95func (b *BucketHandle) Delete(ctx context.Context) (err error) {
96 ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Delete")
97 defer func() { trace.EndSpan(ctx, err) }()
98
99 req, err := b.newDeleteCall()
100 if err != nil {
101 return err
102 }
103 return runWithRetry(ctx, func() error { return req.Context(ctx).Do() })
104}
105
106func (b *BucketHandle) newDeleteCall() (*raw.BucketsDeleteCall, error) {
107 req := b.c.raw.Buckets.Delete(b.name)
108 setClientHeader(req.Header())
109 if err := applyBucketConds("BucketHandle.Delete", b.conds, req); err != nil {
110 return nil, err
111 }
112 if b.userProject != "" {
113 req.UserProject(b.userProject)
114 }
115 return req, nil
116}
117
118// ACL returns an ACLHandle, which provides access to the bucket's access control list.
119// This controls who can list, create or overwrite the objects in a bucket.
120// This call does not perform any network operations.
121func (b *BucketHandle) ACL() *ACLHandle {
122 return &b.acl
123}
124
125// DefaultObjectACL returns an ACLHandle, which provides access to the bucket's default object ACLs.
126// These ACLs are applied to newly created objects in this bucket that do not have a defined ACL.
127// This call does not perform any network operations.
128func (b *BucketHandle) DefaultObjectACL() *ACLHandle {
129 return &b.defaultObjectACL
130}
131
132// Object returns an ObjectHandle, which provides operations on the named object.
133// This call does not perform any network operations.
134//
135// name must consist entirely of valid UTF-8-encoded runes. The full specification
136// for valid object names can be found at:
137// https://cloud.google.com/storage/docs/bucket-naming
138func (b *BucketHandle) Object(name string) *ObjectHandle {
139 return &ObjectHandle{
140 c: b.c,
141 bucket: b.name,
142 object: name,
143 acl: ACLHandle{
144 c: b.c,
145 bucket: b.name,
146 object: name,
147 userProject: b.userProject,
148 },
149 gen: -1,
150 userProject: b.userProject,
151 }
152}
153
154// Attrs returns the metadata for the bucket.
155func (b *BucketHandle) Attrs(ctx context.Context) (attrs *BucketAttrs, err error) {
156 ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Attrs")
157 defer func() { trace.EndSpan(ctx, err) }()
158
159 req, err := b.newGetCall()
160 if err != nil {
161 return nil, err
162 }
163 var resp *raw.Bucket
164 err = runWithRetry(ctx, func() error {
165 resp, err = req.Context(ctx).Do()
166 return err
167 })
168 if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
169 return nil, ErrBucketNotExist
170 }
171 if err != nil {
172 return nil, err
173 }
174 return newBucket(resp)
175}
176
177func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) {
178 req := b.c.raw.Buckets.Get(b.name).Projection("full")
179 setClientHeader(req.Header())
180 if err := applyBucketConds("BucketHandle.Attrs", b.conds, req); err != nil {
181 return nil, err
182 }
183 if b.userProject != "" {
184 req.UserProject(b.userProject)
185 }
186 return req, nil
187}
188
189// Update updates a bucket's attributes.
190func (b *BucketHandle) Update(ctx context.Context, uattrs BucketAttrsToUpdate) (attrs *BucketAttrs, err error) {
191 ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create")
192 defer func() { trace.EndSpan(ctx, err) }()
193
194 req, err := b.newPatchCall(&uattrs)
195 if err != nil {
196 return nil, err
197 }
198 if uattrs.PredefinedACL != "" {
199 req.PredefinedAcl(uattrs.PredefinedACL)
200 }
201 if uattrs.PredefinedDefaultObjectACL != "" {
202 req.PredefinedDefaultObjectAcl(uattrs.PredefinedDefaultObjectACL)
203 }
204 // TODO(jba): retry iff metagen is set?
205 rb, err := req.Context(ctx).Do()
206 if err != nil {
207 return nil, err
208 }
209 return newBucket(rb)
210}
211
212func (b *BucketHandle) newPatchCall(uattrs *BucketAttrsToUpdate) (*raw.BucketsPatchCall, error) {
213 rb := uattrs.toRawBucket()
214 req := b.c.raw.Buckets.Patch(b.name, rb).Projection("full")
215 setClientHeader(req.Header())
216 if err := applyBucketConds("BucketHandle.Update", b.conds, req); err != nil {
217 return nil, err
218 }
219 if b.userProject != "" {
220 req.UserProject(b.userProject)
221 }
222 return req, nil
223}
224
225// BucketAttrs represents the metadata for a Google Cloud Storage bucket.
226// Read-only fields are ignored by BucketHandle.Create.
227type BucketAttrs struct {
228 // Name is the name of the bucket.
229 // This field is read-only.
230 Name string
231
232 // ACL is the list of access control rules on the bucket.
233 ACL []ACLRule
234
235 // BucketPolicyOnly configures access checks to use only bucket-level IAM
236 // policies.
237 BucketPolicyOnly BucketPolicyOnly
238
239 // DefaultObjectACL is the list of access controls to
240 // apply to new objects when no object ACL is provided.
241 DefaultObjectACL []ACLRule
242
243 // DefaultEventBasedHold is the default value for event-based hold on
244 // newly created objects in this bucket. It defaults to false.
245 DefaultEventBasedHold bool
246
247 // If not empty, applies a predefined set of access controls. It should be set
248 // only when creating a bucket.
249 // It is always empty for BucketAttrs returned from the service.
250 // See https://cloud.google.com/storage/docs/json_api/v1/buckets/insert
251 // for valid values.
252 PredefinedACL string
253
254 // If not empty, applies a predefined set of default object access controls.
255 // It should be set only when creating a bucket.
256 // It is always empty for BucketAttrs returned from the service.
257 // See https://cloud.google.com/storage/docs/json_api/v1/buckets/insert
258 // for valid values.
259 PredefinedDefaultObjectACL string
260
261 // Location is the location of the bucket. It defaults to "US".
262 Location string
263
264 // MetaGeneration is the metadata generation of the bucket.
265 // This field is read-only.
266 MetaGeneration int64
267
268 // StorageClass is the default storage class of the bucket. This defines
269 // how objects in the bucket are stored and determines the SLA
270 // and the cost of storage. Typical values are "MULTI_REGIONAL",
271 // "REGIONAL", "NEARLINE", "COLDLINE", "STANDARD" and
272 // "DURABLE_REDUCED_AVAILABILITY". Defaults to "STANDARD", which
273 // is equivalent to "MULTI_REGIONAL" or "REGIONAL" depending on
274 // the bucket's location settings.
275 StorageClass string
276
277 // Created is the creation time of the bucket.
278 // This field is read-only.
279 Created time.Time
280
281 // VersioningEnabled reports whether this bucket has versioning enabled.
282 VersioningEnabled bool
283
284 // Labels are the bucket's labels.
285 Labels map[string]string
286
287 // RequesterPays reports whether the bucket is a Requester Pays bucket.
288 // Clients performing operations on Requester Pays buckets must provide
289 // a user project (see BucketHandle.UserProject), which will be billed
290 // for the operations.
291 RequesterPays bool
292
293 // Lifecycle is the lifecycle configuration for objects in the bucket.
294 Lifecycle Lifecycle
295
296 // Retention policy enforces a minimum retention time for all objects
297 // contained in the bucket. A RetentionPolicy of nil implies the bucket
298 // has no minimum data retention.
299 //
300 // This feature is in private alpha release. It is not currently available to
301 // most customers. It might be changed in backwards-incompatible ways and is not
302 // subject to any SLA or deprecation policy.
303 RetentionPolicy *RetentionPolicy
304
305 // The bucket's Cross-Origin Resource Sharing (CORS) configuration.
306 CORS []CORS
307
308 // The encryption configuration used by default for newly inserted objects.
309 Encryption *BucketEncryption
310
311 // The logging configuration.
312 Logging *BucketLogging
313
314 // The website configuration.
315 Website *BucketWebsite
316}
317
318// BucketPolicyOnly configures access checks to use only bucket-level IAM
319// policies.
320type BucketPolicyOnly struct {
321 // Enabled specifies whether access checks use only bucket-level IAM
322 // policies. Enabled may be disabled until the locked time.
323 Enabled bool
324 // LockedTime specifies the deadline for changing Enabled from true to
325 // false.
326 LockedTime time.Time
327}
328
329// Lifecycle is the lifecycle configuration for objects in the bucket.
330type Lifecycle struct {
331 Rules []LifecycleRule
332}
333
334// RetentionPolicy enforces a minimum retention time for all objects
335// contained in the bucket.
336//
337// Any attempt to overwrite or delete objects younger than the retention
338// period will result in an error. An unlocked retention policy can be
339// modified or removed from the bucket via the Update method. A
340// locked retention policy cannot be removed or shortened in duration
341// for the lifetime of the bucket.
342//
343// This feature is in private alpha release. It is not currently available to
344// most customers. It might be changed in backwards-incompatible ways and is not
345// subject to any SLA or deprecation policy.
346type RetentionPolicy struct {
347 // RetentionPeriod specifies the duration that objects need to be
348 // retained. Retention duration must be greater than zero and less than
349 // 100 years. Note that enforcement of retention periods less than a day
350 // is not guaranteed. Such periods should only be used for testing
351 // purposes.
352 RetentionPeriod time.Duration
353
354 // EffectiveTime is the time from which the policy was enforced and
355 // effective. This field is read-only.
356 EffectiveTime time.Time
357
358 // IsLocked describes whether the bucket is locked. Once locked, an
359 // object retention policy cannot be modified.
360 // This field is read-only.
361 IsLocked bool
362}
363
364const (
365 // RFC3339 date with only the date segment, used for CreatedBefore in LifecycleRule.
366 rfc3339Date = "2006-01-02"
367
368 // DeleteAction is a lifecycle action that deletes a live and/or archived
369 // objects. Takes precedence over SetStorageClass actions.
370 DeleteAction = "Delete"
371
372 // SetStorageClassAction changes the storage class of live and/or archived
373 // objects.
374 SetStorageClassAction = "SetStorageClass"
375)
376
377// LifecycleRule is a lifecycle configuration rule.
378//
379// When all the configured conditions are met by an object in the bucket, the
380// configured action will automatically be taken on that object.
381type LifecycleRule struct {
382 // Action is the action to take when all of the associated conditions are
383 // met.
384 Action LifecycleAction
385
386 // Condition is the set of conditions that must be met for the associated
387 // action to be taken.
388 Condition LifecycleCondition
389}
390
391// LifecycleAction is a lifecycle configuration action.
392type LifecycleAction struct {
393 // Type is the type of action to take on matching objects.
394 //
395 // Acceptable values are "Delete" to delete matching objects and
396 // "SetStorageClass" to set the storage class defined in StorageClass on
397 // matching objects.
398 Type string
399
400 // StorageClass is the storage class to set on matching objects if the Action
401 // is "SetStorageClass".
402 StorageClass string
403}
404
405// Liveness specifies whether the object is live or not.
406type Liveness int
407
408const (
409 // LiveAndArchived includes both live and archived objects.
410 LiveAndArchived Liveness = iota
411 // Live specifies that the object is still live.
412 Live
413 // Archived specifies that the object is archived.
414 Archived
415)
416
417// LifecycleCondition is a set of conditions used to match objects and take an
418// action automatically.
419//
420// All configured conditions must be met for the associated action to be taken.
421type LifecycleCondition struct {
422 // AgeInDays is the age of the object in days.
423 AgeInDays int64
424
425 // CreatedBefore is the time the object was created.
426 //
427 // This condition is satisfied when an object is created before midnight of
428 // the specified date in UTC.
429 CreatedBefore time.Time
430
431 // Liveness specifies the object's liveness. Relevant only for versioned objects
432 Liveness Liveness
433
434 // MatchesStorageClasses is the condition matching the object's storage
435 // class.
436 //
437 // Values include "MULTI_REGIONAL", "REGIONAL", "NEARLINE", "COLDLINE",
438 // "STANDARD", and "DURABLE_REDUCED_AVAILABILITY".
439 MatchesStorageClasses []string
440
441 // NumNewerVersions is the condition matching objects with a number of newer versions.
442 //
443 // If the value is N, this condition is satisfied when there are at least N
444 // versions (including the live version) newer than this version of the
445 // object.
446 NumNewerVersions int64
447}
448
449// BucketLogging holds the bucket's logging configuration, which defines the
450// destination bucket and optional name prefix for the current bucket's
451// logs.
452type BucketLogging struct {
453 // The destination bucket where the current bucket's logs
454 // should be placed.
455 LogBucket string
456
457 // A prefix for log object names.
458 LogObjectPrefix string
459}
460
461// BucketWebsite holds the bucket's website configuration, controlling how the
462// service behaves when accessing bucket contents as a web site. See
463// https://cloud.google.com/storage/docs/static-website for more information.
464type BucketWebsite struct {
465 // If the requested object path is missing, the service will ensure the path has
466 // a trailing '/', append this suffix, and attempt to retrieve the resulting
467 // object. This allows the creation of index.html objects to represent directory
468 // pages.
469 MainPageSuffix string
470
471 // If the requested object path is missing, and any mainPageSuffix object is
472 // missing, if applicable, the service will return the named object from this
473 // bucket as the content for a 404 Not Found result.
474 NotFoundPage string
475}
476
477func newBucket(b *raw.Bucket) (*BucketAttrs, error) {
478 if b == nil {
479 return nil, nil
480 }
481 rp, err := toRetentionPolicy(b.RetentionPolicy)
482 if err != nil {
483 return nil, err
484 }
485 return &BucketAttrs{
486 Name: b.Name,
487 Location: b.Location,
488 MetaGeneration: b.Metageneration,
489 DefaultEventBasedHold: b.DefaultEventBasedHold,
490 StorageClass: b.StorageClass,
491 Created: convertTime(b.TimeCreated),
492 VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled,
493 ACL: toBucketACLRules(b.Acl),
494 DefaultObjectACL: toObjectACLRules(b.DefaultObjectAcl),
495 Labels: b.Labels,
496 RequesterPays: b.Billing != nil && b.Billing.RequesterPays,
497 Lifecycle: toLifecycle(b.Lifecycle),
498 RetentionPolicy: rp,
499 CORS: toCORS(b.Cors),
500 Encryption: toBucketEncryption(b.Encryption),
501 Logging: toBucketLogging(b.Logging),
502 Website: toBucketWebsite(b.Website),
503 BucketPolicyOnly: toBucketPolicyOnly(b.IamConfiguration),
504 }, nil
505}
506
507// toRawBucket copies the editable attribute from b to the raw library's Bucket type.
508func (b *BucketAttrs) toRawBucket() *raw.Bucket {
509 // Copy label map.
510 var labels map[string]string
511 if len(b.Labels) > 0 {
512 labels = make(map[string]string, len(b.Labels))
513 for k, v := range b.Labels {
514 labels[k] = v
515 }
516 }
517 // Ignore VersioningEnabled if it is false. This is OK because
518 // we only call this method when creating a bucket, and by default
519 // new buckets have versioning off.
520 var v *raw.BucketVersioning
521 if b.VersioningEnabled {
522 v = &raw.BucketVersioning{Enabled: true}
523 }
524 var bb *raw.BucketBilling
525 if b.RequesterPays {
526 bb = &raw.BucketBilling{RequesterPays: true}
527 }
528 var bktIAM *raw.BucketIamConfiguration
529 if b.BucketPolicyOnly.Enabled {
530 bktIAM = &raw.BucketIamConfiguration{
531 BucketPolicyOnly: &raw.BucketIamConfigurationBucketPolicyOnly{
532 Enabled: true,
533 },
534 }
535 }
536 return &raw.Bucket{
537 Name: b.Name,
538 Location: b.Location,
539 StorageClass: b.StorageClass,
540 Acl: toRawBucketACL(b.ACL),
541 DefaultObjectAcl: toRawObjectACL(b.DefaultObjectACL),
542 Versioning: v,
543 Labels: labels,
544 Billing: bb,
545 Lifecycle: toRawLifecycle(b.Lifecycle),
546 RetentionPolicy: b.RetentionPolicy.toRawRetentionPolicy(),
547 Cors: toRawCORS(b.CORS),
548 Encryption: b.Encryption.toRawBucketEncryption(),
549 Logging: b.Logging.toRawBucketLogging(),
550 Website: b.Website.toRawBucketWebsite(),
551 IamConfiguration: bktIAM,
552 }
553}
554
555// CORS is the bucket's Cross-Origin Resource Sharing (CORS) configuration.
556type CORS struct {
557 // MaxAge is the value to return in the Access-Control-Max-Age
558 // header used in preflight responses.
559 MaxAge time.Duration
560
561 // Methods is the list of HTTP methods on which to include CORS response
562 // headers, (GET, OPTIONS, POST, etc) Note: "*" is permitted in the list
563 // of methods, and means "any method".
564 Methods []string
565
566 // Origins is the list of Origins eligible to receive CORS response
567 // headers. Note: "*" is permitted in the list of origins, and means
568 // "any Origin".
569 Origins []string
570
571 // ResponseHeaders is the list of HTTP headers other than the simple
572 // response headers to give permission for the user-agent to share
573 // across domains.
574 ResponseHeaders []string
575}
576
577// BucketEncryption is a bucket's encryption configuration.
578type BucketEncryption struct {
579 // A Cloud KMS key name, in the form
580 // projects/P/locations/L/keyRings/R/cryptoKeys/K, that will be used to encrypt
581 // objects inserted into this bucket, if no encryption method is specified.
582 // The key's location must be the same as the bucket's.
583 DefaultKMSKeyName string
584}
585
586// BucketAttrsToUpdate define the attributes to update during an Update call.
587type BucketAttrsToUpdate struct {
588 // If set, updates whether the bucket uses versioning.
589 VersioningEnabled optional.Bool
590
591 // If set, updates whether the bucket is a Requester Pays bucket.
592 RequesterPays optional.Bool
593
594 // DefaultEventBasedHold is the default value for event-based hold on
595 // newly created objects in this bucket.
596 DefaultEventBasedHold optional.Bool
597
598 // BucketPolicyOnly configures access checks to use only bucket-level IAM
599 // policies.
600 BucketPolicyOnly *BucketPolicyOnly
601
602 // If set, updates the retention policy of the bucket. Using
603 // RetentionPolicy.RetentionPeriod = 0 will delete the existing policy.
604 //
605 // This feature is in private alpha release. It is not currently available to
606 // most customers. It might be changed in backwards-incompatible ways and is not
607 // subject to any SLA or deprecation policy.
608 RetentionPolicy *RetentionPolicy
609
610 // If set, replaces the CORS configuration with a new configuration.
611 // An empty (rather than nil) slice causes all CORS policies to be removed.
612 CORS []CORS
613
614 // If set, replaces the encryption configuration of the bucket. Using
615 // BucketEncryption.DefaultKMSKeyName = "" will delete the existing
616 // configuration.
617 Encryption *BucketEncryption
618
619 // If set, replaces the lifecycle configuration of the bucket.
620 Lifecycle *Lifecycle
621
622 // If set, replaces the logging configuration of the bucket.
623 Logging *BucketLogging
624
625 // If set, replaces the website configuration of the bucket.
626 Website *BucketWebsite
627
628 // If not empty, applies a predefined set of access controls.
629 // See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch.
630 PredefinedACL string
631
632 // If not empty, applies a predefined set of default object access controls.
633 // See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch.
634 PredefinedDefaultObjectACL string
635
636 setLabels map[string]string
637 deleteLabels map[string]bool
638}
639
640// SetLabel causes a label to be added or modified when ua is used
641// in a call to Bucket.Update.
642func (ua *BucketAttrsToUpdate) SetLabel(name, value string) {
643 if ua.setLabels == nil {
644 ua.setLabels = map[string]string{}
645 }
646 ua.setLabels[name] = value
647}
648
649// DeleteLabel causes a label to be deleted when ua is used in a
650// call to Bucket.Update.
651func (ua *BucketAttrsToUpdate) DeleteLabel(name string) {
652 if ua.deleteLabels == nil {
653 ua.deleteLabels = map[string]bool{}
654 }
655 ua.deleteLabels[name] = true
656}
657
658func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket {
659 rb := &raw.Bucket{}
660 if ua.CORS != nil {
661 rb.Cors = toRawCORS(ua.CORS)
662 rb.ForceSendFields = append(rb.ForceSendFields, "Cors")
663 }
664 if ua.DefaultEventBasedHold != nil {
665 rb.DefaultEventBasedHold = optional.ToBool(ua.DefaultEventBasedHold)
666 rb.ForceSendFields = append(rb.ForceSendFields, "DefaultEventBasedHold")
667 }
668 if ua.RetentionPolicy != nil {
669 if ua.RetentionPolicy.RetentionPeriod == 0 {
670 rb.NullFields = append(rb.NullFields, "RetentionPolicy")
671 rb.RetentionPolicy = nil
672 } else {
673 rb.RetentionPolicy = ua.RetentionPolicy.toRawRetentionPolicy()
674 }
675 }
676 if ua.VersioningEnabled != nil {
677 rb.Versioning = &raw.BucketVersioning{
678 Enabled: optional.ToBool(ua.VersioningEnabled),
679 ForceSendFields: []string{"Enabled"},
680 }
681 }
682 if ua.RequesterPays != nil {
683 rb.Billing = &raw.BucketBilling{
684 RequesterPays: optional.ToBool(ua.RequesterPays),
685 ForceSendFields: []string{"RequesterPays"},
686 }
687 }
688 if ua.BucketPolicyOnly != nil {
689 rb.IamConfiguration = &raw.BucketIamConfiguration{
690 BucketPolicyOnly: &raw.BucketIamConfigurationBucketPolicyOnly{
691 Enabled: ua.BucketPolicyOnly.Enabled,
692 },
693 }
694 }
695 if ua.Encryption != nil {
696 if ua.Encryption.DefaultKMSKeyName == "" {
697 rb.NullFields = append(rb.NullFields, "Encryption")
698 rb.Encryption = nil
699 } else {
700 rb.Encryption = ua.Encryption.toRawBucketEncryption()
701 }
702 }
703 if ua.Lifecycle != nil {
704 rb.Lifecycle = toRawLifecycle(*ua.Lifecycle)
705 }
706 if ua.Logging != nil {
707 if *ua.Logging == (BucketLogging{}) {
708 rb.NullFields = append(rb.NullFields, "Logging")
709 rb.Logging = nil
710 } else {
711 rb.Logging = ua.Logging.toRawBucketLogging()
712 }
713 }
714 if ua.Website != nil {
715 if *ua.Website == (BucketWebsite{}) {
716 rb.NullFields = append(rb.NullFields, "Website")
717 rb.Website = nil
718 } else {
719 rb.Website = ua.Website.toRawBucketWebsite()
720 }
721 }
722 if ua.PredefinedACL != "" {
723 // Clear ACL or the call will fail.
724 rb.Acl = nil
725 rb.ForceSendFields = append(rb.ForceSendFields, "Acl")
726 }
727 if ua.PredefinedDefaultObjectACL != "" {
728 // Clear ACLs or the call will fail.
729 rb.DefaultObjectAcl = nil
730 rb.ForceSendFields = append(rb.ForceSendFields, "DefaultObjectAcl")
731 }
732 if ua.setLabels != nil || ua.deleteLabels != nil {
733 rb.Labels = map[string]string{}
734 for k, v := range ua.setLabels {
735 rb.Labels[k] = v
736 }
737 if len(rb.Labels) == 0 && len(ua.deleteLabels) > 0 {
738 rb.ForceSendFields = append(rb.ForceSendFields, "Labels")
739 }
740 for l := range ua.deleteLabels {
741 rb.NullFields = append(rb.NullFields, "Labels."+l)
742 }
743 }
744 return rb
745}
746
747// If returns a new BucketHandle that applies a set of preconditions.
748// Preconditions already set on the BucketHandle are ignored.
749// Operations on the new handle will return an error if the preconditions are not
750// satisfied. The only valid preconditions for buckets are MetagenerationMatch
751// and MetagenerationNotMatch.
752func (b *BucketHandle) If(conds BucketConditions) *BucketHandle {
753 b2 := *b
754 b2.conds = &conds
755 return &b2
756}
757
758// BucketConditions constrain bucket methods to act on specific metagenerations.
759//
760// The zero value is an empty set of constraints.
761type BucketConditions struct {
762 // MetagenerationMatch specifies that the bucket must have the given
763 // metageneration for the operation to occur.
764 // If MetagenerationMatch is zero, it has no effect.
765 MetagenerationMatch int64
766
767 // MetagenerationNotMatch specifies that the bucket must not have the given
768 // metageneration for the operation to occur.
769 // If MetagenerationNotMatch is zero, it has no effect.
770 MetagenerationNotMatch int64
771}
772
773func (c *BucketConditions) validate(method string) error {
774 if *c == (BucketConditions{}) {
775 return fmt.Errorf("storage: %s: empty conditions", method)
776 }
777 if c.MetagenerationMatch != 0 && c.MetagenerationNotMatch != 0 {
778 return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method)
779 }
780 return nil
781}
782
783// UserProject returns a new BucketHandle that passes the project ID as the user
784// project for all subsequent calls. Calls with a user project will be billed to that
785// project rather than to the bucket's owning project.
786//
787// A user project is required for all operations on Requester Pays buckets.
788func (b *BucketHandle) UserProject(projectID string) *BucketHandle {
789 b2 := *b
790 b2.userProject = projectID
791 b2.acl.userProject = projectID
792 b2.defaultObjectACL.userProject = projectID
793 return &b2
794}
795
796// LockRetentionPolicy locks a bucket's retention policy until a previously-configured
797// RetentionPeriod past the EffectiveTime. Note that if RetentionPeriod is set to less
798// than a day, the retention policy is treated as a development configuration and locking
799// will have no effect. The BucketHandle must have a metageneration condition that
800// matches the bucket's metageneration. See BucketHandle.If.
801//
802// This feature is in private alpha release. It is not currently available to
803// most customers. It might be changed in backwards-incompatible ways and is not
804// subject to any SLA or deprecation policy.
805func (b *BucketHandle) LockRetentionPolicy(ctx context.Context) error {
806 var metageneration int64
807 if b.conds != nil {
808 metageneration = b.conds.MetagenerationMatch
809 }
810 req := b.c.raw.Buckets.LockRetentionPolicy(b.name, metageneration)
811 _, err := req.Context(ctx).Do()
812 return err
813}
814
815// applyBucketConds modifies the provided call using the conditions in conds.
816// call is something that quacks like a *raw.WhateverCall.
817func applyBucketConds(method string, conds *BucketConditions, call interface{}) error {
818 if conds == nil {
819 return nil
820 }
821 if err := conds.validate(method); err != nil {
822 return err
823 }
824 cval := reflect.ValueOf(call)
825 switch {
826 case conds.MetagenerationMatch != 0:
827 if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) {
828 return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method)
829 }
830 case conds.MetagenerationNotMatch != 0:
831 if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) {
832 return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method)
833 }
834 }
835 return nil
836}
837
838func (rp *RetentionPolicy) toRawRetentionPolicy() *raw.BucketRetentionPolicy {
839 if rp == nil {
840 return nil
841 }
842 return &raw.BucketRetentionPolicy{
843 RetentionPeriod: int64(rp.RetentionPeriod / time.Second),
844 }
845}
846
847func toRetentionPolicy(rp *raw.BucketRetentionPolicy) (*RetentionPolicy, error) {
848 if rp == nil {
849 return nil, nil
850 }
851 t, err := time.Parse(time.RFC3339, rp.EffectiveTime)
852 if err != nil {
853 return nil, err
854 }
855 return &RetentionPolicy{
856 RetentionPeriod: time.Duration(rp.RetentionPeriod) * time.Second,
857 EffectiveTime: t,
858 IsLocked: rp.IsLocked,
859 }, nil
860}
861
862func toRawCORS(c []CORS) []*raw.BucketCors {
863 var out []*raw.BucketCors
864 for _, v := range c {
865 out = append(out, &raw.BucketCors{
866 MaxAgeSeconds: int64(v.MaxAge / time.Second),
867 Method: v.Methods,
868 Origin: v.Origins,
869 ResponseHeader: v.ResponseHeaders,
870 })
871 }
872 return out
873}
874
875func toCORS(rc []*raw.BucketCors) []CORS {
876 var out []CORS
877 for _, v := range rc {
878 out = append(out, CORS{
879 MaxAge: time.Duration(v.MaxAgeSeconds) * time.Second,
880 Methods: v.Method,
881 Origins: v.Origin,
882 ResponseHeaders: v.ResponseHeader,
883 })
884 }
885 return out
886}
887
888func toRawLifecycle(l Lifecycle) *raw.BucketLifecycle {
889 var rl raw.BucketLifecycle
890 if len(l.Rules) == 0 {
891 return nil
892 }
893 for _, r := range l.Rules {
894 rr := &raw.BucketLifecycleRule{
895 Action: &raw.BucketLifecycleRuleAction{
896 Type: r.Action.Type,
897 StorageClass: r.Action.StorageClass,
898 },
899 Condition: &raw.BucketLifecycleRuleCondition{
900 Age: r.Condition.AgeInDays,
901 MatchesStorageClass: r.Condition.MatchesStorageClasses,
902 NumNewerVersions: r.Condition.NumNewerVersions,
903 },
904 }
905
906 switch r.Condition.Liveness {
907 case LiveAndArchived:
908 rr.Condition.IsLive = nil
909 case Live:
910 rr.Condition.IsLive = googleapi.Bool(true)
911 case Archived:
912 rr.Condition.IsLive = googleapi.Bool(false)
913 }
914
915 if !r.Condition.CreatedBefore.IsZero() {
916 rr.Condition.CreatedBefore = r.Condition.CreatedBefore.Format(rfc3339Date)
917 }
918 rl.Rule = append(rl.Rule, rr)
919 }
920 return &rl
921}
922
923func toLifecycle(rl *raw.BucketLifecycle) Lifecycle {
924 var l Lifecycle
925 if rl == nil {
926 return l
927 }
928 for _, rr := range rl.Rule {
929 r := LifecycleRule{
930 Action: LifecycleAction{
931 Type: rr.Action.Type,
932 StorageClass: rr.Action.StorageClass,
933 },
934 Condition: LifecycleCondition{
935 AgeInDays: rr.Condition.Age,
936 MatchesStorageClasses: rr.Condition.MatchesStorageClass,
937 NumNewerVersions: rr.Condition.NumNewerVersions,
938 },
939 }
940
941 switch {
942 case rr.Condition.IsLive == nil:
943 r.Condition.Liveness = LiveAndArchived
944 case *rr.Condition.IsLive == true:
945 r.Condition.Liveness = Live
946 case *rr.Condition.IsLive == false:
947 r.Condition.Liveness = Archived
948 }
949
950 if rr.Condition.CreatedBefore != "" {
951 r.Condition.CreatedBefore, _ = time.Parse(rfc3339Date, rr.Condition.CreatedBefore)
952 }
953 l.Rules = append(l.Rules, r)
954 }
955 return l
956}
957
958func (e *BucketEncryption) toRawBucketEncryption() *raw.BucketEncryption {
959 if e == nil {
960 return nil
961 }
962 return &raw.BucketEncryption{
963 DefaultKmsKeyName: e.DefaultKMSKeyName,
964 }
965}
966
967func toBucketEncryption(e *raw.BucketEncryption) *BucketEncryption {
968 if e == nil {
969 return nil
970 }
971 return &BucketEncryption{DefaultKMSKeyName: e.DefaultKmsKeyName}
972}
973
974func (b *BucketLogging) toRawBucketLogging() *raw.BucketLogging {
975 if b == nil {
976 return nil
977 }
978 return &raw.BucketLogging{
979 LogBucket: b.LogBucket,
980 LogObjectPrefix: b.LogObjectPrefix,
981 }
982}
983
984func toBucketLogging(b *raw.BucketLogging) *BucketLogging {
985 if b == nil {
986 return nil
987 }
988 return &BucketLogging{
989 LogBucket: b.LogBucket,
990 LogObjectPrefix: b.LogObjectPrefix,
991 }
992}
993
994func (w *BucketWebsite) toRawBucketWebsite() *raw.BucketWebsite {
995 if w == nil {
996 return nil
997 }
998 return &raw.BucketWebsite{
999 MainPageSuffix: w.MainPageSuffix,
1000 NotFoundPage: w.NotFoundPage,
1001 }
1002}
1003
1004func toBucketWebsite(w *raw.BucketWebsite) *BucketWebsite {
1005 if w == nil {
1006 return nil
1007 }
1008 return &BucketWebsite{
1009 MainPageSuffix: w.MainPageSuffix,
1010 NotFoundPage: w.NotFoundPage,
1011 }
1012}
1013
1014func toBucketPolicyOnly(b *raw.BucketIamConfiguration) BucketPolicyOnly {
1015 if b == nil || b.BucketPolicyOnly == nil || !b.BucketPolicyOnly.Enabled {
1016 return BucketPolicyOnly{}
1017 }
1018 lt, err := time.Parse(time.RFC3339, b.BucketPolicyOnly.LockedTime)
1019 if err != nil {
1020 return BucketPolicyOnly{
1021 Enabled: true,
1022 }
1023 }
1024 return BucketPolicyOnly{
1025 Enabled: true,
1026 LockedTime: lt,
1027 }
1028}
1029
1030// Objects returns an iterator over the objects in the bucket that match the Query q.
1031// If q is nil, no filtering is done.
1032func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator {
1033 it := &ObjectIterator{
1034 ctx: ctx,
1035 bucket: b,
1036 }
1037 it.pageInfo, it.nextFunc = iterator.NewPageInfo(
1038 it.fetch,
1039 func() int { return len(it.items) },
1040 func() interface{} { b := it.items; it.items = nil; return b })
1041 if q != nil {
1042 it.query = *q
1043 }
1044 return it
1045}
1046
1047// An ObjectIterator is an iterator over ObjectAttrs.
1048type ObjectIterator struct {
1049 ctx context.Context
1050 bucket *BucketHandle
1051 query Query
1052 pageInfo *iterator.PageInfo
1053 nextFunc func() error
1054 items []*ObjectAttrs
1055}
1056
1057// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
1058func (it *ObjectIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
1059
1060// Next returns the next result. Its second return value is iterator.Done if
1061// there are no more results. Once Next returns iterator.Done, all subsequent
1062// calls will return iterator.Done.
1063//
1064// If Query.Delimiter is non-empty, some of the ObjectAttrs returned by Next will
1065// have a non-empty Prefix field, and a zero value for all other fields. These
1066// represent prefixes.
1067func (it *ObjectIterator) Next() (*ObjectAttrs, error) {
1068 if err := it.nextFunc(); err != nil {
1069 return nil, err
1070 }
1071 item := it.items[0]
1072 it.items = it.items[1:]
1073 return item, nil
1074}
1075
1076func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error) {
1077 req := it.bucket.c.raw.Objects.List(it.bucket.name)
1078 setClientHeader(req.Header())
1079 req.Projection("full")
1080 req.Delimiter(it.query.Delimiter)
1081 req.Prefix(it.query.Prefix)
1082 req.Versions(it.query.Versions)
1083 req.PageToken(pageToken)
1084 if it.bucket.userProject != "" {
1085 req.UserProject(it.bucket.userProject)
1086 }
1087 if pageSize > 0 {
1088 req.MaxResults(int64(pageSize))
1089 }
1090 var resp *raw.Objects
1091 var err error
1092 err = runWithRetry(it.ctx, func() error {
1093 resp, err = req.Context(it.ctx).Do()
1094 return err
1095 })
1096 if err != nil {
1097 if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
1098 err = ErrBucketNotExist
1099 }
1100 return "", err
1101 }
1102 for _, item := range resp.Items {
1103 it.items = append(it.items, newObject(item))
1104 }
1105 for _, prefix := range resp.Prefixes {
1106 it.items = append(it.items, &ObjectAttrs{Prefix: prefix})
1107 }
1108 return resp.NextPageToken, nil
1109}
1110
1111// Buckets returns an iterator over the buckets in the project. You may
1112// optionally set the iterator's Prefix field to restrict the list to buckets
1113// whose names begin with the prefix. By default, all buckets in the project
1114// are returned.
1115func (c *Client) Buckets(ctx context.Context, projectID string) *BucketIterator {
1116 it := &BucketIterator{
1117 ctx: ctx,
1118 client: c,
1119 projectID: projectID,
1120 }
1121 it.pageInfo, it.nextFunc = iterator.NewPageInfo(
1122 it.fetch,
1123 func() int { return len(it.buckets) },
1124 func() interface{} { b := it.buckets; it.buckets = nil; return b })
1125 return it
1126}
1127
1128// A BucketIterator is an iterator over BucketAttrs.
1129type BucketIterator struct {
1130 // Prefix restricts the iterator to buckets whose names begin with it.
1131 Prefix string
1132
1133 ctx context.Context
1134 client *Client
1135 projectID string
1136 buckets []*BucketAttrs
1137 pageInfo *iterator.PageInfo
1138 nextFunc func() error
1139}
1140
1141// Next returns the next result. Its second return value is iterator.Done if
1142// there are no more results. Once Next returns iterator.Done, all subsequent
1143// calls will return iterator.Done.
1144func (it *BucketIterator) Next() (*BucketAttrs, error) {
1145 if err := it.nextFunc(); err != nil {
1146 return nil, err
1147 }
1148 b := it.buckets[0]
1149 it.buckets = it.buckets[1:]
1150 return b, nil
1151}
1152
1153// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
1154func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
1155
1156func (it *BucketIterator) fetch(pageSize int, pageToken string) (token string, err error) {
1157 req := it.client.raw.Buckets.List(it.projectID)
1158 setClientHeader(req.Header())
1159 req.Projection("full")
1160 req.Prefix(it.Prefix)
1161 req.PageToken(pageToken)
1162 if pageSize > 0 {
1163 req.MaxResults(int64(pageSize))
1164 }
1165 var resp *raw.Buckets
1166 err = runWithRetry(it.ctx, func() error {
1167 resp, err = req.Context(it.ctx).Do()
1168 return err
1169 })
1170 if err != nil {
1171 return "", err
1172 }
1173 for _, item := range resp.Items {
1174 b, err := newBucket(item)
1175 if err != nil {
1176 return "", err
1177 }
1178 it.buckets = append(it.buckets, b)
1179 }
1180 return resp.NextPageToken, nil
1181}