forked from TrueCloudLab/frostfs-s3-gw
[#253] Add access box cache
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
7ad81c4d09
commit
951eb6fda8
7 changed files with 144 additions and 68 deletions
|
@ -81,9 +81,9 @@ func (p prs) Seek(_ int64, _ int) (int64, error) {
|
||||||
var _ io.ReadSeeker = prs(0)
|
var _ io.ReadSeeker = prs(0)
|
||||||
|
|
||||||
// New creates an instance of AuthCenter.
|
// New creates an instance of AuthCenter.
|
||||||
func New(conns pool.Pool, key *keys.PrivateKey) Center {
|
func New(conns pool.Pool, key *keys.PrivateKey, config *tokens.CacheConfig) Center {
|
||||||
return ¢er{
|
return ¢er{
|
||||||
cli: tokens.New(conns, key),
|
cli: tokens.New(conns, key, config),
|
||||||
reg: ®expSubmatcher{re: authorizationFieldRegexp},
|
reg: ®expSubmatcher{re: authorizationFieldRegexp},
|
||||||
postReg: ®expSubmatcher{re: postPolicyCredentialRegexp},
|
postReg: ®expSubmatcher{re: postPolicyCredentialRegexp},
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,7 +226,7 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
|
||||||
}
|
}
|
||||||
|
|
||||||
address, err := tokens.
|
address, err := tokens.
|
||||||
New(a.pool, secrets.EphemeralKey).
|
New(a.pool, secrets.EphemeralKey, tokens.DefaultCacheConfig()).
|
||||||
Put(ctx, cid, oid, box, lifetime.Exp, options.GatesPublicKeys...)
|
Put(ctx, cid, oid, box, lifetime.Exp, options.GatesPublicKeys...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to put bearer token: %w", err)
|
return fmt.Errorf("failed to put bearer token: %w", err)
|
||||||
|
@ -268,7 +268,7 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
|
||||||
// ObtainSecret receives an existing secret access key from NeoFS and
|
// ObtainSecret receives an existing secret access key from NeoFS and
|
||||||
// writes to io.Writer the secret access key.
|
// writes to io.Writer the secret access key.
|
||||||
func (a *Agent) ObtainSecret(ctx context.Context, w io.Writer, options *ObtainSecretOptions) error {
|
func (a *Agent) ObtainSecret(ctx context.Context, w io.Writer, options *ObtainSecretOptions) error {
|
||||||
bearerCreds := tokens.New(a.pool, options.GatePrivateKey)
|
bearerCreds := tokens.New(a.pool, options.GatePrivateKey, tokens.DefaultCacheConfig())
|
||||||
address := object.NewAddress()
|
address := object.NewAddress()
|
||||||
if err := address.Parse(options.SecretAddress); err != nil {
|
if err := address.Parse(options.SecretAddress); err != nil {
|
||||||
return fmt.Errorf("failed to parse secret address: %w", err)
|
return fmt.Errorf("failed to parse secret address: %w", err)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api"
|
"github.com/nspcc-dev/neofs-s3-gw/api"
|
||||||
|
@ -13,6 +14,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
|
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/handler"
|
"github.com/nspcc-dev/neofs-s3-gw/api/handler"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
|
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
|
||||||
|
"github.com/nspcc-dev/neofs-s3-gw/creds/tokens"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/internal/wallet"
|
"github.com/nspcc-dev/neofs-s3-gw/internal/wallet"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/policy"
|
"github.com/nspcc-dev/neofs-sdk-go/policy"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||||
|
@ -116,7 +118,7 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
|
||||||
obj = layer.NewLayer(l, conns, cacheCfg)
|
obj = layer.NewLayer(l, conns, cacheCfg)
|
||||||
|
|
||||||
// prepare auth center
|
// prepare auth center
|
||||||
ctr = auth.New(conns, key)
|
ctr = auth.New(conns, key, getAccessBoxCacheConfig(v, l))
|
||||||
|
|
||||||
handlerOptions := getHandlerOptions(v, l)
|
handlerOptions := getHandlerOptions(v, l)
|
||||||
|
|
||||||
|
@ -222,53 +224,54 @@ func getCacheOptions(v *viper.Viper, l *zap.Logger) *layer.CacheConfig {
|
||||||
Lifetime: cache.DefaultObjectsCacheLifetime,
|
Lifetime: cache.DefaultObjectsCacheLifetime,
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.IsSet(cfgObjectsCacheLifetime) {
|
cacheCfg.Lifetime = getLifetime(v, l, cfgObjectsCacheLifetime, cacheCfg.Lifetime)
|
||||||
lifetime := v.GetDuration(cfgObjectsCacheLifetime)
|
cacheCfg.Size = getSize(v, l, cfgObjectsCacheSize, cacheCfg.Size)
|
||||||
if lifetime <= 0 {
|
|
||||||
l.Error("invalid cache lifetime, using default value (in seconds)",
|
|
||||||
zap.Duration("value in config", lifetime),
|
|
||||||
zap.Duration("default", cacheCfg.Lifetime))
|
|
||||||
} else {
|
|
||||||
cacheCfg.Lifetime = lifetime
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.IsSet(cfgCacheSize) {
|
cacheCfg.ListObjectsLifetime = getLifetime(v, l, cfgListObjectsCacheLifetime, cacheCfg.ListObjectsLifetime)
|
||||||
size := v.GetInt(cfgCacheSize)
|
cacheCfg.ListObjectsSize = getSize(v, l, cfgListObjectsCacheSize, cacheCfg.ListObjectsSize)
|
||||||
if size <= 0 {
|
|
||||||
l.Error("invalid cache size, using default value",
|
|
||||||
zap.Int("value in config", size),
|
|
||||||
zap.Int("default", cacheCfg.Size))
|
|
||||||
} else {
|
|
||||||
cacheCfg.Size = size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.IsSet(cfgListObjectsCacheLifetime) {
|
|
||||||
lifetime := v.GetDuration(cfgListObjectsCacheLifetime)
|
|
||||||
if lifetime <= 0 {
|
|
||||||
l.Error("invalid list objects cache lifetime, using default value (in seconds)",
|
|
||||||
zap.Duration("value in config", lifetime),
|
|
||||||
zap.Duration("default", cacheCfg.ListObjectsLifetime))
|
|
||||||
} else {
|
|
||||||
cacheCfg.ListObjectsLifetime = lifetime
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.IsSet(cfgListObjectsCacheSize) {
|
|
||||||
size := v.GetInt(cfgListObjectsCacheSize)
|
|
||||||
if size <= 0 {
|
|
||||||
l.Error("invalid cache size, using default value",
|
|
||||||
zap.Int("value in config", size),
|
|
||||||
zap.Int("default", cacheCfg.ListObjectsSize))
|
|
||||||
} else {
|
|
||||||
cacheCfg.Size = size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cacheCfg
|
return &cacheCfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getLifetime(v *viper.Viper, l *zap.Logger, cfgEntry string, defaultValue time.Duration) time.Duration {
|
||||||
|
if v.IsSet(cfgEntry) {
|
||||||
|
lifetime := v.GetDuration(cfgEntry)
|
||||||
|
if lifetime <= 0 {
|
||||||
|
l.Error("invalid lifetime, using default value (in seconds)",
|
||||||
|
zap.String("parameter", cfgEntry),
|
||||||
|
zap.Duration("value in config", lifetime),
|
||||||
|
zap.Duration("default", defaultValue))
|
||||||
|
} else {
|
||||||
|
return lifetime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSize(v *viper.Viper, l *zap.Logger, cfgEntry string, defaultValue int) int {
|
||||||
|
if v.IsSet(cfgEntry) {
|
||||||
|
size := v.GetInt(cfgEntry)
|
||||||
|
if size <= 0 {
|
||||||
|
l.Error("invalid cache size, using default value",
|
||||||
|
zap.String("parameter", cfgEntry),
|
||||||
|
zap.Int("value in config", size),
|
||||||
|
zap.Int("default", defaultValue))
|
||||||
|
} else {
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAccessBoxCacheConfig(v *viper.Viper, l *zap.Logger) *tokens.CacheConfig {
|
||||||
|
cacheCfg := tokens.DefaultCacheConfig()
|
||||||
|
|
||||||
|
cacheCfg.Lifetime = getLifetime(v, l, cfgAccessBoxCacheLifetime, cacheCfg.Lifetime)
|
||||||
|
cacheCfg.Size = getSize(v, l, cfgAccessBoxCacheSize, cacheCfg.Size)
|
||||||
|
|
||||||
|
return cacheCfg
|
||||||
|
}
|
||||||
|
|
||||||
func getHandlerOptions(v *viper.Viper, l *zap.Logger) *handler.Config {
|
func getHandlerOptions(v *viper.Viper, l *zap.Logger) *handler.Config {
|
||||||
var (
|
var (
|
||||||
cfg handler.Config
|
cfg handler.Config
|
||||||
|
|
|
@ -55,10 +55,12 @@ const ( // Settings.
|
||||||
cfgRebalanceTimer = "rebalance_timer"
|
cfgRebalanceTimer = "rebalance_timer"
|
||||||
|
|
||||||
// Caching.
|
// Caching.
|
||||||
cfgObjectsCacheLifetime = "cache.lifetime"
|
cfgObjectsCacheLifetime = "cache.objects.lifetime"
|
||||||
cfgCacheSize = "cache.size"
|
cfgObjectsCacheSize = "cache.objects.size"
|
||||||
cfgListObjectsCacheLifetime = "cache.list_objects_lifetime"
|
cfgListObjectsCacheLifetime = "cache.list.lifetime"
|
||||||
cfgListObjectsCacheSize = "cache.list_objects_size"
|
cfgListObjectsCacheSize = "cache.list.size"
|
||||||
|
cfgAccessBoxCacheLifetime = "cache.accessbox.lifetime"
|
||||||
|
cfgAccessBoxCacheSize = "cache.accessbox.size"
|
||||||
|
|
||||||
// Policy.
|
// Policy.
|
||||||
cfgDefaultPolicy = "default_policy"
|
cfgDefaultPolicy = "default_policy"
|
||||||
|
|
59
creds/tokens/accessbox_cache.go
Normal file
59
creds/tokens/accessbox_cache.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package tokens
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bluele/gcache"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
||||||
|
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultCacheSize is a default maximum number of entries in cache.
|
||||||
|
DefaultCacheSize = 100
|
||||||
|
// DefaultCacheLifetime is a default lifetime of entries in cache.
|
||||||
|
DefaultCacheLifetime = 10 * time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
// CacheConfig stores expiration params for cache.
|
||||||
|
type CacheConfig struct {
|
||||||
|
Size int
|
||||||
|
Lifetime time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultCacheConfig return new default cache expiration values.
|
||||||
|
func DefaultCacheConfig() *CacheConfig {
|
||||||
|
return &CacheConfig{Size: DefaultCacheSize, Lifetime: DefaultCacheLifetime}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccessBoxCache stores access box by its address.
|
||||||
|
type AccessBoxCache struct {
|
||||||
|
cache gcache.Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAccessBoxCache creates an object of BucketCache.
|
||||||
|
func NewAccessBoxCache(config *CacheConfig) *AccessBoxCache {
|
||||||
|
gc := gcache.New(config.Size).LRU().Expiration(config.Lifetime).Build()
|
||||||
|
|
||||||
|
return &AccessBoxCache{cache: gc}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns cached object.
|
||||||
|
func (o *AccessBoxCache) Get(address *object.Address) *accessbox.Box {
|
||||||
|
entry, err := o.cache.Get(address.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result, ok := entry.(*accessbox.Box)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put stores an object to cache.
|
||||||
|
func (o *AccessBoxCache) Put(address *object.Address, box *accessbox.Box) error {
|
||||||
|
return o.cache.Set(address.String(), box)
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ type (
|
||||||
cred struct {
|
cred struct {
|
||||||
key *keys.PrivateKey
|
key *keys.PrivateKey
|
||||||
pool pool.Pool
|
pool pool.Pool
|
||||||
|
cache *AccessBoxCache
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -46,8 +47,8 @@ var bufferPool = sync.Pool{
|
||||||
var _ = New
|
var _ = New
|
||||||
|
|
||||||
// New creates new Credentials instance using given cli and key.
|
// New creates new Credentials instance using given cli and key.
|
||||||
func New(conns pool.Pool, key *keys.PrivateKey) Credentials {
|
func New(conns pool.Pool, key *keys.PrivateKey, config *CacheConfig) Credentials {
|
||||||
return &cred{pool: conns, key: key}
|
return &cred{pool: conns, key: key, cache: NewAccessBoxCache(config)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cred) acquireBuffer() *bytes.Buffer {
|
func (c *cred) acquireBuffer() *bytes.Buffer {
|
||||||
|
@ -59,22 +60,27 @@ func (c *cred) releaseBuffer(buf *bytes.Buffer) {
|
||||||
bufferPool.Put(buf)
|
bufferPool.Put(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cred) GetTokens(ctx context.Context, address *object.Address) (*accessbox.GateData, error) {
|
|
||||||
box, err := c.getAccessBox(ctx, address)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return box.GetTokens(c.key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cred) GetBox(ctx context.Context, address *object.Address) (*accessbox.Box, error) {
|
func (c *cred) GetBox(ctx context.Context, address *object.Address) (*accessbox.Box, error) {
|
||||||
|
cachedBox := c.cache.Get(address)
|
||||||
|
if cachedBox != nil {
|
||||||
|
return cachedBox, nil
|
||||||
|
}
|
||||||
|
|
||||||
box, err := c.getAccessBox(ctx, address)
|
box, err := c.getAccessBox(ctx, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return box.GetBox(c.key)
|
cachedBox, err = box.GetBox(c.key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.cache.Put(address, cachedBox); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedBox, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cred) getAccessBox(ctx context.Context, address *object.Address) (*accessbox.AccessBox, error) {
|
func (c *cred) getAccessBox(ctx context.Context, address *object.Address) (*accessbox.AccessBox, error) {
|
||||||
|
|
|
@ -108,8 +108,14 @@ If the value is not set at all it will be set as `REP 3`.
|
||||||
Parameters for caches in s3-gw can be specified in a .yaml config file. E.g.:
|
Parameters for caches in s3-gw can be specified in a .yaml config file. E.g.:
|
||||||
```
|
```
|
||||||
cache:
|
cache:
|
||||||
|
objects:
|
||||||
lifetime: 300s
|
lifetime: 300s
|
||||||
size: 150
|
size: 150
|
||||||
list_objects_lifetime: 1m
|
list:
|
||||||
|
lifetime: 1m
|
||||||
|
size: 100
|
||||||
|
accessbox:
|
||||||
|
lifetime: 5m
|
||||||
|
size: 10
|
||||||
```
|
```
|
||||||
If invalid values are set, the gateway will use default values instead.
|
If invalid values are set, the gateway will use default values instead.
|
||||||
|
|
Loading…
Reference in a new issue