diff --git a/api/data/locking.go b/api/data/locking.go index 74422cad0..dbf8e568f 100644 --- a/api/data/locking.go +++ b/api/data/locking.go @@ -3,6 +3,8 @@ package data import ( "encoding/xml" "time" + + oid "github.com/nspcc-dev/neofs-sdk-go/object/id" ) type ( @@ -37,5 +39,6 @@ type ( Until time.Time LegalHold bool IsCompliance bool + Objects []oid.ID } ) diff --git a/api/handler/locking.go b/api/handler/locking.go index 1580cc551..92ecd1f5a 100644 --- a/api/handler/locking.go +++ b/api/handler/locking.go @@ -7,6 +7,8 @@ import ( "strconv" "time" + oid "github.com/nspcc-dev/neofs-sdk-go/object/id" + "github.com/nspcc-dev/neofs-s3-gw/api" "github.com/nspcc-dev/neofs-s3-gw/api/data" apiErrors "github.com/nspcc-dev/neofs-s3-gw/api/errors" @@ -173,7 +175,7 @@ func (h *handler) PutObjectLegalHoldHandler(w http.ResponseWriter, r *http.Reque ps := &layer.PutSystemObjectParams{ BktInfo: bktInfo, ObjName: objInfo.LegalHoldObject(), - Lock: &data.ObjectLock{LegalHold: true}, + Lock: &data.ObjectLock{LegalHold: true, Objects: []oid.ID{*objInfo.ID}}, Metadata: make(map[string]string), } if _, err = h.obj.PutSystemObject(r.Context(), ps); err != nil { @@ -272,6 +274,7 @@ func (h *handler) PutObjectRetentionHandler(w http.ResponseWriter, r *http.Reque h.logAndSendError(w, "could not get object info", reqInfo, err) return } + lock.Objects = append(lock.Objects, *objInfo.ID) lockInfo, err := h.obj.HeadSystemObject(r.Context(), bktInfo, objInfo.RetentionObject()) if err != nil && !apiErrors.IsS3Error(err, apiErrors.ErrNoSuchKey) { @@ -279,6 +282,8 @@ func (h *handler) PutObjectRetentionHandler(w http.ResponseWriter, r *http.Reque return } + //objectv2.ReadLock() + if err = checkLockInfo(lockInfo, r.Header); err != nil { h.logAndSendError(w, "couldn't change lock mode", reqInfo, err) return diff --git a/api/layer/neofs/neofs.go b/api/layer/neofs/neofs.go index 595f20106..c1ffe8f49 100644 --- a/api/layer/neofs/neofs.go +++ b/api/layer/neofs/neofs.go @@ -113,6 +113,9 @@ type PrmObjectCreate struct { // Key-value object attributes. Attributes [][2]string + // List of ids to lock (optional). + Locks []oid.ID + // Full payload size (optional). PayloadSize uint64 diff --git a/api/layer/object.go b/api/layer/object.go index b7854c4b2..2ae9a6e39 100644 --- a/api/layer/object.go +++ b/api/layer/object.go @@ -204,6 +204,7 @@ func (n *layer) objectPut(ctx context.Context, bkt *data.BucketInfo, p *PutObjec if p.Lock != nil { objInfo := &data.ObjectInfo{ID: id, Name: p.Object} + p.Lock.Objects = append(p.Lock.Objects, *id) if p.Lock.LegalHold { if err = n.putLockObject(ctx, bkt, objInfo.LegalHoldObject(), p.Lock); err != nil { return nil, err diff --git a/api/layer/system_object.go b/api/layer/system_object.go index 70020f2da..315e9c4ee 100644 --- a/api/layer/system_object.go +++ b/api/layer/system_object.go @@ -100,9 +100,8 @@ func (n *layer) putSystemObjectIntoNeoFS(ctx context.Context, p *PutSystemObject v = tagEmptyMark } - if p.Lock != nil { - // todo form lock system object - + if p.Lock != nil && len(p.Lock.Objects) > 0 { + prm.Locks = p.Lock.Objects prm.Attributes = append(prm.Attributes, attributesFromLock(p.Lock)...) } diff --git a/cmd/s3-gw/neofs.go b/cmd/s3-gw/neofs.go index 3211d2820..037c6022f 100644 --- a/cmd/s3-gw/neofs.go +++ b/cmd/s3-gw/neofs.go @@ -38,5 +38,6 @@ func (x *layerNeoFS) CreateObject(ctx context.Context, prm layer.PrmObjectCreate Payload: prm.Payload, BearerToken: prm.BearerToken, PrivateKey: prm.PrivateKey, + Locks: prm.Locks, }) } diff --git a/internal/neofs/neofs.go b/internal/neofs/neofs.go index 31654630a..868a424cf 100644 --- a/internal/neofs/neofs.go +++ b/internal/neofs/neofs.go @@ -12,6 +12,7 @@ import ( "strings" "time" + objectv2 "github.com/nspcc-dev/neofs-api-go/v2/object" "github.com/nspcc-dev/neofs-s3-gw/api/layer/neofs" "github.com/nspcc-dev/neofs-s3-gw/authmate" "github.com/nspcc-dev/neofs-s3-gw/creds/tokens" @@ -235,6 +236,9 @@ type PrmObjectCreate struct { // Key-value object attributes. Attributes [][2]string + // List of ids to lock (optional). + Locks []oid.ID + // Object payload encapsulated in io.Reader primitive. Payload io.Reader @@ -290,11 +294,17 @@ func (x *NeoFS) CreateObject(ctx context.Context, prm PrmObjectCreate) (*oid.ID, attrs = append(attrs, *a) } - raw := object.New() - raw.SetContainerID(&prm.Container) - raw.SetOwnerID(&prm.Creator) - raw.SetAttributes(attrs...) - raw.SetPayloadSize(prm.PayloadSize) + obj := object.New() + obj.SetContainerID(&prm.Container) + obj.SetOwnerID(&prm.Creator) + obj.SetAttributes(attrs...) + obj.SetPayloadSize(prm.PayloadSize) + + if len(prm.Locks) > 0 { + lock := new(object.Lock) + lock.WriteMembers(prm.Locks) + objectv2.WriteLock(obj.ToV2(), (objectv2.Lock)(*lock)) + } var callOpt pool.CallOption @@ -304,7 +314,7 @@ func (x *NeoFS) CreateObject(ctx context.Context, prm PrmObjectCreate) (*oid.ID, callOpt = pool.WithKey(prm.PrivateKey) } - idObj, err := x.pool.PutObject(ctx, *raw, prm.Payload, callOpt) + idObj, err := x.pool.PutObject(ctx, *obj, prm.Payload, callOpt) if err != nil { return nil, fmt.Errorf("save object via connection pool: %w", err) } diff --git a/internal/neofstest/neofs_mock.go b/internal/neofstest/neofs_mock.go index a47c09b7a..f681a3aca 100644 --- a/internal/neofstest/neofs_mock.go +++ b/internal/neofstest/neofs_mock.go @@ -10,6 +10,7 @@ import ( "strconv" "strings" + objectv2 "github.com/nspcc-dev/neofs-api-go/v2/object" "github.com/nspcc-dev/neofs-s3-gw/api/layer/neofs" "github.com/nspcc-dev/neofs-sdk-go/container" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" @@ -209,6 +210,12 @@ func (t *TestNeoFS) CreateObject(_ context.Context, prm neofs.PrmObjectCreate) ( obj.SetCreationEpoch(t.currentEpoch) t.currentEpoch++ + if len(prm.Locks) > 0 { + lock := new(object.Lock) + lock.WriteMembers(prm.Locks) + objectv2.WriteLock(obj.ToV2(), (objectv2.Lock)(*lock)) + } + if prm.Payload != nil { all, err := io.ReadAll(prm.Payload) if err != nil {