From a6bc8208aecacfa9093eef0c7a2918c769a160c3 Mon Sep 17 00:00:00 2001 From: Nikita Zinkevich Date: Mon, 2 Dec 2024 11:45:30 +0300 Subject: [PATCH] [#166] Fix getting s3 object with the FrostFS OID name Prioritize getting s3 object with the key, which equals to valid FrostFS OID, rather than getting non-existent object with OID via native protocol for GET and HEAD requests Signed-off-by: Nikita Zinkevich --- cmd/http-gw/app.go | 4 +- internal/api/layer/tree_service.go | 22 --- internal/data/{bucket.go => info.go} | 0 internal/{api => data}/tree.go | 9 +- internal/handler/download.go | 49 +++++-- internal/handler/handler.go | 135 +++++------------- internal/handler/handler_test.go | 32 +++-- internal/handler/head.go | 34 ++++- internal/handler/utils.go | 11 +- internal/layer/tree_service.go | 16 +++ internal/logs/logs.go | 5 + .../{pool_wrapper.go => tree_pool_wrapper.go} | 22 +-- tree/tree.go | 35 ++--- 13 files changed, 173 insertions(+), 201 deletions(-) delete mode 100644 internal/api/layer/tree_service.go rename internal/data/{bucket.go => info.go} (100%) rename internal/{api => data}/tree.go (75%) create mode 100644 internal/layer/tree_service.go rename internal/service/frostfs/{pool_wrapper.go => tree_pool_wrapper.go} (89%) diff --git a/cmd/http-gw/app.go b/cmd/http-gw/app.go index 6ac9b1c..d52fad1 100644 --- a/cmd/http-gw/app.go +++ b/cmd/http-gw/app.go @@ -499,10 +499,10 @@ func (a *app) Serve() { close(a.webDone) }() - handler := handler.New(a.AppParams(), a.settings, tree.NewTree(frostfs.NewPoolWrapper(a.treePool)), workerPool) + handle := handler.New(a.AppParams(), a.settings, tree.NewTree(frostfs.NewPoolWrapper(a.treePool)), workerPool) // Configure router. - a.configureRouter(handler) + a.configureRouter(handle) a.startServices() a.initServers(a.ctx) diff --git a/internal/api/layer/tree_service.go b/internal/api/layer/tree_service.go deleted file mode 100644 index beb1e7a..0000000 --- a/internal/api/layer/tree_service.go +++ /dev/null @@ -1,22 +0,0 @@ -package layer - -import ( - "context" - "errors" - - "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/api" - cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" -) - -// TreeService provide interface to interact with tree service using s3 data models. -type TreeService interface { - GetLatestVersion(ctx context.Context, cnrID *cid.ID, objectName string) (*api.NodeVersion, error) -} - -var ( - // ErrNodeNotFound is returned from Tree service in case of not found error. - ErrNodeNotFound = errors.New("not found") - - // ErrNodeAccessDenied is returned from Tree service in case of access denied error. - ErrNodeAccessDenied = errors.New("access denied") -) diff --git a/internal/data/bucket.go b/internal/data/info.go similarity index 100% rename from internal/data/bucket.go rename to internal/data/info.go diff --git a/internal/api/tree.go b/internal/data/tree.go similarity index 75% rename from internal/api/tree.go rename to internal/data/tree.go index 5b1d608..ef20904 100644 --- a/internal/api/tree.go +++ b/internal/data/tree.go @@ -1,4 +1,4 @@ -package api +package data import ( oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" @@ -7,12 +7,13 @@ import ( // NodeVersion represent node from tree service. type NodeVersion struct { BaseNodeVersion - DeleteMarker bool - IsPrefixNode bool + IsUnversioned bool } // BaseNodeVersion is minimal node info from tree service. // Basically used for "system" object. type BaseNodeVersion struct { - OID oid.ID + ID uint64 + OID oid.ID + IsDeleteMarker bool } diff --git a/internal/handler/download.go b/internal/handler/download.go index cd4e55a..5b016fd 100644 --- a/internal/handler/download.go +++ b/internal/handler/download.go @@ -4,6 +4,7 @@ import ( "archive/zip" "bufio" "context" + "errors" "fmt" "io" "net/http" @@ -17,27 +18,53 @@ import ( cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree" "github.com/valyala/fasthttp" "go.uber.org/zap" ) // DownloadByAddressOrBucketName handles download requests using simple cid/oid or bucketname/key format. func (h *Handler) DownloadByAddressOrBucketName(c *fasthttp.RequestCtx) { - oidURLParam := c.UserValue("oid").(string) - downloadQueryParam := c.QueryArgs().GetBool("download") + cidParam := c.UserValue("cid").(string) + oidParam := c.UserValue("oid").(string) + downloadParam := c.QueryArgs().GetBool("download") - switch { - case isObjectID(oidURLParam): - h.byNativeAddress(c, h.receiveFile) - case !isContainerRoot(oidURLParam) && (downloadQueryParam || !isDir(oidURLParam)): - h.byS3Path(c, h.receiveFile) - default: - h.browseIndex(c) + ctx := utils.GetContextFromRequest(c) + log := utils.GetReqLogOrDefault(ctx, h.log).With( + zap.String("cid", cidParam), + zap.String("oid", oidParam), + ) + + bktInfo, err := h.getBucketInfo(ctx, cidParam, log) + if err != nil { + logAndSendBucketError(c, log, err) + return + } + + checkS3Err := h.tree.CheckSettingsNodeExists(ctx, bktInfo) + if checkS3Err != nil && !errors.Is(checkS3Err, tree.ErrNodeNotFound) { + logAndSendBucketError(c, log, checkS3Err) + return + } + + req := h.newRequest(c, log) + + var objID oid.ID + if checkS3Err == nil && shouldDownload(oidParam, downloadParam) { + h.byS3Path(ctx, req, bktInfo.CID, oidParam, h.receiveFile) + } else if err = objID.DecodeString(oidParam); err == nil { + h.byNativeAddress(ctx, req, bktInfo.CID, objID, h.receiveFile) + } else { + h.browseIndex(c, checkS3Err != nil) } } -func (h *Handler) newRequest(ctx *fasthttp.RequestCtx, log *zap.Logger) *request { - return &request{ +func shouldDownload(oidParam string, downloadParam bool) bool { + return !isDir(oidParam) || downloadParam +} + +func (h *Handler) newRequest(ctx *fasthttp.RequestCtx, log *zap.Logger) request { + return request{ RequestCtx: ctx, log: log, } diff --git a/internal/handler/handler.go b/internal/handler/handler.go index 9ed7f99..e6c32da 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -6,14 +6,13 @@ import ( "fmt" "io" "net/url" - "strings" "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/cache" "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/data" "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/handler/middleware" + "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/layer" "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/logs" "git.frostfs.info/TrueCloudLab/frostfs-http-gw/response" - "git.frostfs.info/TrueCloudLab/frostfs-http-gw/tree" "git.frostfs.info/TrueCloudLab/frostfs-http-gw/utils" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" @@ -21,6 +20,7 @@ import ( cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" "github.com/panjf2000/ants/v2" "github.com/valyala/fasthttp" @@ -164,7 +164,7 @@ type Handler struct { ownerID *user.ID config Config containerResolver ContainerResolver - tree *tree.Tree + tree layer.TreeService cache *cache.BucketCache workerPool *ants.Pool } @@ -177,7 +177,7 @@ type AppParams struct { Cache *cache.BucketCache } -func New(params *AppParams, config Config, tree *tree.Tree, workerPool *ants.Pool) *Handler { +func New(params *AppParams, config Config, tree layer.TreeService, workerPool *ants.Pool) *Handler { return &Handler{ log: params.Logger, frostfs: params.FrostFS, @@ -190,79 +190,45 @@ func New(params *AppParams, config Config, tree *tree.Tree, workerPool *ants.Poo } } -// byNativeAddress is a wrapper for function (e.g. request.headObject, request.receiveFile) that -// prepares request and object address to it. -func (h *Handler) byNativeAddress(c *fasthttp.RequestCtx, f func(context.Context, request, oid.Address)) { - idCnr, _ := c.UserValue("cid").(string) - idObj, _ := url.PathUnescape(c.UserValue("oid").(string)) - - ctx := utils.GetContextFromRequest(c) - reqLog := utils.GetReqLogOrDefault(ctx, h.log) - log := reqLog.With(zap.String("cid", idCnr), zap.String("oid", idObj)) - - bktInfo, err := h.getBucketInfo(ctx, idCnr, log) +// resolveContainer decode container id, if it's not a valid container id +// then trey to resolve name using provided resolver. +func (h *Handler) resolveContainer(ctx context.Context, containerID string) (*cid.ID, error) { + cnrID := new(cid.ID) + err := cnrID.DecodeString(containerID) if err != nil { - logAndSendBucketError(c, log, err) - return + cnrID, err = h.containerResolver.Resolve(ctx, containerID) + if err != nil && !errors.Is(err, tree.ErrNodeNotFound) { + err = fmt.Errorf("%w: %s", new(apistatus.ContainerNotFound), err.Error()) + } } - - objID := new(oid.ID) - if err = objID.DecodeString(idObj); err != nil { - log.Error(logs.WrongObjectID, zap.Error(err)) - response.Error(c, "wrong object id", fasthttp.StatusBadRequest) - return - } - - addr := newAddress(bktInfo.CID, *objID) - - f(ctx, *h.newRequest(c, log), addr) + return cnrID, err } -// byS3Path is a wrapper for function (e.g. request.headObject, request.receiveFile) that -// resolves object address from S3-like path /. -func (h *Handler) byS3Path(c *fasthttp.RequestCtx, f func(context.Context, request, oid.Address)) { - bucketname := c.UserValue("cid").(string) - key := c.UserValue("oid").(string) +func (h *Handler) byS3Path(ctx context.Context, req request, cnrID cid.ID, path string, handler func(context.Context, request, oid.Address)) { + c, log := req.RequestCtx, req.log - ctx := utils.GetContextFromRequest(c) - reqLog := utils.GetReqLogOrDefault(ctx, h.log) - log := reqLog.With(zap.String("bucketname", bucketname), zap.String("key", key)) - - unescapedKey, err := url.QueryUnescape(key) + foundOID, err := h.tree.GetLatestVersion(ctx, &cnrID, path) if err != nil { logAndSendBucketError(c, log, err) return } - - bktInfo, err := h.getBucketInfo(ctx, bucketname, log) - if err != nil { - logAndSendBucketError(c, log, err) - return - } - - foundOid, err := h.tree.GetLatestVersion(ctx, &bktInfo.CID, unescapedKey) - if err != nil { - if errors.Is(err, tree.ErrNodeAccessDenied) { - response.Error(c, "Access Denied", fasthttp.StatusForbidden) - } else { - response.Error(c, "object wasn't found", fasthttp.StatusNotFound) - log.Error(logs.GetLatestObjectVersion, zap.Error(err)) - } - return - } - if foundOid.DeleteMarker { + if foundOID.IsDeleteMarker { log.Error(logs.ObjectWasDeleted) response.Error(c, "object deleted", fasthttp.StatusNotFound) return } - addr := newAddress(bktInfo.CID, foundOid.OID) - f(ctx, *h.newRequest(c, log), addr) + addr := newAddress(cnrID, foundOID.OID) + handler(ctx, h.newRequest(c, log), addr) } -// byAttribute is a wrapper similar to byNativeAddress. -func (h *Handler) byAttribute(c *fasthttp.RequestCtx, f func(context.Context, request, oid.Address)) { - scid, _ := c.UserValue("cid").(string) +func (h *Handler) byNativeAddress(ctx context.Context, req request, cnrID cid.ID, objID oid.ID, handler func(context.Context, request, oid.Address)) { + addr := newAddress(cnrID, objID) + handler(ctx, req, addr) +} + +func (h *Handler) byAttribute(c *fasthttp.RequestCtx, handler func(context.Context, request, oid.Address)) { + cidParam, _ := c.UserValue("cid").(string) key, _ := c.UserValue("attr_key").(string) val, _ := c.UserValue("attr_val").(string) @@ -271,21 +237,21 @@ func (h *Handler) byAttribute(c *fasthttp.RequestCtx, f func(context.Context, re key, err := url.QueryUnescape(key) if err != nil { - log.Error(logs.FailedToUnescapeQuery, zap.String("cid", scid), zap.String("attr_key", key), zap.Error(err)) + log.Error(logs.FailedToUnescapeQuery, zap.String("cid", cidParam), zap.String("attr_key", key), zap.Error(err)) response.Error(c, "could not unescape attr_key: "+err.Error(), fasthttp.StatusBadRequest) return } val, err = url.QueryUnescape(val) if err != nil { - log.Error(logs.FailedToUnescapeQuery, zap.String("cid", scid), zap.String("attr_val", val), zap.Error(err)) + log.Error(logs.FailedToUnescapeQuery, zap.String("cid", cidParam), zap.String("attr_val", val), zap.Error(err)) response.Error(c, "could not unescape attr_val: "+err.Error(), fasthttp.StatusBadRequest) return } - log = log.With(zap.String("cid", scid), zap.String("attr_key", key), zap.String("attr_val", val)) + log = log.With(zap.String("cid", cidParam), zap.String("attr_key", key), zap.String("attr_val", val)) - bktInfo, err := h.getBucketInfo(ctx, scid, log) + bktInfo, err := h.getBucketInfo(ctx, cidParam, log) if err != nil { logAndSendBucketError(c, log, err) return @@ -315,25 +281,11 @@ func (h *Handler) byAttribute(c *fasthttp.RequestCtx, f func(context.Context, re return } - var addrObj oid.Address - addrObj.SetContainer(bktInfo.CID) - addrObj.SetObject(buf[0]) + var addr oid.Address + addr.SetContainer(bktInfo.CID) + addr.SetObject(buf[0]) - f(ctx, *h.newRequest(c, log), addrObj) -} - -// resolveContainer decode container id, if it's not a valid container id -// then trey to resolve name using provided resolver. -func (h *Handler) resolveContainer(ctx context.Context, containerID string) (*cid.ID, error) { - cnrID := new(cid.ID) - err := cnrID.DecodeString(containerID) - if err != nil { - cnrID, err = h.containerResolver.Resolve(ctx, containerID) - if err != nil && strings.Contains(err.Error(), "not found") { - err = fmt.Errorf("%w: %s", new(apistatus.ContainerNotFound), err.Error()) - } - } - return cnrID, err + handler(ctx, h.newRequest(c, log), addr) } func (h *Handler) getBucketInfo(ctx context.Context, containerName string, log *zap.Logger) (*data.BucketInfo, error) { @@ -388,7 +340,7 @@ func (h *Handler) readContainer(ctx context.Context, cnrID cid.ID) (*data.Bucket return bktInfo, err } -func (h *Handler) browseIndex(c *fasthttp.RequestCtx) { +func (h *Handler) browseIndex(c *fasthttp.RequestCtx, isNativeList bool) { if !h.config.IndexPageEnabled() { c.SetStatusCode(fasthttp.StatusNotFound) return @@ -414,18 +366,9 @@ func (h *Handler) browseIndex(c *fasthttp.RequestCtx) { } listFunc := h.getDirObjectsS3 - isNativeList := false - - err = h.tree.CheckSettingsNodeExist(ctx, bktInfo) - if err != nil { - if errors.Is(err, tree.ErrNodeNotFound) { - // tree probe failed, try to use native - listFunc = h.getDirObjectsNative - isNativeList = true - } else { - logAndSendBucketError(c, log, err) - return - } + if isNativeList { + // tree probe failed, trying to use native + listFunc = h.getDirObjectsNative } h.browseObjects(c, browseParams{ diff --git a/internal/handler/handler_test.go b/internal/handler/handler_test.go index 34668a5..fae1f55 100644 --- a/internal/handler/handler_test.go +++ b/internal/handler/handler_test.go @@ -24,6 +24,7 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" + treepool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/panjf2000/ants/v2" @@ -32,14 +33,29 @@ import ( "go.uber.org/zap" ) -type treeClientMock struct { +type treeServiceMock struct { + system map[string]map[string]*data.BaseNodeVersion } -func (t *treeClientMock) GetNodes(context.Context, *tree.GetNodesParams) ([]tree.NodeResponse, error) { - return nil, nil +func newTreeService() *treeServiceMock { + return &treeServiceMock{ + system: make(map[string]map[string]*data.BaseNodeVersion), + } } -func (t *treeClientMock) GetSubTree(context.Context, *data.BucketInfo, string, []uint64, uint32, bool) ([]tree.NodeResponse, error) { +func (t *treeServiceMock) CheckSettingsNodeExists(context.Context, *data.BucketInfo) error { + _, ok := t.system["bucket-settings"] + if !ok { + return treepool.ErrNodeNotFound + } + return nil +} + +func (t *treeServiceMock) GetSubTreeByPrefix(context.Context, *data.BucketInfo, string, bool) ([]tree.NodeResponse, string, error) { + return nil, "", nil +} + +func (t *treeServiceMock) GetLatestVersion(context.Context, *cid.ID, string) (*data.NodeVersion, error) { return nil, nil } @@ -84,7 +100,7 @@ type handlerContext struct { h *Handler frostfs *TestFrostFS - tree *treeClientMock + tree *treeServiceMock cfg *configMock } @@ -125,14 +141,14 @@ func prepareHandlerContext() (*handlerContext, error) { }), } - treeMock := &treeClientMock{} + treeMock := newTreeService() cfgMock := &configMock{} - workerPool, err := ants.NewPool(1000) + workerPool, err := ants.NewPool(1) if err != nil { return nil, err } - handler := New(params, cfgMock, tree.NewTree(treeMock), workerPool) + handler := New(params, cfgMock, treeMock, workerPool) return &handlerContext{ key: key, diff --git a/internal/handler/head.go b/internal/handler/head.go index ccd6a91..6ca8eab 100644 --- a/internal/handler/head.go +++ b/internal/handler/head.go @@ -2,6 +2,7 @@ package handler import ( "context" + "errors" "io" "net/http" "strconv" @@ -11,6 +12,7 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-http-gw/utils" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree" "github.com/valyala/fasthttp" "go.uber.org/zap" ) @@ -102,14 +104,36 @@ func idsToResponse(resp *fasthttp.Response, obj *object.Object) { // HeadByAddressOrBucketName handles head requests using simple cid/oid or bucketname/key format. func (h *Handler) HeadByAddressOrBucketName(c *fasthttp.RequestCtx) { - test, _ := c.UserValue("oid").(string) - var id oid.ID + cidParam, _ := c.UserValue("cid").(string) + oidParam, _ := c.UserValue("oid").(string) - err := id.DecodeString(test) + ctx := utils.GetContextFromRequest(c) + log := utils.GetReqLogOrDefault(ctx, h.log).With( + zap.String("cid", cidParam), + zap.String("oid", oidParam), + ) + + bktInfo, err := h.getBucketInfo(ctx, cidParam, log) if err != nil { - h.byS3Path(c, h.headObject) + logAndSendBucketError(c, log, err) + return + } + checkS3Err := h.tree.CheckSettingsNodeExists(ctx, bktInfo) + if checkS3Err != nil && !errors.Is(checkS3Err, tree.ErrNodeNotFound) { + logAndSendBucketError(c, log, checkS3Err) + return + } + + req := h.newRequest(c, log) + + var objID oid.ID + if checkS3Err == nil { + h.byS3Path(ctx, req, bktInfo.CID, oidParam, h.headObject) + } else if err = objID.DecodeString(oidParam); err == nil { + h.byNativeAddress(ctx, req, bktInfo.CID, objID, h.headObject) } else { - h.byNativeAddress(c, h.headObject) + logAndSendBucketError(c, log, checkS3Err) + return } } diff --git a/internal/handler/utils.go b/internal/handler/utils.go index b537d64..d09ed23 100644 --- a/internal/handler/utils.go +++ b/internal/handler/utils.go @@ -42,16 +42,7 @@ func bearerToken(ctx context.Context) *bearer.Token { } func isDir(name string) bool { - return strings.HasSuffix(name, "/") -} - -func isObjectID(s string) bool { - var objID oid.ID - return objID.DecodeString(s) == nil -} - -func isContainerRoot(key string) bool { - return key == "" + return name == "" || strings.HasSuffix(name, "/") } func loadAttributes(attrs []object.Attribute) map[string]string { diff --git a/internal/layer/tree_service.go b/internal/layer/tree_service.go new file mode 100644 index 0000000..11d2c5d --- /dev/null +++ b/internal/layer/tree_service.go @@ -0,0 +1,16 @@ +package layer + +import ( + "context" + + "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/data" + "git.frostfs.info/TrueCloudLab/frostfs-http-gw/tree" + cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" +) + +// TreeService provide interface to interact with tree service using s3 data models. +type TreeService interface { + GetLatestVersion(ctx context.Context, cnrID *cid.ID, objectName string) (*data.NodeVersion, error) + GetSubTreeByPrefix(ctx context.Context, bktInfo *data.BucketInfo, prefix string, latestOnly bool) ([]tree.NodeResponse, string, error) + CheckSettingsNodeExists(ctx context.Context, bktInfo *data.BucketInfo) error +} diff --git a/internal/logs/logs.go b/internal/logs/logs.go index 4dfa21f..5ba321d 100644 --- a/internal/logs/logs.go +++ b/internal/logs/logs.go @@ -79,6 +79,11 @@ const ( InvalidLifetimeUsingDefaultValue = "invalid lifetime, using default value (in seconds)" // Error in ../../cmd/http-gw/settings.go InvalidCacheSizeUsingDefaultValue = "invalid cache size, using default value" // Error in ../../cmd/http-gw/settings.go FailedToUnescapeQuery = "failed to unescape query" + FailedToParseAddressInTreeNode = "failed to parse object addr in tree node" + SettingsNodeInvalidOwnerKey = "settings node: invalid owner key" + SystemNodeHasMultipleIDs = "system node has multiple ids" + FailedToRemoveOldSystemNode = "failed to remove old system node" + BucketSettingsNodeHasMultipleIDs = "bucket settings node has multiple ids" ServerReconnecting = "reconnecting server..." ServerReconnectedSuccessfully = "server reconnected successfully" ServerReconnectFailed = "failed to reconnect server" diff --git a/internal/service/frostfs/pool_wrapper.go b/internal/service/frostfs/tree_pool_wrapper.go similarity index 89% rename from internal/service/frostfs/pool_wrapper.go rename to internal/service/frostfs/tree_pool_wrapper.go index b978d73..56d428e 100644 --- a/internal/service/frostfs/pool_wrapper.go +++ b/internal/service/frostfs/tree_pool_wrapper.go @@ -2,8 +2,6 @@ package frostfs import ( "context" - "errors" - "fmt" "io" "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/data" @@ -59,7 +57,7 @@ func (w *PoolWrapper) GetNodes(ctx context.Context, prm *tree.GetNodesParams) ([ nodes, err := w.p.GetNodes(ctx, poolPrm) if err != nil { - return nil, handleError(err) + return nil, err } res := make([]tree.NodeResponse, len(nodes)) @@ -78,20 +76,6 @@ func getBearer(ctx context.Context) []byte { return token.Marshal() } -func handleError(err error) error { - if err == nil { - return nil - } - if errors.Is(err, treepool.ErrNodeNotFound) { - return fmt.Errorf("%w: %s", tree.ErrNodeNotFound, err.Error()) - } - if errors.Is(err, treepool.ErrNodeAccessDenied) { - return fmt.Errorf("%w: %s", tree.ErrNodeAccessDenied, err.Error()) - } - - return err -} - func (w *PoolWrapper) GetSubTree(ctx context.Context, bktInfo *data.BucketInfo, treeID string, rootID []uint64, depth uint32, sort bool) ([]tree.NodeResponse, error) { order := treepool.NoneOrder if sort { @@ -115,7 +99,7 @@ func (w *PoolWrapper) GetSubTree(ctx context.Context, bktInfo *data.BucketInfo, subTreeReader, err := w.p.GetSubTree(ctx, poolPrm) if err != nil { - return nil, handleError(err) + return nil, err } var subtree []tree.NodeResponse @@ -126,7 +110,7 @@ func (w *PoolWrapper) GetSubTree(ctx context.Context, bktInfo *data.BucketInfo, node, err = subTreeReader.Next() } if err != io.EOF { - return nil, handleError(err) + return nil, err } return subtree, nil diff --git a/tree/tree.go b/tree/tree.go index 40209a5..19fc121 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -6,11 +6,10 @@ import ( "fmt" "strings" - "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/api" - "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/api/layer" "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/data" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool/tree" ) type ( @@ -46,14 +45,6 @@ type ( } ) -var ( - // ErrNodeNotFound is returned from ServiceClient in case of not found error. - ErrNodeNotFound = layer.ErrNodeNotFound - - // ErrNodeAccessDenied is returned from ServiceClient service in case of access denied error. - ErrNodeAccessDenied = layer.ErrNodeAccessDenied -) - const ( FileNameKey = "FileName" settingsFileName = "bucket-settings" @@ -118,7 +109,7 @@ func (n *treeNode) FileName() (string, bool) { return value, ok } -func newNodeVersion(node NodeResponse) (*api.NodeVersion, error) { +func newNodeVersion(node NodeResponse) (*data.NodeVersion, error) { tNode, err := newTreeNode(node) if err != nil { return nil, fmt.Errorf("invalid tree node: %w", err) @@ -127,15 +118,11 @@ func newNodeVersion(node NodeResponse) (*api.NodeVersion, error) { return newNodeVersionFromTreeNode(tNode), nil } -func newNodeVersionFromTreeNode(treeNode *treeNode) *api.NodeVersion { - _, isDeleteMarker := treeNode.Get(isDeleteMarkerKV) - size, _ := treeNode.Get(sizeKV) - version := &api.NodeVersion{ - BaseNodeVersion: api.BaseNodeVersion{ +func newNodeVersionFromTreeNode(treeNode *treeNode) *data.NodeVersion { + version := &data.NodeVersion{ + BaseNodeVersion: data.BaseNodeVersion{ OID: treeNode.ObjID, }, - DeleteMarker: isDeleteMarker, - IsPrefixNode: size == "", } return version @@ -180,7 +167,7 @@ func (m *multiSystemNode) Old() []*treeNode { return m.nodes[1:] } -func (c *Tree) GetLatestVersion(ctx context.Context, cnrID *cid.ID, objectName string) (*api.NodeVersion, error) { +func (c *Tree) GetLatestVersion(ctx context.Context, cnrID *cid.ID, objectName string) (*data.NodeVersion, error) { nodes, err := c.GetVersions(ctx, cnrID, objectName) if err != nil { return nil, err @@ -210,7 +197,7 @@ func (c *Tree) GetVersions(ctx context.Context, cnrID *cid.ID, objectName string return c.service.GetNodes(ctx, p) } -func (c *Tree) CheckSettingsNodeExist(ctx context.Context, bktInfo *data.BucketInfo) error { +func (c *Tree) CheckSettingsNodeExists(ctx context.Context, bktInfo *data.BucketInfo) error { _, err := c.getSystemNode(ctx, bktInfo, settingsFileName) if err != nil { return err @@ -236,7 +223,7 @@ func (c *Tree) getSystemNode(ctx context.Context, bktInfo *data.BucketInfo, name nodes = filterMultipartNodes(nodes) if len(nodes) == 0 { - return nil, ErrNodeNotFound + return nil, tree.ErrNodeNotFound } return newMultiNode(nodes) @@ -277,7 +264,7 @@ func getLatestVersionNode(nodes []NodeResponse) (NodeResponse, error) { } if targetIndexNode == -1 { - return nil, layer.ErrNodeNotFound + return nil, tree.ErrNodeNotFound } return nodes[targetIndexNode], nil @@ -305,7 +292,7 @@ func (c *Tree) GetSubTreeByPrefix(ctx context.Context, bktInfo *data.BucketInfo, } subTree, err := c.service.GetSubTree(ctx, bktInfo, versionTree, rootID, 2, false) if err != nil { - if errors.Is(err, layer.ErrNodeNotFound) { + if errors.Is(err, tree.ErrNodeNotFound) { return nil, "", nil } return nil, "", err @@ -386,7 +373,7 @@ func (c *Tree) getPrefixNodeID(ctx context.Context, bktInfo *data.BucketInfo, tr } if len(intermediateNodes) == 0 { - return nil, layer.ErrNodeNotFound + return nil, tree.ErrNodeNotFound } return intermediateNodes, nil