Errors occurred while processing the request. Perhaps some objects are missing
@@ -57,11 +55,11 @@
- {{ $trimmedPrefix := trimPrefix $prefix }}
- {{if $trimmedPrefix }}
+ {{ $parentPrefix := getParent .Prefix }}
+ {{if $parentPrefix }}
- ⮐..
+ ⮐..
|
|
|
diff --git a/metrics/service.go b/metrics/service.go
index dea5ac0..e6b803b 100644
--- a/metrics/service.go
+++ b/metrics/service.go
@@ -25,24 +25,24 @@ type Config struct {
// Start runs http service with the exposed endpoint on the configured port.
func (ms *Service) Start() {
if ms.enabled {
- ms.log.Info(logs.ServiceIsRunning, zap.String("endpoint", ms.Addr))
+ ms.log.Info(logs.ServiceIsRunning, zap.String("endpoint", ms.Addr), logs.TagField(logs.TagApp))
err := ms.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
- ms.log.Warn(logs.ServiceCouldntStartOnConfiguredPort)
+ ms.log.Warn(logs.ServiceCouldntStartOnConfiguredPort, logs.TagField(logs.TagApp))
}
} else {
- ms.log.Info(logs.ServiceHasntStartedSinceItsDisabled)
+ ms.log.Info(logs.ServiceHasntStartedSinceItsDisabled, logs.TagField(logs.TagApp))
}
}
// ShutDown stops the service.
func (ms *Service) ShutDown(ctx context.Context) {
- ms.log.Info(logs.ShuttingDownService, zap.String("endpoint", ms.Addr))
+ ms.log.Info(logs.ShuttingDownService, zap.String("endpoint", ms.Addr), logs.TagField(logs.TagApp))
err := ms.Shutdown(ctx)
if err != nil {
- ms.log.Error(logs.CantGracefullyShutDownService, zap.Error(err))
+ ms.log.Error(logs.CantGracefullyShutDownService, zap.Error(err), logs.TagField(logs.TagApp))
if err = ms.Close(); err != nil {
- ms.log.Panic(logs.CantShutDownService, zap.Error(err))
+ ms.log.Panic(logs.CantShutDownService, zap.Error(err), logs.TagField(logs.TagApp))
}
}
}
diff --git a/resolver/resolver.go b/resolver/resolver.go
index e7615d4..6d7c5d5 100644
--- a/resolver/resolver.go
+++ b/resolver/resolver.go
@@ -6,7 +6,7 @@ import (
"fmt"
"sync"
- "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/handler/middleware"
+ v2container "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ns"
@@ -29,14 +29,9 @@ type FrostFS interface {
SystemDNS(context.Context) (string, error)
}
-type Settings interface {
- FormContainerZone(ns string) (zone string, isDefault bool)
-}
-
type Config struct {
FrostFS FrostFS
RPCAddress string
- Settings Settings
}
type ContainerResolver struct {
@@ -46,15 +41,15 @@ type ContainerResolver struct {
type Resolver struct {
Name string
- resolve func(context.Context, string) (*cid.ID, error)
+ resolve func(context.Context, string, string) (*cid.ID, error)
}
-func (r *Resolver) SetResolveFunc(fn func(context.Context, string) (*cid.ID, error)) {
+func (r *Resolver) SetResolveFunc(fn func(context.Context, string, string) (*cid.ID, error)) {
r.resolve = fn
}
-func (r *Resolver) Resolve(ctx context.Context, name string) (*cid.ID, error) {
- return r.resolve(ctx, name)
+func (r *Resolver) Resolve(ctx context.Context, zone, name string) (*cid.ID, error) {
+ return r.resolve(ctx, zone, name)
}
func NewContainerResolver(resolverNames []string, cfg *Config) (*ContainerResolver, error) {
@@ -81,13 +76,13 @@ func createResolvers(resolverNames []string, cfg *Config) ([]*Resolver, error) {
return resolvers, nil
}
-func (r *ContainerResolver) Resolve(ctx context.Context, cnrName string) (*cid.ID, error) {
+func (r *ContainerResolver) Resolve(ctx context.Context, cnrZone, cnrName string) (*cid.ID, error) {
r.mu.RLock()
defer r.mu.RUnlock()
var err error
for _, resolver := range r.resolvers {
- cnrID, resolverErr := resolver.Resolve(ctx, cnrName)
+ cnrID, resolverErr := resolver.Resolve(ctx, cnrZone, cnrName)
if resolverErr != nil {
resolverErr = fmt.Errorf("%s: %w", resolver.Name, resolverErr)
if err == nil {
@@ -141,34 +136,25 @@ func (r *ContainerResolver) equals(resolverNames []string) bool {
func newResolver(name string, cfg *Config) (*Resolver, error) {
switch name {
case DNSResolver:
- return NewDNSResolver(cfg.FrostFS, cfg.Settings)
+ return NewDNSResolver(cfg.FrostFS)
case NNSResolver:
- return NewNNSResolver(cfg.RPCAddress, cfg.Settings)
+ return NewNNSResolver(cfg.RPCAddress)
default:
return nil, fmt.Errorf("unknown resolver: %s", name)
}
}
-func NewDNSResolver(frostFS FrostFS, settings Settings) (*Resolver, error) {
+func NewDNSResolver(frostFS FrostFS) (*Resolver, error) {
if frostFS == nil {
return nil, fmt.Errorf("pool must not be nil for DNS resolver")
}
- if settings == nil {
- return nil, fmt.Errorf("resolver settings must not be nil for DNS resolver")
- }
var dns ns.DNS
- resolveFunc := func(ctx context.Context, name string) (*cid.ID, error) {
+ resolveFunc := func(ctx context.Context, zone, name string) (*cid.ID, error) {
var err error
- namespace, err := middleware.GetNamespace(ctx)
- if err != nil {
- return nil, err
- }
-
- zone, isDefault := settings.FormContainerZone(namespace)
- if isDefault {
+ if zone == v2container.SysAttributeZoneDefault {
zone, err = frostFS.SystemDNS(ctx)
if err != nil {
return nil, fmt.Errorf("read system DNS parameter of the FrostFS: %w", err)
@@ -190,13 +176,10 @@ func NewDNSResolver(frostFS FrostFS, settings Settings) (*Resolver, error) {
}, nil
}
-func NewNNSResolver(rpcAddress string, settings Settings) (*Resolver, error) {
+func NewNNSResolver(rpcAddress string) (*Resolver, error) {
if rpcAddress == "" {
return nil, fmt.Errorf("rpc address must not be empty for NNS resolver")
}
- if settings == nil {
- return nil, fmt.Errorf("resolver settings must not be nil for NNS resolver")
- }
var nns ns.NNS
@@ -204,16 +187,9 @@ func NewNNSResolver(rpcAddress string, settings Settings) (*Resolver, error) {
return nil, fmt.Errorf("could not dial nns: %w", err)
}
- resolveFunc := func(ctx context.Context, name string) (*cid.ID, error) {
+ resolveFunc := func(_ context.Context, zone, name string) (*cid.ID, error) {
var d container.Domain
d.SetName(name)
-
- namespace, err := middleware.GetNamespace(ctx)
- if err != nil {
- return nil, err
- }
-
- zone, _ := settings.FormContainerZone(namespace)
d.SetZone(zone)
cnrID, err := nns.ResolveContainerDomain(d)
diff --git a/response/utils.go b/response/utils.go
deleted file mode 100644
index f233943..0000000
--- a/response/utils.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package response
-
-import (
- "errors"
- "fmt"
-
- "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
- sdkstatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
- "github.com/valyala/fasthttp"
- "go.uber.org/zap"
-)
-
-func Error(r *fasthttp.RequestCtx, msg string, code int) {
- r.Error(msg+"\n", code)
-}
-
-func FormErrorResponse(message string, err error) (int, string, []zap.Field) {
- var (
- msg string
- statusCode int
- logFields []zap.Field
- )
-
- st := new(sdkstatus.ObjectAccessDenied)
-
- switch {
- case errors.As(err, &st):
- statusCode = fasthttp.StatusForbidden
- reason := st.Reason()
- msg = fmt.Sprintf("%s: %v: %s", message, err, reason)
- logFields = append(logFields, zap.String("error_detail", reason))
- case client.IsErrObjectNotFound(err) || client.IsErrContainerNotFound(err):
- statusCode = fasthttp.StatusNotFound
- msg = "Not Found"
- default:
- statusCode = fasthttp.StatusBadRequest
- msg = fmt.Sprintf("%s: %v", message, err)
- }
-
- return statusCode, msg, logFields
-}
diff --git a/tokens/bearer-token.go b/tokens/bearer-token.go
index 880a100..24ffcbe 100644
--- a/tokens/bearer-token.go
+++ b/tokens/bearer-token.go
@@ -82,14 +82,22 @@ func fetchBearerToken(ctx *fasthttp.RequestCtx) (*bearer.Token, error) {
tkn = new(bearer.Token)
)
for _, parse := range []fromHandler{BearerTokenFromHeader, BearerTokenFromCookie} {
- if buf = parse(&ctx.Request.Header); buf == nil {
+ buf = parse(&ctx.Request.Header)
+ if buf == nil {
continue
- } else if data, err := base64.StdEncoding.DecodeString(string(buf)); err != nil {
+ }
+
+ data, err := base64.StdEncoding.DecodeString(string(buf))
+ if err != nil {
lastErr = fmt.Errorf("can't base64-decode bearer token: %w", err)
continue
- } else if err = tkn.Unmarshal(data); err != nil {
- lastErr = fmt.Errorf("can't unmarshal bearer token: %w", err)
- continue
+ }
+
+ if err = tkn.Unmarshal(data); err != nil {
+ if err = tkn.UnmarshalJSON(data); err != nil {
+ lastErr = fmt.Errorf("can't unmarshal bearer token: %w", err)
+ continue
+ }
}
return tkn, nil
diff --git a/tokens/bearer-token_test.go b/tokens/bearer-token_test.go
index 6fb3bf4..60e9ea2 100644
--- a/tokens/bearer-token_test.go
+++ b/tokens/bearer-token_test.go
@@ -98,8 +98,14 @@ func TestFetchBearerToken(t *testing.T) {
tkn := new(bearer.Token)
tkn.ForUser(uid)
- t64 := base64.StdEncoding.EncodeToString(tkn.Marshal())
- require.NotEmpty(t, t64)
+ jsonToken, err := tkn.MarshalJSON()
+ require.NoError(t, err)
+
+ jsonTokenBase64 := base64.StdEncoding.EncodeToString(jsonToken)
+ binaryTokenBase64 := base64.StdEncoding.EncodeToString(tkn.Marshal())
+
+ require.NotEmpty(t, jsonTokenBase64)
+ require.NotEmpty(t, binaryTokenBase64)
cases := []struct {
name string
@@ -143,25 +149,47 @@ func TestFetchBearerToken(t *testing.T) {
error: "can't unmarshal bearer token",
},
{
- name: "bad header, but good cookie",
+ name: "bad header, but good cookie with binary token",
header: "dGVzdAo=",
- cookie: t64,
+ cookie: binaryTokenBase64,
expect: tkn,
},
{
- name: "bad cookie, but good header",
- header: t64,
+ name: "bad cookie, but good header with binary token",
+ header: binaryTokenBase64,
cookie: "dGVzdAo=",
expect: tkn,
},
{
- name: "ok for header",
- header: t64,
+ name: "bad header, but good cookie with json token",
+ header: "dGVzdAo=",
+ cookie: jsonTokenBase64,
expect: tkn,
},
{
- name: "ok for cookie",
- cookie: t64,
+ name: "bad cookie, but good header with json token",
+ header: jsonTokenBase64,
+ cookie: "dGVzdAo=",
+ expect: tkn,
+ },
+ {
+ name: "ok for header with binary token",
+ header: binaryTokenBase64,
+ expect: tkn,
+ },
+ {
+ name: "ok for cookie with binary token",
+ cookie: binaryTokenBase64,
+ expect: tkn,
+ },
+ {
+ name: "ok for header with json token",
+ header: jsonTokenBase64,
+ expect: tkn,
+ },
+ {
+ name: "ok for cookie with json token",
+ cookie: jsonTokenBase64,
expect: tkn,
},
}
diff --git a/tree/tree.go b/tree/tree.go
index bf0aff9..d99e24b 100644
--- a/tree/tree.go
+++ b/tree/tree.go
@@ -7,14 +7,18 @@ import (
"strings"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/data"
- "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/utils"
+ "git.frostfs.info/TrueCloudLab/frostfs-observability/tracing"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
+ "go.uber.org/zap"
)
type (
Tree struct {
service ServiceClient
+ log *zap.Logger
}
// ServiceClient is a client to interact with tree service.
@@ -47,10 +51,10 @@ type (
var (
// ErrNodeNotFound is returned from ServiceClient in case of not found error.
- ErrNodeNotFound = layer.ErrNodeNotFound
+ ErrNodeNotFound = errors.New("not found")
// ErrNodeAccessDenied is returned from ServiceClient service in case of access denied error.
- ErrNodeAccessDenied = layer.ErrNodeAccessDenied
+ ErrNodeAccessDenied = errors.New("access denied")
)
const (
@@ -72,8 +76,8 @@ const (
)
// NewTree creates instance of Tree using provided address and create grpc connection.
-func NewTree(service ServiceClient) *Tree {
- return &Tree{service: service}
+func NewTree(service ServiceClient, log *zap.Logger) *Tree {
+ return &Tree{service: service, log: log}
}
type Meta interface {
@@ -190,6 +194,9 @@ func (m *multiSystemNode) Old() []*treeNode {
}
func (c *Tree) GetLatestVersion(ctx context.Context, cnrID *cid.ID, objectName string) (*data.NodeVersion, error) {
+ ctx, span := tracing.StartSpanFromContext(ctx, "tree.GetLatestVersion")
+ defer span.End()
+
nodes, err := c.GetVersions(ctx, cnrID, objectName)
if err != nil {
return nil, err
@@ -204,6 +211,9 @@ func (c *Tree) GetLatestVersion(ctx context.Context, cnrID *cid.ID, objectName s
}
func (c *Tree) GetVersions(ctx context.Context, cnrID *cid.ID, objectName string) ([]NodeResponse, error) {
+ ctx, span := tracing.StartSpanFromContext(ctx, "tree.GetVersions")
+ defer span.End()
+
meta := []string{oidKV, isDeleteMarkerKV, sizeKV}
path := pathFromName(objectName)
@@ -220,6 +230,9 @@ func (c *Tree) GetVersions(ctx context.Context, cnrID *cid.ID, objectName string
}
func (c *Tree) CheckSettingsNodeExists(ctx context.Context, bktInfo *data.BucketInfo) error {
+ ctx, span := tracing.StartSpanFromContext(ctx, "tree.CheckSettingsNodeExists")
+ defer span.End()
+
_, err := c.getSystemNode(ctx, bktInfo, settingsFileName)
if err != nil {
return err
@@ -245,7 +258,10 @@ func (c *Tree) getSystemNode(ctx context.Context, bktInfo *data.BucketInfo, name
nodes = filterMultipartNodes(nodes)
if len(nodes) == 0 {
- return nil, layer.ErrNodeNotFound
+ return nil, ErrNodeNotFound
+ }
+ if len(nodes) != 1 {
+ c.reqLogger(ctx).Warn(logs.FoundSeveralSystemTreeNodes, zap.String("name", name), logs.TagField(logs.TagExternalStorageTree))
}
return newMultiNode(nodes)
@@ -286,7 +302,7 @@ func getLatestVersionNode(nodes []NodeResponse) (NodeResponse, error) {
}
if targetIndexNode == -1 {
- return nil, layer.ErrNodeNotFound
+ return nil, fmt.Errorf("latest version: %w", ErrNodeNotFound)
}
return nodes[targetIndexNode], nil
@@ -307,17 +323,23 @@ func pathFromName(objectName string) []string {
return strings.Split(objectName, separator)
}
-func (c *Tree) GetSubTreeByPrefix(ctx context.Context, bktInfo *data.BucketInfo, prefix string, latestOnly bool) ([]data.NodeInfo, string, error) {
- rootID, tailPrefix, err := c.determinePrefixNode(ctx, bktInfo, versionTree, prefix)
+func (c *Tree) GetSubTreeByPrefix(ctx context.Context, bktInfo *data.BucketInfo, prefix string, latestOnly bool) ([]data.NodeInfo, error) {
+ ctx, span := tracing.StartSpanFromContext(ctx, "tree.GetSubTreeByPrefix")
+ defer span.End()
+
+ rootID, err := c.getPrefixNodeID(ctx, bktInfo, versionTree, strings.Split(prefix, separator))
if err != nil {
- return nil, "", err
+ if errors.Is(err, ErrNodeNotFound) {
+ return nil, nil
+ }
+ return nil, err
}
subTree, err := c.service.GetSubTree(ctx, bktInfo, versionTree, rootID, 2, false)
if err != nil {
if errors.Is(err, ErrNodeNotFound) {
- return nil, "", nil
+ return nil, nil
}
- return nil, "", err
+ return nil, err
}
nodesMap := make(map[string][]NodeResponse, len(subTree))
@@ -327,10 +349,6 @@ func (c *Tree) GetSubTreeByPrefix(ctx context.Context, bktInfo *data.BucketInfo,
}
fileName := GetFilename(node)
- if !strings.HasPrefix(fileName, tailPrefix) {
- continue
- }
-
nodes := nodesMap[fileName]
// Add all nodes if flag latestOnly is false.
@@ -354,7 +372,7 @@ func (c *Tree) GetSubTreeByPrefix(ctx context.Context, bktInfo *data.BucketInfo,
result = append(result, nodeResponseToNodeInfo(nodes)...)
}
- return result, strings.TrimSuffix(prefix, tailPrefix), nil
+ return result, nil
}
func nodeResponseToNodeInfo(nodes []NodeResponse) []data.NodeInfo {
@@ -366,22 +384,6 @@ func nodeResponseToNodeInfo(nodes []NodeResponse) []data.NodeInfo {
return nodesInfo
}
-func (c *Tree) determinePrefixNode(ctx context.Context, bktInfo *data.BucketInfo, treeID, prefix string) ([]uint64, string, error) {
- rootID := []uint64{0}
- path := strings.Split(prefix, separator)
- tailPrefix := path[len(path)-1]
-
- if len(path) > 1 {
- var err error
- rootID, err = c.getPrefixNodeID(ctx, bktInfo, treeID, path[:len(path)-1])
- if err != nil {
- return nil, "", err
- }
- }
-
- return rootID, tailPrefix, nil
-}
-
func (c *Tree) getPrefixNodeID(ctx context.Context, bktInfo *data.BucketInfo, treeID string, prefixPath []string) ([]uint64, error) {
p := &GetNodesParams{
CnrID: bktInfo.CID,
@@ -404,12 +406,16 @@ func (c *Tree) getPrefixNodeID(ctx context.Context, bktInfo *data.BucketInfo, tr
}
if len(intermediateNodes) == 0 {
- return nil, layer.ErrNodeNotFound
+ return nil, ErrNodeNotFound
}
return intermediateNodes, nil
}
+func (c *Tree) reqLogger(ctx context.Context) *zap.Logger {
+ return utils.GetReqLogOrDefault(ctx, c.log)
+}
+
func GetFilename(node NodeResponse) string {
for _, kv := range node.GetMeta() {
if kv.GetKey() == FileNameKey {
diff --git a/utils/attributes.go b/utils/attributes.go
index 4d277a9..55fadaa 100644
--- a/utils/attributes.go
+++ b/utils/attributes.go
@@ -11,6 +11,8 @@ import (
"time"
"unicode"
"unicode/utf8"
+
+ "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
)
type EpochDurations struct {
@@ -256,3 +258,12 @@ func (t systemTransformer) updateExpirationHeader(headers map[string]string, dur
headers[t.expirationEpochAttr()] = strconv.FormatUint(expirationEpoch, 10)
}
+
+func GetAttributeValue(attrs []object.Attribute, key string) string {
+ for _, attr := range attrs {
+ if attr.Key() == key {
+ return attr.Value()
+ }
+ }
+ return ""
+}