bucket.go 35 KB

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