forked from TrueCloudLab/frostfs-s3-gw
[#269] Create frostfsid wrapper with cache
(cherry picked from commit 5315f7b733
)
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
188e0cfd01
commit
0cf19d24ee
5 changed files with 143 additions and 9 deletions
|
@ -26,6 +26,7 @@ This document outlines major changes between releases.
|
||||||
- Support `policy` contract (#259)
|
- Support `policy` contract (#259)
|
||||||
- Support `proxy` contract (#287)
|
- Support `proxy` contract (#287)
|
||||||
- Authmate: support custom attributes (#292)
|
- Authmate: support custom attributes (#292)
|
||||||
|
- Add FrostfsID cache (#269)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Generalise config param `use_default_xmlns_for_complete_multipart` to `use_default_xmlns` so that use default xmlns for all requests (#221)
|
- 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-contract/frostfsid/client"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"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/bluele/gcache"
|
||||||
"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/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -20,11 +18,6 @@ type FrostfsIDCache struct {
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type FrostfsIDCacheKey struct {
|
|
||||||
Target engine.Target
|
|
||||||
Name chain.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DefaultFrostfsIDCacheSize is a default maximum number of entries in cache.
|
// DefaultFrostfsIDCacheSize is a default maximum number of entries in cache.
|
||||||
DefaultFrostfsIDCacheSize = 1e4
|
DefaultFrostfsIDCacheSize = 1e4
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"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"
|
||||||
"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"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
"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/policy/contract"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/services"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/services"
|
||||||
|
@ -453,8 +454,7 @@ func (a *App) initMetrics() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initFrostfsID(ctx context.Context) {
|
func (a *App) initFrostfsID(ctx context.Context) {
|
||||||
var err error
|
cli, err := ffidcontract.New(ctx, ffidcontract.Config{
|
||||||
a.frostfsid, err = frostfsid.New(ctx, frostfsid.Config{
|
|
||||||
RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
|
RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
|
||||||
Contract: a.cfg.GetString(cfgFrostfsIDContract),
|
Contract: a.cfg.GetString(cfgFrostfsIDContract),
|
||||||
ProxyContract: a.cfg.GetString(cfgProxyContract),
|
ProxyContract: a.cfg.GetString(cfgProxyContract),
|
||||||
|
@ -463,6 +463,15 @@ func (a *App) initFrostfsID(ctx context.Context) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.log.Fatal(logs.InitFrostfsIDContractFailed, zap.Error(err))
|
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) {
|
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
|
||||||
|
}
|
|
@ -150,4 +150,7 @@ const (
|
||||||
InvalidTreeKV = "invalid tree service meta KV"
|
InvalidTreeKV = "invalid tree service meta KV"
|
||||||
FailedToWriteResponse = "failed to write response"
|
FailedToWriteResponse = "failed to write response"
|
||||||
PolicyCouldntBeConvertedToNativeRules = "policy couldn't be converted to native rules, only s3 rules be applied"
|
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