forked from TrueCloudLab/frostfs-s3-gw
[#488] Sync using oid.ID
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
85c203e157
commit
c88a9842db
18 changed files with 224 additions and 139 deletions
|
@ -75,9 +75,61 @@ func (p *PartInfo) ToHeaderString() string {
|
||||||
|
|
||||||
// LockInfo is lock information to create appropriate tree node.
|
// LockInfo is lock information to create appropriate tree node.
|
||||||
type LockInfo struct {
|
type LockInfo struct {
|
||||||
ID uint64
|
id uint64
|
||||||
LegalHoldOID *oid.ID
|
|
||||||
RetentionOID *oid.ID
|
legalHoldOID oid.ID
|
||||||
UntilDate string
|
setLegalHold bool
|
||||||
IsCompliance 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,12 +120,12 @@ func (h *handler) setLockingHeaders(bktInfo *data.BucketInfo, lockInfo *data.Loc
|
||||||
legalHold := &data.LegalHold{Status: legalHoldOff}
|
legalHold := &data.LegalHold{Status: legalHoldOff}
|
||||||
retention := &data.Retention{Mode: governanceMode}
|
retention := &data.Retention{Mode: governanceMode}
|
||||||
|
|
||||||
if lockInfo.LegalHoldOID != nil {
|
if lockInfo.IsLegalHoldSet() {
|
||||||
legalHold.Status = legalHoldOn
|
legalHold.Status = legalHoldOn
|
||||||
}
|
}
|
||||||
if lockInfo.RetentionOID != nil {
|
if lockInfo.IsRetentionSet() {
|
||||||
retention.RetainUntilDate = lockInfo.UntilDate
|
retention.RetainUntilDate = lockInfo.UntilDate()
|
||||||
if lockInfo.IsCompliance {
|
if lockInfo.IsCompliance() {
|
||||||
retention.Mode = complianceMode
|
retention.Mode = complianceMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,7 +174,7 @@ func (h *handler) GetObjectLegalHoldHandler(w http.ResponseWriter, r *http.Reque
|
||||||
}
|
}
|
||||||
|
|
||||||
legalHold := &data.LegalHold{Status: legalHoldOff}
|
legalHold := &data.LegalHold{Status: legalHoldOff}
|
||||||
if lockInfo.LegalHoldOID != nil {
|
if lockInfo.IsLegalHoldSet() {
|
||||||
legalHold.Status = legalHoldOn
|
legalHold.Status = legalHoldOn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,16 +248,16 @@ func (h *handler) GetObjectRetentionHandler(w http.ResponseWriter, r *http.Reque
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if lockInfo.RetentionOID == nil {
|
if !lockInfo.IsRetentionSet() {
|
||||||
h.logAndSendError(w, "retention lock isn't set", reqInfo, apiErrors.GetAPIError(apiErrors.ErrNoSuchKey))
|
h.logAndSendError(w, "retention lock isn't set", reqInfo, apiErrors.GetAPIError(apiErrors.ErrNoSuchKey))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
retention := &data.Retention{
|
retention := &data.Retention{
|
||||||
Mode: governanceMode,
|
Mode: governanceMode,
|
||||||
RetainUntilDate: lockInfo.UntilDate,
|
RetainUntilDate: lockInfo.UntilDate(),
|
||||||
}
|
}
|
||||||
if lockInfo.IsCompliance {
|
if lockInfo.IsCompliance() {
|
||||||
retention.Mode = complianceMode
|
retention.Mode = complianceMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,12 +49,13 @@ func (n *layer) PutBucketCORS(ctx context.Context, p *PutCORSParams) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
objIDToDelete, err := n.treeService.PutBucketCORS(ctx, p.BktInfo.CID, objID)
|
objIDToDelete, err := n.treeService.PutBucketCORS(ctx, p.BktInfo.CID, objID)
|
||||||
if err != nil {
|
objIDToDeleteNotFound := errorsStd.Is(err, ErrNoNodeToRemove)
|
||||||
|
if err != nil && !objIDToDeleteNotFound {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if objIDToDelete != nil {
|
if !objIDToDeleteNotFound {
|
||||||
if err = n.objectDelete(ctx, p.BktInfo, *objIDToDelete); err != nil {
|
if err = n.objectDelete(ctx, p.BktInfo, objIDToDelete); err != nil {
|
||||||
n.log.Error("couldn't delete cors object", zap.Error(err),
|
n.log.Error("couldn't delete cors object", zap.Error(err),
|
||||||
zap.String("cnrID", p.BktInfo.CID.EncodeToString()),
|
zap.String("cnrID", p.BktInfo.CID.EncodeToString()),
|
||||||
zap.String("bucket name", p.BktInfo.Name),
|
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 {
|
func (n *layer) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) error {
|
||||||
objID, err := n.treeService.DeleteBucketCORS(ctx, bktInfo.CID)
|
objID, err := n.treeService.DeleteBucketCORS(ctx, bktInfo.CID)
|
||||||
if err != nil {
|
objIDNotFound := errorsStd.Is(err, ErrNoNodeToRemove)
|
||||||
|
if err != nil && !objIDNotFound {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if objID != nil {
|
if !objIDNotFound {
|
||||||
if err = n.objectDelete(ctx, bktInfo, *objID); err != nil {
|
if err = n.objectDelete(ctx, bktInfo, objID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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{}
|
b := [32]byte{}
|
||||||
if _, err := rand.Read(b[:]); err != nil {
|
if _, err := rand.Read(b[:]); err != nil {
|
||||||
return nil, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var objID oid.ID
|
var objID oid.ID
|
||||||
objID.SetSHA256(b)
|
objID.SetSHA256(b)
|
||||||
return &objID, nil
|
return objID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteObject removes all objects with the passed nice name.
|
// 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{
|
newVersion := &data.NodeVersion{
|
||||||
BaseNodeVersion: data.BaseNodeVersion{
|
BaseNodeVersion: data.BaseNodeVersion{
|
||||||
OID: *randOID,
|
OID: randOID,
|
||||||
FilePath: obj.Name,
|
FilePath: obj.Name,
|
||||||
},
|
},
|
||||||
DeleteMarker: &data.DeleteMarkerInfo{
|
DeleteMarker: &data.DeleteMarkerInfo{
|
||||||
|
|
|
@ -36,7 +36,7 @@ func TestObjectLockAttributes(t *testing.T) {
|
||||||
foundLock, err := tc.layer.GetLockInfo(tc.ctx, p)
|
foundLock, err := tc.layer.GetLockInfo(tc.ctx, p)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
lockObj := tc.getObjectByID(*foundLock.RetentionOID)
|
lockObj := tc.getObjectByID(foundLock.Retention())
|
||||||
require.NotNil(t, lockObj)
|
require.NotNil(t, lockObj)
|
||||||
|
|
||||||
expEpoch := false
|
expEpoch := false
|
||||||
|
|
|
@ -198,18 +198,19 @@ func (n *layer) uploadPart(ctx context.Context, multipartInfo *data.MultipartInf
|
||||||
Key: p.Info.Key,
|
Key: p.Info.Key,
|
||||||
UploadID: p.Info.UploadID,
|
UploadID: p.Info.UploadID,
|
||||||
Number: p.PartNumber,
|
Number: p.PartNumber,
|
||||||
OID: *id,
|
OID: id,
|
||||||
Size: p.Size,
|
Size: p.Size,
|
||||||
ETag: hex.EncodeToString(hash),
|
ETag: hex.EncodeToString(hash),
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
oldPartID, err := n.treeService.AddPart(ctx, bktInfo.CID, multipartInfo.ID, partInfo)
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
if oldPartID != nil {
|
if !oldPartIDNotFound {
|
||||||
if err = n.objectDelete(ctx, bktInfo, *oldPartID); err != nil {
|
if err = n.objectDelete(ctx, bktInfo, oldPartID); err != nil {
|
||||||
n.log.Error("couldn't delete old part object", zap.Error(err),
|
n.log.Error("couldn't delete old part object", zap.Error(err),
|
||||||
zap.String("cnrID", bktInfo.CID.EncodeToString()),
|
zap.String("cnrID", bktInfo.CID.EncodeToString()),
|
||||||
zap.String("bucket name", bktInfo.Name),
|
zap.String("bucket name", bktInfo.Name),
|
||||||
|
@ -218,7 +219,7 @@ func (n *layer) uploadPart(ctx context.Context, multipartInfo *data.MultipartInf
|
||||||
}
|
}
|
||||||
|
|
||||||
objInfo := &data.ObjectInfo{
|
objInfo := &data.ObjectInfo{
|
||||||
ID: *id,
|
ID: id,
|
||||||
CID: bktInfo.CID,
|
CID: bktInfo.CID,
|
||||||
|
|
||||||
Owner: bktInfo.Owner,
|
Owner: bktInfo.Owner,
|
||||||
|
|
|
@ -146,7 +146,7 @@ type NeoFS interface {
|
||||||
//
|
//
|
||||||
// Created container is public with enabled ACL extension.
|
// 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.
|
// prevented the container from being created.
|
||||||
CreateContainer(context.Context, PrmContainerCreate) (cid.ID, error)
|
CreateContainer(context.Context, PrmContainerCreate) (cid.ID, error)
|
||||||
|
|
||||||
|
@ -214,9 +214,9 @@ type NeoFS interface {
|
||||||
//
|
//
|
||||||
// It returns ErrAccessDenied on write access violation.
|
// 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.
|
// 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.
|
// DeleteObject marks the object to be removed from the NeoFS container by identifier.
|
||||||
// Successful return does not guarantee actual removal.
|
// Successful return does not guarantee actual removal.
|
||||||
|
|
|
@ -178,10 +178,10 @@ func (t *TestNeoFS) ReadObject(_ context.Context, prm PrmObjectRead) (*ObjectPar
|
||||||
return nil, fmt.Errorf("object not found %s", addr)
|
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)
|
b := make([]byte, 32)
|
||||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
||||||
return nil, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
var id oid.ID
|
var id oid.ID
|
||||||
id.SetSHA256(sha256.Sum256(b))
|
id.SetSHA256(sha256.Sum256(b))
|
||||||
|
@ -219,7 +219,7 @@ func (t *TestNeoFS) CreateObject(_ context.Context, prm PrmObjectCreate) (*oid.I
|
||||||
if prm.Payload != nil {
|
if prm.Payload != nil {
|
||||||
all, err := io.ReadAll(prm.Payload)
|
all, err := io.ReadAll(prm.Payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
obj.SetPayload(all)
|
obj.SetPayload(all)
|
||||||
obj.SetPayloadSize(uint64(len(all)))
|
obj.SetPayloadSize(uint64(len(all)))
|
||||||
|
@ -233,7 +233,7 @@ func (t *TestNeoFS) CreateObject(_ context.Context, prm PrmObjectCreate) (*oid.I
|
||||||
|
|
||||||
addr := newAddress(cnrID, objID)
|
addr := newAddress(cnrID, objID)
|
||||||
t.objects[addr.EncodeToString()] = obj
|
t.objects[addr.EncodeToString()] = obj
|
||||||
return &objID, nil
|
return objID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TestNeoFS) DeleteObject(_ context.Context, prm PrmObjectDelete) error {
|
func (t *TestNeoFS) DeleteObject(_ context.Context, prm PrmObjectDelete) error {
|
||||||
|
|
|
@ -39,12 +39,13 @@ func (n *layer) PutBucketNotificationConfiguration(ctx context.Context, p *PutBu
|
||||||
}
|
}
|
||||||
|
|
||||||
objIDToDelete, err := n.treeService.PutNotificationConfigurationNode(ctx, p.BktInfo.CID, objID)
|
objIDToDelete, err := n.treeService.PutNotificationConfigurationNode(ctx, p.BktInfo.CID, objID)
|
||||||
if err != nil {
|
objIDToDeleteNotFound := errorsStd.Is(err, ErrNoNodeToRemove)
|
||||||
|
if err != nil && !objIDToDeleteNotFound {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if objIDToDelete != nil {
|
if !objIDToDeleteNotFound {
|
||||||
if err = n.objectDelete(ctx, p.BktInfo, *objIDToDelete); err != nil {
|
if err = n.objectDelete(ctx, p.BktInfo, objIDToDelete); err != nil {
|
||||||
n.log.Error("couldn't delete notification configuration object", zap.Error(err),
|
n.log.Error("couldn't delete notification configuration object", zap.Error(err),
|
||||||
zap.String("cnrID", p.BktInfo.CID.EncodeToString()),
|
zap.String("cnrID", p.BktInfo.CID.EncodeToString()),
|
||||||
zap.String("bucket name", p.BktInfo.Name),
|
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)
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
conf := &data.NotificationConfiguration{}
|
conf := &data.NotificationConfiguration{}
|
||||||
|
|
||||||
if objID != nil {
|
if !objIDNotFound {
|
||||||
obj, err := n.objectGet(ctx, bktInfo, *objID)
|
obj, err := n.objectGet(ctx, bktInfo, objID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,7 +189,7 @@ func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Object
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
newVersion.OID = *id
|
newVersion.OID = id
|
||||||
if err = n.treeService.AddVersion(ctx, p.BktInfo.CID, newVersion); err != nil {
|
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)
|
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)
|
n.listsCache.CleanCacheEntriesContainingObject(p.Object, p.BktInfo.CID)
|
||||||
|
|
||||||
objInfo := &data.ObjectInfo{
|
objInfo := &data.ObjectInfo{
|
||||||
ID: *id,
|
ID: id,
|
||||||
CID: p.BktInfo.CID,
|
CID: p.BktInfo.CID,
|
||||||
|
|
||||||
Owner: own,
|
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.
|
// objectPutAndHash prepare auth parameters and invoke neofs.CreateObject.
|
||||||
// Returns object ID and payload sha256 hash.
|
// 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)
|
n.prepareAuthParameters(ctx, &prm.PrmAuth, bktInfo.Owner)
|
||||||
hash := sha256.New()
|
hash := sha256.New()
|
||||||
prm.Payload = wrapReader(prm.Payload, 64*1024, func(buf []byte) {
|
prm.Payload = wrapReader(prm.Payload, 64*1024, func(buf []byte) {
|
||||||
|
|
|
@ -36,18 +36,19 @@ func (n *layer) PutLockInfo(ctx context.Context, objVersion *ObjectVersion, newL
|
||||||
}
|
}
|
||||||
|
|
||||||
if newLock.Retention != nil {
|
if newLock.Retention != nil {
|
||||||
if lockInfo.RetentionOID != nil {
|
if lockInfo.IsRetentionSet() {
|
||||||
if lockInfo.IsCompliance {
|
if lockInfo.IsCompliance() {
|
||||||
return fmt.Errorf("you cannot change compliance mode")
|
return fmt.Errorf("you cannot change compliance mode")
|
||||||
}
|
}
|
||||||
if !newLock.Retention.ByPassedGovernance {
|
if !newLock.Retention.ByPassedGovernance {
|
||||||
return fmt.Errorf("you cannot bypass governence mode")
|
return fmt.Errorf("you cannot bypass governence mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(lockInfo.UntilDate) > 0 {
|
untilDate := lockInfo.UntilDate()
|
||||||
parsedTime, err := time.Parse(time.RFC3339, lockInfo.UntilDate)
|
if len(untilDate) > 0 {
|
||||||
|
parsedTime, err := time.Parse(time.RFC3339, untilDate)
|
||||||
if err != nil {
|
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) {
|
if parsedTime.After(newLock.Retention.Until) {
|
||||||
return fmt.Errorf("you couldn't short the until date")
|
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}
|
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
|
return err
|
||||||
}
|
}
|
||||||
lockInfo.IsCompliance = newLock.Retention.IsCompliance
|
lockInfo.SetRetention(retentionOID, newLock.Retention.Until.UTC().Format(time.RFC3339), newLock.Retention.IsCompliance)
|
||||||
lockInfo.UntilDate = newLock.Retention.Until.UTC().Format(time.RFC3339)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if newLock.LegalHold != nil {
|
if newLock.LegalHold != nil {
|
||||||
if newLock.LegalHold.Enabled && lockInfo.LegalHoldOID == nil {
|
if newLock.LegalHold.Enabled && !lockInfo.IsLegalHoldSet() {
|
||||||
lock := &data.ObjectLock{LegalHold: newLock.LegalHold}
|
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
|
return err
|
||||||
}
|
}
|
||||||
} else if !newLock.LegalHold.Enabled && lockInfo.LegalHoldOID != nil {
|
lockInfo.SetLegalHold(legalHoldOID)
|
||||||
if err = n.objectDelete(ctx, objVersion.BktInfo, *lockInfo.LegalHoldOID); err != nil {
|
} else if !newLock.LegalHold.Enabled && lockInfo.IsLegalHoldSet() {
|
||||||
return fmt.Errorf("couldn't delete lock object '%s' to remove legal hold: %w", lockInfo.LegalHoldOID.EncodeToString(), err)
|
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
|
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{
|
prm := PrmObjectCreate{
|
||||||
Container: bktInfo.CID,
|
Container: bktInfo.CID,
|
||||||
Creator: bktInfo.Owner,
|
Creator: bktInfo.Owner,
|
||||||
|
@ -97,7 +100,7 @@ func (n *layer) putLockObject(ctx context.Context, bktInfo *data.BucketInfo, obj
|
||||||
var err error
|
var err error
|
||||||
prm.Attributes, err = n.attributesFromLock(ctx, lock)
|
prm.Attributes, err = n.attributesFromLock(ctx, lock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
id, _, err := n.objectPutAndHash(ctx, prm, bktInfo)
|
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
|
return cors, nil
|
||||||
}
|
}
|
||||||
objID, err := n.treeService.GetBucketCORS(ctx, bkt.CID)
|
objID, err := n.treeService.GetBucketCORS(ctx, bkt.CID)
|
||||||
if err != nil {
|
objIDNotFound := errorsStd.Is(err, ErrNodeNotFound)
|
||||||
|
if err != nil && !objIDNotFound {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if objID == nil {
|
if objIDNotFound {
|
||||||
return nil, errors.GetAPIError(errors.ErrNoSuchCORSConfiguration)
|
return nil, errors.GetAPIError(errors.ErrNoSuchCORSConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := n.objectGet(ctx, bkt, *objID)
|
obj, err := n.objectGet(ctx, bkt, objID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,23 +81,23 @@ func (t *TreeServiceMock) GetSettingsNode(_ context.Context, id cid.ID) (*data.B
|
||||||
return settings, nil
|
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")
|
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")
|
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")
|
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")
|
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")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,14 +294,14 @@ func (t *TreeServiceMock) GetMultipartUpload(_ context.Context, cnrID cid.ID, ob
|
||||||
return nil, ErrNodeNotFound
|
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)
|
multipartInfo, err := t.GetMultipartUpload(ctx, cnrID, info.Key, info.UploadID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if multipartInfo.ID != multipartNodeID {
|
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]
|
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
|
partsMap[info.Number] = info
|
||||||
|
|
||||||
t.parts[info.UploadID] = partsMap
|
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) {
|
func (t *TreeServiceMock) GetParts(_ context.Context, cnrID cid.ID, multipartNodeID uint64) ([]*data.PartInfo, error) {
|
||||||
|
|
|
@ -16,19 +16,34 @@ type TreeService interface {
|
||||||
|
|
||||||
// GetSettingsNode retrieves the settings node from the tree service and form data.BucketSettings.
|
// 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)
|
GetSettingsNode(context.Context, cid.ID) (*data.BucketSettings, error)
|
||||||
|
|
||||||
GetNotificationConfigurationNode(ctx context.Context, cnrID cid.ID) (*oid.ID, error)
|
// GetNotificationConfigurationNode gets an object id that corresponds to object with bucket CORS.
|
||||||
// PutNotificationConfigurationNode puts a node to a system tree
|
//
|
||||||
// and returns objectID of a previous notif config which must be deleted in NeoFS
|
// If tree node is not found returns ErrNodeNotFound error.
|
||||||
PutNotificationConfigurationNode(ctx context.Context, cnrID cid.ID, objID *oid.ID) (*oid.ID, error)
|
GetNotificationConfigurationNode(ctx context.Context, cnrID cid.ID) (oid.ID, error)
|
||||||
|
|
||||||
GetBucketCORS(ctx context.Context, cnrID cid.ID) (*oid.ID, error)
|
// PutNotificationConfigurationNode puts a node to a system tree
|
||||||
// PutBucketCORS puts a node to a system tree and returns objectID of a previous cors config which must be deleted in NeoFS
|
// and returns objectID of a previous notif 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
|
// If object id to remove is not found returns ErrNoNodeToRemove error.
|
||||||
DeleteBucketCORS(ctx context.Context, cnrID cid.ID) (*oid.ID, 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)
|
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
|
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
|
// 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.
|
// 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)
|
GetParts(ctx context.Context, cnrID cid.ID, multipartNodeID uint64) ([]*data.PartInfo, error)
|
||||||
|
|
||||||
// Compound methods for optimizations
|
// 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)
|
GetObjectTaggingAndLock(ctx context.Context, cnrID cid.ID, objVersion *data.NodeVersion) (map[string]string, *data.LockInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
// ErrNodeNotFound is returned from Tree service in case of not found error.
|
// ErrNodeNotFound is returned from Tree service in case of not found error.
|
||||||
var ErrNodeNotFound = errors.New("not found")
|
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")
|
||||||
|
)
|
||||||
|
|
|
@ -3,7 +3,6 @@ package authmate
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -29,9 +28,9 @@ func TestContainerSessionRules(t *testing.T) {
|
||||||
|
|
||||||
require.Len(t, sessionContext, 3)
|
require.Len(t, sessionContext, 3)
|
||||||
require.Equal(t, sessionContext[0].verb, session.VerbContainerPut)
|
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.Equal(t, sessionContext[1].verb, session.VerbContainerDelete)
|
||||||
require.NotNil(t, sessionContext[1].containerID)
|
require.NotNil(t, sessionContext[1].containerID)
|
||||||
require.Equal(t, sessionContext[2].verb, session.VerbContainerSetEACL)
|
require.Equal(t, sessionContext[2].verb, session.VerbContainerSetEACL)
|
||||||
require.Equal(t, cid.ID{}, sessionContext[2].containerID)
|
require.Zero(t, sessionContext[2].containerID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ type NeoFS interface {
|
||||||
//
|
//
|
||||||
// It returns exactly one non-nil value. It returns any error encountered which
|
// It returns exactly one non-nil value. It returns any error encountered which
|
||||||
// prevented the object from being created.
|
// 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
|
// ReadObjectPayload reads payload of the object from NeoFS network by address
|
||||||
// into memory.
|
// 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
|
var addr oid.Address
|
||||||
addr.SetObject(*idObj)
|
addr.SetObject(idObj)
|
||||||
addr.SetContainer(idCnr)
|
addr.SetContainer(idCnr)
|
||||||
|
|
||||||
return &addr, nil
|
return &addr, nil
|
||||||
|
|
|
@ -215,7 +215,7 @@ func (x *NeoFS) DeleteContainer(ctx context.Context, id cid.ID, token *session.C
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateObject implements neofs.NeoFS interface method.
|
// 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
|
attrNum := len(prm.Attributes) + 1 // + creation time
|
||||||
|
|
||||||
if prm.Filename != "" {
|
if prm.Filename != "" {
|
||||||
|
@ -270,12 +270,12 @@ func (x *NeoFS) CreateObject(ctx context.Context, prm layer.PrmObjectCreate) (*o
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reason, ok := isErrAccessDenied(err)
|
reason, ok := isErrAccessDenied(err)
|
||||||
if ok {
|
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.
|
// 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.
|
// 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{
|
return x.neoFS.CreateObject(ctx, layer.PrmObjectCreate{
|
||||||
Creator: prm.Creator,
|
Creator: prm.Creator,
|
||||||
Container: prm.Container,
|
Container: prm.Container,
|
||||||
|
|
|
@ -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)
|
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})
|
node, err := c.getSystemNode(ctx, cnrID, []string{notifConfFileName}, []string{oidKV})
|
||||||
if err != nil {
|
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})
|
node, err := c.getSystemNode(ctx, cnrID, []string{notifConfFileName}, []string{oidKV})
|
||||||
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
||||||
if err != nil && !isErrNotFound {
|
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)
|
meta := make(map[string]string)
|
||||||
|
@ -321,27 +321,29 @@ func (c *TreeClient) PutNotificationConfigurationNode(ctx context.Context, cnrID
|
||||||
meta[oidKV] = objID.EncodeToString()
|
meta[oidKV] = objID.EncodeToString()
|
||||||
|
|
||||||
if isErrNotFound {
|
if isErrNotFound {
|
||||||
_, err = c.addNode(ctx, cnrID, systemTree, 0, meta)
|
if _, err = c.addNode(ctx, cnrID, systemTree, 0, meta); err != nil {
|
||||||
return nil, err
|
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})
|
node, err := c.getSystemNode(ctx, cnrID, []string{corsFilename}, []string{oidKV})
|
||||||
if err != nil {
|
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})
|
node, err := c.getSystemNode(ctx, cnrID, []string{corsFilename}, []string{oidKV})
|
||||||
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
isErrNotFound := errors.Is(err, layer.ErrNodeNotFound)
|
||||||
if err != nil && !isErrNotFound {
|
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)
|
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()
|
meta[oidKV] = objID.EncodeToString()
|
||||||
|
|
||||||
if isErrNotFound {
|
if isErrNotFound {
|
||||||
_, err = c.addNode(ctx, cnrID, systemTree, 0, meta)
|
if _, err = c.addNode(ctx, cnrID, systemTree, 0, meta); err != nil {
|
||||||
return nil, err
|
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})
|
node, err := c.getSystemNode(ctx, cnrID, []string{corsFilename}, []string{oidKV})
|
||||||
if err != nil && !errors.Is(err, layer.ErrNodeNotFound) {
|
if err != nil && !errors.Is(err, layer.ErrNodeNotFound) {
|
||||||
return nil, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if node != nil {
|
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) {
|
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
|
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)
|
parts, err := c.getSubTree(ctx, cnrID, systemTree, multipartNodeID, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return oid.ID{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
meta := map[string]string{
|
meta := map[string]string{
|
||||||
|
@ -906,14 +910,16 @@ func (c *TreeClient) AddPart(ctx context.Context, cnrID cid.ID, multipartNodeID
|
||||||
}
|
}
|
||||||
if partInfo.Number == info.Number {
|
if partInfo.Number == info.Number {
|
||||||
foundPartID = part.GetNodeId()
|
foundPartID = part.GetNodeId()
|
||||||
oldObjIDToDelete = &partInfo.OID
|
oldObjIDToDelete = partInfo.OID
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if oldObjIDToDelete == nil {
|
if foundPartID != multipartNodeID {
|
||||||
_, err = c.addNode(ctx, cnrID, systemTree, multipartNodeID, meta)
|
if _, err = c.addNode(ctx, cnrID, systemTree, multipartNodeID, meta); err != nil {
|
||||||
return nil, err
|
return oid.ID{}, err
|
||||||
|
}
|
||||||
|
return oid.ID{}, layer.ErrNoNodeToRemove
|
||||||
}
|
}
|
||||||
|
|
||||||
return oldObjIDToDelete, c.moveNode(ctx, cnrID, systemTree, foundPartID, multipartNodeID, meta)
|
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 {
|
func (c *TreeClient) PutLock(ctx context.Context, cnrID cid.ID, nodeID uint64, lock *data.LockInfo) error {
|
||||||
meta := map[string]string{isLockKV: "true"}
|
meta := map[string]string{isLockKV: "true"}
|
||||||
|
|
||||||
if lock.LegalHoldOID != nil {
|
if lock.IsLegalHoldSet() {
|
||||||
meta[legalHoldOIDKV] = lock.LegalHoldOID.EncodeToString()
|
meta[legalHoldOIDKV] = lock.LegalHold().EncodeToString()
|
||||||
}
|
}
|
||||||
if lock.RetentionOID != nil {
|
if lock.IsRetentionSet() {
|
||||||
meta[retentionOIDKV] = lock.RetentionOID.EncodeToString()
|
meta[retentionOIDKV] = lock.Retention().EncodeToString()
|
||||||
meta[untilDateKV] = lock.UntilDate
|
meta[untilDateKV] = lock.UntilDate()
|
||||||
if lock.IsCompliance {
|
if lock.IsCompliance() {
|
||||||
meta[isComplianceKV] = "true"
|
meta[isComplianceKV] = "true"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if lock.ID == 0 {
|
if lock.ID() == 0 {
|
||||||
_, err := c.addNode(ctx, cnrID, versionTree, nodeID, meta)
|
_, err := c.addNode(ctx, cnrID, versionTree, nodeID, meta)
|
||||||
return err
|
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) {
|
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) {
|
func getLock(lockNode *TreeNode) (*data.LockInfo, error) {
|
||||||
lockInfo := &data.LockInfo{}
|
|
||||||
if lockNode == nil {
|
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 {
|
if legalHold, ok := lockNode.Get(legalHoldOIDKV); ok {
|
||||||
var legalHoldOID oid.ID
|
var legalHoldOID oid.ID
|
||||||
if err := legalHoldOID.DecodeString(legalHold); err != nil {
|
if err := legalHoldOID.DecodeString(legalHold); err != nil {
|
||||||
return nil, fmt.Errorf("invalid legal hold object id: %w", err)
|
return nil, fmt.Errorf("invalid legal hold object id: %w", err)
|
||||||
}
|
}
|
||||||
lockInfo.LegalHoldOID = &legalHoldOID
|
lockInfo.SetLegalHold(legalHoldOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if retention, ok := lockNode.Get(retentionOIDKV); ok {
|
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 {
|
if err := retentionOID.DecodeString(retention); err != nil {
|
||||||
return nil, fmt.Errorf("invalid retention object id: %w", err)
|
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
|
return lockInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue