You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

991 lines
30 KiB

  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. package storage
  15. import (
  16. "fmt"
  17. "net/http"
  18. "reflect"
  19. "time"
  20. "cloud.google.com/go/internal/optional"
  21. "cloud.google.com/go/internal/trace"
  22. "golang.org/x/net/context"
  23. "google.golang.org/api/googleapi"
  24. "google.golang.org/api/iterator"
  25. raw "google.golang.org/api/storage/v1"
  26. )
  27. // BucketHandle provides operations on a Google Cloud Storage bucket.
  28. // Use Client.Bucket to get a handle.
  29. type BucketHandle struct {
  30. c *Client
  31. name string
  32. acl ACLHandle
  33. defaultObjectACL ACLHandle
  34. conds *BucketConditions
  35. userProject string // project for Requester Pays buckets
  36. }
  37. // Bucket returns a BucketHandle, which provides operations on the named bucket.
  38. // This call does not perform any network operations.
  39. //
  40. // The supplied name must contain only lowercase letters, numbers, dashes,
  41. // underscores, and dots. The full specification for valid bucket names can be
  42. // found at:
  43. // https://cloud.google.com/storage/docs/bucket-naming
  44. func (c *Client) Bucket(name string) *BucketHandle {
  45. return &BucketHandle{
  46. c: c,
  47. name: name,
  48. acl: ACLHandle{
  49. c: c,
  50. bucket: name,
  51. },
  52. defaultObjectACL: ACLHandle{
  53. c: c,
  54. bucket: name,
  55. isDefault: true,
  56. },
  57. }
  58. }
  59. // Create creates the Bucket in the project.
  60. // If attrs is nil the API defaults will be used.
  61. func (b *BucketHandle) Create(ctx context.Context, projectID string, attrs *BucketAttrs) (err error) {
  62. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create")
  63. defer func() { trace.EndSpan(ctx, err) }()
  64. var bkt *raw.Bucket
  65. if attrs != nil {
  66. bkt = attrs.toRawBucket()
  67. } else {
  68. bkt = &raw.Bucket{}
  69. }
  70. bkt.Name = b.name
  71. // If there is lifecycle information but no location, explicitly set
  72. // the location. This is a GCS quirk/bug.
  73. if bkt.Location == "" && bkt.Lifecycle != nil {
  74. bkt.Location = "US"
  75. }
  76. req := b.c.raw.Buckets.Insert(projectID, bkt)
  77. setClientHeader(req.Header())
  78. return runWithRetry(ctx, func() error { _, err := req.Context(ctx).Do(); return err })
  79. }
  80. // Delete deletes the Bucket.
  81. func (b *BucketHandle) Delete(ctx context.Context) (err error) {
  82. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Delete")
  83. defer func() { trace.EndSpan(ctx, err) }()
  84. req, err := b.newDeleteCall()
  85. if err != nil {
  86. return err
  87. }
  88. return runWithRetry(ctx, func() error { return req.Context(ctx).Do() })
  89. }
  90. func (b *BucketHandle) newDeleteCall() (*raw.BucketsDeleteCall, error) {
  91. req := b.c.raw.Buckets.Delete(b.name)
  92. setClientHeader(req.Header())
  93. if err := applyBucketConds("BucketHandle.Delete", b.conds, req); err != nil {
  94. return nil, err
  95. }
  96. if b.userProject != "" {
  97. req.UserProject(b.userProject)
  98. }
  99. return req, nil
  100. }
  101. // ACL returns an ACLHandle, which provides access to the bucket's access control list.
  102. // This controls who can list, create or overwrite the objects in a bucket.
  103. // This call does not perform any network operations.
  104. func (b *BucketHandle) ACL() *ACLHandle {
  105. return &b.acl
  106. }
  107. // DefaultObjectACL returns an ACLHandle, which provides access to the bucket's default object ACLs.
  108. // These ACLs are applied to newly created objects in this bucket that do not have a defined ACL.
  109. // This call does not perform any network operations.
  110. func (b *BucketHandle) DefaultObjectACL() *ACLHandle {
  111. return &b.defaultObjectACL
  112. }
  113. // Object returns an ObjectHandle, which provides operations on the named object.
  114. // This call does not perform any network operations.
  115. //
  116. // name must consist entirely of valid UTF-8-encoded runes. The full specification
  117. // for valid object names can be found at:
  118. // https://cloud.google.com/storage/docs/bucket-naming
  119. func (b *BucketHandle) Object(name string) *ObjectHandle {
  120. return &ObjectHandle{
  121. c: b.c,
  122. bucket: b.name,
  123. object: name,
  124. acl: ACLHandle{
  125. c: b.c,
  126. bucket: b.name,
  127. object: name,
  128. userProject: b.userProject,
  129. },
  130. gen: -1,
  131. userProject: b.userProject,
  132. }
  133. }
  134. // Attrs returns the metadata for the bucket.
  135. func (b *BucketHandle) Attrs(ctx context.Context) (attrs *BucketAttrs, err error) {
  136. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Attrs")
  137. defer func() { trace.EndSpan(ctx, err) }()
  138. req, err := b.newGetCall()
  139. if err != nil {
  140. return nil, err
  141. }
  142. var resp *raw.Bucket
  143. err = runWithRetry(ctx, func() error {
  144. resp, err = req.Context(ctx).Do()
  145. return err
  146. })
  147. if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
  148. return nil, ErrBucketNotExist
  149. }
  150. if err != nil {
  151. return nil, err
  152. }
  153. return newBucket(resp)
  154. }
  155. func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) {
  156. req := b.c.raw.Buckets.Get(b.name).Projection("full")
  157. setClientHeader(req.Header())
  158. if err := applyBucketConds("BucketHandle.Attrs", b.conds, req); err != nil {
  159. return nil, err
  160. }
  161. if b.userProject != "" {
  162. req.UserProject(b.userProject)
  163. }
  164. return req, nil
  165. }
  166. func (b *BucketHandle) Update(ctx context.Context, uattrs BucketAttrsToUpdate) (attrs *BucketAttrs, err error) {
  167. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create")
  168. defer func() { trace.EndSpan(ctx, err) }()
  169. req, err := b.newPatchCall(&uattrs)
  170. if err != nil {
  171. return nil, err
  172. }
  173. // TODO(jba): retry iff metagen is set?
  174. rb, err := req.Context(ctx).Do()
  175. if err != nil {
  176. return nil, err
  177. }
  178. return newBucket(rb)
  179. }
  180. func (b *BucketHandle) newPatchCall(uattrs *BucketAttrsToUpdate) (*raw.BucketsPatchCall, error) {
  181. rb := uattrs.toRawBucket()
  182. req := b.c.raw.Buckets.Patch(b.name, rb).Projection("full")
  183. setClientHeader(req.Header())
  184. if err := applyBucketConds("BucketHandle.Update", b.conds, req); err != nil {
  185. return nil, err
  186. }
  187. if b.userProject != "" {
  188. req.UserProject(b.userProject)
  189. }
  190. return req, nil
  191. }
  192. // BucketAttrs represents the metadata for a Google Cloud Storage bucket.
  193. // Read-only fields are ignored by BucketHandle.Create.
  194. type BucketAttrs struct {
  195. // Name is the name of the bucket.
  196. // This field is read-only.
  197. Name string
  198. // ACL is the list of access control rules on the bucket.
  199. ACL []ACLRule
  200. // DefaultObjectACL is the list of access controls to
  201. // apply to new objects when no object ACL is provided.
  202. DefaultObjectACL []ACLRule
  203. // Location is the location of the bucket. It defaults to "US".
  204. Location string
  205. // MetaGeneration is the metadata generation of the bucket.
  206. // This field is read-only.
  207. MetaGeneration int64
  208. // StorageClass is the default storage class of the bucket. This defines
  209. // how objects in the bucket are stored and determines the SLA
  210. // and the cost of storage. Typical values are "MULTI_REGIONAL",
  211. // "REGIONAL", "NEARLINE", "COLDLINE", "STANDARD" and
  212. // "DURABLE_REDUCED_AVAILABILITY". Defaults to "STANDARD", which
  213. // is equivalent to "MULTI_REGIONAL" or "REGIONAL" depending on
  214. // the bucket's location settings.
  215. StorageClass string
  216. // Created is the creation time of the bucket.
  217. // This field is read-only.
  218. Created time.Time
  219. // VersioningEnabled reports whether this bucket has versioning enabled.
  220. VersioningEnabled bool
  221. // Labels are the bucket's labels.
  222. Labels map[string]string
  223. // RequesterPays reports whether the bucket is a Requester Pays bucket.
  224. // Clients performing operations on Requester Pays buckets must provide
  225. // a user project (see BucketHandle.UserProject), which will be billed
  226. // for the operations.
  227. RequesterPays bool
  228. // Lifecycle is the lifecycle configuration for objects in the bucket.
  229. Lifecycle Lifecycle
  230. // Retention policy enforces a minimum retention time for all objects
  231. // contained in the bucket. A RetentionPolicy of nil implies the bucket
  232. // has no minimum data retention.
  233. //
  234. // This feature is in private alpha release. It is not currently available to
  235. // most customers. It might be changed in backwards-incompatible ways and is not
  236. // subject to any SLA or deprecation policy.
  237. RetentionPolicy *RetentionPolicy
  238. // The bucket's Cross-Origin Resource Sharing (CORS) configuration.
  239. CORS []CORS
  240. // The encryption configuration used by default for newly inserted objects.
  241. Encryption *BucketEncryption
  242. }
  243. // Lifecycle is the lifecycle configuration for objects in the bucket.
  244. type Lifecycle struct {
  245. Rules []LifecycleRule
  246. }
  247. // Retention policy enforces a minimum retention time for all objects
  248. // contained in the bucket.
  249. //
  250. // Any attempt to overwrite or delete objects younger than the retention
  251. // period will result in an error. An unlocked retention policy can be
  252. // modified or removed from the bucket via the Update method. A
  253. // locked retention policy cannot be removed or shortened in duration
  254. // for the lifetime of the bucket.
  255. //
  256. // This feature is in private alpha release. It is not currently available to
  257. // most customers. It might be changed in backwards-incompatible ways and is not
  258. // subject to any SLA or deprecation policy.
  259. type RetentionPolicy struct {
  260. // RetentionPeriod specifies the duration that objects need to be
  261. // retained. Retention duration must be greater than zero and less than
  262. // 100 years. Note that enforcement of retention periods less than a day
  263. // is not guaranteed. Such periods should only be used for testing
  264. // purposes.
  265. RetentionPeriod time.Duration
  266. // EffectiveTime is the time from which the policy was enforced and
  267. // effective. This field is read-only.
  268. EffectiveTime time.Time
  269. }
  270. const (
  271. // RFC3339 date with only the date segment, used for CreatedBefore in LifecycleRule.
  272. rfc3339Date = "2006-01-02"
  273. // DeleteAction is a lifecycle action that deletes a live and/or archived
  274. // objects. Takes precedence over SetStorageClass actions.
  275. DeleteAction = "Delete"
  276. // SetStorageClassAction changes the storage class of live and/or archived
  277. // objects.
  278. SetStorageClassAction = "SetStorageClass"
  279. )
  280. // LifecycleRule is a lifecycle configuration rule.
  281. //
  282. // When all the configured conditions are met by an object in the bucket, the
  283. // configured action will automatically be taken on that object.
  284. type LifecycleRule struct {
  285. // Action is the action to take when all of the associated conditions are
  286. // met.
  287. Action LifecycleAction
  288. // Condition is the set of conditions that must be met for the associated
  289. // action to be taken.
  290. Condition LifecycleCondition
  291. }
  292. // LifecycleAction is a lifecycle configuration action.
  293. type LifecycleAction struct {
  294. // Type is the type of action to take on matching objects.
  295. //
  296. // Acceptable values are "Delete" to delete matching objects and
  297. // "SetStorageClass" to set the storage class defined in StorageClass on
  298. // matching objects.
  299. Type string
  300. // StorageClass is the storage class to set on matching objects if the Action
  301. // is "SetStorageClass".
  302. StorageClass string
  303. }
  304. // Liveness specifies whether the object is live or not.
  305. type Liveness int
  306. const (
  307. // LiveAndArchived includes both live and archived objects.
  308. LiveAndArchived Liveness = iota
  309. // Live specifies that the object is still live.
  310. Live
  311. // Archived specifies that the object is archived.
  312. Archived
  313. )
  314. // LifecycleCondition is a set of conditions used to match objects and take an
  315. // action automatically.
  316. //
  317. // All configured conditions must be met for the associated action to be taken.
  318. type LifecycleCondition struct {
  319. // AgeInDays is the age of the object in days.
  320. AgeInDays int64
  321. // CreatedBefore is the time the object was created.
  322. //
  323. // This condition is satisfied when an object is created before midnight of
  324. // the specified date in UTC.
  325. CreatedBefore time.Time
  326. // Liveness specifies the object's liveness. Relevant only for versioned objects
  327. Liveness Liveness
  328. // MatchesStorageClasses is the condition matching the object's storage
  329. // class.
  330. //
  331. // Values include "MULTI_REGIONAL", "REGIONAL", "NEARLINE", "COLDLINE",
  332. // "STANDARD", and "DURABLE_REDUCED_AVAILABILITY".
  333. MatchesStorageClasses []string
  334. // NumNewerVersions is the condition matching objects with a number of newer versions.
  335. //
  336. // If the value is N, this condition is satisfied when there are at least N
  337. // versions (including the live version) newer than this version of the
  338. // object.
  339. NumNewerVersions int64
  340. }
  341. func newBucket(b *raw.Bucket) (*BucketAttrs, error) {
  342. if b == nil {
  343. return nil, nil
  344. }
  345. rp, err := toRetentionPolicy(b.RetentionPolicy)
  346. if err != nil {
  347. return nil, err
  348. }
  349. bucket := &BucketAttrs{
  350. Name: b.Name,
  351. Location: b.Location,
  352. MetaGeneration: b.Metageneration,
  353. StorageClass: b.StorageClass,
  354. Created: convertTime(b.TimeCreated),
  355. VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled,
  356. Labels: b.Labels,
  357. RequesterPays: b.Billing != nil && b.Billing.RequesterPays,
  358. Lifecycle: toLifecycle(b.Lifecycle),
  359. RetentionPolicy: rp,
  360. CORS: toCORS(b.Cors),
  361. Encryption: toBucketEncryption(b.Encryption),
  362. }
  363. acl := make([]ACLRule, len(b.Acl))
  364. for i, rule := range b.Acl {
  365. acl[i] = ACLRule{
  366. Entity: ACLEntity(rule.Entity),
  367. Role: ACLRole(rule.Role),
  368. }
  369. }
  370. bucket.ACL = acl
  371. objACL := make([]ACLRule, len(b.DefaultObjectAcl))
  372. for i, rule := range b.DefaultObjectAcl {
  373. objACL[i] = ACLRule{
  374. Entity: ACLEntity(rule.Entity),
  375. Role: ACLRole(rule.Role),
  376. }
  377. }
  378. bucket.DefaultObjectACL = objACL
  379. return bucket, nil
  380. }
  381. // toRawBucket copies the editable attribute from b to the raw library's Bucket type.
  382. func (b *BucketAttrs) toRawBucket() *raw.Bucket {
  383. var acl []*raw.BucketAccessControl
  384. if len(b.ACL) > 0 {
  385. acl = make([]*raw.BucketAccessControl, len(b.ACL))
  386. for i, rule := range b.ACL {
  387. acl[i] = &raw.BucketAccessControl{
  388. Entity: string(rule.Entity),
  389. Role: string(rule.Role),
  390. }
  391. }
  392. }
  393. dACL := toRawObjectACL(b.DefaultObjectACL)
  394. // Copy label map.
  395. var labels map[string]string
  396. if len(b.Labels) > 0 {
  397. labels = make(map[string]string, len(b.Labels))
  398. for k, v := range b.Labels {
  399. labels[k] = v
  400. }
  401. }
  402. // Ignore VersioningEnabled if it is false. This is OK because
  403. // we only call this method when creating a bucket, and by default
  404. // new buckets have versioning off.
  405. var v *raw.BucketVersioning
  406. if b.VersioningEnabled {
  407. v = &raw.BucketVersioning{Enabled: true}
  408. }
  409. var bb *raw.BucketBilling
  410. if b.RequesterPays {
  411. bb = &raw.BucketBilling{RequesterPays: true}
  412. }
  413. return &raw.Bucket{
  414. Name: b.Name,
  415. DefaultObjectAcl: dACL,
  416. Location: b.Location,
  417. StorageClass: b.StorageClass,
  418. Acl: acl,
  419. Versioning: v,
  420. Labels: labels,
  421. Billing: bb,
  422. Lifecycle: toRawLifecycle(b.Lifecycle),
  423. RetentionPolicy: b.RetentionPolicy.toRawRetentionPolicy(),
  424. Cors: toRawCORS(b.CORS),
  425. Encryption: b.Encryption.toRawBucketEncryption(),
  426. }
  427. }
  428. // CORS is the bucket's Cross-Origin Resource Sharing (CORS) configuration.
  429. type CORS struct {
  430. // MaxAge is the value to return in the Access-Control-Max-Age
  431. // header used in preflight responses.
  432. MaxAge time.Duration
  433. // Methods is the list of HTTP methods on which to include CORS response
  434. // headers, (GET, OPTIONS, POST, etc) Note: "*" is permitted in the list
  435. // of methods, and means "any method".
  436. Methods []string
  437. // Origins is the list of Origins eligible to receive CORS response
  438. // headers. Note: "*" is permitted in the list of origins, and means
  439. // "any Origin".
  440. Origins []string
  441. // ResponseHeaders is the list of HTTP headers other than the simple
  442. // response headers to give permission for the user-agent to share
  443. // across domains.
  444. ResponseHeaders []string
  445. }
  446. // BucketEncryption is a bucket's encryption configuration.
  447. type BucketEncryption struct {
  448. // A Cloud KMS key name, in the form
  449. // projects/P/locations/L/keyRings/R/cryptoKeys/K, that will be used to encrypt
  450. // objects inserted into this bucket, if no encryption method is specified.
  451. // The key's location must be the same as the bucket's.
  452. DefaultKMSKeyName string
  453. }
  454. type BucketAttrsToUpdate struct {
  455. // If set, updates whether the bucket uses versioning.
  456. VersioningEnabled optional.Bool
  457. // If set, updates whether the bucket is a Requester Pays bucket.
  458. RequesterPays optional.Bool
  459. // If set, updates the retention policy of the bucket. Using
  460. // RetentionPolicy.RetentionPeriod = 0 will delete the existing policy.
  461. //
  462. // This feature is in private alpha release. It is not currently available to
  463. // most customers. It might be changed in backwards-incompatible ways and is not
  464. // subject to any SLA or deprecation policy.
  465. RetentionPolicy *RetentionPolicy
  466. // If set, replaces the CORS configuration with a new configuration.
  467. // An empty (rather than nil) slice causes all CORS policies to be removed.
  468. CORS []CORS
  469. // If set, replaces the encryption configuration of the bucket. Using
  470. // BucketEncryption.DefaultKMSKeyName = "" will delete the existing
  471. // configuration.
  472. Encryption *BucketEncryption
  473. // If set, replaces the lifecycle configuration of the bucket.
  474. Lifecycle *Lifecycle
  475. setLabels map[string]string
  476. deleteLabels map[string]bool
  477. }
  478. // SetLabel causes a label to be added or modified when ua is used
  479. // in a call to Bucket.Update.
  480. func (ua *BucketAttrsToUpdate) SetLabel(name, value string) {
  481. if ua.setLabels == nil {
  482. ua.setLabels = map[string]string{}
  483. }
  484. ua.setLabels[name] = value
  485. }
  486. // DeleteLabel causes a label to be deleted when ua is used in a
  487. // call to Bucket.Update.
  488. func (ua *BucketAttrsToUpdate) DeleteLabel(name string) {
  489. if ua.deleteLabels == nil {
  490. ua.deleteLabels = map[string]bool{}
  491. }
  492. ua.deleteLabels[name] = true
  493. }
  494. func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket {
  495. rb := &raw.Bucket{}
  496. if ua.CORS != nil {
  497. rb.Cors = toRawCORS(ua.CORS)
  498. rb.ForceSendFields = append(rb.ForceSendFields, "Cors")
  499. }
  500. if ua.RetentionPolicy != nil {
  501. if ua.RetentionPolicy.RetentionPeriod == 0 {
  502. rb.NullFields = append(rb.NullFields, "RetentionPolicy")
  503. rb.RetentionPolicy = nil
  504. } else {
  505. rb.RetentionPolicy = ua.RetentionPolicy.toRawRetentionPolicy()
  506. }
  507. }
  508. if ua.VersioningEnabled != nil {
  509. rb.Versioning = &raw.BucketVersioning{
  510. Enabled: optional.ToBool(ua.VersioningEnabled),
  511. ForceSendFields: []string{"Enabled"},
  512. }
  513. }
  514. if ua.RequesterPays != nil {
  515. rb.Billing = &raw.BucketBilling{
  516. RequesterPays: optional.ToBool(ua.RequesterPays),
  517. ForceSendFields: []string{"RequesterPays"},
  518. }
  519. }
  520. if ua.Encryption != nil {
  521. if ua.Encryption.DefaultKMSKeyName == "" {
  522. rb.NullFields = append(rb.NullFields, "Encryption")
  523. rb.Encryption = nil
  524. } else {
  525. rb.Encryption = ua.Encryption.toRawBucketEncryption()
  526. }
  527. }
  528. if ua.Lifecycle != nil {
  529. rb.Lifecycle = toRawLifecycle(*ua.Lifecycle)
  530. }
  531. if ua.setLabels != nil || ua.deleteLabels != nil {
  532. rb.Labels = map[string]string{}
  533. for k, v := range ua.setLabels {
  534. rb.Labels[k] = v
  535. }
  536. if len(rb.Labels) == 0 && len(ua.deleteLabels) > 0 {
  537. rb.ForceSendFields = append(rb.ForceSendFields, "Labels")
  538. }
  539. for l := range ua.deleteLabels {
  540. rb.NullFields = append(rb.NullFields, "Labels."+l)
  541. }
  542. }
  543. return rb
  544. }
  545. // If returns a new BucketHandle that applies a set of preconditions.
  546. // Preconditions already set on the BucketHandle are ignored.
  547. // Operations on the new handle will only occur if the preconditions are
  548. // satisfied. The only valid preconditions for buckets are MetagenerationMatch
  549. // and MetagenerationNotMatch.
  550. func (b *BucketHandle) If(conds BucketConditions) *BucketHandle {
  551. b2 := *b
  552. b2.conds = &conds
  553. return &b2
  554. }
  555. // BucketConditions constrain bucket methods to act on specific metagenerations.
  556. //
  557. // The zero value is an empty set of constraints.
  558. type BucketConditions struct {
  559. // MetagenerationMatch specifies that the bucket must have the given
  560. // metageneration for the operation to occur.
  561. // If MetagenerationMatch is zero, it has no effect.
  562. MetagenerationMatch int64
  563. // MetagenerationNotMatch specifies that the bucket must not have the given
  564. // metageneration for the operation to occur.
  565. // If MetagenerationNotMatch is zero, it has no effect.
  566. MetagenerationNotMatch int64
  567. }
  568. func (c *BucketConditions) validate(method string) error {
  569. if *c == (BucketConditions{}) {
  570. return fmt.Errorf("storage: %s: empty conditions", method)
  571. }
  572. if c.MetagenerationMatch != 0 && c.MetagenerationNotMatch != 0 {
  573. return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method)
  574. }
  575. return nil
  576. }
  577. // UserProject returns a new BucketHandle that passes the project ID as the user
  578. // project for all subsequent calls. Calls with a user project will be billed to that
  579. // project rather than to the bucket's owning project.
  580. //
  581. // A user project is required for all operations on Requester Pays buckets.
  582. func (b *BucketHandle) UserProject(projectID string) *BucketHandle {
  583. b2 := *b
  584. b2.userProject = projectID
  585. b2.acl.userProject = projectID
  586. b2.defaultObjectACL.userProject = projectID
  587. return &b2
  588. }
  589. // LockRetentionPolicy locks a bucket's retention policy until a previously-configured
  590. // RetentionPeriod past the EffectiveTime. Note that if RetentionPeriod is set to less
  591. // than a day, the retention policy is treated as a development configuration and locking
  592. // will have no effect. The BucketHandle must have a metageneration condition that
  593. // matches the bucket's metageneration. See BucketHandle.If.
  594. //
  595. // This feature is in private alpha release. It is not currently available to
  596. // most customers. It might be changed in backwards-incompatible ways and is not
  597. // subject to any SLA or deprecation policy.
  598. func (b *BucketHandle) LockRetentionPolicy(ctx context.Context) error {
  599. var metageneration int64
  600. if b.conds != nil {
  601. metageneration = b.conds.MetagenerationMatch
  602. }
  603. req := b.c.raw.Buckets.LockRetentionPolicy(b.name, metageneration)
  604. _, err := req.Context(ctx).Do()
  605. return err
  606. }
  607. // applyBucketConds modifies the provided call using the conditions in conds.
  608. // call is something that quacks like a *raw.WhateverCall.
  609. func applyBucketConds(method string, conds *BucketConditions, call interface{}) error {
  610. if conds == nil {
  611. return nil
  612. }
  613. if err := conds.validate(method); err != nil {
  614. return err
  615. }
  616. cval := reflect.ValueOf(call)
  617. switch {
  618. case conds.MetagenerationMatch != 0:
  619. if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) {
  620. return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method)
  621. }
  622. case conds.MetagenerationNotMatch != 0:
  623. if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) {
  624. return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method)
  625. }
  626. }
  627. return nil
  628. }
  629. func (rp *RetentionPolicy) toRawRetentionPolicy() *raw.BucketRetentionPolicy {
  630. if rp == nil {
  631. return nil
  632. }
  633. return &raw.BucketRetentionPolicy{
  634. RetentionPeriod: int64(rp.RetentionPeriod / time.Second),
  635. }
  636. }
  637. func toRetentionPolicy(rp *raw.BucketRetentionPolicy) (*RetentionPolicy, error) {
  638. if rp == nil {
  639. return nil, nil
  640. }
  641. t, err := time.Parse(time.RFC3339, rp.EffectiveTime)
  642. if err != nil {
  643. return nil, err
  644. }
  645. return &RetentionPolicy{
  646. RetentionPeriod: time.Duration(rp.RetentionPeriod) * time.Second,
  647. EffectiveTime: t,
  648. }, nil
  649. }
  650. func toRawCORS(c []CORS) []*raw.BucketCors {
  651. var out []*raw.BucketCors
  652. for _, v := range c {
  653. out = append(out, &raw.BucketCors{
  654. MaxAgeSeconds: int64(v.MaxAge / time.Second),
  655. Method: v.Methods,
  656. Origin: v.Origins,
  657. ResponseHeader: v.ResponseHeaders,
  658. })
  659. }
  660. return out
  661. }
  662. func toCORS(rc []*raw.BucketCors) []CORS {
  663. var out []CORS
  664. for _, v := range rc {
  665. out = append(out, CORS{
  666. MaxAge: time.Duration(v.MaxAgeSeconds) * time.Second,
  667. Methods: v.Method,
  668. Origins: v.Origin,
  669. ResponseHeaders: v.ResponseHeader,
  670. })
  671. }
  672. return out
  673. }
  674. func toRawLifecycle(l Lifecycle) *raw.BucketLifecycle {
  675. var rl raw.BucketLifecycle
  676. if len(l.Rules) == 0 {
  677. return nil
  678. }
  679. for _, r := range l.Rules {
  680. rr := &raw.BucketLifecycleRule{
  681. Action: &raw.BucketLifecycleRuleAction{
  682. Type: r.Action.Type,
  683. StorageClass: r.Action.StorageClass,
  684. },
  685. Condition: &raw.BucketLifecycleRuleCondition{
  686. Age: r.Condition.AgeInDays,
  687. MatchesStorageClass: r.Condition.MatchesStorageClasses,
  688. NumNewerVersions: r.Condition.NumNewerVersions,
  689. },
  690. }
  691. switch r.Condition.Liveness {
  692. case LiveAndArchived:
  693. rr.Condition.IsLive = nil
  694. case Live:
  695. rr.Condition.IsLive = googleapi.Bool(true)
  696. case Archived:
  697. rr.Condition.IsLive = googleapi.Bool(false)
  698. }
  699. if !r.Condition.CreatedBefore.IsZero() {
  700. rr.Condition.CreatedBefore = r.Condition.CreatedBefore.Format(rfc3339Date)
  701. }
  702. rl.Rule = append(rl.Rule, rr)
  703. }
  704. return &rl
  705. }
  706. func toLifecycle(rl *raw.BucketLifecycle) Lifecycle {
  707. var l Lifecycle
  708. if rl == nil {
  709. return l
  710. }
  711. for _, rr := range rl.Rule {
  712. r := LifecycleRule{
  713. Action: LifecycleAction{
  714. Type: rr.Action.Type,
  715. StorageClass: rr.Action.StorageClass,
  716. },
  717. Condition: LifecycleCondition{
  718. AgeInDays: rr.Condition.Age,
  719. MatchesStorageClasses: rr.Condition.MatchesStorageClass,
  720. NumNewerVersions: rr.Condition.NumNewerVersions,
  721. },
  722. }
  723. switch {
  724. case rr.Condition.IsLive == nil:
  725. r.Condition.Liveness = LiveAndArchived
  726. case *rr.Condition.IsLive == true:
  727. r.Condition.Liveness = Live
  728. case *rr.Condition.IsLive == false:
  729. r.Condition.Liveness = Archived
  730. }
  731. if rr.Condition.CreatedBefore != "" {
  732. r.Condition.CreatedBefore, _ = time.Parse(rfc3339Date, rr.Condition.CreatedBefore)
  733. }
  734. l.Rules = append(l.Rules, r)
  735. }
  736. return l
  737. }
  738. func (e *BucketEncryption) toRawBucketEncryption() *raw.BucketEncryption {
  739. if e == nil {
  740. return nil
  741. }
  742. return &raw.BucketEncryption{
  743. DefaultKmsKeyName: e.DefaultKMSKeyName,
  744. }
  745. }
  746. func toBucketEncryption(e *raw.BucketEncryption) *BucketEncryption {
  747. if e == nil {
  748. return nil
  749. }
  750. return &BucketEncryption{DefaultKMSKeyName: e.DefaultKmsKeyName}
  751. }
  752. // Objects returns an iterator over the objects in the bucket that match the Query q.
  753. // If q is nil, no filtering is done.
  754. func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator {
  755. it := &ObjectIterator{
  756. ctx: ctx,
  757. bucket: b,
  758. }
  759. it.pageInfo, it.nextFunc = iterator.NewPageInfo(
  760. it.fetch,
  761. func() int { return len(it.items) },
  762. func() interface{} { b := it.items; it.items = nil; return b })
  763. if q != nil {
  764. it.query = *q
  765. }
  766. return it
  767. }
  768. // An ObjectIterator is an iterator over ObjectAttrs.
  769. type ObjectIterator struct {
  770. ctx context.Context
  771. bucket *BucketHandle
  772. query Query
  773. pageInfo *iterator.PageInfo
  774. nextFunc func() error
  775. items []*ObjectAttrs
  776. }
  777. // PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
  778. func (it *ObjectIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
  779. // Next returns the next result. Its second return value is iterator.Done if
  780. // there are no more results. Once Next returns iterator.Done, all subsequent
  781. // calls will return iterator.Done.
  782. //
  783. // If Query.Delimiter is non-empty, some of the ObjectAttrs returned by Next will
  784. // have a non-empty Prefix field, and a zero value for all other fields. These
  785. // represent prefixes.
  786. func (it *ObjectIterator) Next() (*ObjectAttrs, error) {
  787. if err := it.nextFunc(); err != nil {
  788. return nil, err
  789. }
  790. item := it.items[0]
  791. it.items = it.items[1:]
  792. return item, nil
  793. }
  794. func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error) {
  795. req := it.bucket.c.raw.Objects.List(it.bucket.name)
  796. setClientHeader(req.Header())
  797. req.Projection("full")
  798. req.Delimiter(it.query.Delimiter)
  799. req.Prefix(it.query.Prefix)
  800. req.Versions(it.query.Versions)
  801. req.PageToken(pageToken)
  802. if it.bucket.userProject != "" {
  803. req.UserProject(it.bucket.userProject)
  804. }
  805. if pageSize > 0 {
  806. req.MaxResults(int64(pageSize))
  807. }
  808. var resp *raw.Objects
  809. var err error
  810. err = runWithRetry(it.ctx, func() error {
  811. resp, err = req.Context(it.ctx).Do()
  812. return err
  813. })
  814. if err != nil {
  815. if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
  816. err = ErrBucketNotExist
  817. }
  818. return "", err
  819. }
  820. for _, item := range resp.Items {
  821. it.items = append(it.items, newObject(item))
  822. }
  823. for _, prefix := range resp.Prefixes {
  824. it.items = append(it.items, &ObjectAttrs{Prefix: prefix})
  825. }
  826. return resp.NextPageToken, nil
  827. }
  828. // Buckets returns an iterator over the buckets in the project. You may
  829. // optionally set the iterator's Prefix field to restrict the list to buckets
  830. // whose names begin with the prefix. By default, all buckets in the project
  831. // are returned.
  832. func (c *Client) Buckets(ctx context.Context, projectID string) *BucketIterator {
  833. it := &BucketIterator{
  834. ctx: ctx,
  835. client: c,
  836. projectID: projectID,
  837. }
  838. it.pageInfo, it.nextFunc = iterator.NewPageInfo(
  839. it.fetch,
  840. func() int { return len(it.buckets) },
  841. func() interface{} { b := it.buckets; it.buckets = nil; return b })
  842. return it
  843. }
  844. // A BucketIterator is an iterator over BucketAttrs.
  845. type BucketIterator struct {
  846. // Prefix restricts the iterator to buckets whose names begin with it.
  847. Prefix string
  848. ctx context.Context
  849. client *Client
  850. projectID string
  851. buckets []*BucketAttrs
  852. pageInfo *iterator.PageInfo
  853. nextFunc func() error
  854. }
  855. // Next returns the next result. Its second return value is iterator.Done if
  856. // there are no more results. Once Next returns iterator.Done, all subsequent
  857. // calls will return iterator.Done.
  858. func (it *BucketIterator) Next() (*BucketAttrs, error) {
  859. if err := it.nextFunc(); err != nil {
  860. return nil, err
  861. }
  862. b := it.buckets[0]
  863. it.buckets = it.buckets[1:]
  864. return b, nil
  865. }
  866. // PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
  867. func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
  868. func (it *BucketIterator) fetch(pageSize int, pageToken string) (token string, err error) {
  869. req := it.client.raw.Buckets.List(it.projectID)
  870. setClientHeader(req.Header())
  871. req.Projection("full")
  872. req.Prefix(it.Prefix)
  873. req.PageToken(pageToken)
  874. if pageSize > 0 {
  875. req.MaxResults(int64(pageSize))
  876. }
  877. var resp *raw.Buckets
  878. err = runWithRetry(it.ctx, func() error {
  879. resp, err = req.Context(it.ctx).Do()
  880. return err
  881. })
  882. if err != nil {
  883. return "", err
  884. }
  885. for _, item := range resp.Items {
  886. b, err := newBucket(item)
  887. if err != nil {
  888. return "", err
  889. }
  890. it.buckets = append(it.buckets, b)
  891. }
  892. return resp.NextPageToken, nil
  893. }