[#488] Sync using oid.ID

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2022-06-27 12:33:36 +03:00 committed by Alex Vanin
parent 85c203e157
commit c88a9842db
18 changed files with 224 additions and 139 deletions

View file

@ -75,9 +75,61 @@ func (p *PartInfo) ToHeaderString() string {
// LockInfo is lock information to create appropriate tree node.
type LockInfo struct {
ID uint64
LegalHoldOID *oid.ID
RetentionOID *oid.ID
UntilDate string
IsCompliance bool
id uint64
legalHoldOID oid.ID
setLegalHold bool
retentionOID oid.ID
setRetention bool
untilDate string
isCompliance bool
}
func NewLockInfo(id uint64) *LockInfo {
return &LockInfo{id: id}
}
func (l LockInfo) ID() uint64 {
return l.id
}
func (l *LockInfo) SetLegalHold(objID oid.ID) {
l.legalHoldOID = objID
l.setLegalHold = true
}
func (l *LockInfo) ResetLegalHold() {
l.setLegalHold = false
}
func (l LockInfo) LegalHold() oid.ID {
return l.legalHoldOID
}
func (l LockInfo) IsLegalHoldSet() bool {
return l.setLegalHold
}
func (l *LockInfo) SetRetention(objID oid.ID, until string, isCompliance bool) {
l.retentionOID = objID
l.setRetention = true
l.untilDate = until
l.isCompliance = isCompliance
}
func (l LockInfo) IsRetentionSet() bool {
return l.setRetention
}
func (l LockInfo) Retention() oid.ID {
return l.retentionOID
}
func (l LockInfo) UntilDate() string {
return l.untilDate
}
func (l LockInfo) IsCompliance() bool {
return l.isCompliance
}

View file

@ -120,12 +120,12 @@ func (h *handler) setLockingHeaders(bktInfo *data.BucketInfo, lockInfo *data.Loc
legalHold := &data.LegalHold{Status: legalHoldOff}
retention := &data.Retention{Mode: governanceMode}
if lockInfo.LegalHoldOID != nil {
if lockInfo.IsLegalHoldSet() {
legalHold.Status = legalHoldOn
}
if lockInfo.RetentionOID != nil {
retention.RetainUntilDate = lockInfo.UntilDate
if lockInfo.IsCompliance {
if lockInfo.IsRetentionSet() {
retention.RetainUntilDate = lockInfo.UntilDate()
if lockInfo.IsCompliance() {
retention.Mode = complianceMode
}
}

View file

@ -174,7 +174,7 @@ func (h *handler) GetObjectLegalHoldHandler(w http.ResponseWriter, r *http.Reque
}
legalHold := &data.LegalHold{Status: legalHoldOff}
if lockInfo.LegalHoldOID != nil {
if lockInfo.IsLegalHoldSet() {
legalHold.Status = legalHoldOn
}
@ -248,16 +248,16 @@ func (h *handler) GetObjectRetentionHandler(w http.ResponseWriter, r *http.Reque
return
}
if lockInfo.RetentionOID == nil {
if !lockInfo.IsRetentionSet() {
h.logAndSendError(w, "retention lock isn't set", reqInfo, apiErrors.GetAPIError(apiErrors.ErrNoSuchKey))
return
}
retention := &data.Retention{
Mode: governanceMode,
RetainUntilDate: lockInfo.UntilDate,
RetainUntilDate: lockInfo.UntilDate(),
}
if lockInfo.IsCompliance {
if lockInfo.IsCompliance() {
retention.Mode = complianceMode
}

View file

@ -49,12 +49,13 @@ func (n *layer) PutBucketCORS(ctx context.Context, p *PutCORSParams) error {
}
objIDToDelete, err := n.treeService.PutBucketCORS(ctx, p.BktInfo.CID, objID)
if err != nil {
objIDToDeleteNotFound := errorsStd.Is(err, ErrNoNodeToRemove)
if err != nil && !objIDToDeleteNotFound {
return err
}
if objIDToDelete != nil {
if err = n.objectDelete(ctx, p.BktInfo, *objIDToDelete); err != nil {
if !objIDToDeleteNotFound {
if err = n.objectDelete(ctx, p.BktInfo, objIDToDelete); err != nil {
n.log.Error("couldn't delete cors object", zap.Error(err),
zap.String("cnrID", p.BktInfo.CID.EncodeToString()),
zap.String("bucket name", p.BktInfo.Name),
@ -83,11 +84,12 @@ func (n *layer) GetBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (*d
func (n *layer) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) error {
objID, err := n.treeService.DeleteBucketCORS(ctx, bktInfo.CID)
if err != nil {
objIDNotFound := errorsStd.Is(err, ErrNoNodeToRemove)
if err != nil && !objIDNotFound {
return err
}
if objID != nil {
if err = n.objectDelete(ctx, bktInfo, *objID); err != nil {
if !objIDNotFound {
if err = n.objectDelete(ctx, bktInfo, objID); err != nil {
return err
}
}

View file

@ -462,15 +462,15 @@ func (n *layer) CopyObject(ctx context.Context, p *CopyObjectParams) (*data.Obje
})
}
func getRandomOID() (*oid.ID, error) {
func getRandomOID() (oid.ID, error) {
b := [32]byte{}
if _, err := rand.Read(b[:]); err != nil {
return nil, err
return oid.ID{}, err
}
var objID oid.ID
objID.SetSHA256(b)
return &objID, nil
return objID, nil
}
// DeleteObject removes all objects with the passed nice name.
@ -505,7 +505,7 @@ func (n *layer) deleteObject(ctx context.Context, bkt *data.BucketInfo, obj *Ver
newVersion := &data.NodeVersion{
BaseNodeVersion: data.BaseNodeVersion{
OID: *randOID,
OID: randOID,
FilePath: obj.Name,
},
DeleteMarker: &data.DeleteMarkerInfo{

View file

@ -36,7 +36,7 @@ func TestObjectLockAttributes(t *testing.T) {
foundLock, err := tc.layer.GetLockInfo(tc.ctx, p)
require.NoError(t, err)
lockObj := tc.getObjectByID(*foundLock.RetentionOID)
lockObj := tc.getObjectByID(foundLock.Retention())
require.NotNil(t, lockObj)
expEpoch := false

View file

@ -198,18 +198,19 @@ func (n *layer) uploadPart(ctx context.Context, multipartInfo *data.MultipartInf
Key: p.Info.Key,
UploadID: p.Info.UploadID,
Number: p.PartNumber,
OID: *id,
OID: id,
Size: p.Size,
ETag: hex.EncodeToString(hash),
Created: time.Now(),
}
oldPartID, err := n.treeService.AddPart(ctx, bktInfo.CID, multipartInfo.ID, partInfo)
if err != nil {
oldPartIDNotFound := stderrors.Is(err, ErrNoNodeToRemove)
if err != nil && !oldPartIDNotFound {
return nil, err
}
if oldPartID != nil {
if err = n.objectDelete(ctx, bktInfo, *oldPartID); err != nil {
if !oldPartIDNotFound {
if err = n.objectDelete(ctx, bktInfo, oldPartID); err != nil {
n.log.Error("couldn't delete old part object", zap.Error(err),
zap.String("cnrID", bktInfo.CID.EncodeToString()),
zap.String("bucket name", bktInfo.Name),
@ -218,7 +219,7 @@ func (n *layer) uploadPart(ctx context.Context, multipartInfo *data.MultipartInf
}
objInfo := &data.ObjectInfo{
ID: *id,
ID: id,
CID: bktInfo.CID,
Owner: bktInfo.Owner,

View file

@ -146,7 +146,7 @@ type NeoFS interface {
//
// Created container is public with enabled ACL extension.
//
// It returns exactly one non-nil value. It returns any error encountered which
// It returns exactly one non-zero value. It returns any error encountered which
// prevented the container from being created.
CreateContainer(context.Context, PrmContainerCreate) (cid.ID, error)
@ -214,9 +214,9 @@ type NeoFS interface {
//
// It returns ErrAccessDenied on write access violation.
//
// It returns exactly one non-nil value. It returns any error encountered which
// It returns exactly one non-zero value. It returns any error encountered which
// prevented the container from being created.
CreateObject(context.Context, PrmObjectCreate) (*oid.ID, error)
CreateObject(context.Context, PrmObjectCreate) (oid.ID, error)
// DeleteObject marks the object to be removed from the NeoFS container by identifier.
// Successful return does not guarantee actual removal.

View file

@ -178,10 +178,10 @@ func (t *TestNeoFS) ReadObject(_ context.Context, prm PrmObjectRead) (*ObjectPar
return nil, fmt.Errorf("object not found %s", addr)
}
func (t *TestNeoFS) CreateObject(_ context.Context, prm PrmObjectCreate) (*oid.ID, error) {
func (t *TestNeoFS) CreateObject(_ context.Context, prm PrmObjectCreate) (oid.ID, error) {
b := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, b); err != nil {
return nil, err
return oid.ID{}, err
}
var id oid.ID
id.SetSHA256(sha256.Sum256(b))
@ -219,7 +219,7 @@ func (t *TestNeoFS) CreateObject(_ context.Context, prm PrmObjectCreate) (*oid.I
if prm.Payload != nil {
all, err := io.ReadAll(prm.Payload)
if err != nil {
return nil, err
return oid.ID{}, err
}
obj.SetPayload(all)
obj.SetPayloadSize(uint64(len(all)))
@ -233,7 +233,7 @@ func (t *TestNeoFS) CreateObject(_ context.Context, prm PrmObjectCreate) (*oid.I
addr := newAddress(cnrID, objID)
t.objects[addr.EncodeToString()] = obj
return &objID, nil
return objID, nil
}
func (t *TestNeoFS) DeleteObject(_ context.Context, prm PrmObjectDelete) error {

View file

@ -39,12 +39,13 @@ func (n *layer) PutBucketNotificationConfiguration(ctx context.Context, p *PutBu
}
objIDToDelete, err := n.treeService.PutNotificationConfigurationNode(ctx, p.BktInfo.CID, objID)
if err != nil {
objIDToDeleteNotFound := errorsStd.Is(err, ErrNoNodeToRemove)
if err != nil && !objIDToDeleteNotFound {
return err
}
if objIDToDelete != nil {
if err = n.objectDelete(ctx, p.BktInfo, *objIDToDelete); err != nil {
if !objIDToDeleteNotFound {
if err = n.objectDelete(ctx, p.BktInfo, objIDToDelete); err != nil {
n.log.Error("couldn't delete notification configuration object", zap.Error(err),
zap.String("cnrID", p.BktInfo.CID.EncodeToString()),
zap.String("bucket name", p.BktInfo.Name),
@ -67,14 +68,15 @@ func (n *layer) GetBucketNotificationConfiguration(ctx context.Context, bktInfo
}
objID, err := n.treeService.GetNotificationConfigurationNode(ctx, bktInfo.CID)
if err != nil && !errorsStd.Is(err, ErrNodeNotFound) {
objIDNotFound := errorsStd.Is(err, ErrNodeNotFound)
if err != nil && !objIDNotFound {
return nil, err
}
conf := &data.NotificationConfiguration{}
if objID != nil {
obj, err := n.objectGet(ctx, bktInfo, *objID)
if !objIDNotFound {
obj, err := n.objectGet(ctx, bktInfo, objID)
if err != nil {
return nil, err
}

View file

@ -189,7 +189,7 @@ func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Object
return nil, err
}
newVersion.OID = *id
newVersion.OID = id
if err = n.treeService.AddVersion(ctx, p.BktInfo.CID, newVersion); err != nil {
return nil, fmt.Errorf("couldn't add new verion to tree service: %w", err)
}
@ -209,7 +209,7 @@ func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Object
n.listsCache.CleanCacheEntriesContainingObject(p.Object, p.BktInfo.CID)
objInfo := &data.ObjectInfo{
ID: *id,
ID: id,
CID: p.BktInfo.CID,
Owner: own,
@ -344,7 +344,7 @@ func (n *layer) objectDelete(ctx context.Context, bktInfo *data.BucketInfo, idOb
// objectPutAndHash prepare auth parameters and invoke neofs.CreateObject.
// Returns object ID and payload sha256 hash.
func (n *layer) objectPutAndHash(ctx context.Context, prm PrmObjectCreate, bktInfo *data.BucketInfo) (*oid.ID, []byte, error) {
func (n *layer) objectPutAndHash(ctx context.Context, prm PrmObjectCreate, bktInfo *data.BucketInfo) (oid.ID, []byte, error) {
n.prepareAuthParameters(ctx, &prm.PrmAuth, bktInfo.Owner)
hash := sha256.New()
prm.Payload = wrapReader(prm.Payload, 64*1024, func(buf []byte) {

View file

@ -36,18 +36,19 @@ func (n *layer) PutLockInfo(ctx context.Context, objVersion *ObjectVersion, newL
}
if newLock.Retention != nil {
if lockInfo.RetentionOID != nil {
if lockInfo.IsCompliance {
if lockInfo.IsRetentionSet() {
if lockInfo.IsCompliance() {
return fmt.Errorf("you cannot change compliance mode")
}
if !newLock.Retention.ByPassedGovernance {
return fmt.Errorf("you cannot bypass governence mode")
}
if len(lockInfo.UntilDate) > 0 {
parsedTime, err := time.Parse(time.RFC3339, lockInfo.UntilDate)
untilDate := lockInfo.UntilDate()
if len(untilDate) > 0 {
parsedTime, err := time.Parse(time.RFC3339, untilDate)
if err != nil {
return fmt.Errorf("couldn't parse time '%s': %w", lockInfo.UntilDate, err)
return fmt.Errorf("couldn't parse time '%s': %w", untilDate, err)
}
if parsedTime.After(newLock.Retention.Until) {
return fmt.Errorf("you couldn't short the until date")
@ -55,24 +56,26 @@ func (n *layer) PutLockInfo(ctx context.Context, objVersion *ObjectVersion, newL
}
}
lock := &data.ObjectLock{Retention: newLock.Retention}
if lockInfo.RetentionOID, err = n.putLockObject(ctx, objVersion.BktInfo, versionNode.OID, lock); err != nil {
retentionOID, err := n.putLockObject(ctx, objVersion.BktInfo, versionNode.OID, lock)
if err != nil {
return err
}
lockInfo.IsCompliance = newLock.Retention.IsCompliance
lockInfo.UntilDate = newLock.Retention.Until.UTC().Format(time.RFC3339)
lockInfo.SetRetention(retentionOID, newLock.Retention.Until.UTC().Format(time.RFC3339), newLock.Retention.IsCompliance)
}
if newLock.LegalHold != nil {
if newLock.LegalHold.Enabled && lockInfo.LegalHoldOID == nil {
if newLock.LegalHold.Enabled && !lockInfo.IsLegalHoldSet() {
lock := &data.ObjectLock{LegalHold: newLock.LegalHold}
if lockInfo.LegalHoldOID, err = n.putLockObject(ctx, objVersion.BktInfo, versionNode.OID, lock); err != nil {
legalHoldOID, err := n.putLockObject(ctx, objVersion.BktInfo, versionNode.OID, lock)
if err != nil {
return err
}
} else if !newLock.LegalHold.Enabled && lockInfo.LegalHoldOID != nil {
if err = n.objectDelete(ctx, objVersion.BktInfo, *lockInfo.LegalHoldOID); err != nil {
return fmt.Errorf("couldn't delete lock object '%s' to remove legal hold: %w", lockInfo.LegalHoldOID.EncodeToString(), err)
lockInfo.SetLegalHold(legalHoldOID)
} else if !newLock.LegalHold.Enabled && lockInfo.IsLegalHoldSet() {
if err = n.objectDelete(ctx, objVersion.BktInfo, lockInfo.LegalHold()); err != nil {
return fmt.Errorf("couldn't delete lock object '%s' to remove legal hold: %w", lockInfo.LegalHold().EncodeToString(), err)
}
lockInfo.LegalHoldOID = nil
lockInfo.ResetLegalHold()
}
}
@ -87,7 +90,7 @@ func (n *layer) PutLockInfo(ctx context.Context, objVersion *ObjectVersion, newL
return nil
}
func (n *layer) putLockObject(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID, lock *data.ObjectLock) (*oid.ID, error) {
func (n *layer) putLockObject(ctx context.Context, bktInfo *data.BucketInfo, objID oid.ID, lock *data.ObjectLock) (oid.ID, error) {
prm := PrmObjectCreate{
Container: bktInfo.CID,
Creator: bktInfo.Owner,
@ -97,7 +100,7 @@ func (n *layer) putLockObject(ctx context.Context, bktInfo *data.BucketInfo, obj
var err error
prm.Attributes, err = n.attributesFromLock(ctx, lock)
if err != nil {
return nil, err
return oid.ID{}, err
}
id, _, err := n.objectPutAndHash(ctx, prm, bktInfo)
@ -134,15 +137,16 @@ func (n *layer) getCORS(ctx context.Context, bkt *data.BucketInfo, sysName strin
return cors, nil
}
objID, err := n.treeService.GetBucketCORS(ctx, bkt.CID)
if err != nil {
objIDNotFound := errorsStd.Is(err, ErrNodeNotFound)
if err != nil && !objIDNotFound {
return nil, err
}
if objID == nil {
if objIDNotFound {
return nil, errors.GetAPIError(errors.ErrNoSuchCORSConfiguration)
}
obj, err := n.objectGet(ctx, bkt, *objID)
obj, err := n.objectGet(ctx, bkt, objID)
if err != nil {
return nil, err
}

View file

@ -81,23 +81,23 @@ func (t *TreeServiceMock) GetSettingsNode(_ context.Context, id cid.ID) (*data.B
return settings, nil
}
func (t *TreeServiceMock) GetNotificationConfigurationNode(ctx context.Context, cnrID cid.ID) (*oid.ID, error) {
func (t *TreeServiceMock) GetNotificationConfigurationNode(ctx context.Context, cnrID cid.ID) (oid.ID, error) {
panic("implement me")
}
func (t *TreeServiceMock) PutNotificationConfigurationNode(ctx context.Context, cnrID cid.ID, objID *oid.ID) (*oid.ID, error) {
func (t *TreeServiceMock) PutNotificationConfigurationNode(ctx context.Context, cnrID cid.ID, objID oid.ID) (oid.ID, error) {
panic("implement me")
}
func (t *TreeServiceMock) GetBucketCORS(ctx context.Context, cnrID cid.ID) (*oid.ID, error) {
func (t *TreeServiceMock) GetBucketCORS(ctx context.Context, cnrID cid.ID) (oid.ID, error) {
panic("implement me")
}
func (t *TreeServiceMock) PutBucketCORS(ctx context.Context, cnrID cid.ID, objID *oid.ID) (*oid.ID, error) {
func (t *TreeServiceMock) PutBucketCORS(ctx context.Context, cnrID cid.ID, objID oid.ID) (oid.ID, error) {
panic("implement me")
}
func (t *TreeServiceMock) DeleteBucketCORS(ctx context.Context, cnrID cid.ID) (*oid.ID, error) {
func (t *TreeServiceMock) DeleteBucketCORS(ctx context.Context, cnrID cid.ID) (oid.ID, error) {
panic("implement me")
}
@ -294,14 +294,14 @@ func (t *TreeServiceMock) GetMultipartUpload(_ context.Context, cnrID cid.ID, ob
return nil, ErrNodeNotFound
}
func (t *TreeServiceMock) AddPart(ctx context.Context, cnrID cid.ID, multipartNodeID uint64, info *data.PartInfo) (oldObjIDToDelete *oid.ID, err error) {
func (t *TreeServiceMock) AddPart(ctx context.Context, cnrID cid.ID, multipartNodeID uint64, info *data.PartInfo) (oldObjIDToDelete oid.ID, err error) {
multipartInfo, err := t.GetMultipartUpload(ctx, cnrID, info.Key, info.UploadID)
if err != nil {
return nil, err
return oid.ID{}, err
}
if multipartInfo.ID != multipartNodeID {
return nil, fmt.Errorf("invalid multipart info id")
return oid.ID{}, fmt.Errorf("invalid multipart info id")
}
partsMap, ok := t.parts[info.UploadID]
@ -312,7 +312,7 @@ func (t *TreeServiceMock) AddPart(ctx context.Context, cnrID cid.ID, multipartNo
partsMap[info.Number] = info
t.parts[info.UploadID] = partsMap
return nil, nil
return oid.ID{}, nil
}
func (t *TreeServiceMock) GetParts(_ context.Context, cnrID cid.ID, multipartNodeID uint64) ([]*data.PartInfo, error) {

View file

@ -16,19 +16,34 @@ type TreeService interface {
// GetSettingsNode retrieves the settings node from the tree service and form data.BucketSettings.
//
// If node is not found returns ErrNodeNotFound error.
// If tree node is not found returns ErrNodeNotFound error.
GetSettingsNode(context.Context, cid.ID) (*data.BucketSettings, error)
GetNotificationConfigurationNode(ctx context.Context, cnrID cid.ID) (*oid.ID, error)
// PutNotificationConfigurationNode puts a node to a system tree
// and returns objectID of a previous notif config which must be deleted in NeoFS
PutNotificationConfigurationNode(ctx context.Context, cnrID cid.ID, objID *oid.ID) (*oid.ID, error)
// GetNotificationConfigurationNode gets an object id that corresponds to object with bucket CORS.
//
// If tree node is not found returns ErrNodeNotFound error.
GetNotificationConfigurationNode(ctx context.Context, cnrID cid.ID) (oid.ID, error)
GetBucketCORS(ctx context.Context, cnrID cid.ID) (*oid.ID, error)
// PutBucketCORS puts a node to a system tree and returns objectID of a previous cors config which must be deleted in NeoFS
PutBucketCORS(ctx context.Context, cnrID cid.ID, objID *oid.ID) (*oid.ID, error)
// DeleteBucketCORS removes a node from a system tree and returns objID which must be deleted in NeoFS
DeleteBucketCORS(ctx context.Context, cnrID cid.ID) (*oid.ID, error)
// PutNotificationConfigurationNode puts a node to a system tree
// and returns objectID of a previous notif config which must be deleted in NeoFS.
//
// If object id to remove is not found returns ErrNoNodeToRemove error.
PutNotificationConfigurationNode(ctx context.Context, cnrID cid.ID, objID oid.ID) (oid.ID, error)
// GetBucketCORS gets an object id that corresponds to object with bucket CORS.
//
// If object id is not found returns ErrNodeNotFound error.
GetBucketCORS(ctx context.Context, cnrID cid.ID) (oid.ID, error)
// PutBucketCORS puts a node to a system tree and returns objectID of a previous cors config which must be deleted in NeoFS.
//
// If object id to remove is not found returns ErrNoNodeToRemove error.
PutBucketCORS(ctx context.Context, cnrID cid.ID, objID oid.ID) (oid.ID, error)
// DeleteBucketCORS removes a node from a system tree and returns objID which must be deleted in NeoFS.
//
// If object id to remove is not found returns ErrNoNodeToRemove error.
DeleteBucketCORS(ctx context.Context, cnrID cid.ID) (oid.ID, error)
GetObjectTagging(ctx context.Context, cnrID cid.ID, objVersion *data.NodeVersion) (map[string]string, error)
PutObjectTagging(ctx context.Context, cnrID cid.ID, objVersion *data.NodeVersion, tagSet map[string]string) error
@ -56,8 +71,9 @@ type TreeService interface {
// AddPart puts a node to a system tree as a child of appropriate multipart upload
// and returns objectID of a previous part which must be deleted in NeoFS.
// If a part is being added for the first time, the previous part ID will be nil.
AddPart(ctx context.Context, cnrID cid.ID, multipartNodeID uint64, info *data.PartInfo) (oldObjIDToDelete *oid.ID, err error)
//
// If object id to remove is not found returns ErrNoNodeToRemove error.
AddPart(ctx context.Context, cnrID cid.ID, multipartNodeID uint64, info *data.PartInfo) (oldObjIDToDelete oid.ID, err error)
GetParts(ctx context.Context, cnrID cid.ID, multipartNodeID uint64) ([]*data.PartInfo, error)
// Compound methods for optimizations
@ -66,5 +82,10 @@ type TreeService interface {
GetObjectTaggingAndLock(ctx context.Context, cnrID cid.ID, objVersion *data.NodeVersion) (map[string]string, *data.LockInfo, error)
}
// ErrNodeNotFound is returned from Tree service in case of not found error.
var ErrNodeNotFound = errors.New("not found")
var (
// ErrNodeNotFound is returned from Tree service in case of not found error.
ErrNodeNotFound = errors.New("not found")
// ErrNoNodeToRemove is returned from Tree service in case of the lack of node with OID to remove.
ErrNoNodeToRemove = errors.New("no node to remove")
)

View file

@ -3,7 +3,6 @@ package authmate
import (
"testing"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/stretchr/testify/require"
)
@ -29,9 +28,9 @@ func TestContainerSessionRules(t *testing.T) {
require.Len(t, sessionContext, 3)
require.Equal(t, sessionContext[0].verb, session.VerbContainerPut)
require.Equal(t, cid.ID{}, sessionContext[0].containerID)
require.Zero(t, sessionContext[0].containerID)
require.Equal(t, sessionContext[1].verb, session.VerbContainerDelete)
require.NotNil(t, sessionContext[1].containerID)
require.Equal(t, sessionContext[2].verb, session.VerbContainerSetEACL)
require.Equal(t, cid.ID{}, sessionContext[2].containerID)
require.Zero(t, sessionContext[2].containerID)
}

View file

@ -55,7 +55,7 @@ type NeoFS interface {
//
// It returns exactly one non-nil value. It returns any error encountered which
// prevented the object from being created.
CreateObject(context.Context, PrmObjectCreate) (*oid.ID, error)
CreateObject(context.Context, PrmObjectCreate) (oid.ID, error)
// ReadObjectPayload reads payload of the object from NeoFS network by address
// into memory.
@ -140,7 +140,7 @@ func (c *cred) Put(ctx context.Context, idCnr cid.ID, issuer user.ID, box *acces
}
var addr oid.Address
addr.SetObject(*idObj)
addr.SetObject(idObj)
addr.SetContainer(idCnr)
return &addr, nil

View file

@ -215,7 +215,7 @@ func (x *NeoFS) DeleteContainer(ctx context.Context, id cid.ID, token *session.C
}
// CreateObject implements neofs.NeoFS interface method.
func (x *NeoFS) CreateObject(ctx context.Context, prm layer.PrmObjectCreate) (*oid.ID, error) {
func (x *NeoFS) CreateObject(ctx context.Context, prm layer.PrmObjectCreate) (oid.ID, error) {
attrNum := len(prm.Attributes) + 1 // + creation time
if prm.Filename != "" {
@ -270,12 +270,12 @@ func (x *NeoFS) CreateObject(ctx context.Context, prm layer.PrmObjectCreate) (*o
if err != nil {
reason, ok := isErrAccessDenied(err)
if ok {
return nil, fmt.Errorf("%w: %s", layer.ErrAccessDenied, reason)
return oid.ID{}, fmt.Errorf("%w: %s", layer.ErrAccessDenied, reason)
}
return nil, fmt.Errorf("save object via connection pool: %w", err)
return oid.ID{}, fmt.Errorf("save object via connection pool: %w", err)
}
return idObj, nil
return *idObj, nil
}
// SelectObjects implements neofs.NeoFS interface method.
@ -570,7 +570,7 @@ func (x *AuthmateNeoFS) ReadObjectPayload(ctx context.Context, addr oid.Address)
}
// CreateObject implements authmate.NeoFS interface method.
func (x *AuthmateNeoFS) CreateObject(ctx context.Context, prm tokens.PrmObjectCreate) (*oid.ID, error) {
func (x *AuthmateNeoFS) CreateObject(ctx context.Context, prm tokens.PrmObjectCreate) (oid.ID, error) {
return x.neoFS.CreateObject(ctx, layer.PrmObjectCreate{
Creator: prm.Creator,
Container: prm.Container,

View file

@ -300,20 +300,20 @@ func (c *TreeClient) PutSettingsNode(ctx context.Context, cnrID cid.ID, settings
return c.moveNode(ctx, cnrID, systemTree, node.ID, 0, meta)
}
func (c *TreeClient) GetNotificationConfigurationNode(ctx context.Context, cnrID cid.ID) (*oid.ID, error) {
func (c *TreeClient) GetNotificationConfigurationNode(ctx context.Context, cnrID cid.ID) (oid.ID, error) {
node, err := c.getSystemNode(ctx, cnrID, []string{notifConfFileName}, []string{oidKV})
if err != nil {
return nil, err
return oid.ID{}, err
}
return &node.ObjID, nil
return node.ObjID, nil
}
func (c *TreeClient) PutNotificationConfigurationNode(ctx context.Context, cnrID cid.ID, objID *oid.ID) (*oid.ID, error) {
func (c *TreeClient) PutNotificationConfigurationNode(ctx context.Context, cnrID cid.ID, objID oid.ID) (oid.ID, error) {
node, err := c.getSystemNode(ctx, cnrID, []string{notifConfFileName}, []string{oidKV})
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
if err != nil && !isErrNotFound {
return nil, fmt.Errorf("couldn't get node: %w", err)
return oid.ID{}, fmt.Errorf("couldn't get node: %w", err)
}
meta := make(map[string]string)
@ -321,27 +321,29 @@ func (c *TreeClient) PutNotificationConfigurationNode(ctx context.Context, cnrID
meta[oidKV] = objID.EncodeToString()
if isErrNotFound {
_, err = c.addNode(ctx, cnrID, systemTree, 0, meta)
return nil, err
if _, err = c.addNode(ctx, cnrID, systemTree, 0, meta); err != nil {
return oid.ID{}, err
}
return oid.ID{}, layer.ErrNoNodeToRemove
}
return &node.ObjID, c.moveNode(ctx, cnrID, systemTree, node.ID, 0, meta)
return node.ObjID, c.moveNode(ctx, cnrID, systemTree, node.ID, 0, meta)
}
func (c *TreeClient) GetBucketCORS(ctx context.Context, cnrID cid.ID) (*oid.ID, error) {
func (c *TreeClient) GetBucketCORS(ctx context.Context, cnrID cid.ID) (oid.ID, error) {
node, err := c.getSystemNode(ctx, cnrID, []string{corsFilename}, []string{oidKV})
if err != nil {
return nil, err
return oid.ID{}, err
}
return &node.ObjID, nil
return node.ObjID, nil
}
func (c *TreeClient) PutBucketCORS(ctx context.Context, cnrID cid.ID, objID *oid.ID) (*oid.ID, error) {
func (c *TreeClient) PutBucketCORS(ctx context.Context, cnrID cid.ID, objID oid.ID) (oid.ID, error) {
node, err := c.getSystemNode(ctx, cnrID, []string{corsFilename}, []string{oidKV})
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
if err != nil && !isErrNotFound {
return nil, fmt.Errorf("couldn't get node: %w", err)
return oid.ID{}, fmt.Errorf("couldn't get node: %w", err)
}
meta := make(map[string]string)
@ -349,24 +351,26 @@ func (c *TreeClient) PutBucketCORS(ctx context.Context, cnrID cid.ID, objID *oid
meta[oidKV] = objID.EncodeToString()
if isErrNotFound {
_, err = c.addNode(ctx, cnrID, systemTree, 0, meta)
return nil, err
if _, err = c.addNode(ctx, cnrID, systemTree, 0, meta); err != nil {
return oid.ID{}, err
}
return oid.ID{}, layer.ErrNoNodeToRemove
}
return &node.ObjID, c.moveNode(ctx, cnrID, systemTree, node.ID, 0, meta)
return node.ObjID, c.moveNode(ctx, cnrID, systemTree, node.ID, 0, meta)
}
func (c *TreeClient) DeleteBucketCORS(ctx context.Context, cnrID cid.ID) (*oid.ID, error) {
func (c *TreeClient) DeleteBucketCORS(ctx context.Context, cnrID cid.ID) (oid.ID, error) {
node, err := c.getSystemNode(ctx, cnrID, []string{corsFilename}, []string{oidKV})
if err != nil && !errors.Is(err, layer.ErrNodeNotFound) {
return nil, err
return oid.ID{}, err
}
if node != nil {
return &node.ObjID, c.removeNode(ctx, cnrID, systemTree, node.ID)
return node.ObjID, c.removeNode(ctx, cnrID, systemTree, node.ID)
}
return nil, nil
return oid.ID{}, layer.ErrNoNodeToRemove
}
func (c *TreeClient) GetObjectTagging(ctx context.Context, cnrID cid.ID, objVersion *data.NodeVersion) (map[string]string, error) {
@ -881,10 +885,10 @@ func (c *TreeClient) GetMultipartUpload(ctx context.Context, cnrID cid.ID, objec
return nil, layer.ErrNodeNotFound
}
func (c *TreeClient) AddPart(ctx context.Context, cnrID cid.ID, multipartNodeID uint64, info *data.PartInfo) (oldObjIDToDelete *oid.ID, err error) {
func (c *TreeClient) AddPart(ctx context.Context, cnrID cid.ID, multipartNodeID uint64, info *data.PartInfo) (oldObjIDToDelete oid.ID, err error) {
parts, err := c.getSubTree(ctx, cnrID, systemTree, multipartNodeID, 1)
if err != nil {
return nil, err
return oid.ID{}, err
}
meta := map[string]string{
@ -906,14 +910,16 @@ func (c *TreeClient) AddPart(ctx context.Context, cnrID cid.ID, multipartNodeID
}
if partInfo.Number == info.Number {
foundPartID = part.GetNodeId()
oldObjIDToDelete = &partInfo.OID
oldObjIDToDelete = partInfo.OID
break
}
}
if oldObjIDToDelete == nil {
_, err = c.addNode(ctx, cnrID, systemTree, multipartNodeID, meta)
return nil, err
if foundPartID != multipartNodeID {
if _, err = c.addNode(ctx, cnrID, systemTree, multipartNodeID, meta); err != nil {
return oid.ID{}, err
}
return oid.ID{}, layer.ErrNoNodeToRemove
}
return oldObjIDToDelete, c.moveNode(ctx, cnrID, systemTree, foundPartID, multipartNodeID, meta)
@ -947,23 +953,23 @@ func (c *TreeClient) DeleteMultipartUpload(ctx context.Context, cnrID cid.ID, mu
func (c *TreeClient) PutLock(ctx context.Context, cnrID cid.ID, nodeID uint64, lock *data.LockInfo) error {
meta := map[string]string{isLockKV: "true"}
if lock.LegalHoldOID != nil {
meta[legalHoldOIDKV] = lock.LegalHoldOID.EncodeToString()
if lock.IsLegalHoldSet() {
meta[legalHoldOIDKV] = lock.LegalHold().EncodeToString()
}
if lock.RetentionOID != nil {
meta[retentionOIDKV] = lock.RetentionOID.EncodeToString()
meta[untilDateKV] = lock.UntilDate
if lock.IsCompliance {
if lock.IsRetentionSet() {
meta[retentionOIDKV] = lock.Retention().EncodeToString()
meta[untilDateKV] = lock.UntilDate()
if lock.IsCompliance() {
meta[isComplianceKV] = "true"
}
}
if lock.ID == 0 {
if lock.ID() == 0 {
_, err := c.addNode(ctx, cnrID, versionTree, nodeID, meta)
return err
}
return c.moveNode(ctx, cnrID, versionTree, lock.ID, nodeID, meta)
return c.moveNode(ctx, cnrID, versionTree, lock.ID(), nodeID, meta)
}
func (c *TreeClient) GetLock(ctx context.Context, cnrID cid.ID, nodeID uint64) (*data.LockInfo, error) {
@ -976,18 +982,17 @@ func (c *TreeClient) GetLock(ctx context.Context, cnrID cid.ID, nodeID uint64) (
}
func getLock(lockNode *TreeNode) (*data.LockInfo, error) {
lockInfo := &data.LockInfo{}
if lockNode == nil {
return lockInfo, nil
return &data.LockInfo{}, nil
}
lockInfo.ID = lockNode.ID
lockInfo := data.NewLockInfo(lockNode.ID)
if legalHold, ok := lockNode.Get(legalHoldOIDKV); ok {
var legalHoldOID oid.ID
if err := legalHoldOID.DecodeString(legalHold); err != nil {
return nil, fmt.Errorf("invalid legal hold object id: %w", err)
}
lockInfo.LegalHoldOID = &legalHoldOID
lockInfo.SetLegalHold(legalHoldOID)
}
if retention, ok := lockNode.Get(retentionOIDKV); ok {
@ -995,12 +1000,11 @@ func getLock(lockNode *TreeNode) (*data.LockInfo, error) {
if err := retentionOID.DecodeString(retention); err != nil {
return nil, fmt.Errorf("invalid retention object id: %w", err)
}
lockInfo.RetentionOID = &retentionOID
_, isCompliance := lockNode.Get(isComplianceKV)
untilDate, _ := lockNode.Get(untilDateKV)
lockInfo.SetRetention(retentionOID, untilDate, isCompliance)
}
_, lockInfo.IsCompliance = lockNode.Get(isComplianceKV)
lockInfo.UntilDate, _ = lockNode.Get(untilDateKV)
return lockInfo, nil
}