forked from TrueCloudLab/frostfs-s3-gw
[#269] Create frostfsid wrapper with cache
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
43a687b572
commit
5315f7b733
5 changed files with 143 additions and 9 deletions
|
@ -29,6 +29,7 @@ This document outlines major changes between releases.
|
|||
- Authmate: support custom attributes (#292)
|
||||
- Add new `reconnect_interval` config param (#291)
|
||||
- Support `GetBucketPolicyStatus` (#301)
|
||||
- Add FrostfsID cache (#269)
|
||||
|
||||
### Changed
|
||||
- Generalise config param `use_default_xmlns_for_complete_multipart` to `use_default_xmlns` so that use default xmlns for all requests (#221)
|
||||
|
|
7
api/cache/frostfsid.go
vendored
7
api/cache/frostfsid.go
vendored
|
@ -6,8 +6,6 @@ import (
|
|||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||
"github.com/bluele/gcache"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
@ -20,11 +18,6 @@ type FrostfsIDCache struct {
|
|||
logger *zap.Logger
|
||||
}
|
||||
|
||||
type FrostfsIDCacheKey struct {
|
||||
Target engine.Target
|
||||
Name chain.Name
|
||||
}
|
||||
|
||||
const (
|
||||
// DefaultFrostfsIDCacheSize is a default maximum number of entries in cache.
|
||||
DefaultFrostfsIDCacheSize = 1e4
|
||||
|
|
|
@ -30,6 +30,7 @@ import (
|
|||
"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/frostfsid"
|
||||
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/contract"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/services"
|
||||
|
@ -457,8 +458,7 @@ func (a *App) initMetrics() {
|
|||
}
|
||||
|
||||
func (a *App) initFrostfsID(ctx context.Context) {
|
||||
var err error
|
||||
a.frostfsid, err = frostfsid.New(ctx, frostfsid.Config{
|
||||
cli, err := ffidcontract.New(ctx, ffidcontract.Config{
|
||||
RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
|
||||
Contract: a.cfg.GetString(cfgFrostfsIDContract),
|
||||
ProxyContract: a.cfg.GetString(cfgProxyContract),
|
||||
|
@ -467,6 +467,15 @@ func (a *App) initFrostfsID(ctx context.Context) {
|
|||
if err != nil {
|
||||
a.log.Fatal(logs.InitFrostfsIDContractFailed, zap.Error(err))
|
||||
}
|
||||
|
||||
a.frostfsid, err = frostfsid.NewFrostFSID(frostfsid.Config{
|
||||
Cache: cache.NewFrostfsIDCache(getFrostfsIDCacheConfig(a.cfg, a.log)),
|
||||
FrostFSID: cli,
|
||||
Logger: a.log,
|
||||
})
|
||||
if err != nil {
|
||||
a.log.Fatal(logs.InitFrostfsIDContractFailed, zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) initPolicyStorage(ctx context.Context) {
|
||||
|
|
128
internal/frostfs/frostfsid/frostfsid.go
Normal file
128
internal/frostfs/frostfsid/frostfsid.go
Normal file
|
@ -0,0 +1,128 @@
|
|||
package frostfsid
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/handler"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid/contract"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type FrostFSID struct {
|
||||
frostfsid *contract.FrostFSID
|
||||
cache *cache.FrostfsIDCache
|
||||
log *zap.Logger
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Cache *cache.FrostfsIDCache
|
||||
FrostFSID *contract.FrostFSID
|
||||
Logger *zap.Logger
|
||||
}
|
||||
|
||||
var (
|
||||
_ api.FrostFSID = (*FrostFSID)(nil)
|
||||
_ handler.FrostFSID = (*FrostFSID)(nil)
|
||||
)
|
||||
|
||||
// NewFrostFSID creates new FrostfsID wrapper.
|
||||
func NewFrostFSID(cfg Config) (*FrostFSID, error) {
|
||||
switch {
|
||||
case cfg.FrostFSID == nil:
|
||||
return nil, errors.New("missing frostfsid client")
|
||||
case cfg.Cache == nil:
|
||||
return nil, errors.New("missing frostfsid cache")
|
||||
case cfg.Logger == nil:
|
||||
return nil, errors.New("missing frostfsid logger")
|
||||
}
|
||||
|
||||
return &FrostFSID{
|
||||
frostfsid: cfg.FrostFSID,
|
||||
cache: cfg.Cache,
|
||||
log: cfg.Logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *FrostFSID) ValidatePublicKey(key *keys.PublicKey) error {
|
||||
_, err := f.getSubject(key.GetScriptHash())
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *FrostFSID) GetUserGroupIDs(userHash util.Uint160) ([]string, error) {
|
||||
subj, err := f.getSubject(userHash)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
f.log.Debug(logs.UserGroupsListIsEmpty, zap.Error(err))
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make([]string, len(subj.Groups))
|
||||
for i, group := range subj.Groups {
|
||||
res[i] = strconv.FormatInt(group.ID, 10)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (f *FrostFSID) getSubject(addr util.Uint160) (*client.SubjectExtended, error) {
|
||||
if subj := f.cache.GetSubject(addr); subj != nil {
|
||||
return subj, nil
|
||||
}
|
||||
|
||||
subj, err := f.frostfsid.GetSubjectExtended(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = f.cache.PutSubject(addr, subj); err != nil {
|
||||
f.log.Warn(logs.CouldntCacheSubject, zap.Error(err))
|
||||
}
|
||||
|
||||
return subj, nil
|
||||
}
|
||||
|
||||
func (f *FrostFSID) GetUserAddress(namespace, name string) (string, error) {
|
||||
userKey, err := f.getUserKey(namespace, name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return userKey.Address(), nil
|
||||
}
|
||||
|
||||
func (f *FrostFSID) GetUserKey(namespace, name string) (string, error) {
|
||||
userKey, err := f.getUserKey(namespace, name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return hex.EncodeToString(userKey.Bytes()), nil
|
||||
}
|
||||
|
||||
func (f *FrostFSID) getUserKey(namespace, name string) (*keys.PublicKey, error) {
|
||||
if userKey := f.cache.GetUserKey(namespace, name); userKey != nil {
|
||||
return userKey, nil
|
||||
}
|
||||
|
||||
userKey, err := f.frostfsid.GetSubjectKeyByName(namespace, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = f.cache.PutUserKey(namespace, name, userKey); err != nil {
|
||||
f.log.Warn(logs.CouldntCacheUserKey, zap.Error(err))
|
||||
}
|
||||
|
||||
return userKey, nil
|
||||
}
|
|
@ -154,4 +154,7 @@ const (
|
|||
FailedToWriteResponse = "failed to write response"
|
||||
WarnDuplicateAddress = "duplicate address"
|
||||
PolicyCouldntBeConvertedToNativeRules = "policy couldn't be converted to native rules, only s3 rules be applied"
|
||||
CouldntCacheSubject = "couldn't cache subject info"
|
||||
UserGroupsListIsEmpty = "user groups list is empty, subject not found"
|
||||
CouldntCacheUserKey = "couldn't cache user key"
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue