copy.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // Copyright 2016 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. "errors"
  18. "fmt"
  19. "cloud.google.com/go/internal/trace"
  20. )
  21. // CopierFrom creates a Copier that can copy src to dst.
  22. // You can immediately call Run on the returned Copier, or
  23. // you can configure it first.
  24. //
  25. // For Requester Pays buckets, the user project of dst is billed, unless it is empty,
  26. // in which case the user project of src is billed.
  27. func (dst *ObjectHandle) CopierFrom(src *ObjectHandle) *Copier {
  28. return &Copier{dst: dst, src: src}
  29. }
  30. // A Copier copies a source object to a destination.
  31. type Copier struct {
  32. // ObjectAttrs are optional attributes to set on the destination object.
  33. // Any attributes must be initialized before any calls on the Copier. Nil
  34. // or zero-valued attributes are ignored.
  35. ObjectAttrs
  36. // RewriteToken can be set before calling Run to resume a copy
  37. // operation. After Run returns a non-nil error, RewriteToken will
  38. // have been updated to contain the value needed to resume the copy.
  39. RewriteToken string
  40. // ProgressFunc can be used to monitor the progress of a multi-RPC copy
  41. // operation. If ProgressFunc is not nil and copying requires multiple
  42. // calls to the underlying service (see
  43. // https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite), then
  44. // ProgressFunc will be invoked after each call with the number of bytes of
  45. // content copied so far and the total size in bytes of the source object.
  46. //
  47. // ProgressFunc is intended to make upload progress available to the
  48. // application. For example, the implementation of ProgressFunc may update
  49. // a progress bar in the application's UI, or log the result of
  50. // float64(copiedBytes)/float64(totalBytes).
  51. //
  52. // ProgressFunc should return quickly without blocking.
  53. ProgressFunc func(copiedBytes, totalBytes uint64)
  54. // The Cloud KMS key, in the form projects/P/locations/L/keyRings/R/cryptoKeys/K,
  55. // that will be used to encrypt the object. Overrides the object's KMSKeyName, if
  56. // any.
  57. //
  58. // Providing both a DestinationKMSKeyName and a customer-supplied encryption key
  59. // (via ObjectHandle.Key) on the destination object will result in an error when
  60. // Run is called.
  61. DestinationKMSKeyName string
  62. dst, src *ObjectHandle
  63. // The maximum number of bytes that will be rewritten per rewrite request.
  64. // Most callers shouldn't need to specify this parameter - it is primarily
  65. // in place to support testing. If specified the value must be an integral
  66. // multiple of 1 MiB (1048576). Also, this only applies to requests where
  67. // the source and destination span locations and/or storage classes. Finally,
  68. // this value must not change across rewrite calls else you'll get an error
  69. // that the `rewriteToken` is invalid.
  70. maxBytesRewrittenPerCall int64
  71. }
  72. // Run performs the copy.
  73. func (c *Copier) Run(ctx context.Context) (attrs *ObjectAttrs, err error) {
  74. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Copier.Run")
  75. defer func() { trace.EndSpan(ctx, err) }()
  76. if err := c.src.validate(); err != nil {
  77. return nil, err
  78. }
  79. if err := c.dst.validate(); err != nil {
  80. return nil, err
  81. }
  82. if c.DestinationKMSKeyName != "" && c.dst.encryptionKey != nil {
  83. return nil, errors.New("storage: cannot use DestinationKMSKeyName with a customer-supplied encryption key")
  84. }
  85. if c.dst.gen != defaultGen {
  86. return nil, fmt.Errorf("storage: generation cannot be specified on copy destination, got %v", c.dst.gen)
  87. }
  88. // Convert destination attributes to raw form, omitting the bucket.
  89. // If the bucket is included but name or content-type aren't, the service
  90. // returns a 400 with "Required" as the only message. Omitting the bucket
  91. // does not cause any problems.
  92. req := &rewriteObjectRequest{
  93. srcObject: sourceObject{
  94. name: c.src.object,
  95. bucket: c.src.bucket,
  96. gen: c.src.gen,
  97. conds: c.src.conds,
  98. encryptionKey: c.src.encryptionKey,
  99. },
  100. dstObject: destinationObject{
  101. name: c.dst.object,
  102. bucket: c.dst.bucket,
  103. conds: c.dst.conds,
  104. attrs: &c.ObjectAttrs,
  105. encryptionKey: c.dst.encryptionKey,
  106. keyName: c.DestinationKMSKeyName,
  107. },
  108. predefinedACL: c.PredefinedACL,
  109. token: c.RewriteToken,
  110. maxBytesRewrittenPerCall: c.maxBytesRewrittenPerCall,
  111. }
  112. isIdempotent := c.dst.conds != nil && (c.dst.conds.GenerationMatch != 0 || c.dst.conds.DoesNotExist)
  113. var userProject string
  114. if c.dst.userProject != "" {
  115. userProject = c.dst.userProject
  116. } else if c.src.userProject != "" {
  117. userProject = c.src.userProject
  118. }
  119. opts := makeStorageOpts(isIdempotent, c.dst.retry, userProject)
  120. for {
  121. res, err := c.dst.c.tc.RewriteObject(ctx, req, opts...)
  122. if err != nil {
  123. return nil, err
  124. }
  125. c.RewriteToken = res.token
  126. req.token = res.token
  127. if c.ProgressFunc != nil {
  128. c.ProgressFunc(uint64(res.written), uint64(res.size))
  129. }
  130. if res.done { // Finished successfully.
  131. return res.resource, nil
  132. }
  133. }
  134. }
  135. // ComposerFrom creates a Composer that can compose srcs into dst.
  136. // You can immediately call Run on the returned Composer, or you can
  137. // configure it first.
  138. //
  139. // The encryption key for the destination object will be used to decrypt all
  140. // source objects and encrypt the destination object. It is an error
  141. // to specify an encryption key for any of the source objects.
  142. func (dst *ObjectHandle) ComposerFrom(srcs ...*ObjectHandle) *Composer {
  143. return &Composer{dst: dst, srcs: srcs}
  144. }
  145. // A Composer composes source objects into a destination object.
  146. //
  147. // For Requester Pays buckets, the user project of dst is billed.
  148. type Composer struct {
  149. // ObjectAttrs are optional attributes to set on the destination object.
  150. // Any attributes must be initialized before any calls on the Composer. Nil
  151. // or zero-valued attributes are ignored.
  152. ObjectAttrs
  153. // SendCRC specifies whether to transmit a CRC32C field. It should be set
  154. // to true in addition to setting the Composer's CRC32C field, because zero
  155. // is a valid CRC and normally a zero would not be transmitted.
  156. // If a CRC32C is sent, and the data in the destination object does not match
  157. // the checksum, the compose will be rejected.
  158. SendCRC32C bool
  159. dst *ObjectHandle
  160. srcs []*ObjectHandle
  161. }
  162. // Run performs the compose operation.
  163. func (c *Composer) Run(ctx context.Context) (attrs *ObjectAttrs, err error) {
  164. ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Composer.Run")
  165. defer func() { trace.EndSpan(ctx, err) }()
  166. if err := c.dst.validate(); err != nil {
  167. return nil, err
  168. }
  169. if c.dst.gen != defaultGen {
  170. return nil, fmt.Errorf("storage: generation cannot be specified on compose destination, got %v", c.dst.gen)
  171. }
  172. if len(c.srcs) == 0 {
  173. return nil, errors.New("storage: at least one source object must be specified")
  174. }
  175. for _, src := range c.srcs {
  176. if err := src.validate(); err != nil {
  177. return nil, err
  178. }
  179. if src.bucket != c.dst.bucket {
  180. return nil, fmt.Errorf("storage: all source objects must be in bucket %q, found %q", c.dst.bucket, src.bucket)
  181. }
  182. if src.encryptionKey != nil {
  183. return nil, fmt.Errorf("storage: compose source %s.%s must not have encryption key", src.bucket, src.object)
  184. }
  185. }
  186. req := &composeObjectRequest{
  187. dstBucket: c.dst.bucket,
  188. predefinedACL: c.PredefinedACL,
  189. sendCRC32C: c.SendCRC32C,
  190. }
  191. req.dstObject = destinationObject{
  192. name: c.dst.object,
  193. bucket: c.dst.bucket,
  194. conds: c.dst.conds,
  195. attrs: &c.ObjectAttrs,
  196. encryptionKey: c.dst.encryptionKey,
  197. }
  198. for _, src := range c.srcs {
  199. s := sourceObject{
  200. name: src.object,
  201. bucket: src.bucket,
  202. gen: src.gen,
  203. conds: src.conds,
  204. }
  205. req.srcs = append(req.srcs, s)
  206. }
  207. isIdempotent := c.dst.conds != nil && (c.dst.conds.GenerationMatch != 0 || c.dst.conds.DoesNotExist)
  208. opts := makeStorageOpts(isIdempotent, c.dst.retry, c.dst.userProject)
  209. return c.dst.c.tc.ComposeObject(ctx, req, opts...)
  210. }