bucket.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. // Copyright 2014 Google Inc. LiveAndArchived Rights Reserved.
  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 precendence 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. setLabels map[string]string
  474. deleteLabels map[string]bool
  475. }
  476. // SetLabel causes a label to be added or modified when ua is used
  477. // in a call to Bucket.Update.
  478. func (ua *BucketAttrsToUpdate) SetLabel(name, value string) {
  479. if ua.setLabels == nil {
  480. ua.setLabels = map[string]string{}
  481. }
  482. ua.setLabels[name] = value
  483. }
  484. // DeleteLabel causes a label to be deleted when ua is used in a
  485. // call to Bucket.Update.
  486. func (ua *BucketAttrsToUpdate) DeleteLabel(name string) {
  487. if ua.deleteLabels == nil {
  488. ua.deleteLabels = map[string]bool{}
  489. }
  490. ua.deleteLabels[name] = true
  491. }
  492. func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket {
  493. rb := &raw.Bucket{}
  494. if ua.CORS != nil {
  495. rb.Cors = toRawCORS(ua.CORS)
  496. rb.ForceSendFields = append(rb.ForceSendFields, "Cors")
  497. }
  498. if ua.RetentionPolicy != nil {
  499. if ua.RetentionPolicy.RetentionPeriod == 0 {
  500. rb.NullFields = append(rb.NullFields, "RetentionPolicy")
  501. rb.RetentionPolicy = nil
  502. } else {
  503. rb.RetentionPolicy = ua.RetentionPolicy.toRawRetentionPolicy()
  504. }
  505. }
  506. if ua.VersioningEnabled != nil {
  507. rb.Versioning = &raw.BucketVersioning{
  508. Enabled: optional.ToBool(ua.VersioningEnabled),
  509. ForceSendFields: []string{"Enabled"},
  510. }
  511. }
  512. if ua.RequesterPays != nil {
  513. rb.Billing = &raw.BucketBilling{
  514. RequesterPays: optional.ToBool(ua.RequesterPays),
  515. ForceSendFields: []string{"RequesterPays"},
  516. }
  517. }
  518. if ua.Encryption != nil {
  519. if ua.Encryption.DefaultKMSKeyName == "" {
  520. rb.NullFields = append(rb.NullFields, "Encryption")
  521. rb.Encryption = nil
  522. } else {
  523. rb.Encryption = ua.Encryption.toRawBucketEncryption()
  524. }
  525. }
  526. if ua.setLabels != nil || ua.deleteLabels != nil {
  527. rb.Labels = map[string]string{}
  528. for k, v := range ua.setLabels {
  529. rb.Labels[k] = v
  530. }
  531. if len(rb.Labels) == 0 && len(ua.deleteLabels) > 0 {
  532. rb.ForceSendFields = append(rb.ForceSendFields, "Labels")
  533. }
  534. for l := range ua.deleteLabels {
  535. rb.NullFields = append(rb.NullFields, "Labels."+l)
  536. }
  537. }
  538. return rb
  539. }
  540. // If returns a new BucketHandle that applies a set of preconditions.
  541. // Preconditions already set on the BucketHandle are ignored.
  542. // Operations on the new handle will only occur if the preconditions are
  543. // satisfied. The only valid preconditions for buckets are MetagenerationMatch
  544. // and MetagenerationNotMatch.
  545. func (b *BucketHandle) If(conds BucketConditions) *BucketHandle {
  546. b2 := *b
  547. b2.conds = &conds
  548. return &b2
  549. }
  550. // BucketConditions constrain bucket methods to act on specific metagenerations.
  551. //
  552. // The zero value is an empty set of constraints.
  553. type BucketConditions struct {
  554. // MetagenerationMatch specifies that the bucket must have the given
  555. // metageneration for the operation to occur.
  556. // If MetagenerationMatch is zero, it has no effect.
  557. MetagenerationMatch int64
  558. // MetagenerationNotMatch specifies that the bucket must not have the given
  559. // metageneration for the operation to occur.
  560. // If MetagenerationNotMatch is zero, it has no effect.
  561. MetagenerationNotMatch int64
  562. }
  563. func (c *BucketConditions) validate(method string) error {
  564. if *c == (BucketConditions{}) {
  565. return fmt.Errorf("storage: %s: empty conditions", method)
  566. }
  567. if c.MetagenerationMatch != 0 && c.MetagenerationNotMatch != 0 {
  568. return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method)
  569. }
  570. return nil
  571. }
  572. // UserProject returns a new BucketHandle that passes the project ID as the user
  573. // project for all subsequent calls. Calls with a user project will be billed to that
  574. // project rather than to the bucket's owning project.
  575. //
  576. // A user project is required for all operations on Requester Pays buckets.
  577. func (b *BucketHandle) UserProject(projectID string) *BucketHandle {
  578. b2 := *b
  579. b2.userProject = projectID
  580. b2.acl.userProject = projectID
  581. b2.defaultObjectACL.userProject = projectID
  582. return &b2
  583. }
  584. // LockRetentionPolicy locks a bucket's retention policy until a previously-configured
  585. // RetentionPeriod past the EffectiveTime. Note that if RetentionPeriod is set to less
  586. // than a day, the retention policy is treated as a development configuration and locking
  587. // will have no effect. The BucketHandle must have a metageneration condition that
  588. // matches the bucket's metageneration. See BucketHandle.If.
  589. //
  590. // This feature is in private alpha release. It is not currently available to
  591. // most customers. It might be changed in backwards-incompatible ways and is not
  592. // subject to any SLA or deprecation policy.
  593. func (b *BucketHandle) LockRetentionPolicy(ctx context.Context) error {
  594. var metageneration int64
  595. if b.conds != nil {
  596. metageneration = b.conds.MetagenerationMatch
  597. }
  598. req := b.c.raw.Buckets.LockRetentionPolicy(b.name, metageneration)
  599. _, err := req.Context(ctx).Do()
  600. return err
  601. }
  602. // applyBucketConds modifies the provided call using the conditions in conds.
  603. // call is something that quacks like a *raw.WhateverCall.
  604. func applyBucketConds(method string, conds *BucketConditions, call interface{}) error {
  605. if conds == nil {
  606. return nil
  607. }
  608. if err := conds.validate(method); err != nil {
  609. return err
  610. }
  611. cval := reflect.ValueOf(call)
  612. switch {
  613. case conds.MetagenerationMatch != 0:
  614. if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) {
  615. return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method)
  616. }
  617. case conds.MetagenerationNotMatch != 0:
  618. if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) {
  619. return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method)
  620. }
  621. }
  622. return nil
  623. }
  624. func (rp *RetentionPolicy) toRawRetentionPolicy() *raw.BucketRetentionPolicy {
  625. if rp == nil {
  626. return nil
  627. }
  628. return &raw.BucketRetentionPolicy{
  629. RetentionPeriod: int64(rp.RetentionPeriod / time.Second),
  630. }
  631. }
  632. func toRetentionPolicy(rp *raw.BucketRetentionPolicy) (*RetentionPolicy, error) {
  633. if rp == nil {
  634. return nil, nil
  635. }
  636. t, err := time.Parse(time.RFC3339, rp.EffectiveTime)
  637. if err != nil {
  638. return nil, err
  639. }
  640. return &RetentionPolicy{
  641. RetentionPeriod: time.Duration(rp.RetentionPeriod) * time.Second,
  642. EffectiveTime: t,
  643. }, nil
  644. }
  645. func toRawCORS(c []CORS) []*raw.BucketCors {
  646. var out []*raw.BucketCors
  647. for _, v := range c {
  648. out = append(out, &raw.BucketCors{
  649. MaxAgeSeconds: int64(v.MaxAge / time.Second),
  650. Method: v.Methods,
  651. Origin: v.Origins,
  652. ResponseHeader: v.ResponseHeaders,
  653. })
  654. }
  655. return out
  656. }
  657. func toCORS(rc []*raw.BucketCors) []CORS {
  658. var out []CORS
  659. for _, v := range rc {
  660. out = append(out, CORS{
  661. MaxAge: time.Duration(v.MaxAgeSeconds) * time.Second,
  662. Methods: v.Method,
  663. Origins: v.Origin,
  664. ResponseHeaders: v.ResponseHeader,
  665. })
  666. }
  667. return out
  668. }
  669. func toRawLifecycle(l Lifecycle) *raw.BucketLifecycle {
  670. var rl raw.BucketLifecycle
  671. if len(l.Rules) == 0 {
  672. return nil
  673. }
  674. for _, r := range l.Rules {
  675. rr := &raw.BucketLifecycleRule{
  676. Action: &raw.BucketLifecycleRuleAction{
  677. Type: r.Action.Type,
  678. StorageClass: r.Action.StorageClass,
  679. },
  680. Condition: &raw.BucketLifecycleRuleCondition{
  681. Age: r.Condition.AgeInDays,
  682. MatchesStorageClass: r.Condition.MatchesStorageClasses,
  683. NumNewerVersions: r.Condition.NumNewerVersions,
  684. },
  685. }
  686. switch r.Condition.Liveness {
  687. case LiveAndArchived:
  688. rr.Condition.IsLive = nil
  689. case Live:
  690. rr.Condition.IsLive = googleapi.Bool(true)
  691. case Archived:
  692. rr.Condition.IsLive = googleapi.Bool(false)
  693. }
  694. if !r.Condition.CreatedBefore.IsZero() {
  695. rr.Condition.CreatedBefore = r.Condition.CreatedBefore.Format(rfc3339Date)
  696. }
  697. rl.Rule = append(rl.Rule, rr)
  698. }
  699. return &rl
  700. }
  701. func toLifecycle(rl *raw.BucketLifecycle) Lifecycle {
  702. var l Lifecycle
  703. if rl == nil {
  704. return l
  705. }
  706. for _, rr := range rl.Rule {
  707. r := LifecycleRule{
  708. Action: LifecycleAction{
  709. Type: rr.Action.Type,
  710. StorageClass: rr.Action.StorageClass,
  711. },
  712. Condition: LifecycleCondition{
  713. AgeInDays: rr.Condition.Age,
  714. MatchesStorageClasses: rr.Condition.MatchesStorageClass,
  715. NumNewerVersions: rr.Condition.NumNewerVersions,
  716. },
  717. }
  718. switch {
  719. case rr.Condition.IsLive == nil:
  720. r.Condition.Liveness = LiveAndArchived
  721. case *rr.Condition.IsLive == true:
  722. r.Condition.Liveness = Live
  723. case *rr.Condition.IsLive == false:
  724. r.Condition.Liveness = Archived
  725. }
  726. if rr.Condition.CreatedBefore != "" {
  727. r.Condition.CreatedBefore, _ = time.Parse(rfc3339Date, rr.Condition.CreatedBefore)
  728. }
  729. l.Rules = append(l.Rules, r)
  730. }
  731. return l
  732. }
  733. func (e *BucketEncryption) toRawBucketEncryption() *raw.BucketEncryption {
  734. if e == nil {
  735. return nil
  736. }
  737. return &raw.BucketEncryption{
  738. DefaultKmsKeyName: e.DefaultKMSKeyName,
  739. }
  740. }
  741. func toBucketEncryption(e *raw.BucketEncryption) *BucketEncryption {
  742. if e == nil {
  743. return nil
  744. }
  745. return &BucketEncryption{DefaultKMSKeyName: e.DefaultKmsKeyName}
  746. }
  747. // Objects returns an iterator over the objects in the bucket that match the Query q.
  748. // If q is nil, no filtering is done.
  749. func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator {
  750. it := &ObjectIterator{
  751. ctx: ctx,
  752. bucket: b,
  753. }
  754. it.pageInfo, it.nextFunc = iterator.NewPageInfo(
  755. it.fetch,
  756. func() int { return len(it.items) },
  757. func() interface{} { b := it.items; it.items = nil; return b })
  758. if q != nil {
  759. it.query = *q
  760. }
  761. return it
  762. }
  763. // An ObjectIterator is an iterator over ObjectAttrs.
  764. type ObjectIterator struct {
  765. ctx context.Context
  766. bucket *BucketHandle
  767. query Query
  768. pageInfo *iterator.PageInfo
  769. nextFunc func() error
  770. items []*ObjectAttrs
  771. }
  772. // PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
  773. func (it *ObjectIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
  774. // Next returns the next result. Its second return value is iterator.Done if
  775. // there are no more results. Once Next returns iterator.Done, all subsequent
  776. // calls will return iterator.Done.
  777. //
  778. // If Query.Delimiter is non-empty, some of the ObjectAttrs returned by Next will
  779. // have a non-empty Prefix field, and a zero value for all other fields. These
  780. // represent prefixes.
  781. func (it *ObjectIterator) Next() (*ObjectAttrs, error) {
  782. if err := it.nextFunc(); err != nil {
  783. return nil, err
  784. }
  785. item := it.items[0]
  786. it.items = it.items[1:]
  787. return item, nil
  788. }
  789. func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error) {
  790. req := it.bucket.c.raw.Objects.List(it.bucket.name)
  791. setClientHeader(req.Header())
  792. req.Projection("full")
  793. req.Delimiter(it.query.Delimiter)
  794. req.Prefix(it.query.Prefix)
  795. req.Versions(it.query.Versions)
  796. req.PageToken(pageToken)
  797. if it.bucket.userProject != "" {
  798. req.UserProject(it.bucket.userProject)
  799. }
  800. if pageSize > 0 {
  801. req.MaxResults(int64(pageSize))
  802. }
  803. var resp *raw.Objects
  804. var err error
  805. err = runWithRetry(it.ctx, func() error {
  806. resp, err = req.Context(it.ctx).Do()
  807. return err
  808. })
  809. if err != nil {
  810. if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
  811. err = ErrBucketNotExist
  812. }
  813. return "", err
  814. }
  815. for _, item := range resp.Items {
  816. it.items = append(it.items, newObject(item))
  817. }
  818. for _, prefix := range resp.Prefixes {
  819. it.items = append(it.items, &ObjectAttrs{Prefix: prefix})
  820. }
  821. return resp.NextPageToken, nil
  822. }
  823. // Buckets returns an iterator over the buckets in the project. You may
  824. // optionally set the iterator's Prefix field to restrict the list to buckets
  825. // whose names begin with the prefix. By default, all buckets in the project
  826. // are returned.
  827. func (c *Client) Buckets(ctx context.Context, projectID string) *BucketIterator {
  828. it := &BucketIterator{
  829. ctx: ctx,
  830. client: c,
  831. projectID: projectID,
  832. }
  833. it.pageInfo, it.nextFunc = iterator.NewPageInfo(
  834. it.fetch,
  835. func() int { return len(it.buckets) },
  836. func() interface{} { b := it.buckets; it.buckets = nil; return b })
  837. return it
  838. }
  839. // A BucketIterator is an iterator over BucketAttrs.
  840. type BucketIterator struct {
  841. // Prefix restricts the iterator to buckets whose names begin with it.
  842. Prefix string
  843. ctx context.Context
  844. client *Client
  845. projectID string
  846. buckets []*BucketAttrs
  847. pageInfo *iterator.PageInfo
  848. nextFunc func() error
  849. }
  850. // Next returns the next result. Its second return value is iterator.Done if
  851. // there are no more results. Once Next returns iterator.Done, all subsequent
  852. // calls will return iterator.Done.
  853. func (it *BucketIterator) Next() (*BucketAttrs, error) {
  854. if err := it.nextFunc(); err != nil {
  855. return nil, err
  856. }
  857. b := it.buckets[0]
  858. it.buckets = it.buckets[1:]
  859. return b, nil
  860. }
  861. // PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
  862. func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
  863. func (it *BucketIterator) fetch(pageSize int, pageToken string) (token string, err error) {
  864. req := it.client.raw.Buckets.List(it.projectID)
  865. setClientHeader(req.Header())
  866. req.Projection("full")
  867. req.Prefix(it.Prefix)
  868. req.PageToken(pageToken)
  869. if pageSize > 0 {
  870. req.MaxResults(int64(pageSize))
  871. }
  872. var resp *raw.Buckets
  873. err = runWithRetry(it.ctx, func() error {
  874. resp, err = req.Context(it.ctx).Do()
  875. return err
  876. })
  877. if err != nil {
  878. return "", err
  879. }
  880. for _, item := range resp.Items {
  881. b, err := newBucket(item)
  882. if err != nil {
  883. return "", err
  884. }
  885. it.buckets = append(it.buckets, b)
  886. }
  887. return resp.NextPageToken, nil
  888. }