From 9a8ce9b94ce77edc8ed76c96409a573329afddba Mon Sep 17 00:00:00 2001 From: Jeremy Wharton Date: Mon, 1 Apr 2024 09:12:32 -0500 Subject: [PATCH] uplink,private/{metaclient,object}: add retention info to download info This change includes the retention mode and retention period expiration in the download info for versioned objects. This makes it possible for the gateway to return retention info via the GetObject and HeadObject S3 actions. Change-Id: Id2594240b8072de1a3f01ec20946044cf73b6986 --- download.go | 20 +++++++++++++++----- object.go | 4 ++-- private/metaclient/client.go | 7 +++++++ private/metaclient/objects.go | 2 ++ private/metaclient/types.go | 10 ++++++++++ private/object/object.go | 10 +++++++--- 6 files changed, 43 insertions(+), 10 deletions(-) diff --git a/download.go b/download.go index 770fb1a9..fb9e2626 100644 --- a/download.go +++ b/download.go @@ -123,7 +123,7 @@ func (project *Project) downloadObjectWithVersion(ctx context.Context, bucket, k } download.streams = streams - download.object = convertObject(&objectDownload.Object) + download.object = &objectDownload.Object download.download = stream.NewDownloadRange(ctx, objectDownload, streams, streamRange.Start, streamRange.Limit-streamRange.Start) download.tracker = project.tracker.Child("download", 1) return download, nil @@ -133,7 +133,7 @@ func (project *Project) downloadObjectWithVersion(ctx context.Context, bucket, k type Download struct { mu sync.Mutex download *stream.Download - object *Object + object *metaclient.Object bucket string streams *streams.Store @@ -149,7 +149,7 @@ type Download struct { // Info returns the last information about the object. func (download *Download) Info() *Object { - return download.object + return convertObject(download.object) } // Read downloads up to len(p) bytes into p from the object's data stream. @@ -167,7 +167,7 @@ func (download *Download) Read(p []byte) (n int, err error) { } track() download.mu.Unlock() - return n, convertKnownErrors(err, download.bucket, download.object.Key) + return n, convertKnownErrors(err, download.bucket, download.object.Path) } // Close closes the reader of the download. @@ -183,7 +183,7 @@ func (download *Download) Close() error { download.stats.flagFailure(err) download.emitEvent() download.mu.Unlock() - return convertKnownErrors(err, download.bucket, download.object.Key) + return convertKnownErrors(err, download.bucket, download.object.Path) } func pathChecksum(encPath paths.Encrypted) []byte { @@ -232,3 +232,13 @@ func (download *Download) emitEvent() { func downloadObjectWithVersion(ctx context.Context, project *Project, bucket, key string, version []byte, options *DownloadOptions) (_ *Download, err error) { return project.downloadObjectWithVersion(ctx, bucket, key, version, options) } + +// download_getMetaclientObject exposes the object downloaded from the metainfo database. +// +// NB: this is used with linkname in private/object. +// It needs to be updated when this is updated. +// +//lint:ignore U1000, used with linkname +//nolint:deadcode,unused +//go:linkname download_getMetaclientObject +func download_getMetaclientObject(dl *Download) *metaclient.Object { return dl.object } diff --git a/object.go b/object.go index 188fa1c5..a7b74159 100644 --- a/object.go +++ b/object.go @@ -142,9 +142,9 @@ func (project *Project) UpdateObjectMetadata(ctx context.Context, bucket, key st return nil } -// convertObject converts metainfo.Object to uplink.Object. +// convertObject converts metaclient.Object to uplink.Object. func convertObject(obj *metaclient.Object) *Object { - if obj.Bucket.Name == "" { // zero object + if obj == nil || obj.Bucket.Name == "" { // nil or zero object return nil } diff --git a/private/metaclient/client.go b/private/metaclient/client.go index 3d38bbfd..48672e8d 100644 --- a/private/metaclient/client.go +++ b/private/metaclient/client.go @@ -682,6 +682,13 @@ func newObjectInfo(object *pb.Object) RawObjectItem { EncryptedMetadataEncryptedKey: object.EncryptedMetadataEncryptedKey, } + if object.Retention != nil { + info.Retention = &Retention{ + Mode: storj.RetentionMode(object.Retention.Mode), + RetainUntil: object.Retention.RetainUntil, + } + } + if object.EncryptionParameters != nil { info.EncryptionParameters = storj.EncryptionParameters{ CipherSuite: storj.CipherSuite(object.EncryptionParameters.CipherSuite), diff --git a/private/metaclient/objects.go b/private/metaclient/objects.go index efb11f9b..69f283f9 100644 --- a/private/metaclient/objects.go +++ b/private/metaclient/objects.go @@ -700,6 +700,8 @@ func (db *DB) ObjectFromRawObjectItem(ctx context.Context, bucket, key string, o Modified: objectInfo.Created, // TODO: use correct field Expires: objectInfo.Expires, // TODO: use correct field + Retention: objectInfo.Retention, + Stream: Stream{ ID: objectInfo.StreamID, diff --git a/private/metaclient/types.go b/private/metaclient/types.go index 9a8e9490..d567d0b9 100644 --- a/private/metaclient/types.go +++ b/private/metaclient/types.go @@ -31,6 +31,14 @@ type RawObjectItem struct { EncryptionParameters storj.EncryptionParameters RedundancyScheme storj.RedundancyScheme + + Retention *Retention +} + +// Retention represents an object's Object Lock retention information. +type Retention struct { + Mode storj.RetentionMode + RetainUntil time.Time } // IsDeleteMarker returns true if object is a delete marker. @@ -127,6 +135,8 @@ type Object struct { Modified time.Time Expires time.Time + Retention *Retention + Stream } diff --git a/private/object/object.go b/private/object/object.go index 2e74a1c1..0820e48c 100644 --- a/private/object/object.go +++ b/private/object/object.go @@ -36,6 +36,7 @@ type VersionedObject struct { uplink.Object Version []byte IsDeleteMarker bool + Retention *metaclient.Retention } // VersionedUpload represents upload which returnes object version at the end. @@ -94,8 +95,7 @@ type VersionedDownload struct { // Info returns the last information about the object. func (download *VersionedDownload) Info() *VersionedObject { - info := download.download.Info() - return convertUplinkObject(info) + return convertObject(download_getMetaclientObject(download.download)) } // Read downloads up to len(p) bytes into p from the object's data stream. @@ -283,7 +283,7 @@ func CopyObject(ctx context.Context, project *uplink.Project, sourceBucket, sour // convertObject converts metainfo.Object to Version. func convertObject(obj *metaclient.Object) *VersionedObject { - if obj.Bucket.Name == "" { // zero object + if obj == nil || obj.Bucket.Name == "" { // nil or zero object return nil } @@ -300,6 +300,7 @@ func convertObject(obj *metaclient.Object) *VersionedObject { }, Version: obj.Version, IsDeleteMarker: obj.IsDeleteMarker, + Retention: obj.Retention, } } @@ -336,3 +337,6 @@ func objectVersion(object *uplink.Object) []byte //go:linkname downloadObjectWithVersion storj.io/uplink.downloadObjectWithVersion func downloadObjectWithVersion(ctx context.Context, project *uplink.Project, bucket, key string, version []byte, options *uplink.DownloadOptions) (_ *uplink.Download, err error) + +//go:linkname download_getMetaclientObject storj.io/uplink.download_getMetaclientObject +func download_getMetaclientObject(dl *uplink.Download) *metaclient.Object