[#1689] object: Make APE middleware form container system attributes

* Extract container system attributes into request info;
* Form APE-resource proprties from the extracted attributes;
* Fix unit-test.

Change-Id: I8fbd9a167ad05af0e75df350ac882b866da7bdcb
Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
Airat Arifullin 2025-04-24 18:57:23 +03:00
parent a5f76a609d
commit c2a495814f
5 changed files with 128 additions and 88 deletions

View file

@ -64,6 +64,9 @@ type Prm struct {
// An encoded container's owner user ID.
ContainerOwner user.ID
// Attributes defined for the container.
ContainerAttributes map[string]string
// The request's bearer token. It is used in order to check APE overrides with the token.
BearerToken *bearer.Token

View file

@ -63,6 +63,8 @@ type RequestInfo struct {
ContainerOwner user.ID
ContainerAttributes map[string]string
// Namespace defines to which namespace a container is belonged.
Namespace string
@ -131,6 +133,11 @@ func (e *extractor) GetRequestInfo(ctx context.Context, m Metadata, method strin
ri.Role = nativeSchemaRole(res.Role)
ri.ContainerOwner = cnr.Value.Owner()
ri.ContainerAttributes = map[string]string{}
for key, val := range cnr.Value.Attributes() {
ri.ContainerAttributes[key] = val
}
cnrNamespace, hasNamespace := strings.CutSuffix(cnrSDK.ReadDomain(cnr.Value).Zone(), ".ns")
if hasNamespace {
ri.Namespace = cnrNamespace

View file

@ -57,11 +57,16 @@ func resourceName(cid cid.ID, oid *oid.ID, namespace string) string {
}
// objectProperties collects object properties from address parameters and a header if it is passed.
func objectProperties(cnr cid.ID, oid *oid.ID, cnrOwner user.ID, header *objectV2.Header) map[string]string {
func objectProperties(cnr cid.ID, oid *oid.ID, cnrOwner user.ID, cnrAttrs map[string]string, header *objectV2.Header) map[string]string {
objectProps := map[string]string{
nativeschema.PropertyKeyObjectContainerID: cnr.EncodeToString(),
}
for attrName, attrValue := range cnrAttrs {
prop := fmt.Sprintf(nativeschema.PropertyKeyFormatObjectContainerAttribute, attrName)
objectProps[prop] = attrValue
}
objectProps[nativeschema.PropertyKeyContainerOwnerID] = cnrOwner.EncodeToString()
if oid != nil {
@ -155,7 +160,7 @@ func (c *checkerImpl) newAPERequest(ctx context.Context, prm Prm) (aperequest.Re
prm.Method,
aperequest.NewResource(
resourceName(prm.Container, prm.Object, prm.Namespace),
objectProperties(prm.Container, prm.Object, prm.ContainerOwner, header),
objectProperties(prm.Container, prm.Object, prm.ContainerOwner, prm.ContainerAttributes, header),
),
reqProps,
), nil

View file

@ -7,6 +7,7 @@ import (
"testing"
aperequest "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/ape/request"
cnrV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container"
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object"
checksumtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum/test"
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
@ -22,8 +23,17 @@ const (
testOwnerID = "NURFM8PWbLA2aLt2vrD8q4FyfAdgESwM8y"
incomingIP = "192.92.33.1"
testSysAttrName = "unittest"
testSysAttrZone = "eggplant"
)
var containerAttrs = map[string]string{
cnrV2.SysAttributeName: testSysAttrName,
cnrV2.SysAttributeZone: testSysAttrZone,
}
func ctxWithPeerInfo() context.Context {
return peer.NewContext(context.Background(), &peer.Peer{
Addr: &net.TCPAddr{
@ -105,7 +115,7 @@ func TestObjectProperties(t *testing.T) {
var testCnrOwner user.ID
require.NoError(t, testCnrOwner.DecodeString(testOwnerID))
props := objectProperties(cnr, obj, testCnrOwner, header.ToV2().GetHeader())
props := objectProperties(cnr, obj, testCnrOwner, containerAttrs, header.ToV2().GetHeader())
require.Equal(t, test.container, props[nativeschema.PropertyKeyObjectContainerID])
require.Equal(t, testOwnerID, props[nativeschema.PropertyKeyContainerOwnerID])
@ -124,6 +134,8 @@ func TestObjectProperties(t *testing.T) {
require.Equal(t, test.header.typ.String(), props[nativeschema.PropertyKeyObjectType])
require.Equal(t, test.header.payloadChecksum.String(), props[nativeschema.PropertyKeyObjectPayloadHash])
require.Equal(t, test.header.payloadHomomorphicHash.String(), props[nativeschema.PropertyKeyObjectHomomorphicHash])
require.Equal(t, containerAttrs[cnrV2.SysAttributeName], props[fmt.Sprintf(nativeschema.PropertyKeyFormatObjectContainerAttribute, cnrV2.SysAttributeName)])
require.Equal(t, containerAttrs[cnrV2.SysAttributeZone], props[fmt.Sprintf(nativeschema.PropertyKeyFormatObjectContainerAttribute, cnrV2.SysAttributeZone)])
for _, attr := range test.header.attributes {
require.Equal(t, attr.val, props[attr.key])
@ -245,6 +257,10 @@ func TestNewAPERequest(t *testing.T) {
Role: role,
SenderKey: senderKey,
ContainerOwner: testCnrOwner,
ContainerAttributes: map[string]string{
cnrV2.SysAttributeZone: testSysAttrZone,
cnrV2.SysAttributeName: testSysAttrName,
},
}
headerSource := newHeaderProviderMock()
@ -277,7 +293,7 @@ func TestNewAPERequest(t *testing.T) {
method,
aperequest.NewResource(
resourceName(cnr, obj, prm.Namespace),
objectProperties(cnr, obj, testCnrOwner, func() *objectV2.Header {
objectProperties(cnr, obj, testCnrOwner, containerAttrs, func() *objectV2.Header {
if headerObjSDK != nil {
return headerObjSDK.ToV2().GetHeader()
}

View file

@ -86,16 +86,17 @@ func (g *getStreamBasicChecker) Send(resp *objectV2.GetResponse) error {
}
prm := Prm{
Namespace: g.reqInfo.Namespace,
Container: cnrID,
Object: objID,
Header: partInit.GetHeader(),
Method: nativeschema.MethodGetObject,
SenderKey: g.reqInfo.SenderKey,
ContainerOwner: g.reqInfo.ContainerOwner,
Role: g.reqInfo.Role,
BearerToken: g.metadata.BearerToken,
XHeaders: resp.GetMetaHeader().GetXHeaders(),
Namespace: g.reqInfo.Namespace,
Container: cnrID,
Object: objID,
Header: partInit.GetHeader(),
Method: nativeschema.MethodGetObject,
SenderKey: g.reqInfo.SenderKey,
ContainerOwner: g.reqInfo.ContainerOwner,
ContainerAttributes: g.reqInfo.ContainerAttributes,
Role: g.reqInfo.Role,
BearerToken: g.metadata.BearerToken,
XHeaders: resp.GetMetaHeader().GetXHeaders(),
}
if err := g.apeChecker.CheckAPE(g.Context(), prm); err != nil {
@ -142,16 +143,17 @@ func (p *putStreamBasicChecker) Send(ctx context.Context, request *objectV2.PutR
}
prm := Prm{
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Header: partInit.GetHeader(),
Method: nativeschema.MethodPutObject,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
Role: reqInfo.Role,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Header: partInit.GetHeader(),
Method: nativeschema.MethodPutObject,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
ContainerAttributes: reqInfo.ContainerAttributes,
Role: reqInfo.Role,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
}
if err := p.apeChecker.CheckAPE(ctx, prm); err != nil {
@ -200,15 +202,16 @@ func (p *patchStreamBasicChecker) Send(ctx context.Context, request *objectV2.Pa
}
prm := Prm{
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Method: nativeschema.MethodPatchObject,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
Role: reqInfo.Role,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Method: nativeschema.MethodPatchObject,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
ContainerAttributes: reqInfo.ContainerAttributes,
Role: reqInfo.Role,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
}
if err := p.apeChecker.CheckAPE(ctx, prm); err != nil {
@ -268,16 +271,17 @@ func (c *Service) Head(ctx context.Context, request *objectV2.HeadRequest) (*obj
}
err = c.apeChecker.CheckAPE(ctx, Prm{
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Header: header,
Method: nativeschema.MethodHeadObject,
Role: reqInfo.Role,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Header: header,
Method: nativeschema.MethodHeadObject,
Role: reqInfo.Role,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
ContainerAttributes: reqInfo.ContainerAttributes,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
})
if err != nil {
return nil, toStatusErr(err)
@ -296,14 +300,15 @@ func (c *Service) Search(request *objectV2.SearchRequest, stream objectSvc.Searc
}
err = c.apeChecker.CheckAPE(stream.Context(), Prm{
Namespace: reqInfo.Namespace,
Container: md.Container,
Method: nativeschema.MethodSearchObject,
Role: reqInfo.Role,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
Namespace: reqInfo.Namespace,
Container: md.Container,
Method: nativeschema.MethodSearchObject,
Role: reqInfo.Role,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
ContainerAttributes: reqInfo.ContainerAttributes,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
})
if err != nil {
return toStatusErr(err)
@ -323,15 +328,16 @@ func (c *Service) Delete(ctx context.Context, request *objectV2.DeleteRequest) (
}
err = c.apeChecker.CheckAPE(ctx, Prm{
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Method: nativeschema.MethodDeleteObject,
Role: reqInfo.Role,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Method: nativeschema.MethodDeleteObject,
Role: reqInfo.Role,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
ContainerAttributes: reqInfo.ContainerAttributes,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
})
if err != nil {
return nil, toStatusErr(err)
@ -356,15 +362,16 @@ func (c *Service) GetRange(request *objectV2.GetRangeRequest, stream objectSvc.G
}
err = c.apeChecker.CheckAPE(stream.Context(), Prm{
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Method: nativeschema.MethodRangeObject,
Role: reqInfo.Role,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Method: nativeschema.MethodRangeObject,
Role: reqInfo.Role,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
ContainerAttributes: reqInfo.ContainerAttributes,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
})
if err != nil {
return toStatusErr(err)
@ -384,15 +391,16 @@ func (c *Service) GetRangeHash(ctx context.Context, request *objectV2.GetRangeHa
}
prm := Prm{
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Method: nativeschema.MethodHashObject,
Role: reqInfo.Role,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Method: nativeschema.MethodHashObject,
Role: reqInfo.Role,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
ContainerAttributes: reqInfo.ContainerAttributes,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
}
resp, err := c.next.GetRangeHash(ctx, request)
@ -417,16 +425,17 @@ func (c *Service) PutSingle(ctx context.Context, request *objectV2.PutSingleRequ
}
prm := Prm{
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Header: request.GetBody().GetObject().GetHeader(),
Method: nativeschema.MethodPutObject,
Role: reqInfo.Role,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
Namespace: reqInfo.Namespace,
Container: md.Container,
Object: md.Object,
Header: request.GetBody().GetObject().GetHeader(),
Method: nativeschema.MethodPutObject,
Role: reqInfo.Role,
SenderKey: reqInfo.SenderKey,
ContainerOwner: reqInfo.ContainerOwner,
ContainerAttributes: reqInfo.ContainerAttributes,
BearerToken: md.BearerToken,
XHeaders: md.MetaHeader.GetXHeaders(),
}
if err = c.apeChecker.CheckAPE(ctx, prm); err != nil {