Strict APE check for EC & fix sign EC part put requests #1451

Merged
fyrchik merged 5 commits from dstepanov-yadro/frostfs-node:fix/ec_ape_strict into master 2024-11-06 08:18:11 +00:00
2 changed files with 30 additions and 15 deletions
Showing only changes of commit de3a89a0ba - Show all commits

View file

@ -695,6 +695,7 @@ func TestPutECChunk(t *testing.T) {
nm := &netmapStub{ nm := &netmapStub{
currentEpoch: 100, currentEpoch: 100,
netmaps: map[uint64]*netmapSDK.NetMap{ netmaps: map[uint64]*netmapSDK.NetMap{
99: netmap,

Why this change is necessary?

Why this change is necessary?

previously, checking that the node is a container node ignored the error that netmap is not defined for previous epoch

previously, checking that the node is a container node ignored the error that netmap is not defined for previous epoch
100: netmap, 100: netmap,
}, },
} }

View file

@ -3,6 +3,7 @@ package ape
import ( import (
"context" "context"
"crypto/sha256" "crypto/sha256"
"errors"
"fmt" "fmt"
"net" "net"
"strconv" "strconv"
@ -11,6 +12,7 @@ import (
aperequest "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/request" aperequest "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/request"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
@ -24,6 +26,8 @@ import (
var defaultRequest = aperequest.Request{} var defaultRequest = aperequest.Request{}
var errECMissingParentObjectID = errors.New("missing EC parent object ID")
func nativeSchemaRole(role acl.Role) string { func nativeSchemaRole(role acl.Role) string {
switch role { switch role {
case acl.RoleOwner: case acl.RoleOwner:
@ -122,7 +126,10 @@ func (c *checkerImpl) newAPERequest(ctx context.Context, prm Prm) (aperequest.Re
header = headerObjSDK.ToV2().GetHeader() header = headerObjSDK.ToV2().GetHeader()
} }
} }

It looks even too strict if you look at the line above:


	} else if prm.Object != nil {
		headerObjSDK, err := c.headerProvider.GetHeader(ctx, prm.Container, *prm.Object, true)
		if err == nil {
			header = headerObjSDK.ToV2().GetHeader()
		}
	}
It looks even too strict if you look at the line above: ``` } else if prm.Object != nil { headerObjSDK, err := c.headerProvider.GetHeader(ctx, prm.Container, *prm.Object, true) if err == nil { header = headerObjSDK.ToV2().GetHeader() } } ```
header = c.fillHeaderWithECParent(ctx, prm, header) header, err := c.fillHeaderWithECParent(ctx, prm, header)
if err != nil {
return defaultRequest, fmt.Errorf("get EC parent header: %w", err)
}
reqProps := map[string]string{ reqProps := map[string]string{
nativeschema.PropertyKeyActorPublicKey: prm.SenderKey, nativeschema.PropertyKeyActorPublicKey: prm.SenderKey,
nativeschema.PropertyKeyActorRole: prm.Role, nativeschema.PropertyKeyActorRole: prm.Role,
@ -133,7 +140,6 @@ func (c *checkerImpl) newAPERequest(ctx context.Context, prm Prm) (aperequest.Re
reqProps[xheadKey] = xhead.GetValue() reqProps[xheadKey] = xhead.GetValue()
} }
var err error
reqProps, err = c.fillWithUserClaimTags(reqProps, prm) reqProps, err = c.fillWithUserClaimTags(reqProps, prm)
if err != nil { if err != nil {
return defaultRequest, err return defaultRequest, err
@ -155,35 +161,43 @@ func (c *checkerImpl) newAPERequest(ctx context.Context, prm Prm) (aperequest.Re
), nil ), nil
} }
func (c *checkerImpl) fillHeaderWithECParent(ctx context.Context, prm Prm, header *objectV2.Header) *objectV2.Header { func (c *checkerImpl) fillHeaderWithECParent(ctx context.Context, prm Prm, header *objectV2.Header) (*objectV2.Header, error) {

I do not completely understand this function.
In what circumstances do we return header and not parent header and, more importantly, why?

I do not completely understand this function. In what circumstances do we return `header` and not parent header and, more importantly, why?
  1. if it is not EC chunk
  2. if current node is IR or container node: APE skips check for inside-container requests; not sure about the same for IR, maybe should delete it
  3. if parent object does not exist
  4. if current node is not container node: in this case node has no permissions to collect EC object
1. if it is not EC chunk 2. if current node is IR or container node: APE skips check for inside-container requests; not sure about the same for IR, maybe should delete it 3. if parent object does not exist 4. if current node is not container node: in this case node has no permissions to collect EC object

If ape skips checks for in-container requests, why do we call this function at all?

If ape skips checks for in-container requests, why do we _call_ this function at all?

Oh, mistake. It must be:

2. if request is from IR or container node: APE skips check for inside-container requests; not sure about the same for IR, maybe 

Then container node tries to collect headers if request is done be owner or other user.

Oh, mistake. It must be: ``` 2. if request is from IR or container node: APE skips check for inside-container requests; not sure about the same for IR, maybe ``` Then container node tries to collect headers if request is done be owner or other user.

Again, if APE skips check, why do we call this function?
It doesn't seem we signify the "skip" part with our return value in any way.

Again, if APE skips check, why do we call this function? It doesn't seem we signify the "skip" part with our return value in any way.

Removed pt.2 as it is checker before this function call.

Removed pt.2 as it is checker before this function call.
if header == nil { if header == nil {
return header return header, nil
} }
if header.GetEC() == nil { if header.GetEC() == nil {
return header return header, nil
}
if prm.Role == nativeschema.PropertyValueContainerRoleContainer ||
prm.Role == nativeschema.PropertyValueContainerRoleIR {
return header
} }
parentObjRefID := header.GetEC().Parent parentObjRefID := header.GetEC().Parent
if parentObjRefID == nil { if parentObjRefID == nil {
return header return nil, errECMissingParentObjectID
} }
var parentObjID oid.ID var parentObjID oid.ID
if err := parentObjID.ReadFromV2(*parentObjRefID); err != nil { if err := parentObjID.ReadFromV2(*parentObjRefID); err != nil {
return header return nil, fmt.Errorf("EC parent object ID format error: %w", err)
} }
// only container node have access to collect parent object // only container node have access to collect parent object
contNode, err := c.currentNodeIsContainerNode(prm.Container) contNode, err := c.currentNodeIsContainerNode(prm.Container)
if err != nil || !contNode { if err != nil {
return header return nil, fmt.Errorf("check container node status: %w", err)
}
if !contNode {
return header, nil
} }
parentObj, err := c.headerProvider.GetHeader(ctx, prm.Container, parentObjID, false) parentObj, err := c.headerProvider.GetHeader(ctx, prm.Container, parentObjID, false)
if err != nil { if err != nil {
return header if isLogicalError(err) {
return header, nil
} }
return parentObj.ToV2().GetHeader() return nil, fmt.Errorf("EC parent header request: %w", err)
}
return parentObj.ToV2().GetHeader(), nil
}
func isLogicalError(err error) bool {
var errObjRemoved *apistatus.ObjectAlreadyRemoved
var errObjNotFound *apistatus.ObjectNotFound
return errors.As(err, &errObjRemoved) || errors.As(err, &errObjNotFound)
} }
func (c *checkerImpl) currentNodeIsContainerNode(cnrID cid.ID) (bool, error) { func (c *checkerImpl) currentNodeIsContainerNode(cnrID cid.ID) (bool, error) {