forked from TrueCloudLab/frostfs-s3-gw
[#346] *: Refactor communication with NeoFS at the protocol level
Make `tokens`, `authmate` and `layer` packages to depend from locally defined `NeoFS` interface of the virtual connection to NeoFS network. Create internal `neofs` package and implement these interfaces through `pool.Pool` there. Implement mediators between `NeoFS` interfaces and `neofs.NeoFS` implementation. Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
34a221c5c9
commit
cd64f41ce8
14 changed files with 1348 additions and 606 deletions
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
stderrors "errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
|
@ -18,6 +19,8 @@ import (
|
|||
"github.com/nspcc-dev/neofs-s3-gw/api/notifications"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/api/resolver"
|
||||
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/acl"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/eacl"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||
|
@ -27,12 +30,216 @@ import (
|
|||
"github.com/nspcc-dev/neofs-sdk-go/owner"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/token"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// PrmContainerCreate groups parameters of NeoFS.CreateContainer operation.
|
||||
type PrmContainerCreate struct {
|
||||
// NeoFS identifier of the container creator.
|
||||
Creator owner.ID
|
||||
|
||||
// Container placement policy.
|
||||
Policy netmap.PlacementPolicy
|
||||
|
||||
// Name for the container.
|
||||
Name string
|
||||
|
||||
// Token of the container's creation session. Nil means session absence.
|
||||
SessionToken *session.Token
|
||||
|
||||
// Time when container is created.
|
||||
Time time.Time
|
||||
|
||||
// Basic ACL of the container.
|
||||
BasicACL acl.BasicACL
|
||||
|
||||
// Attribute for LocationConstraint parameter (optional).
|
||||
LocationConstraintAttribute *container.Attribute
|
||||
}
|
||||
|
||||
// PrmAuth groups authentication parameters for the NeoFS operation.
|
||||
type PrmAuth struct {
|
||||
// Bearer token to be used for the operation. Overlaps PrivateKey. Optional.
|
||||
BearerToken *token.BearerToken
|
||||
|
||||
// Private key used for the operation if BearerToken is missing (in this case non-nil).
|
||||
PrivateKey *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
// PrmObjectSelect groups parameters of NeoFS.SelectObjects operation.
|
||||
type PrmObjectSelect struct {
|
||||
// Authentication parameters.
|
||||
PrmAuth
|
||||
|
||||
// Container to select the objects from.
|
||||
Container cid.ID
|
||||
|
||||
// Key-value object attribute which should exactly be
|
||||
// presented in selected objects. Optional, empty key means any.
|
||||
ExactAttribute [2]string
|
||||
|
||||
// File prefix of the selected objects. Optional, empty value means any.
|
||||
FilePrefix string
|
||||
}
|
||||
|
||||
// PrmObjectRead groups parameters of NeoFS.ReadObject operation.
|
||||
type PrmObjectRead struct {
|
||||
// Authentication parameters.
|
||||
PrmAuth
|
||||
|
||||
// Container to read the object header from.
|
||||
Container cid.ID
|
||||
|
||||
// ID of the object for which to read the header.
|
||||
Object oid.ID
|
||||
|
||||
// Flag to read object header.
|
||||
WithHeader bool
|
||||
|
||||
// Flag to read object payload. False overlaps payload range.
|
||||
WithPayload bool
|
||||
|
||||
// Offset-length range of the object payload to be read.
|
||||
PayloadRange [2]uint64
|
||||
}
|
||||
|
||||
// ObjectPart represents partially read NeoFS object.
|
||||
type ObjectPart struct {
|
||||
// Object header with optional in-memory payload part.
|
||||
Head *object.Object
|
||||
|
||||
// Object payload part encapsulated in io.Reader primitive.
|
||||
// Returns ErrAccessDenied on read access violation.
|
||||
Payload io.ReadCloser
|
||||
}
|
||||
|
||||
// PrmObjectCreate groups parameters of NeoFS.CreateObject operation.
|
||||
type PrmObjectCreate struct {
|
||||
// Authentication parameters.
|
||||
PrmAuth
|
||||
|
||||
// Container to store the object.
|
||||
Container cid.ID
|
||||
|
||||
// NeoFS identifier of the object creator.
|
||||
Creator owner.ID
|
||||
|
||||
// Key-value object attributes.
|
||||
Attributes [][2]string
|
||||
|
||||
// Full payload size (optional).
|
||||
PayloadSize uint64
|
||||
|
||||
// Associated filename (optional).
|
||||
Filename string
|
||||
|
||||
// Object payload encapsulated in io.Reader primitive.
|
||||
Payload io.Reader
|
||||
}
|
||||
|
||||
// PrmObjectDelete groups parameters of NeoFS.DeleteObject operation.
|
||||
type PrmObjectDelete struct {
|
||||
// Authentication parameters.
|
||||
PrmAuth
|
||||
|
||||
// Container to delete the object from.
|
||||
Container cid.ID
|
||||
|
||||
// Identifier of the removed object.
|
||||
Object oid.ID
|
||||
}
|
||||
|
||||
// ErrAccessDenied is returned from NeoFS in case of access violation.
|
||||
var ErrAccessDenied = stderrors.New("access denied")
|
||||
|
||||
// NeoFS represents virtual connection to NeoFS network.
|
||||
type NeoFS interface {
|
||||
// CreateContainer creates and saves parameterized container in NeoFS.
|
||||
// Returns ID of the saved container.
|
||||
//
|
||||
// Returns exactly one non-nil value. Returns any error encountered which
|
||||
// prevented the container to be created.
|
||||
CreateContainer(context.Context, PrmContainerCreate) (*cid.ID, error)
|
||||
|
||||
// Container reads container from NeoFS by ID.
|
||||
//
|
||||
// Returns exactly one non-nil value. Returns any error encountered which
|
||||
// prevented the container to be read.
|
||||
Container(context.Context, cid.ID) (*container.Container, error)
|
||||
|
||||
// UserContainers reads list of the containers owned by specified user.
|
||||
//
|
||||
// Returns exactly one non-nil value. Returns any error encountered which
|
||||
// prevented the containers to be listed.
|
||||
UserContainers(context.Context, owner.ID) ([]cid.ID, error)
|
||||
|
||||
// SetContainerEACL saves eACL table of the container in NeoFS.
|
||||
//
|
||||
// Returns any error encountered which prevented the eACL to be saved.
|
||||
SetContainerEACL(context.Context, eacl.Table) error
|
||||
|
||||
// ContainerEACL reads container eACL from NeoFS by container ID.
|
||||
//
|
||||
// Returns exactly one non-nil value. Returns any error encountered which
|
||||
// prevented the eACL to be read.
|
||||
ContainerEACL(context.Context, cid.ID) (*eacl.Table, error)
|
||||
|
||||
// DeleteContainer marks the container to be removed from NeoFS by ID.
|
||||
// Request is sent within session if the session token is specified.
|
||||
// Successful return does not guarantee the actual removal.
|
||||
//
|
||||
// Returns any error encountered which prevented the removal request to be sent.
|
||||
DeleteContainer(context.Context, cid.ID, *session.Token) error
|
||||
|
||||
// SelectObjects perform object selection from the NeoFS container according
|
||||
// to specified parameters. Selects user objects only.
|
||||
//
|
||||
// Returns ErrAccessDenied on selection access violation.
|
||||
//
|
||||
// Returns exactly one non-nil value. Returns any error encountered which
|
||||
// prevented the objects to be selected.
|
||||
SelectObjects(context.Context, PrmObjectSelect) ([]oid.ID, error)
|
||||
|
||||
// ReadObject reads part of the object from the NeoFS container by identifier.
|
||||
// Exact part is returned according to the parameters:
|
||||
// * with header only: empty payload (both in-mem and reader parts are nil);
|
||||
// * with payload only: header is nil (zero range means full payload);
|
||||
// * with header and payload: full in-mem object, payload reader is nil.
|
||||
//
|
||||
// WithHeader or WithPayload is true. Range length is positive if offset is positive.
|
||||
//
|
||||
// Payload reader should be closed if it is no longer needed.
|
||||
//
|
||||
// Returns ErrAccessDenied on read access violation.
|
||||
//
|
||||
// Returns exactly one non-nil value. Returns any error encountered which
|
||||
// prevented the object header to be read.
|
||||
ReadObject(context.Context, PrmObjectRead) (*ObjectPart, error)
|
||||
|
||||
// CreateObject creates and saves parameterized object in the NeoFS container.
|
||||
// Returns ID of the saved object.
|
||||
//
|
||||
// Creation time should be written into object (UTC).
|
||||
//
|
||||
// Returns ErrAccessDenied on write access violation.
|
||||
//
|
||||
// Returns exactly one non-nil value. Returns any error encountered which
|
||||
// prevented the container to be created.
|
||||
CreateObject(context.Context, PrmObjectCreate) (*oid.ID, error)
|
||||
|
||||
// DeleteObject marks the object to be removed from the NeoFS container by identifier.
|
||||
// Successful return does not guarantee the actual removal.
|
||||
//
|
||||
// Returns ErrAccessDenied on remove access violation.
|
||||
//
|
||||
// Returns any error encountered which prevented the removal request to be sent.
|
||||
DeleteObject(context.Context, PrmObjectDelete) error
|
||||
}
|
||||
|
||||
type (
|
||||
layer struct {
|
||||
pool pool.Pool
|
||||
neoFS NeoFS
|
||||
log *zap.Logger
|
||||
anonKey AnonymousKey
|
||||
resolver *resolver.BucketResolver
|
||||
|
@ -66,14 +273,6 @@ type (
|
|||
System *cache.Config
|
||||
}
|
||||
|
||||
// Params stores basic API parameters.
|
||||
Params struct {
|
||||
Pool pool.Pool
|
||||
Logger *zap.Logger
|
||||
Timeout time.Duration
|
||||
Key *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
// GetObjectParams stores object get request parameters.
|
||||
GetObjectParams struct {
|
||||
Range *RangeParams
|
||||
|
@ -183,15 +382,8 @@ type (
|
|||
TagSet map[string]string
|
||||
}
|
||||
|
||||
// NeoFS provides basic NeoFS interface.
|
||||
NeoFS interface {
|
||||
Get(ctx context.Context, address *address.Address) (*object.Object, error)
|
||||
}
|
||||
|
||||
// Client provides S3 API client interface.
|
||||
Client interface {
|
||||
NeoFS
|
||||
|
||||
EphemeralKey() *keys.PublicKey
|
||||
|
||||
PutBucketVersioning(ctx context.Context, p *PutVersioningParams) (*data.ObjectInfo, error)
|
||||
|
@ -262,9 +454,9 @@ func DefaultCachesConfigs() *CachesConfig {
|
|||
|
||||
// NewLayer creates instance of layer. It checks credentials
|
||||
// and establishes gRPC connection with node.
|
||||
func NewLayer(log *zap.Logger, conns pool.Pool, config *Config) Client {
|
||||
func NewLayer(log *zap.Logger, neoFS NeoFS, config *Config) Client {
|
||||
return &layer{
|
||||
pool: conns,
|
||||
neoFS: neoFS,
|
||||
log: log,
|
||||
anonKey: config.AnonKey,
|
||||
resolver: config.Resolver,
|
||||
|
@ -293,17 +485,26 @@ func IsAuthenticatedRequest(ctx context.Context) bool {
|
|||
|
||||
// Owner returns owner id from BearerToken (context) or from client owner.
|
||||
func (n *layer) Owner(ctx context.Context) *owner.ID {
|
||||
if data, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && data != nil && data.Gate != nil {
|
||||
return data.Gate.BearerToken.Issuer()
|
||||
if bd, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && bd != nil && bd.Gate != nil {
|
||||
return bd.Gate.BearerToken.Issuer()
|
||||
}
|
||||
|
||||
return owner.NewIDFromPublicKey((*ecdsa.PublicKey)(n.EphemeralKey()))
|
||||
}
|
||||
|
||||
func (n *layer) prepareAuthParameters(ctx context.Context, prm *PrmAuth) {
|
||||
if bd, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && bd != nil && bd.Gate != nil {
|
||||
prm.BearerToken = bd.Gate.BearerToken
|
||||
return
|
||||
}
|
||||
|
||||
prm.PrivateKey = &n.anonKey.Key.PrivateKey
|
||||
}
|
||||
|
||||
// CallOptions returns []pool.CallOption options: client.WithBearer or client.WithKey (if request is anonymous).
|
||||
func (n *layer) CallOptions(ctx context.Context) []pool.CallOption {
|
||||
if data, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && data != nil && data.Gate != nil {
|
||||
return []pool.CallOption{pool.WithBearer(data.Gate.BearerToken)}
|
||||
if bd, ok := ctx.Value(api.BoxData).(*accessbox.Box); ok && bd != nil && bd.Gate != nil {
|
||||
return []pool.CallOption{pool.WithBearer(bd.Gate.BearerToken)}
|
||||
}
|
||||
|
||||
return []pool.CallOption{pool.WithKey(&n.anonKey.Key.PrivateKey)}
|
||||
|
@ -341,14 +542,14 @@ func (n *layer) GetBucketACL(ctx context.Context, name string) (*BucketACL, erro
|
|||
return nil, err
|
||||
}
|
||||
|
||||
eacl, err := n.GetContainerEACL(ctx, inf.CID)
|
||||
eACL, err := n.GetContainerEACL(ctx, inf.CID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &BucketACL{
|
||||
Info: inf,
|
||||
EACL: eacl,
|
||||
EACL: eACL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue