[#306] Use session token for container read operations

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2024-03-01 17:11:07 +03:00
parent c12e264697
commit 8050ca2d51
12 changed files with 116 additions and 41 deletions

View file

@ -16,6 +16,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
s3errors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
@ -1320,7 +1321,7 @@ func TestPutBucketAPE(t *testing.T) {
info := createBucket(hc, bktName)
_, err := hc.tp.ContainerEACL(hc.Context(), info.BktInfo.CID)
_, err := hc.tp.ContainerEACL(hc.Context(), layer.PrmContainerEACL{ContainerID: info.BktInfo.CID})
require.ErrorContains(t, err, "not found")
chains, err := hc.h.ape.(*apeMock).ListChains(engine.NamespaceTarget(""))

View file

@ -32,20 +32,21 @@ const (
AttributeLockEnabled = "LockEnabled"
)
func (n *layer) containerInfo(ctx context.Context, idCnr cid.ID) (*data.BucketInfo, error) {
func (n *layer) containerInfo(ctx context.Context, prm PrmContainer) (*data.BucketInfo, error) {
var (
err error
res *container.Container
log = n.reqLogger(ctx).With(zap.Stringer("cid", idCnr))
log = n.reqLogger(ctx).With(zap.Stringer("cid", prm.ContainerID))
info = &data.BucketInfo{
CID: idCnr,
Name: idCnr.EncodeToString(),
CID: prm.ContainerID,
Name: prm.ContainerID.EncodeToString(),
}
reqInfo = middleware.GetReqInfo(ctx)
)
res, err = n.frostFS.Container(ctx, idCnr)
res, err = n.frostFS.Container(ctx, prm)
if err != nil {
if client.IsErrContainerNotFound(err) {
return nil, fmt.Errorf("%w: %s", s3errors.GetAPIError(s3errors.ErrNoSuchBucket), err.Error())
@ -78,7 +79,7 @@ func (n *layer) containerInfo(ctx context.Context, idCnr cid.ID) (*data.BucketIn
zone, _ := n.features.FormContainerZone(reqInfo.Namespace)
if zone != info.Zone {
return nil, fmt.Errorf("ns '%s' and zone '%s' are mismatched for container '%s'", zone, info.Zone, idCnr)
return nil, fmt.Errorf("ns '%s' and zone '%s' are mismatched for container '%s'", zone, info.Zone, prm.ContainerID)
}
n.cache.PutBucket(info)
@ -87,7 +88,14 @@ func (n *layer) containerInfo(ctx context.Context, idCnr cid.ID) (*data.BucketIn
}
func (n *layer) containerList(ctx context.Context) ([]*data.BucketInfo, error) {
res, err := n.frostFS.UserContainers(ctx, n.BearerOwner(ctx))
stoken := n.SessionTokenForRead(ctx)
prm := PrmUserContainers{
UserID: n.BearerOwner(ctx),
SessionToken: stoken,
}
res, err := n.frostFS.UserContainers(ctx, prm)
if err != nil {
n.reqLogger(ctx).Error(logs.CouldNotListUserContainers, zap.Error(err))
return nil, err
@ -95,7 +103,11 @@ func (n *layer) containerList(ctx context.Context) ([]*data.BucketInfo, error) {
list := make([]*data.BucketInfo, 0, len(res))
for i := range res {
info, err := n.containerInfo(ctx, res[i])
getPrm := PrmContainer{
ContainerID: res[i],
SessionToken: stoken,
}
info, err := n.containerInfo(ctx, getPrm)
if err != nil {
n.reqLogger(ctx).Error(logs.CouldNotFetchContainerInfo, zap.Error(err))
continue
@ -167,6 +179,10 @@ func (n *layer) setContainerEACLTable(ctx context.Context, idCnr cid.ID, table *
return n.frostFS.SetContainerEACL(ctx, *table, sessionToken)
}
func (n *layer) GetContainerEACL(ctx context.Context, idCnr cid.ID) (*eacl.Table, error) {
return n.frostFS.ContainerEACL(ctx, idCnr)
func (n *layer) GetContainerEACL(ctx context.Context, cnrID cid.ID) (*eacl.Table, error) {
prm := PrmContainerEACL{
ContainerID: cnrID,
SessionToken: n.SessionTokenForRead(ctx),
}
return n.frostFS.ContainerEACL(ctx, prm)
}

View file

@ -46,6 +46,33 @@ type PrmContainerCreate struct {
AdditionalAttributes [][2]string
}
// PrmContainer groups parameters of FrostFS.Container operation.
type PrmContainer struct {
// Container identifier.
ContainerID cid.ID
// Token of the container's creation session. Nil means session absence.
SessionToken *session.Container
}
// PrmUserContainers groups parameters of FrostFS.UserContainers operation.
type PrmUserContainers struct {
// User identifier.
UserID user.ID
// Token of the container's creation session. Nil means session absence.
SessionToken *session.Container
}
// PrmContainerEACL groups parameters of FrostFS.ContainerEACL operation.
type PrmContainerEACL struct {
// Container identifier.
ContainerID cid.ID
// Token of the container's creation session. Nil means session absence.
SessionToken *session.Container
}
// ContainerCreateResult is a result parameter of FrostFS.CreateContainer operation.
type ContainerCreateResult struct {
ContainerID cid.ID
@ -181,13 +208,13 @@ type FrostFS interface {
//
// It returns exactly one non-nil value. It returns any error encountered which
// prevented the container from being read.
Container(context.Context, cid.ID) (*container.Container, error)
Container(context.Context, PrmContainer) (*container.Container, error)
// UserContainers reads a list of the containers owned by the specified user.
//
// It returns exactly one non-nil value. It returns any error encountered which
// prevented the containers from being listed.
UserContainers(context.Context, user.ID) ([]cid.ID, error)
UserContainers(context.Context, PrmUserContainers) ([]cid.ID, error)
// SetContainerEACL saves the eACL table of the container in FrostFS. The
// extended ACL is modified within session if session token is not nil.
@ -199,7 +226,7 @@ type FrostFS interface {
//
// It returns exactly one non-nil value. It returns any error encountered which
// prevented the eACL from being read.
ContainerEACL(context.Context, cid.ID) (*eacl.Table, error)
ContainerEACL(context.Context, PrmContainerEACL) (*eacl.Table, error)
// DeleteContainer marks the container to be removed from FrostFS by ID.
// Request is sent within session if the session token is specified.

View file

@ -184,17 +184,17 @@ func (t *TestFrostFS) DeleteContainer(_ context.Context, cnrID cid.ID, _ *sessio
return nil
}
func (t *TestFrostFS) Container(_ context.Context, id cid.ID) (*container.Container, error) {
func (t *TestFrostFS) Container(_ context.Context, prm PrmContainer) (*container.Container, error) {
for k, v := range t.containers {
if k == id.EncodeToString() {
if k == prm.ContainerID.EncodeToString() {
return v, nil
}
}
return nil, fmt.Errorf("container not found %s", id)
return nil, fmt.Errorf("container not found %s", prm.ContainerID)
}
func (t *TestFrostFS) UserContainers(_ context.Context, _ user.ID) ([]cid.ID, error) {
func (t *TestFrostFS) UserContainers(context.Context, PrmUserContainers) ([]cid.ID, error) {
var res []cid.ID
for k := range t.containers {
var idCnr cid.ID
@ -284,7 +284,7 @@ func (t *TestFrostFS) CreateObject(_ context.Context, prm PrmObjectCreate) (oid.
obj.SetPayloadSize(prm.PayloadSize)
obj.SetAttributes(attrs...)
obj.SetCreationEpoch(t.currentEpoch)
obj.SetOwnerID(&owner)
obj.SetOwnerID(owner)
t.currentEpoch++
if len(prm.Locks) > 0 {
@ -367,8 +367,8 @@ func (t *TestFrostFS) SetContainerEACL(_ context.Context, table eacl.Table, _ *s
return nil
}
func (t *TestFrostFS) ContainerEACL(_ context.Context, cnrID cid.ID) (*eacl.Table, error) {
table, ok := t.eaclTables[cnrID.EncodeToString()]
func (t *TestFrostFS) ContainerEACL(_ context.Context, prm PrmContainerEACL) (*eacl.Table, error) {
table, ok := t.eaclTables[prm.ContainerID.EncodeToString()]
if !ok {
return nil, errors.New("not found")
}

View file

@ -378,6 +378,15 @@ func (n *layer) BearerOwner(ctx context.Context) user.ID {
return ownerID
}
// SessionTokenForRead returns session container token.
func (n *layer) SessionTokenForRead(ctx context.Context) *session.Container {
if bd, err := middleware.GetBoxData(ctx); err == nil && bd.Gate != nil {
return bd.Gate.SessionToken()
}
return nil
}
func (n *layer) reqLogger(ctx context.Context) *zap.Logger {
reqLogger := middleware.GetReqLog(ctx)
if reqLogger != nil {
@ -419,7 +428,12 @@ func (n *layer) GetBucketInfo(ctx context.Context, name string) (*data.BucketInf
return nil, err
}
return n.containerInfo(ctx, containerID)
prm := PrmContainer{
ContainerID: containerID,
SessionToken: n.SessionTokenForRead(ctx),
}
return n.containerInfo(ctx, prm)
}
// ResolveCID returns container id by name.

View file

@ -56,7 +56,7 @@ func objectInfoFromMeta(bkt *data.BucketInfo, meta *object.Object) *data.ObjectI
Created: creation,
ContentType: mimeType,
Headers: headers,
Owner: *meta.OwnerID(),
Owner: meta.OwnerID(),
Size: meta.PayloadSize(),
CreationEpoch: meta.CreationEpoch(),
HashSum: hex.EncodeToString(payloadChecksum.Value()),

View file

@ -59,6 +59,14 @@ func (g *GateData) SessionTokenForSetEACL() *session.Container {
return g.containerSessionToken(session.VerbContainerSetEACL)
}
// SessionToken returns the first container session context.
func (g *GateData) SessionToken() *session.Container {
if len(g.SessionTokens) != 0 {
return g.SessionTokens[0]
}
return nil
}
func (g *GateData) containerSessionToken(verb session.ContainerVerb) *session.Container {
for _, sessionToken := range g.SessionTokens {
if isAppropriateContainerContext(sessionToken, verb) {

4
go.mod
View file

@ -3,10 +3,10 @@ module git.frostfs.info/TrueCloudLab/frostfs-s3-gw
go 1.20
require (
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20231121085847-241a9f1ad0a4
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240215114728-2a124b95bc02
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231218084346-bce7ef18c83b
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20231107114540-ab75edd70939
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240301150205-6fe4e2541d0b
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240226094215-c960b1b08831
git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02
github.com/aws/aws-sdk-go v1.44.6

8
go.sum
View file

@ -36,16 +36,16 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20231121085847-241a9f1ad0a4 h1:wjLfZ3WCt7qNGsQv+Jl0TXnmtg0uVk/jToKPFTBc/jo=
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20231121085847-241a9f1ad0a4/go.mod h1:uY0AYmCznjZdghDnAk7THFIe1Vlg531IxUcus7ZfUJI=
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240215114728-2a124b95bc02 h1:SAoUNpK1KBcY9NwP3ZZwDMXB5bvGCQiHxpXCw6wdpAI=
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20240215114728-2a124b95bc02/go.mod h1:uY0AYmCznjZdghDnAk7THFIe1Vlg531IxUcus7ZfUJI=
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231218084346-bce7ef18c83b h1:zdbOxyqkxRyOLc7/2oNFu5tBwwg0Q6+0tJM3RkAxHlE=
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231218084346-bce7ef18c83b/go.mod h1:YMFtNZy2MgeiSwt0t8lqk8dYBGzlbhmV1cbbstJJ6oY=
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6 h1:aGQ6QaAnTerQ5Dq5b2/f9DUQtSqPkZZ/bkMx/HKuLCo=
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6/go.mod h1:W8Nn08/l6aQ7UlIbpF7FsQou7TVpcRD1ZT1KG4TrFhE=
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20231107114540-ab75edd70939 h1:jZEepi9yWmqrWgLRQcHQu4YPJaudmd7d2AEhpmM3m4U=
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20231107114540-ab75edd70939/go.mod h1:t1akKcUH7iBrFHX8rSXScYMP17k2kYQXMbZooiL5Juw=
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240301150205-6fe4e2541d0b h1:nLIWYXe4e1fWgpKeMfVke/CNBn388egh4fArFdvhfHw=
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20240301150205-6fe4e2541d0b/go.mod h1:XcgrbZ88XfvhAMxmZCQJ0dv6FyRSq6Mg2J7nN8uuO0k=
git.frostfs.info/TrueCloudLab/hrw v1.2.1 h1:ccBRK21rFvY5R1WotI6LNoPlizk7qSvdfD8lNIRudVc=
git.frostfs.info/TrueCloudLab/hrw v1.2.1/go.mod h1:C1Ygde2n843yTZEQ0FP69jYiuaYV0kriLvP4zm8JuvM=
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240226094215-c960b1b08831 h1:yK2iGQlg5kMmU47ZHor/g52mVS1xEgJSRQ4Olp76Cg8=

View file

@ -36,7 +36,7 @@ func NewAuthmateFrostFS(p *pool.Pool, key *keys.PrivateKey) *AuthmateFrostFS {
// ContainerExists implements authmate.FrostFS interface method.
func (x *AuthmateFrostFS) ContainerExists(ctx context.Context, idCnr cid.ID) error {
_, err := x.frostFS.Container(ctx, idCnr)
_, err := x.frostFS.Container(ctx, layer.PrmContainer{ContainerID: idCnr})
if err != nil {
return fmt.Errorf("get container via connection pool: %w", err)
}

View file

@ -89,8 +89,11 @@ func (x *FrostFS) TimeToEpoch(ctx context.Context, now, futureTime time.Time) (u
}
// Container implements frostfs.FrostFS interface method.
func (x *FrostFS) Container(ctx context.Context, idCnr cid.ID) (*container.Container, error) {
prm := pool.PrmContainerGet{ContainerID: idCnr}
func (x *FrostFS) Container(ctx context.Context, layerPrm layer.PrmContainer) (*container.Container, error) {
prm := pool.PrmContainerGet{
ContainerID: layerPrm.ContainerID,
Session: layerPrm.SessionToken,
}
res, err := x.pool.GetContainer(ctx, prm)
if err != nil {
@ -149,9 +152,11 @@ func (x *FrostFS) CreateContainer(ctx context.Context, prm layer.PrmContainerCre
}
// UserContainers implements frostfs.FrostFS interface method.
func (x *FrostFS) UserContainers(ctx context.Context, id user.ID) ([]cid.ID, error) {
var prm pool.PrmContainerList
prm.SetOwnerID(id)
func (x *FrostFS) UserContainers(ctx context.Context, layerPrm layer.PrmUserContainers) ([]cid.ID, error) {
prm := pool.PrmContainerList{
OwnerID: layerPrm.UserID,
Session: layerPrm.SessionToken,
}
r, err := x.pool.ListContainers(ctx, prm)
return r, handleObjectError("list user containers via connection pool", err)
@ -166,9 +171,11 @@ func (x *FrostFS) SetContainerEACL(ctx context.Context, table eacl.Table, sessio
}
// ContainerEACL implements frostfs.FrostFS interface method.
func (x *FrostFS) ContainerEACL(ctx context.Context, id cid.ID) (*eacl.Table, error) {
var prm pool.PrmContainerEACL
prm.SetContainerID(id)
func (x *FrostFS) ContainerEACL(ctx context.Context, layerPrm layer.PrmContainerEACL) (*eacl.Table, error) {
prm := pool.PrmContainerEACL{
ContainerID: layerPrm.ContainerID,
Session: layerPrm.SessionToken,
}
res, err := x.pool.GetEACL(ctx, prm)
if err != nil {
@ -224,14 +231,14 @@ func (x *FrostFS) CreateObject(ctx context.Context, prm layer.PrmObjectCreate) (
obj := object.New()
obj.SetContainerID(prm.Container)
obj.SetOwnerID(&x.owner)
obj.SetOwnerID(x.owner)
obj.SetAttributes(attrs...)
obj.SetPayloadSize(prm.PayloadSize)
if prm.BearerToken == nil && prm.PrivateKey != nil {
var owner user.ID
user.IDFromKey(&owner, prm.PrivateKey.PublicKey)
obj.SetOwnerID(&owner)
obj.SetOwnerID(owner)
}
if len(prm.Locks) > 0 {

View file

@ -148,6 +148,8 @@ func TestTreeServiceAddVersion(t *testing.T) {
CID: cidtest.ID(),
}
userID := usertest.ID()
now := time.Now()
version := &data.NodeVersion{
BaseNodeVersion: data.BaseNodeVersion{
@ -155,7 +157,7 @@ func TestTreeServiceAddVersion(t *testing.T) {
Size: 10,
ETag: "etag",
FilePath: "path/to/version",
Owner: usertest.ID(),
Owner: &userID,
Created: &now,
},
IsUnversioned: true,