Fix access denied error handling for GET requests #1340

Merged
fyrchik merged 1 commit from dstepanov-yadro/frostfs-node:fix/get_ape_err_handling into master 2024-08-28 12:15:05 +00:00
3 changed files with 29 additions and 12 deletions

View file

@ -2,9 +2,11 @@ package getsvc
import ( import (
"context" "context"
"errors"
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs" "git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -120,6 +122,12 @@ func (exec *request) analyzeStatus(ctx context.Context, execCnr bool) {
exec.log.Debug(logs.OperationFinishedWithError, exec.log.Debug(logs.OperationFinishedWithError,
zap.Error(exec.err), zap.Error(exec.err),
) )
var errAccessDenied *apistatus.ObjectAccessDenied
if execCnr && errors.As(exec.err, &errAccessDenied) {
// Local get can't return access denied error, so this error was returned by
// write to the output stream. So there is no need to try to find object on other nodes.
return
}
if execCnr { if execCnr {
exec.executeOnContainer(ctx) exec.executeOnContainer(ctx)

View file

@ -31,6 +31,7 @@ func (r *request) processNode(ctx context.Context, info client.NodeInfo) bool {
var errECInfo *objectSDK.ECInfoError var errECInfo *objectSDK.ECInfoError
var errRemoved *apistatus.ObjectAlreadyRemoved var errRemoved *apistatus.ObjectAlreadyRemoved
var errOutOfRange *apistatus.ObjectOutOfRange var errOutOfRange *apistatus.ObjectOutOfRange
var errAccessDenied *apistatus.ObjectAccessDenied
switch { switch {
default: default:
@ -38,8 +39,12 @@ func (r *request) processNode(ctx context.Context, info client.NodeInfo) bool {
if r.status != statusEC { if r.status != statusEC {
// for raw requests, continue to collect other parts // for raw requests, continue to collect other parts
r.status = statusUndefined r.status = statusUndefined
if errors.As(err, &errAccessDenied) {
r.err = err
} else {
r.err = new(apistatus.ObjectNotFound) r.err = new(apistatus.ObjectNotFound)
} }
}
return false return false
case err == nil: case err == nil:
r.status = statusOK r.status = statusOK

View file

@ -24,11 +24,13 @@ import (
type getRequestForwarder struct { type getRequestForwarder struct {
OnceResign sync.Once OnceResign sync.Once
OnceHeaderSending sync.Once
GlobalProgress int GlobalProgress int
Key *ecdsa.PrivateKey Key *ecdsa.PrivateKey
Request *objectV2.GetRequest Request *objectV2.GetRequest
Stream *streamObjectWriter Stream *streamObjectWriter
headerSent bool
headerSentGuard sync.Mutex
} }
func (f *getRequestForwarder) forwardRequestToNode(ctx context.Context, addr network.Address, c client.MultiAddressClient, pubkey []byte) (*objectSDK.Object, error) { func (f *getRequestForwarder) forwardRequestToNode(ctx context.Context, addr network.Address, c client.MultiAddressClient, pubkey []byte) (*objectSDK.Object, error) {
@ -83,13 +85,15 @@ func (f *getRequestForwarder) writeHeader(ctx context.Context, v *objectV2.GetOb
obj.SetSignature(v.GetSignature()) obj.SetSignature(v.GetSignature())
obj.SetHeader(v.GetHeader()) obj.SetHeader(v.GetHeader())
var err error f.headerSentGuard.Lock()
fyrchik marked this conversation as resolved
Review

Missed this in support branch, could you explain, how is this different from sync.Once?

Missed this in support branch, could you explain, how is this different from `sync.Once`?
Review

sync.Once doesn't take err into account: in case of error sync.Once will not run second time.

`sync.Once` doesn't take `err` into account: in case of error `sync.Once` will not run second time.
f.OnceHeaderSending.Do(func() { defer f.headerSentGuard.Unlock()
err = f.Stream.WriteHeader(ctx, objectSDK.NewFromV2(obj)) if f.headerSent {
}) return nil
if err != nil { }
if err := f.Stream.WriteHeader(ctx, objectSDK.NewFromV2(obj)); err != nil {
return errCouldNotWriteObjHeader(err) return errCouldNotWriteObjHeader(err)
} }
f.headerSent = true
return nil return nil
} }