]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/cloud.google.com/go/storage/bucket.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / cloud.google.com / go / storage / bucket.go
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
15 package storage
16
17 import (
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.
33 type 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
49 func (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.
67 func (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.
95 func (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
106 func (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.
121 func (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.
128 func (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
138 func (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.
155 func (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
177 func (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.
190 func (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
212 func (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.
227 type 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.
320 type 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.
330 type 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.
346 type 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
364 const (
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.
381 type 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.
392 type 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.
406 type Liveness int
407
408 const (
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.
421 type 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.
452 type 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.
464 type 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
477 func 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.
508 func (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.
556 type 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.
578 type 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.
587 type 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.
642 func (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.
651 func (ua *BucketAttrsToUpdate) DeleteLabel(name string) {
652 if ua.deleteLabels == nil {
653 ua.deleteLabels = map[string]bool{}
654 }
655 ua.deleteLabels[name] = true
656 }
657
658 func (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.
752 func (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.
761 type 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
773 func (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.
788 func (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.
805 func (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.
817 func 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
838 func (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
847 func 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
862 func 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
875 func 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
888 func 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
923 func 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
958 func (e *BucketEncryption) toRawBucketEncryption() *raw.BucketEncryption {
959 if e == nil {
960 return nil
961 }
962 return &raw.BucketEncryption{
963 DefaultKmsKeyName: e.DefaultKMSKeyName,
964 }
965 }
966
967 func toBucketEncryption(e *raw.BucketEncryption) *BucketEncryption {
968 if e == nil {
969 return nil
970 }
971 return &BucketEncryption{DefaultKMSKeyName: e.DefaultKmsKeyName}
972 }
973
974 func (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
984 func 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
994 func (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
1004 func 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
1014 func 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.
1032 func (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.
1048 type 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.
1058 func (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.
1067 func (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
1076 func (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.
1115 func (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.
1129 type 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.
1144 func (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.
1154 func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
1155
1156 func (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 }