[#449] Add tree service for object tagging

Signed-off-by: Angira Kekteeva <kira@nspcc.ru>
This commit is contained in:
Angira Kekteeva 2022-05-24 09:58:33 +03:00 committed by Alex Vanin
parent 9c74cca9af
commit 99feb1d936
13 changed files with 367 additions and 152 deletions

18
api/cache/system.go vendored
View file

@ -104,6 +104,20 @@ func (o *SystemCache) GetNotificationConfiguration(key string) *data.Notificatio
return result
}
func (o *SystemCache) GetObjectTagging(key string) map[string]string {
entry, err := o.cache.Get(key)
if err != nil {
return nil
}
result, ok := entry.(map[string]string)
if !ok {
return nil
}
return result
}
// PutObject puts an object to cache.
func (o *SystemCache) PutObject(key string, obj *data.ObjectInfo) error {
return o.cache.Set(key, obj)
@ -121,6 +135,10 @@ func (o *SystemCache) PutNotificationConfiguration(key string, obj *data.Notific
return o.cache.Set(key, obj)
}
func (o *SystemCache) PutObjectTagging(key string, tagSet map[string]string) error {
return o.cache.Set(key, tagSet)
}
// Delete deletes an object from cache.
func (o *SystemCache) Delete(key string) bool {
return o.cache.Remove(key)

View file

@ -102,9 +102,6 @@ func (o *ObjectInfo) Address() oid.Address {
return addr
}
// TagsObject returns the name of a system object for tags.
func (o *ObjectInfo) TagsObject() string { return ".tagset." + o.Name + "." + o.Version() }
// LegalHoldObject returns the name of a system object for a lock object.
func (o *ObjectInfo) LegalHoldObject() string { return ".lock." + o.Name + "." + o.Version() }

View file

@ -3,6 +3,7 @@ package data
import (
"time"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/user"
)
@ -35,3 +36,9 @@ type BaseNodeVersion struct {
OID oid.ID
Timestamp uint64
}
type ObjectTaggingInfo struct {
CnrID *cid.ID
ObjName string
VersionID string
}

View file

@ -138,7 +138,13 @@ func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
return
}
tagSet, err := h.obj.GetObjectTagging(r.Context(), info)
t := &data.ObjectTaggingInfo{
CnrID: &info.CID,
ObjName: info.Name,
VersionID: info.Version(),
}
tagSet, err := h.obj.GetObjectTagging(r.Context(), t)
if err != nil && !errors.IsS3Error(err, errors.ErrNoSuchKey) {
h.logAndSendError(w, "could not get object tag set", reqInfo, err)
return

View file

@ -62,7 +62,13 @@ func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
return
}
tagSet, err := h.obj.GetObjectTagging(r.Context(), info)
t := &data.ObjectTaggingInfo{
CnrID: &info.CID,
ObjName: info.Name,
VersionID: info.Version(),
}
tagSet, err := h.obj.GetObjectTagging(r.Context(), t)
if err != nil && !errors.IsS3Error(err, errors.ErrNoSuchKey) {
h.logAndSendError(w, "could not get object tag set", reqInfo, err)
return

View file

@ -412,11 +412,12 @@ func (h *handler) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http.
}
if len(uploadData.TagSet) != 0 {
t := &layer.PutTaggingParams{
ObjectInfo: objInfo,
TagSet: uploadData.TagSet,
t := &data.ObjectTaggingInfo{
CnrID: &bktInfo.CID,
ObjName: objInfo.Name,
VersionID: objInfo.Version(),
}
if err = h.obj.PutObjectTagging(r.Context(), t); err != nil {
if err = h.obj.PutObjectTagging(r.Context(), t, uploadData.TagSet); err != nil {
h.logAndSendError(w, "could not put tagging file of completed multipart upload", reqInfo, err, additional...)
return
}

View file

@ -252,8 +252,13 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
}
}
t := &data.ObjectTaggingInfo{
CnrID: &info.CID,
ObjName: info.Name,
VersionID: info.Version(),
}
if tagSet != nil {
if err = h.obj.PutObjectTagging(r.Context(), &layer.PutTaggingParams{ObjectInfo: info, TagSet: tagSet}); err != nil {
if err = h.obj.PutObjectTagging(r.Context(), t, tagSet); err != nil {
h.logAndSendError(w, "could not upload object tagging", reqInfo, err)
return
}
@ -374,8 +379,14 @@ func (h *handler) PostObject(w http.ResponseWriter, r *http.Request) {
}
}
t := &data.ObjectTaggingInfo{
CnrID: &info.CID,
ObjName: info.Name,
VersionID: info.Version(),
}
if tagSet != nil {
if err = h.obj.PutObjectTagging(r.Context(), &layer.PutTaggingParams{ObjectInfo: info, TagSet: tagSet}); err != nil {
if err = h.obj.PutObjectTagging(r.Context(), t, tagSet); err != nil {
h.logAndSendError(w, "could not upload object tagging", reqInfo, err)
return
}

View file

@ -9,8 +9,8 @@ import (
"unicode"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/data"
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
"go.uber.org/zap"
)
@ -37,31 +37,22 @@ func (h *handler) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request
return
}
p := &layer.HeadObjectParams{
BktInfo: bktInfo,
Object: reqInfo.ObjectName,
p := &data.ObjectTaggingInfo{
CnrID: &bktInfo.CID,
ObjName: reqInfo.ObjectName,
VersionID: reqInfo.URL.Query().Get("versionId"),
}
objInfo, err := h.obj.GetObjectInfo(r.Context(), p)
if err != nil {
h.logAndSendError(w, "could not get object info", reqInfo, err)
return
}
p2 := &layer.PutTaggingParams{
ObjectInfo: objInfo,
TagSet: tagSet,
}
if err = h.obj.PutObjectTagging(r.Context(), p2); err != nil {
if err = h.obj.PutObjectTagging(r.Context(), p, tagSet); err != nil {
h.logAndSendError(w, "could not put object tagging", reqInfo, err)
return
}
s := &SendNotificationParams{
Event: EventObjectTaggingPut,
ObjInfo: objInfo,
Event: EventObjectTaggingPut,
ObjInfo: &data.ObjectInfo{
Name: reqInfo.ObjectName,
},
BktInfo: bktInfo,
ReqInfo: reqInfo,
}
@ -74,6 +65,7 @@ func (h *handler) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request
func (h *handler) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {
reqInfo := api.GetReqInfo(r.Context())
versionID := reqInfo.URL.Query().Get("versionId")
bktInfo, err := h.getBucketAndCheckOwner(r, reqInfo.BucketName)
if err != nil {
@ -81,25 +73,19 @@ func (h *handler) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request
return
}
p := &layer.HeadObjectParams{
BktInfo: bktInfo,
Object: reqInfo.ObjectName,
VersionID: reqInfo.URL.Query().Get("versionId"),
p := &data.ObjectTaggingInfo{
CnrID: &bktInfo.CID,
ObjName: reqInfo.ObjectName,
VersionID: versionID,
}
objInfo, err := h.obj.GetObjectInfo(r.Context(), p)
if err != nil {
h.logAndSendError(w, "could not get object info", reqInfo, err)
return
}
tagSet, err := h.obj.GetObjectTagging(r.Context(), objInfo)
tagSet, err := h.obj.GetObjectTagging(r.Context(), p)
if err != nil {
h.logAndSendError(w, "could not get object tagging", reqInfo, err)
return
}
w.Header().Set(api.AmzVersionID, objInfo.Version())
w.Header().Set(api.AmzVersionID, versionID)
if err = api.EncodeToResponse(w, encodeTagging(tagSet)); err != nil {
h.logAndSendError(w, "something went wrong", reqInfo, err)
}
@ -114,26 +100,22 @@ func (h *handler) DeleteObjectTaggingHandler(w http.ResponseWriter, r *http.Requ
return
}
p := &layer.HeadObjectParams{
BktInfo: bktInfo,
Object: reqInfo.ObjectName,
p := &data.ObjectTaggingInfo{
CnrID: &bktInfo.CID,
ObjName: reqInfo.ObjectName,
VersionID: reqInfo.URL.Query().Get("versionId"),
}
objInfo, err := h.obj.GetObjectInfo(r.Context(), p)
if err != nil {
h.logAndSendError(w, "could not get object info", reqInfo, err)
return
}
if err = h.obj.DeleteObjectTagging(r.Context(), bktInfo, objInfo); err != nil {
if err = h.obj.DeleteObjectTagging(r.Context(), p); err != nil {
h.logAndSendError(w, "could not delete object tagging", reqInfo, err)
return
}
s := &SendNotificationParams{
Event: EventObjectTaggingDelete,
ObjInfo: objInfo,
Event: EventObjectTaggingDelete,
ObjInfo: &data.ObjectInfo{
Name: reqInfo.ObjectName,
},
BktInfo: bktInfo,
ReqInfo: reqInfo,
}

View file

@ -7,7 +7,6 @@ import (
"fmt"
"io"
"net/url"
"strings"
"time"
"github.com/nats-io/nats.go"
@ -189,12 +188,6 @@ type (
Error error
}
// PutTaggingParams stores tag set params.
PutTaggingParams struct {
ObjectInfo *data.ObjectInfo
TagSet map[string]string
}
// Client provides S3 API client interface.
Client interface {
Initialize(ctx context.Context, c EventListener) error
@ -217,13 +210,17 @@ type (
GetObject(ctx context.Context, p *GetObjectParams) error
HeadSystemObject(ctx context.Context, bktInfo *data.BucketInfo, name string) (*data.ObjectInfo, error)
GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*data.ObjectInfo, error)
GetObjectTagging(ctx context.Context, p *data.ObjectInfo) (map[string]string, error)
GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) (map[string]string, error)
PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo, tagSet map[string]string) error
DeleteBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) error
GetObjectTagging(ctx context.Context, p *data.ObjectTaggingInfo) (map[string]string, error)
PutObjectTagging(ctx context.Context, p *data.ObjectTaggingInfo, tagSet map[string]string) error
DeleteObjectTagging(ctx context.Context, p *data.ObjectTaggingInfo) error
PutObject(ctx context.Context, p *PutObjectParams) (*data.ObjectInfo, error)
PutSystemObject(ctx context.Context, p *PutSystemObjectParams) (*data.ObjectInfo, error)
PutObjectTagging(ctx context.Context, p *PutTaggingParams) error
PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo, tagSet map[string]string) error
CopyObject(ctx context.Context, p *CopyObjectParams) (*data.ObjectInfo, error)
@ -233,8 +230,6 @@ type (
DeleteObjects(ctx context.Context, p *DeleteObjectParams) ([]*VersionedObject, error)
DeleteSystemObject(ctx context.Context, bktInfo *data.BucketInfo, name string) error
DeleteObjectTagging(ctx context.Context, bktInfo *data.BucketInfo, objInfo *data.ObjectInfo) error
DeleteBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) error
CompleteMultipartUpload(ctx context.Context, p *CompleteMultipartParams) (*data.ObjectInfo, error)
UploadPart(ctx context.Context, p *UploadPartParams) (*data.ObjectInfo, error)
@ -430,92 +425,6 @@ func (n *layer) GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*data.O
return n.headVersion(ctx, p.BktInfo, p)
}
// GetObjectTagging from storage.
func (n *layer) GetObjectTagging(ctx context.Context, oi *data.ObjectInfo) (map[string]string, error) {
bktInfo := &data.BucketInfo{
Name: oi.Bucket,
CID: oi.CID,
Owner: oi.Owner,
}
objInfo, err := n.HeadSystemObject(ctx, bktInfo, oi.TagsObject())
if err != nil && !errors.IsS3Error(err, errors.ErrNoSuchKey) {
return nil, err
}
return formTagSet(objInfo), nil
}
// GetBucketTagging from storage.
func (n *layer) GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) (map[string]string, error) {
objInfo, err := n.HeadSystemObject(ctx, bktInfo, formBucketTagObjectName(bktInfo.Name))
if err != nil && !errors.IsS3Error(err, errors.ErrNoSuchKey) {
return nil, err
}
return formTagSet(objInfo), nil
}
func formTagSet(objInfo *data.ObjectInfo) map[string]string {
var tagSet map[string]string
if objInfo != nil {
tagSet = make(map[string]string, len(objInfo.Headers))
for k, v := range objInfo.Headers {
if strings.HasPrefix(k, tagPrefix) {
if v == tagEmptyMark {
v = ""
}
tagSet[strings.TrimPrefix(k, tagPrefix)] = v
}
}
}
return tagSet
}
// PutObjectTagging into storage.
func (n *layer) PutObjectTagging(ctx context.Context, p *PutTaggingParams) error {
bktInfo := &data.BucketInfo{
Name: p.ObjectInfo.Bucket,
CID: p.ObjectInfo.CID,
Owner: p.ObjectInfo.Owner,
}
s := &PutSystemObjectParams{
BktInfo: bktInfo,
ObjName: p.ObjectInfo.TagsObject(),
Metadata: p.TagSet,
Prefix: tagPrefix,
Reader: nil,
}
_, err := n.PutSystemObject(ctx, s)
return err
}
// PutBucketTagging into storage.
func (n *layer) PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo, tagSet map[string]string) error {
s := &PutSystemObjectParams{
BktInfo: bktInfo,
ObjName: formBucketTagObjectName(bktInfo.Name),
Metadata: tagSet,
Prefix: tagPrefix,
Reader: nil,
}
_, err := n.PutSystemObject(ctx, s)
return err
}
// DeleteObjectTagging from storage.
func (n *layer) DeleteObjectTagging(ctx context.Context, bktInfo *data.BucketInfo, objInfo *data.ObjectInfo) error {
return n.DeleteSystemObject(ctx, bktInfo, objInfo.TagsObject())
}
// DeleteBucketTagging from storage.
func (n *layer) DeleteBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) error {
return n.DeleteSystemObject(ctx, bktInfo, formBucketTagObjectName(bktInfo.Name))
}
// CopyObject from one bucket into another bucket.
func (n *layer) CopyObject(ctx context.Context, p *CopyObjectParams) (*data.ObjectInfo, error) {
pr, pw := io.Pipe()
@ -618,7 +527,12 @@ func (n *layer) removeVersionIfFound(ctx context.Context, bkt *data.BucketInfo,
return deleteMarkVersion, err
}
return deleteMarkVersion, n.DeleteObjectTagging(ctx, bkt, &data.ObjectInfo{ID: version.OID, Bucket: bkt.Name, Name: obj.Name})
p := &data.ObjectTaggingInfo{
CnrID: &bkt.CID,
ObjName: obj.Name,
VersionID: version.OID.EncodeToString(),
}
return deleteMarkVersion, n.DeleteObjectTagging(ctx, p)
}
return "", errors.GetAPIError(errors.ErrNoSuchVersion)

169
api/layer/tagging.go Normal file
View file

@ -0,0 +1,169 @@
package layer
import (
"context"
errorsStd "errors"
"strings"
"go.uber.org/zap"
"github.com/nspcc-dev/neofs-s3-gw/api/data"
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
)
func (n *layer) GetObjectTagging(ctx context.Context, p *data.ObjectTaggingInfo) (map[string]string, error) {
var (
err error
tags map[string]string
)
tags = n.systemCache.GetObjectTagging(objectTaggingCacheKey(p))
if tags != nil {
return tags, nil
}
version, err := n.getTaggedObjectVersion(ctx, p)
if err != nil {
return nil, err
}
tags, err = n.treeService.GetObjectTagging(ctx, p.CnrID, version)
if err != nil {
if errorsStd.Is(err, ErrNodeNotFound) {
return nil, errors.GetAPIError(errors.ErrNoSuchKey)
}
return nil, err
}
if err = n.systemCache.PutObjectTagging(objectTaggingCacheKey(p), tags); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
return tags, nil
}
func (n *layer) PutObjectTagging(ctx context.Context, p *data.ObjectTaggingInfo, tagSet map[string]string) error {
version, err := n.getTaggedObjectVersion(ctx, p)
if err != nil {
return err
}
err = n.treeService.PutObjectTagging(ctx, p.CnrID, version, tagSet)
if err != nil {
if errorsStd.Is(err, ErrNodeNotFound) {
return errors.GetAPIError(errors.ErrNoSuchKey)
}
return err
}
if err = n.systemCache.PutObjectTagging(objectTaggingCacheKey(p), tagSet); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
return nil
}
func (n *layer) DeleteObjectTagging(ctx context.Context, p *data.ObjectTaggingInfo) error {
version, err := n.getTaggedObjectVersion(ctx, p)
if err != nil {
return err
}
err = n.treeService.DeleteObjectTagging(ctx, p.CnrID, version)
if err != nil {
if errorsStd.Is(err, ErrNodeNotFound) {
return errors.GetAPIError(errors.ErrNoSuchKey)
}
return err
}
n.systemCache.Delete(objectTaggingCacheKey(p))
return nil
}
func (n *layer) GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) (map[string]string, error) {
objInfo, err := n.HeadSystemObject(ctx, bktInfo, formBucketTagObjectName(bktInfo.Name))
if err != nil && !errors.IsS3Error(err, errors.ErrNoSuchKey) {
return nil, err
}
return formTagSet(objInfo), nil
}
func (n *layer) PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo, tagSet map[string]string) error {
s := &PutSystemObjectParams{
BktInfo: bktInfo,
ObjName: formBucketTagObjectName(bktInfo.Name),
Metadata: tagSet,
Prefix: tagPrefix,
Reader: nil,
}
_, err := n.PutSystemObject(ctx, s)
return err
}
func (n *layer) DeleteBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) error {
return n.DeleteSystemObject(ctx, bktInfo, formBucketTagObjectName(bktInfo.Name))
}
func formTagSet(objInfo *data.ObjectInfo) map[string]string {
var tagSet map[string]string
if objInfo != nil {
tagSet = make(map[string]string, len(objInfo.Headers))
for k, v := range objInfo.Headers {
if strings.HasPrefix(k, tagPrefix) {
if v == tagEmptyMark {
v = ""
}
tagSet[strings.TrimPrefix(k, tagPrefix)] = v
}
}
}
return tagSet
}
func objectTaggingCacheKey(p *data.ObjectTaggingInfo) string {
return ".tagset." + p.CnrID.EncodeToString() + "." + p.ObjName + "." + p.VersionID
}
func (n *layer) getTaggedObjectVersion(ctx context.Context, p *data.ObjectTaggingInfo) (*data.NodeVersion, error) {
var (
err error
version *data.NodeVersion
)
if p.VersionID == "null" {
if version, err = n.treeService.GetUnversioned(ctx, p.CnrID, p.ObjName); err != nil {
if strings.Contains(err.Error(), "not found") {
return nil, errors.GetAPIError(errors.ErrNoSuchKey)
}
return nil, err
}
} else if len(p.VersionID) == 0 {
if version, err = n.treeService.GetLatestVersion(ctx, p.CnrID, p.ObjName); err != nil {
if strings.Contains(err.Error(), "not found") {
return nil, errors.GetAPIError(errors.ErrNoSuchKey)
}
return nil, err
}
} else {
versions, err := n.treeService.GetVersions(ctx, p.CnrID, p.ObjName)
if err != nil {
return nil, err
}
for _, v := range versions {
if v.OID.EncodeToString() == p.VersionID {
version = v
break
}
}
}
if version == nil || version.DeleteMarker != nil {
return nil, errors.GetAPIError(errors.ErrNoSuchKey)
}
return version, nil
}

View file

@ -30,6 +30,10 @@ type TreeService interface {
// 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)
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
DeleteObjectTagging(ctx context.Context, cnrID *cid.ID, objVersion *data.NodeVersion) error
GetVersions(ctx context.Context, cnrID *cid.ID, objectName string) ([]*data.NodeVersion, error)
GetLatestVersion(ctx context.Context, cnrID *cid.ID, objectName string) (*data.NodeVersion, error)
GetLatestVersionsByPrefix(ctx context.Context, cnrID *cid.ID, prefix string) ([]oid.ID, error)

View file

@ -44,6 +44,7 @@ const (
fileNameKV = "FileName"
systemNameKV = "SystemName"
isUnversionedKV = "IsUnversioned"
isTagKV = "isTag"
// keys for delete marker nodes
isDeleteMarkerKV = "IdDeleteMarker"
@ -274,6 +275,75 @@ func (c *TreeClient) DeleteBucketCORS(ctx context.Context, cnrID *cid.ID) (*oid.
return nil, nil
}
func (c *TreeClient) GetObjectTagging(ctx context.Context, cnrID *cid.ID, objVersion *data.NodeVersion) (map[string]string, error) {
tagNode, err := c.getObjectTaggingNode(ctx, cnrID, objVersion)
if err != nil {
return nil, err
}
if tagNode == nil {
return nil, nil
}
delete(tagNode.Meta, isTagKV)
return tagNode.Meta, nil
}
func (c *TreeClient) PutObjectTagging(ctx context.Context, cnrID *cid.ID, objVersion *data.NodeVersion, tagSet map[string]string) error {
tagNode, err := c.getObjectTaggingNode(ctx, cnrID, objVersion)
if err != nil {
return err
}
tagSet[isTagKV] = "true"
if tagNode == nil {
_, err = c.addNode(ctx, cnrID, versionTree, objVersion.ID, tagSet)
} else {
err = c.moveNode(ctx, cnrID, versionTree, tagNode.ID, objVersion.ID, tagSet)
}
delete(tagSet, isTagKV)
return err
}
func (c *TreeClient) DeleteObjectTagging(ctx context.Context, cnrID *cid.ID, objVersion *data.NodeVersion) error {
tagNode, err := c.getObjectTaggingNode(ctx, cnrID, objVersion)
if err != nil {
return err
}
if tagNode == nil {
return nil
}
return c.removeNode(ctx, cnrID, versionTree, tagNode.ID)
}
func (c *TreeClient) getObjectTaggingNode(ctx context.Context, cnrID *cid.ID, objVersion *data.NodeVersion) (*TreeNode, error) {
subtree, err := c.getSubTree(ctx, cnrID, versionTree, objVersion.ID, 1)
if err != nil {
return nil, err
}
var tagNode *TreeNode
for _, s := range subtree {
node, err := newTreeNode(s)
if err != nil {
return nil, err
}
if _, ok := node.Get(isTagKV); ok {
tagNode = node
break
}
}
return tagNode, nil
}
func (c *TreeClient) GetVersions(ctx context.Context, cnrID *cid.ID, filepath string) ([]*data.NodeVersion, error) {
return c.getVersions(ctx, cnrID, versionTree, filepath, false)
}

View file

@ -17,6 +17,21 @@ type TreeServiceMock struct {
system map[string]map[string]*data.BaseNodeVersion
}
func (t *TreeServiceMock) GetObjectTagging(ctx context.Context, cnrID *cid.ID, objVersion *data.NodeVersion) (map[string]string, error) {
//TODO implement me
panic("implement me")
}
func (t *TreeServiceMock) PutObjectTagging(ctx context.Context, cnrID *cid.ID, objVersion *data.NodeVersion, tagSet map[string]string) error {
//TODO implement me
panic("implement me")
}
func (t *TreeServiceMock) DeleteObjectTagging(ctx context.Context, cnrID *cid.ID, objVersion *data.NodeVersion) error {
//TODO implement me
panic("implement me")
}
var ErrNodeNotFound = errors.New("not found")
func NewTreeService() *TreeServiceMock {
@ -205,3 +220,18 @@ func (t *TreeServiceMock) RemoveSystemVersion(ctx context.Context, cnrID *cid.ID
func (t *TreeServiceMock) GetAllVersionsByPrefix(ctx context.Context, cnrID *cid.ID, prefix string) ([]*data.NodeVersion, error) {
panic("implement me")
}
func (t *TreeServiceMock) GetObjectTagging(ctx context.Context, p *data.ObjectTaggingInfo) (map[string]string, error) {
//TODO implement me
panic("implement me")
}
func (t *TreeServiceMock) PutObjectTagging(ctx context.Context, p *data.ObjectTaggingInfo) error {
//TODO implement me
panic("implement me")
}
func (t *TreeServiceMock) DeleteObjectTagging(ctx context.Context, p *data.ObjectTaggingInfo) error {
//TODO implement me
panic("implement me")
}