diff --git a/api/layer/container.go b/api/layer/container.go index 5307c2ca..cf05ff52 100644 --- a/api/layer/container.go +++ b/api/layer/container.go @@ -26,6 +26,8 @@ type ( } ) +const nnsNameAttr = "__NEOFS__NAME" + func (n *layer) containerInfo(ctx context.Context, cid *cid.ID) (*data.BucketInfo, error) { var ( err error @@ -126,6 +128,7 @@ func (n *layer) createContainer(ctx context.Context, p *CreateBucketParams) (*ci container.WithPolicy(p.Policy), container.WithCustomBasicACL(p.ACL), container.WithAttribute(container.AttributeName, p.Name), + container.WithAttribute(nnsNameAttr, p.Name), container.WithAttribute(container.AttributeTimestamp, strconv.FormatInt(bktInfo.Created.Unix(), 10))) cnr.SetSessionToken(p.SessionToken) diff --git a/api/layer/layer.go b/api/layer/layer.go index c689ddb3..5de98473 100644 --- a/api/layer/layer.go +++ b/api/layer/layer.go @@ -24,6 +24,7 @@ import ( "github.com/nspcc-dev/neofs-sdk-go/object" "github.com/nspcc-dev/neofs-sdk-go/owner" "github.com/nspcc-dev/neofs-sdk-go/pool" + "github.com/nspcc-dev/neofs-sdk-go/resolver" "github.com/nspcc-dev/neofs-sdk-go/session" "go.uber.org/zap" ) @@ -40,6 +41,12 @@ type ( systemCache *cache.SystemCache } + Config struct { + ChainAddress string + Caches *CachesConfig + AnonKey AnonymousKey + } + // AnonymousKey contains data for anonymous requests. AnonymousKey struct { Key *keys.PrivateKey @@ -218,8 +225,9 @@ type ( ) const ( - tagPrefix = "S3-Tag-" - tagEmptyMark = "\\" + tagPrefix = "S3-Tag-" + tagEmptyMark = "\\" + networkSystemDNSParam = "SystemDNS" ) func (t *VersionedObject) String() string { @@ -239,16 +247,16 @@ 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 *CachesConfig, anonKey AnonymousKey) Client { +func NewLayer(log *zap.Logger, conns pool.Pool, config *Config) Client { return &layer{ pool: conns, log: log, - anonKey: anonKey, - listsCache: cache.NewObjectsListCache(config.ObjectsList), - objCache: cache.New(config.Objects), - namesCache: cache.NewObjectsNameCache(config.Names), - bucketCache: cache.NewBucketCache(config.Buckets), - systemCache: cache.NewSystemCache(config.System), + anonKey: config.AnonKey, + listsCache: cache.NewObjectsListCache(config.Caches.ObjectsList), + objCache: cache.New(config.Caches.Objects), + namesCache: cache.NewObjectsNameCache(config.Caches.Names), + bucketCache: cache.NewBucketCache(config.Caches.Buckets), + systemCache: cache.NewSystemCache(config.Caches.System), } } @@ -301,18 +309,9 @@ func (n *layer) GetBucketInfo(ctx context.Context, name string) (*data.BucketInf return bktInfo, nil } - containerID := new(cid.ID) - if err := containerID.Parse(name); err != nil { - list, err := n.containerList(ctx) - if err != nil { - return nil, err - } - for _, bkt := range list { - if bkt.Name == name { - return bkt, nil - } - } - + containerID, err := n.ResolveBucket(ctx, name) + if err != nil { + n.log.Debug("bucket not found", zap.Error(err)) return nil, errors.GetAPIError(errors.ErrNoSuchBucket) } @@ -636,6 +635,45 @@ func (n *layer) CreateBucket(ctx context.Context, p *CreateBucketParams) (*cid.I return nil, errors.GetAPIError(errors.ErrBucketAlreadyExists) } +func (n *layer) ResolveBucket(ctx context.Context, name string) (*cid.ID, error) { + cnrID := cid.New() + if err := cnrID.Parse(name); err != nil { + conn, _, err := n.pool.Connection() + if err != nil { + return nil, err + } + + networkInfo, err := conn.NetworkInfo(ctx) + if err != nil { + return nil, err + } + + var domain string + networkInfo.NetworkConfig().IterateParameters(func(parameter *netmap.NetworkParameter) bool { + if string(parameter.Key()) == networkSystemDNSParam { + domain = string(parameter.Value()) + return true + } + return false + }) + + if domain != "" { + domain = name + "." + domain + if cnrID, err = resolver.ResolveContainerDomainName(domain); err == nil { + return cnrID, nil + } + n.log.Debug("trying fallback to direct nns since couldn't resolve system dns record", + zap.String("domain", domain), zap.Error(err)) + } + + // todo add fallback to use nns contract directly + + return nil, fmt.Errorf("couldn't resolve container name '%s': not found", name) + } + + return cnrID, nil +} + func (n *layer) DeleteBucket(ctx context.Context, p *DeleteBucketParams) error { bucketInfo, err := n.GetBucketInfo(ctx, p.Name) if err != nil { diff --git a/api/layer/versioning_test.go b/api/layer/versioning_test.go index 7756d267..408b7bbf 100644 --- a/api/layer/versioning_test.go +++ b/api/layer/versioning_test.go @@ -214,7 +214,7 @@ func (t *testPool) WaitForContainerPresence(ctx context.Context, id *cid.ID, par func (tc *testContext) putObject(content []byte) *data.ObjectInfo { objInfo, err := tc.layer.PutObject(tc.ctx, &PutObjectParams{ - Bucket: tc.bkt, + Bucket: tc.bktID.String(), Object: tc.obj, Size: int64(len(content)), Reader: bytes.NewReader(content), @@ -348,9 +348,14 @@ func prepareContext(t *testing.T, cachesConfig ...*CachesConfig) *testContext { config = cachesConfig[0] } + layerCfg := &Config{ + Caches: config, + AnonKey: AnonymousKey{Key: key}, + } + return &testContext{ ctx: ctx, - layer: NewLayer(l, tp, config, AnonymousKey{Key: key}), + layer: NewLayer(l, tp, layerCfg), bkt: bktName, bktID: bktID, obj: "obj1", @@ -362,7 +367,7 @@ func prepareContext(t *testing.T, cachesConfig ...*CachesConfig) *testContext { func TestSimpleVersioning(t *testing.T) { tc := prepareContext(t) _, err := tc.layer.PutBucketVersioning(tc.ctx, &PutVersioningParams{ - Bucket: tc.bkt, + Bucket: tc.bktID.String(), Settings: &BucketSettings{VersioningEnabled: true}, }) require.NoError(t, err) @@ -403,7 +408,7 @@ func TestSimpleNoVersioning(t *testing.T) { func TestVersioningDeleteObject(t *testing.T) { tc := prepareContext(t) _, err := tc.layer.PutBucketVersioning(tc.ctx, &PutVersioningParams{ - Bucket: tc.bkt, + Bucket: tc.bktID.String(), Settings: &BucketSettings{VersioningEnabled: true}, }) require.NoError(t, err) @@ -420,7 +425,7 @@ func TestVersioningDeleteObject(t *testing.T) { func TestVersioningDeleteSpecificObjectVersion(t *testing.T) { tc := prepareContext(t) _, err := tc.layer.PutBucketVersioning(tc.ctx, &PutVersioningParams{ - Bucket: tc.bkt, + Bucket: tc.bktID.String(), Settings: &BucketSettings{VersioningEnabled: true}, }) require.NoError(t, err) @@ -751,7 +756,7 @@ func TestSystemObjectsVersioning(t *testing.T) { tc := prepareContext(t, cacheConfig) objInfo, err := tc.layer.PutBucketVersioning(tc.ctx, &PutVersioningParams{ - Bucket: tc.bkt, + Bucket: tc.bktID.String(), Settings: &BucketSettings{VersioningEnabled: false}, }) require.NoError(t, err) @@ -760,7 +765,7 @@ func TestSystemObjectsVersioning(t *testing.T) { require.True(t, ok) _, err = tc.layer.PutBucketVersioning(tc.ctx, &PutVersioningParams{ - Bucket: tc.bkt, + Bucket: tc.bktID.String(), Settings: &BucketSettings{VersioningEnabled: true}, }) require.NoError(t, err) @@ -783,10 +788,10 @@ func TestDeleteSystemObjectsVersioning(t *testing.T) { "tag1": "val1", } - err := tc.layer.PutBucketTagging(tc.ctx, tc.bkt, tagSet) + err := tc.layer.PutBucketTagging(tc.ctx, tc.bktID.String(), tagSet) require.NoError(t, err) - objMeta := tc.getSystemObject(formBucketTagObjectName(tc.bkt)) + objMeta := tc.getSystemObject(formBucketTagObjectName(tc.bktID.String())) tagSet["tag2"] = "val2" err = tc.layer.PutBucketTagging(tc.ctx, tc.bkt, tagSet) diff --git a/cmd/s3-gw/app.go b/cmd/s3-gw/app.go index 745bffd0..3e6ff669 100644 --- a/cmd/s3-gw/app.go +++ b/cmd/s3-gw/app.go @@ -117,14 +117,16 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App { if err != nil { l.Fatal("couldn't generate random key", zap.Error(err)) } - anonKey := layer.AnonymousKey{ - Key: randomKey, + + layerCfg := &layer.Config{ + Caches: getCacheOptions(v, l), + AnonKey: layer.AnonymousKey{ + Key: randomKey, + }, } - cacheCfg := getCacheOptions(v, l) - // prepare object layer - obj = layer.NewLayer(l, conns, cacheCfg, anonKey) + obj = layer.NewLayer(l, conns, layerCfg) // prepare auth center ctr = auth.New(conns, key, getAccessBoxCacheConfig(v, l)) diff --git a/go.mod b/go.mod index 75b4f634..7c0f7a1c 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/gorilla/mux v1.8.0 github.com/nspcc-dev/neo-go v0.97.3 github.com/nspcc-dev/neofs-api-go v1.30.0 - github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211115110427-df6a622c20e8 + github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211122074021-02f328a03cfb github.com/prometheus/client_golang v1.11.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.1 diff --git a/go.sum b/go.sum index 6668fe62..ea4a3a15 100644 --- a/go.sum +++ b/go.sum @@ -23,6 +23,7 @@ github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= +github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig= github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg= github.com/abiosoft/ishell/v2 v2.0.2/go.mod h1:E4oTCXfo6QjoCart0QYa5m9w4S+deXs/P/9jA77A9Bs= @@ -195,6 +196,7 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGa github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -314,8 +316,8 @@ github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9K github.com/nspcc-dev/neofs-crypto v0.2.3/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw= github.com/nspcc-dev/neofs-crypto v0.3.0 h1:zlr3pgoxuzrmGCxc5W8dGVfA9Rro8diFvVnBg0L4ifM= github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw= -github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211115110427-df6a622c20e8 h1:nhJSZwE2qbrCrVq4TsHlqYlwXePpqD7BsoEsu4TY5vs= -github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211115110427-df6a622c20e8/go.mod h1:kISVlyRa5l6UIDFigT2AZSW7yUK0QOEmd5mw9WPeYVI= +github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211122074021-02f328a03cfb h1:OBdHw4soQoO7B+61+UQXZLnLspTB4iRV7cVMSpKO5nU= +github.com/nspcc-dev/neofs-sdk-go v0.0.0-20211122074021-02f328a03cfb/go.mod h1:kISVlyRa5l6UIDFigT2AZSW7yUK0QOEmd5mw9WPeYVI= github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE= github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso= @@ -433,6 +435,7 @@ github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 h1:JwtAtbp7r/7QSyGz8mKUbYJBg2+6Cd7OjM8o/GNOcVo= github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74/go.mod h1:RmMWU37GKR2s6pgrIEB4ixgpVCt/cf7dnJv3fuH1J1c= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=