diff --git a/pkg/object/interface.go b/pkg/object/interface.go index 16e766746a7f..e96d592e2943 100644 --- a/pkg/object/interface.go +++ b/pkg/object/interface.go @@ -84,6 +84,8 @@ type ObjectStorage interface { Get(key string, off, limit int64) (io.ReadCloser, error) // Put data read from a reader to an object specified by key. Put(key string, in io.Reader) error + // Copy an object from src to dst. + Copy(dst, src string) error // Delete a object. Delete(key string) error diff --git a/pkg/object/object_storage.go b/pkg/object/object_storage.go index 867019844049..789bef5f4b94 100644 --- a/pkg/object/object_storage.go +++ b/pkg/object/object_storage.go @@ -124,6 +124,10 @@ func (s DefaultObjectStorage) Head(key string) (Object, error) { return nil, notSupported } +func (s DefaultObjectStorage) Copy(dst, src string) error { + return notSupported +} + func (s DefaultObjectStorage) CreateMultipartUpload(key string) (*MultipartUpload, error) { return nil, notSupported } diff --git a/pkg/object/object_storage_test.go b/pkg/object/object_storage_test.go index 3bef6f468f83..4961cec26bc7 100644 --- a/pkg/object/object_storage_test.go +++ b/pkg/object/object_storage_test.go @@ -122,7 +122,8 @@ func testStorage(t *testing.T, s ObjectStorage) { if err := s.Create(); err != nil { t.Fatalf("err should be nil when creating a bucket with the same name") } - s = WithPrefix(s, "unit-test/") + prefix := "unit-test/" + s = WithPrefix(s, prefix) defer func() { if err := s.Delete("test"); err != nil { t.Fatalf("delete failed: %s", err) @@ -371,6 +372,20 @@ func testStorage(t *testing.T, s ObjectStorage) { t.Fatalf("storage class should be %s but got %s", sc, o.StorageClass()) } + dstKey := "test-copy" + defer s.Delete(dstKey) + err = s.Copy(fmt.Sprintf("%s%s", prefix, dstKey), fmt.Sprintf("%stest", prefix)) + if err != nil && err != notSupported { + t.Fatalf("copy failed: %s", err.Error()) + } + if err == nil { + if o, err := s.Head(dstKey); err != nil { + t.Fatalf("check exists failed: %s", err.Error()) + } else if sc != "" && o.StorageClass() != sc { + t.Fatalf("storage class should be %s but got %s", sc, o.StorageClass()) + } + } + if err := s.Delete("test"); err != nil { t.Fatalf("delete failed: %s", err) } diff --git a/pkg/object/prefix.go b/pkg/object/prefix.go index 95dc0a842bf5..bb68b27284a5 100644 --- a/pkg/object/prefix.go +++ b/pkg/object/prefix.go @@ -117,6 +117,10 @@ func (p *withPrefix) Put(key string, in io.Reader) error { return p.os.Put(p.prefix+key, in) } +func (p *withPrefix) Copy(dst, src string) error { + return p.os.Copy(dst, src) +} + func (p *withPrefix) Delete(key string) error { return p.os.Delete(p.prefix + key) } diff --git a/pkg/object/sharding.go b/pkg/object/sharding.go index 7c545710ce5d..b63d3b41dffe 100644 --- a/pkg/object/sharding.go +++ b/pkg/object/sharding.go @@ -69,6 +69,10 @@ func (s *sharded) Put(key string, body io.Reader) error { return s.pick(key).Put(key, body) } +func (s *sharded) Copy(dst, src string) error { + return notSupported +} + func (s *sharded) Delete(key string) error { return s.pick(key).Delete(key) }