forked from TrueCloudLab/frostfs-s3-gw
[#455] Use contract to get containers
Signed-off-by: Marina Biryukova <m.biryukova@yadro.com>
This commit is contained in:
parent
949fc0b484
commit
2ad2531d3a
16 changed files with 193 additions and 47 deletions
|
@ -256,6 +256,7 @@ func prepareHandlerContextBase(config *handlerConfig, log *zap.Logger) (*handler
|
||||||
GateOwner: owner,
|
GateOwner: owner,
|
||||||
GateKey: key,
|
GateKey: key,
|
||||||
WorkerPool: pool,
|
WorkerPool: pool,
|
||||||
|
CnrContract: tp,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !config.withoutCORS {
|
if !config.withoutCORS {
|
||||||
|
|
|
@ -7,14 +7,15 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
containerContract "git.frostfs.info/TrueCloudLab/frostfs-contract/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
||||||
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,23 +24,23 @@ const (
|
||||||
AttributeLockEnabled = "LockEnabled"
|
AttributeLockEnabled = "LockEnabled"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (n *Layer) containerInfo(ctx context.Context, prm frostfs.PrmContainer) (*data.BucketInfo, error) {
|
func (n *Layer) containerInfo(ctx context.Context, cnrID cid.ID) (*data.BucketInfo, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
res *container.Container
|
res *container.Container
|
||||||
log = n.reqLogger(ctx).With(zap.Stringer("cid", prm.ContainerID))
|
log = n.reqLogger(ctx).With(zap.Stringer("cid", cnrID))
|
||||||
|
|
||||||
info = &data.BucketInfo{
|
info = &data.BucketInfo{
|
||||||
CID: prm.ContainerID,
|
CID: cnrID,
|
||||||
Name: prm.ContainerID.EncodeToString(),
|
Name: cnrID.EncodeToString(),
|
||||||
}
|
}
|
||||||
|
|
||||||
reqInfo = middleware.GetReqInfo(ctx)
|
reqInfo = middleware.GetReqInfo(ctx)
|
||||||
)
|
)
|
||||||
|
|
||||||
res, err = n.frostFS.Container(ctx, prm)
|
res, err = n.cnrContract.GetContainerByID(cnrID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if client.IsErrContainerNotFound(err) {
|
if strings.Contains(err.Error(), containerContract.NotFoundError) {
|
||||||
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchBucket), err.Error())
|
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrNoSuchBucket), err.Error())
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("get frostfs container: %w", err)
|
return nil, fmt.Errorf("get frostfs container: %w", err)
|
||||||
|
@ -71,7 +72,7 @@ func (n *Layer) containerInfo(ctx context.Context, prm frostfs.PrmContainer) (*d
|
||||||
|
|
||||||
zone := n.features.FormContainerZone(reqInfo.Namespace)
|
zone := n.features.FormContainerZone(reqInfo.Namespace)
|
||||||
if zone != info.Zone {
|
if zone != info.Zone {
|
||||||
return nil, fmt.Errorf("ns '%s' and zone '%s' are mismatched for container '%s'", zone, info.Zone, prm.ContainerID)
|
return nil, fmt.Errorf("ns '%s' and zone '%s' are mismatched for container '%s'", zone, info.Zone, cnrID)
|
||||||
}
|
}
|
||||||
|
|
||||||
n.cache.PutBucket(info)
|
n.cache.PutBucket(info)
|
||||||
|
@ -95,11 +96,7 @@ func (n *Layer) containerList(ctx context.Context, listParams ListBucketsParams)
|
||||||
|
|
||||||
list := make([]*data.BucketInfo, 0, len(res))
|
list := make([]*data.BucketInfo, 0, len(res))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
getPrm := frostfs.PrmContainer{
|
info, err := n.containerInfo(ctx, res[i])
|
||||||
ContainerID: res[i],
|
|
||||||
SessionToken: stoken,
|
|
||||||
}
|
|
||||||
info, err := n.containerInfo(ctx, getPrm)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.reqLogger(ctx).Error(logs.CouldNotFetchContainerInfo, zap.Error(err), logs.TagField(logs.TagExternalStorage))
|
n.reqLogger(ctx).Error(logs.CouldNotFetchContainerInfo, zap.Error(err), logs.TagField(logs.TagExternalStorage))
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -361,3 +361,8 @@ type FrostFS interface {
|
||||||
// NetmapSnapshot returns information about FrostFS network map.
|
// NetmapSnapshot returns information about FrostFS network map.
|
||||||
NetmapSnapshot(context.Context) (netmap.NetMap, error)
|
NetmapSnapshot(context.Context) (netmap.NetMap, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ContainerContract interface {
|
||||||
|
// GetContainerByID reads a container from contract by ID.
|
||||||
|
GetContainerByID(cid.ID) (*container.Container, error)
|
||||||
|
}
|
||||||
|
|
|
@ -621,6 +621,16 @@ func (t *TestFrostFS) AddContainerPolicyChain(_ context.Context, prm frostfs.Prm
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *TestFrostFS) GetContainerByID(cid cid.ID) (*container.Container, error) {
|
||||||
|
for k, v := range t.containers {
|
||||||
|
if k == cid.EncodeToString() {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("container does not exist %s", cid)
|
||||||
|
}
|
||||||
|
|
||||||
func (t *TestFrostFS) checkAccess(cnrID cid.ID, owner user.ID) bool {
|
func (t *TestFrostFS) checkAccess(cnrID cid.ID, owner user.ID) bool {
|
||||||
cnr, ok := t.containers[cnrID.EncodeToString()]
|
cnr, ok := t.containers[cnrID.EncodeToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -67,6 +67,7 @@ type (
|
||||||
lifecycleCnrInfo *data.BucketInfo
|
lifecycleCnrInfo *data.BucketInfo
|
||||||
workerPool *ants.Pool
|
workerPool *ants.Pool
|
||||||
removalChan chan removalParams
|
removalChan chan removalParams
|
||||||
|
cnrContract frostfs.ContainerContract
|
||||||
}
|
}
|
||||||
|
|
||||||
removalParams struct {
|
removalParams struct {
|
||||||
|
@ -89,6 +90,7 @@ type (
|
||||||
CORSCnrInfo *data.BucketInfo
|
CORSCnrInfo *data.BucketInfo
|
||||||
LifecycleCnrInfo *data.BucketInfo
|
LifecycleCnrInfo *data.BucketInfo
|
||||||
WorkerPool *ants.Pool
|
WorkerPool *ants.Pool
|
||||||
|
CnrContract frostfs.ContainerContract
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnonymousKey contains data for anonymous requests.
|
// AnonymousKey contains data for anonymous requests.
|
||||||
|
@ -284,6 +286,7 @@ func NewLayer(ctx context.Context, log *zap.Logger, frostFS frostfs.FrostFS, con
|
||||||
workerPool: config.WorkerPool,
|
workerPool: config.WorkerPool,
|
||||||
// TODO: consider closing channel
|
// TODO: consider closing channel
|
||||||
removalChan: make(chan removalParams, config.Features.RemoveOnReplaceQueue()),
|
removalChan: make(chan removalParams, config.Features.RemoveOnReplaceQueue()),
|
||||||
|
cnrContract: config.CnrContract,
|
||||||
}
|
}
|
||||||
|
|
||||||
go layer.removalRoutine(ctx)
|
go layer.removalRoutine(ctx)
|
||||||
|
@ -379,12 +382,7 @@ func (n *Layer) GetBucketInfo(ctx context.Context, name string) (*data.BucketInf
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
prm := frostfs.PrmContainer{
|
return n.containerInfo(ctx, containerID)
|
||||||
ContainerID: containerID,
|
|
||||||
SessionToken: n.SessionTokenForRead(ctx),
|
|
||||||
}
|
|
||||||
|
|
||||||
return n.containerInfo(ctx, prm)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolveCID returns container id by name.
|
// ResolveCID returns container id by name.
|
||||||
|
|
|
@ -176,6 +176,7 @@ func prepareContext(t *testing.T, cachesConfig ...*CachesConfig) *testContext {
|
||||||
TreeService: NewTreeService(),
|
TreeService: NewTreeService(),
|
||||||
Features: &FeatureSettingsMock{},
|
Features: &FeatureSettingsMock{},
|
||||||
GateOwner: owner,
|
GateOwner: owner,
|
||||||
|
CnrContract: tp,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &testContext{
|
return &testContext{
|
||||||
|
@ -237,6 +238,7 @@ func prepareCORSContext(t *testing.T, cachesConfig ...*CachesConfig) *testContex
|
||||||
CORSCnrInfo: corsCnrInfo,
|
CORSCnrInfo: corsCnrInfo,
|
||||||
LifecycleCnrInfo: lifecycleCnrInfo,
|
LifecycleCnrInfo: lifecycleCnrInfo,
|
||||||
GateKey: key,
|
GateKey: key,
|
||||||
|
CnrContract: tp,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &testContext{
|
return &testContext{
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/wallet"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -112,6 +113,11 @@ func parseKeys() (userKey *keys.PrivateKey, contractKey *keys.PrivateKey, err er
|
||||||
func initFrostFSIDContract(ctx context.Context, log *zap.Logger, key *keys.PrivateKey) (*ffsidContract.FrostFSID, error) {
|
func initFrostFSIDContract(ctx context.Context, log *zap.Logger, key *keys.PrivateKey) (*ffsidContract.FrostFSID, error) {
|
||||||
log.Debug(logs.PrepareFrostfsIDClient)
|
log.Debug(logs.PrepareFrostfsIDClient)
|
||||||
|
|
||||||
|
rpcCli, err := rpcclient.New(ctx, viper.GetString(rpcEndpointFlag), rpcclient.Options{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("create rpc client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
cfg := ffsidContract.Config{
|
cfg := ffsidContract.Config{
|
||||||
RPCAddress: viper.GetString(rpcEndpointFlag),
|
RPCAddress: viper.GetString(rpcEndpointFlag),
|
||||||
Contract: viper.GetString(frostfsIDContractFlag),
|
Contract: viper.GetString(frostfsIDContractFlag),
|
||||||
|
@ -121,9 +127,10 @@ func initFrostFSIDContract(ctx context.Context, log *zap.Logger, key *keys.Priva
|
||||||
IgnoreAlreadyExistsError: false,
|
IgnoreAlreadyExistsError: false,
|
||||||
VerifyExecResults: true,
|
VerifyExecResults: true,
|
||||||
},
|
},
|
||||||
|
RPCClient: rpcCli,
|
||||||
}
|
}
|
||||||
|
|
||||||
cli, err := ffsidContract.New(ctx, cfg)
|
cli, err := ffsidContract.New(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("create frostfsid client: %w", err)
|
return nil, fmt.Errorf("create frostfsid client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -160,14 +167,20 @@ func registerPublicKey(log *zap.Logger, cli *ffsidContract.FrostFSID, key *keys.
|
||||||
func initPolicyContract(ctx context.Context, log *zap.Logger, key *keys.PrivateKey) (*policyContact.Client, error) {
|
func initPolicyContract(ctx context.Context, log *zap.Logger, key *keys.PrivateKey) (*policyContact.Client, error) {
|
||||||
log.Debug(logs.PreparePolicyClient)
|
log.Debug(logs.PreparePolicyClient)
|
||||||
|
|
||||||
|
rpcCli, err := rpcclient.New(ctx, viper.GetString(rpcEndpointFlag), rpcclient.Options{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("create rpc client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
cfg := policyContact.Config{
|
cfg := policyContact.Config{
|
||||||
RPCAddress: viper.GetString(rpcEndpointFlag),
|
RPCAddress: viper.GetString(rpcEndpointFlag),
|
||||||
Contract: viper.GetString(policyContractFlag),
|
Contract: viper.GetString(policyContractFlag),
|
||||||
ProxyContract: viper.GetString(proxyContractFlag),
|
ProxyContract: viper.GetString(proxyContractFlag),
|
||||||
Key: key,
|
Key: key,
|
||||||
|
RPCClient: rpcCli,
|
||||||
}
|
}
|
||||||
|
|
||||||
cli, err := policyContact.New(ctx, cfg)
|
cli, err := policyContact.New(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("create policy client: %w", err)
|
return nil, fmt.Errorf("create policy client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/resolver"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/resolver"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/tokens"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
|
||||||
|
containerClient "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
|
||||||
ffidcontract "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
|
ffidcontract "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
||||||
|
@ -51,6 +52,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -249,14 +251,23 @@ func (a *App) init(ctx context.Context) {
|
||||||
a.initResolver()
|
a.initResolver()
|
||||||
a.initAuthCenter(ctx)
|
a.initAuthCenter(ctx)
|
||||||
a.setRuntimeParameters()
|
a.setRuntimeParameters()
|
||||||
a.initFrostfsID(ctx)
|
rpcCli := a.initRPCClient(ctx)
|
||||||
a.initPolicyStorage(ctx)
|
a.initFrostfsID(rpcCli)
|
||||||
a.initAPI(ctx)
|
a.initPolicyStorage(rpcCli)
|
||||||
|
a.initAPI(ctx, rpcCli)
|
||||||
a.initMetrics()
|
a.initMetrics()
|
||||||
a.initServers(ctx)
|
a.initServers(ctx)
|
||||||
a.initTracing(ctx)
|
a.initTracing(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) initRPCClient(ctx context.Context) *rpcclient.Client {
|
||||||
|
rpcCli, err := rpcclient.New(ctx, a.config().GetString(cfgRPCEndpoint), rpcclient.Options{})
|
||||||
|
if err != nil {
|
||||||
|
a.log.Fatal(logs.InitRPCClientFailed, zap.Error(err), logs.TagField(logs.TagApp))
|
||||||
|
}
|
||||||
|
return rpcCli
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) initAuthCenter(ctx context.Context) {
|
func (a *App) initAuthCenter(ctx context.Context) {
|
||||||
if a.config().IsSet(cfgContainersAccessBox) {
|
if a.config().IsSet(cfgContainersAccessBox) {
|
||||||
cnrID, err := a.resolveContainerID(ctx, cfgContainersAccessBox)
|
cnrID, err := a.resolveContainerID(ctx, cfgContainersAccessBox)
|
||||||
|
@ -276,7 +287,7 @@ func (a *App) initAuthCenter(ctx context.Context) {
|
||||||
a.ctr = auth.New(tokens.New(cfg), a.config().GetStringSlice(cfgAllowedAccessKeyIDPrefixes), a.settings)
|
a.ctr = auth.New(tokens.New(cfg), a.config().GetStringSlice(cfgAllowedAccessKeyIDPrefixes), a.settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initLayer(ctx context.Context) {
|
func (a *App) initLayer(ctx context.Context, rpcCli *rpcclient.Client) {
|
||||||
// prepare random key for anonymous requests
|
// prepare random key for anonymous requests
|
||||||
randomKey, err := keys.NewPrivateKey()
|
randomKey, err := keys.NewPrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -299,6 +310,16 @@ func (a *App) initLayer(ctx context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cnrClient, err := containerClient.New(containerClient.Config{
|
||||||
|
RPCAddress: a.config().GetString(cfgRPCEndpoint),
|
||||||
|
Contract: a.config().GetString(cfgContractsContainerName),
|
||||||
|
Key: a.key,
|
||||||
|
RPCClient: rpcCli,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
a.log.Fatal(logs.InitContainerContractFailed, zap.Error(err), logs.TagField(logs.TagApp))
|
||||||
|
}
|
||||||
|
|
||||||
layerCfg := &layer.Config{
|
layerCfg := &layer.Config{
|
||||||
Cache: a.cache,
|
Cache: a.cache,
|
||||||
AnonKey: layer.AnonymousKey{
|
AnonKey: layer.AnonymousKey{
|
||||||
|
@ -312,6 +333,7 @@ func (a *App) initLayer(ctx context.Context) {
|
||||||
CORSCnrInfo: corsCnrInfo,
|
CORSCnrInfo: corsCnrInfo,
|
||||||
LifecycleCnrInfo: lifecycleCnrInfo,
|
LifecycleCnrInfo: lifecycleCnrInfo,
|
||||||
WorkerPool: a.initWorkerPool(),
|
WorkerPool: a.initWorkerPool(),
|
||||||
|
CnrContract: cnrClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare object layer
|
// prepare object layer
|
||||||
|
@ -694,8 +716,8 @@ func (s *appSettings) LifecycleCopiesNumbers() []uint32 {
|
||||||
return s.lifecycleCopiesNumbers
|
return s.lifecycleCopiesNumbers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initAPI(ctx context.Context) {
|
func (a *App) initAPI(ctx context.Context, rpcCli *rpcclient.Client) {
|
||||||
a.initLayer(ctx)
|
a.initLayer(ctx, rpcCli)
|
||||||
a.initHandler()
|
a.initHandler()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,8 +734,8 @@ func (a *App) initMetrics() {
|
||||||
a.loggerSettings.setMetrics(a.metrics)
|
a.loggerSettings.setMetrics(a.metrics)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initFrostfsID(ctx context.Context) {
|
func (a *App) initFrostfsID(rpcCli *rpcclient.Client) {
|
||||||
cli, err := ffidcontract.New(ctx, ffidcontract.Config{
|
cli, err := ffidcontract.New(ffidcontract.Config{
|
||||||
RPCAddress: a.config().GetString(cfgRPCEndpoint),
|
RPCAddress: a.config().GetString(cfgRPCEndpoint),
|
||||||
Contract: a.config().GetString(cfgFrostfsIDContract),
|
Contract: a.config().GetString(cfgFrostfsIDContract),
|
||||||
ProxyContract: a.config().GetString(cfgProxyContract),
|
ProxyContract: a.config().GetString(cfgProxyContract),
|
||||||
|
@ -722,6 +744,7 @@ func (a *App) initFrostfsID(ctx context.Context) {
|
||||||
IgnoreAlreadyExistsError: false,
|
IgnoreAlreadyExistsError: false,
|
||||||
VerifyExecResults: true,
|
VerifyExecResults: true,
|
||||||
},
|
},
|
||||||
|
RPCClient: rpcCli,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.log.Fatal(logs.InitFrostfsIDFailed, zap.Error(err), logs.TagField(logs.TagApp))
|
a.log.Fatal(logs.InitFrostfsIDFailed, zap.Error(err), logs.TagField(logs.TagApp))
|
||||||
|
@ -737,8 +760,8 @@ func (a *App) initFrostfsID(ctx context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initPolicyStorage(ctx context.Context) {
|
func (a *App) initPolicyStorage(rpcCli *rpcclient.Client) {
|
||||||
policyContract, err := contract.New(ctx, contract.Config{
|
policyContract, err := contract.New(contract.Config{
|
||||||
RPCAddress: a.config().GetString(cfgRPCEndpoint),
|
RPCAddress: a.config().GetString(cfgRPCEndpoint),
|
||||||
Contract: a.config().GetString(cfgPolicyContract),
|
Contract: a.config().GetString(cfgPolicyContract),
|
||||||
ProxyContract: a.config().GetString(cfgProxyContract),
|
ProxyContract: a.config().GetString(cfgProxyContract),
|
||||||
|
@ -747,6 +770,7 @@ func (a *App) initPolicyStorage(ctx context.Context) {
|
||||||
IgnoreAlreadyExistsError: false,
|
IgnoreAlreadyExistsError: false,
|
||||||
VerifyExecResults: true,
|
VerifyExecResults: true,
|
||||||
},
|
},
|
||||||
|
RPCClient: rpcCli,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.log.Fatal(logs.InitPolicyContractFailed, zap.Error(err), logs.TagField(logs.TagApp))
|
a.log.Fatal(logs.InitPolicyContractFailed, zap.Error(err), logs.TagField(logs.TagApp))
|
||||||
|
|
|
@ -306,6 +306,9 @@ const (
|
||||||
// Encryption.
|
// Encryption.
|
||||||
cfgEncryptionTLSTerminationHeader = "encryption.tls_termination_header"
|
cfgEncryptionTLSTerminationHeader = "encryption.tls_termination_header"
|
||||||
|
|
||||||
|
// Contracts.
|
||||||
|
cfgContractsContainerName = "contracts.container.name"
|
||||||
|
|
||||||
// envPrefix is an environment variables prefix used for configuration.
|
// envPrefix is an environment variables prefix used for configuration.
|
||||||
envPrefix = "S3_GW"
|
envPrefix = "S3_GW"
|
||||||
)
|
)
|
||||||
|
@ -1190,6 +1193,9 @@ func setDefaults(v *viper.Viper, flags *pflag.FlagSet) {
|
||||||
// proxy
|
// proxy
|
||||||
v.SetDefault(cfgProxyContract, "proxy.frostfs")
|
v.SetDefault(cfgProxyContract, "proxy.frostfs")
|
||||||
|
|
||||||
|
// contracts
|
||||||
|
v.SetDefault(cfgContractsContainerName, "container.frostfs")
|
||||||
|
|
||||||
// resolve
|
// resolve
|
||||||
v.SetDefault(cfgResolveNamespaceHeader, defaultNamespaceHeader)
|
v.SetDefault(cfgResolveNamespaceHeader, defaultNamespaceHeader)
|
||||||
|
|
||||||
|
|
|
@ -307,3 +307,6 @@ S3_GW_MULTINET_SUBNETS_1_SOURCE_IPS=1.2.3.4 1.2.3.5
|
||||||
|
|
||||||
# Header for determining the termination of TLS.
|
# Header for determining the termination of TLS.
|
||||||
S3_GW_ENCRYPTION_TLS_TERMINATION_TLS_HEADER=X-Frostfs-TLS-Termination
|
S3_GW_ENCRYPTION_TLS_TERMINATION_TLS_HEADER=X-Frostfs-TLS-Termination
|
||||||
|
|
||||||
|
# Container contract hash (LE) or name in NNS.
|
||||||
|
S3_GW_CONTRACTS_CONTAINER_NAME=container.frostfs
|
||||||
|
|
|
@ -362,3 +362,8 @@ multinet:
|
||||||
|
|
||||||
encryption:
|
encryption:
|
||||||
tls_termination_header: X-Frostfs-TLS-Termination
|
tls_termination_header: X-Frostfs-TLS-Termination
|
||||||
|
|
||||||
|
contracts:
|
||||||
|
container:
|
||||||
|
# Container contract hash (LE) or name in NNS.
|
||||||
|
name: container.frostfs
|
||||||
|
|
|
@ -202,6 +202,7 @@ There are some custom types used for brevity:
|
||||||
| `vhs` | [VHS configuration](#vhs-section) |
|
| `vhs` | [VHS configuration](#vhs-section) |
|
||||||
| `multinet` | [Multinet configuration](#multinet-section) |
|
| `multinet` | [Multinet configuration](#multinet-section) |
|
||||||
| `encryption` | [Encryption configuration](#encryption-section) |
|
| `encryption` | [Encryption configuration](#encryption-section) |
|
||||||
|
| `contracts` | [Contracts configuration](#contracts-section) |
|
||||||
|
|
||||||
### General section
|
### General section
|
||||||
|
|
||||||
|
@ -971,3 +972,16 @@ encryption:
|
||||||
| Parameter | Type | SIGHUP reload | Default value | Description |
|
| Parameter | Type | SIGHUP reload | Default value | Description |
|
||||||
|--------------------------|----------|---------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|--------------------------|----------|---------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `tls_termination_header` | `string` | yes | | The header for determining whether TLS needs to be checked. If the system requests come through a proxy server and TLS can terminate at the proxy level, you should use this header to disable TLS verification at server-side encryption. If the header is not specified or an empty string is set as the value, TLS will always be checked. |
|
| `tls_termination_header` | `string` | yes | | The header for determining whether TLS needs to be checked. If the system requests come through a proxy server and TLS can terminate at the proxy level, you should use this header to disable TLS verification at server-side encryption. If the header is not specified or an empty string is set as the value, TLS will always be checked. |
|
||||||
|
|
||||||
|
# `contracts` section
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
contracts:
|
||||||
|
container:
|
||||||
|
name: container.frostfs
|
||||||
|
```
|
||||||
|
|
||||||
|
| Parameter | Type | SIGHUP reload | Default value | Description |
|
||||||
|
|------------------|----------|---------------|---------------------|----------------------------------------------|
|
||||||
|
| `container.name` | `string` | no | `container.frostfs` | Container contract hash (LE) or name in NNS. |
|
||||||
|
|
||||||
|
|
72
internal/frostfs/container/client.go
Normal file
72
internal/frostfs/container/client.go
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
containerContract "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/container"
|
||||||
|
frostfsutil "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
contract *containerContract.Contract
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
RPCAddress string
|
||||||
|
Contract string
|
||||||
|
Key *keys.PrivateKey
|
||||||
|
RPCClient *rpcclient.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg Config) (*Client, error) {
|
||||||
|
contractHash, err := frostfsutil.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
key := cfg.Key
|
||||||
|
if key == nil {
|
||||||
|
if key, err = keys.NewPrivateKey(); err != nil {
|
||||||
|
return nil, fmt.Errorf("generate anon private key for container contract: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc := wallet.NewAccountFromPrivateKey(key)
|
||||||
|
|
||||||
|
act, err := actor.NewSimple(cfg.RPCClient, acc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("create new actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Client{
|
||||||
|
contract: containerContract.New(act, contractHash),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetContainerByID(cnrID cid.ID) (*container.Container, error) {
|
||||||
|
items, err := c.contract.Get(cnrID[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("get container by cid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(items) != 4 {
|
||||||
|
return nil, fmt.Errorf("unexpected container stack item count: %d", len(items))
|
||||||
|
}
|
||||||
|
|
||||||
|
cnrBytes, err := items[0].TryBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not get byte array of container: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var cnr container.Container
|
||||||
|
if err = cnr.Unmarshal(cnrBytes); err != nil {
|
||||||
|
return nil, fmt.Errorf("can't unmarshal container: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cnr, nil
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package contract
|
package contract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/commonclient"
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/commonclient"
|
||||||
|
@ -34,10 +33,13 @@ type Config struct {
|
||||||
// Waiter contains options for awaiting blockchain transactions
|
// Waiter contains options for awaiting blockchain transactions
|
||||||
// submitted via the contract client.
|
// submitted via the contract client.
|
||||||
Waiter commonclient.WaiterOptions
|
Waiter commonclient.WaiterOptions
|
||||||
|
|
||||||
|
// RPCClient is a client to neo rpc.
|
||||||
|
RPCClient *rpcclient.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
|
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
|
||||||
func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
|
func New(cfg Config) (*FrostFSID, error) {
|
||||||
contractHash, err := frostfsutil.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
|
contractHash, err := frostfsutil.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
||||||
|
@ -50,11 +52,6 @@ func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcCli, err := rpcclient.New(ctx, cfg.RPCAddress, rpcclient.Options{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("init rpc client: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var opt client.Options
|
var opt client.Options
|
||||||
opt.ProxyContract, err = frostfsutil.ResolveContractHash(cfg.ProxyContract, cfg.RPCAddress)
|
opt.ProxyContract, err = frostfsutil.ResolveContractHash(cfg.ProxyContract, cfg.RPCAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -62,7 +59,7 @@ func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
|
||||||
}
|
}
|
||||||
opt.Waiter = cfg.Waiter
|
opt.Waiter = cfg.Waiter
|
||||||
|
|
||||||
cli, err := client.New(rpcCli, wallet.NewAccountFromPrivateKey(key), contractHash, opt)
|
cli, err := client.New(cfg.RPCClient, wallet.NewAccountFromPrivateKey(key), contractHash, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("init frostfsid client: %w", err)
|
return nil, fmt.Errorf("init frostfsid client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package contract
|
package contract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
@ -45,6 +44,9 @@ type Config struct {
|
||||||
// Waiter contains options for awaiting blockchain transactions
|
// Waiter contains options for awaiting blockchain transactions
|
||||||
// submitted via the contract client.
|
// submitted via the contract client.
|
||||||
Waiter commonclient.WaiterOptions
|
Waiter commonclient.WaiterOptions
|
||||||
|
|
||||||
|
// RPCClient is a client to neo rpc.
|
||||||
|
RPCClient *rpcclient.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -55,7 +57,7 @@ const (
|
||||||
var _ policy.Contract = (*Client)(nil)
|
var _ policy.Contract = (*Client)(nil)
|
||||||
|
|
||||||
// New creates new Policy contract wrapper.
|
// New creates new Policy contract wrapper.
|
||||||
func New(ctx context.Context, cfg Config) (*Client, error) {
|
func New(cfg Config) (*Client, error) {
|
||||||
contractHash, err := frostfsutil.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
|
contractHash, err := frostfsutil.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
||||||
|
@ -68,17 +70,12 @@ func New(ctx context.Context, cfg Config) (*Client, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcCli, err := rpcclient.New(ctx, cfg.RPCAddress, rpcclient.Options{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("create policy rpc client: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyContractHash, err := frostfsutil.ResolveContractHash(cfg.ProxyContract, cfg.RPCAddress)
|
proxyContractHash, err := frostfsutil.ResolveContractHash(cfg.ProxyContract, cfg.RPCAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
act, err := actor.New(rpcCli, getSigners(key, proxyContractHash, contractHash))
|
act, err := actor.New(cfg.RPCClient, getSigners(key, proxyContractHash, contractHash))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("create new actor: %w", err)
|
return nil, fmt.Errorf("create new actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,8 @@ const (
|
||||||
WarnDuplicateNamespaceVHS = "duplicate namespace with enabled VHS, config value skipped"
|
WarnDuplicateNamespaceVHS = "duplicate namespace with enabled VHS, config value skipped"
|
||||||
WarnValueVHSEnabledFlagWrongType = "the value of the VHS enable flag for the namespace is of the wrong type, config value skipped"
|
WarnValueVHSEnabledFlagWrongType = "the value of the VHS enable flag for the namespace is of the wrong type, config value skipped"
|
||||||
WarnDomainContainsInvalidPlaceholder = "the domain contains an invalid placeholder, domain skipped"
|
WarnDomainContainsInvalidPlaceholder = "the domain contains an invalid placeholder, domain skipped"
|
||||||
|
InitContainerContractFailed = "init container contract failed"
|
||||||
|
InitRPCClientFailed = "init rpc client failed"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Datapath.
|
// Datapath.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue