forked from TrueCloudLab/frostfs-s3-gw
[#306] Reduce number of policy contract invocations
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
499a202d28
commit
c452d58ce2
11 changed files with 235 additions and 159 deletions
|
@ -27,7 +27,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||||
engineiam "git.frostfs.info/TrueCloudLab/policy-engine/iam"
|
engineiam "git.frostfs.info/TrueCloudLab/policy-engine/iam"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -439,14 +438,10 @@ func (h *handler) putBucketACLAPEHandler(w http.ResponseWriter, r *http.Request,
|
||||||
}
|
}
|
||||||
|
|
||||||
chainRules := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID)
|
chainRules := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID)
|
||||||
|
if err = h.ape.SaveACLChains(reqInfo.Namespace, chainRules); err != nil {
|
||||||
target := engine.NamespaceTarget(reqInfo.Namespace)
|
h.logAndSendError(w, "failed to add morph rule chains", reqInfo, err)
|
||||||
for _, chainPolicy := range chainRules {
|
|
||||||
if err = h.ape.AddChain(target, chainPolicy); err != nil {
|
|
||||||
h.logAndSendError(w, "failed to add morph rule chain", reqInfo, err, zap.String("chain_id", string(chainPolicy.ID)))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
settings.CannedACL = cannedACL
|
settings.CannedACL = cannedACL
|
||||||
|
|
||||||
|
@ -654,7 +649,7 @@ func (h *handler) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonPolicy, err := h.ape.GetPolicy(reqInfo.Namespace, bktInfo.CID)
|
jsonPolicy, err := h.ape.GetBucketPolicy(reqInfo.Namespace, bktInfo.CID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "not found") {
|
if strings.Contains(err.Error(), "not found") {
|
||||||
err = fmt.Errorf("%w: %s", errors.GetAPIError(errors.ErrNoSuchBucketPolicy), err.Error())
|
err = fmt.Errorf("%w: %s", errors.GetAPIError(errors.ErrNoSuchBucketPolicy), err.Error())
|
||||||
|
@ -680,14 +675,7 @@ func (h *handler) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Reque
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
target := engine.NamespaceTarget(reqInfo.Namespace)
|
if err = h.ape.DeleteBucketPolicy(reqInfo.Namespace, bktInfo.CID, getBucketChainID(bktInfo)); err != nil {
|
||||||
chainID := getBucketChainID(bktInfo)
|
|
||||||
if err = h.ape.RemoveChain(target, chainID); err != nil {
|
|
||||||
h.logAndSendError(w, "failed to remove morph rule chain", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = h.ape.DeletePolicy(reqInfo.Namespace, bktInfo.CID); err != nil {
|
|
||||||
h.logAndSendError(w, "failed to delete policy from storage", reqInfo, err)
|
h.logAndSendError(w, "failed to delete policy from storage", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -743,14 +731,8 @@ func (h *handler) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
target := engine.NamespaceTarget(reqInfo.Namespace)
|
if err = h.ape.PutBucketPolicy(reqInfo.Namespace, bktInfo.CID, jsonPolicy, s3Chain); err != nil {
|
||||||
if err = h.ape.AddChain(target, s3Chain); err != nil {
|
h.logAndSendError(w, "failed to update policy in contract", reqInfo, err)
|
||||||
h.logAndSendError(w, "failed to add morph rule chain", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = h.ape.PutPolicy(reqInfo.Namespace, bktInfo.CID, jsonPolicy); err != nil {
|
|
||||||
h.logAndSendError(w, "failed to save policy to storage", reqInfo, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1325,7 +1325,7 @@ func TestPutBucketAPE(t *testing.T) {
|
||||||
_, err := hc.tp.ContainerEACL(hc.Context(), info.BktInfo.CID)
|
_, err := hc.tp.ContainerEACL(hc.Context(), info.BktInfo.CID)
|
||||||
require.ErrorContains(t, err, "not found")
|
require.ErrorContains(t, err, "not found")
|
||||||
|
|
||||||
chains, err := hc.h.ape.ListChains(engine.NamespaceTarget(""))
|
chains, err := hc.h.ape.(*apeMock).ListChains(engine.NamespaceTarget(""))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, chains, 2)
|
require.Len(t, chains, 2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -55,23 +54,10 @@ type (
|
||||||
|
|
||||||
// APE is Access Policy Engine that needs to save policy and acl info to different places.
|
// APE is Access Policy Engine that needs to save policy and acl info to different places.
|
||||||
APE interface {
|
APE interface {
|
||||||
MorphRuleChainStorage
|
PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, s3Chain *chain.Chain) error
|
||||||
PolicyStorage
|
DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error
|
||||||
}
|
GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error)
|
||||||
|
SaveACLChains(ns string, chains []*chain.Chain) error
|
||||||
// MorphRuleChainStorage is a similar to engine.MorphRuleChainStorage
|
|
||||||
// but doesn't know anything about tx.
|
|
||||||
MorphRuleChainStorage interface {
|
|
||||||
AddChain(target engine.Target, c *chain.Chain) error
|
|
||||||
RemoveChain(target engine.Target, chainID chain.ID) error
|
|
||||||
ListChains(target engine.Target) ([]*chain.Chain, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PolicyStorage is interface to save intact initial user provided policy.
|
|
||||||
PolicyStorage interface {
|
|
||||||
PutPolicy(namespace string, cnrID cid.ID, policy []byte) error
|
|
||||||
GetPolicy(namespace string, cnrID cid.ID) ([]byte, error)
|
|
||||||
DeletePolicy(namespace string, cnrID cid.ID) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
frostfsIDDisabled struct{}
|
frostfsIDDisabled struct{}
|
||||||
|
|
|
@ -251,8 +251,27 @@ func (a *apeMock) PutPolicy(namespace string, cnrID cid.ID, policy []byte) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *apeMock) GetPolicy(namespace string, cnrID cid.ID) ([]byte, error) {
|
func (a *apeMock) DeletePolicy(namespace string, cnrID cid.ID) error {
|
||||||
policy, ok := a.policyMap[namespace+cnrID.EncodeToString()]
|
delete(a.policyMap, namespace+cnrID.EncodeToString())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *apeMock) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, s3Chain *chain.Chain) error {
|
||||||
|
if err := a.PutPolicy(ns, cnrID, policy); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return a.AddChain(engine.NamespaceTarget(ns), s3Chain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *apeMock) DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error {
|
||||||
|
if err := a.DeletePolicy(ns, cnrID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return a.RemoveChain(engine.NamespaceTarget(ns), chainID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *apeMock) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error) {
|
||||||
|
policy, ok := a.policyMap[ns+cnrID.EncodeToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not found")
|
return nil, errors.New("not found")
|
||||||
}
|
}
|
||||||
|
@ -260,8 +279,13 @@ func (a *apeMock) GetPolicy(namespace string, cnrID cid.ID) ([]byte, error) {
|
||||||
return policy, nil
|
return policy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *apeMock) DeletePolicy(namespace string, cnrID cid.ID) error {
|
func (a *apeMock) SaveACLChains(ns string, chains []*chain.Chain) error {
|
||||||
delete(a.policyMap, namespace+cnrID.EncodeToString())
|
for i := range chains {
|
||||||
|
if err := a.AddChain(engine.NamespaceTarget(ns), chains[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
"git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/schema/s3"
|
"git.frostfs.info/TrueCloudLab/policy-engine/schema/s3"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
@ -822,15 +821,11 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
h.reqLogger(ctx).Info(logs.BucketIsCreated, zap.Stringer("container_id", bktInfo.CID))
|
h.reqLogger(ctx).Info(logs.BucketIsCreated, zap.Stringer("container_id", bktInfo.CID))
|
||||||
|
|
||||||
chainRules := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID)
|
chains := bucketCannedACLToAPERules(cannedACL, reqInfo, key, bktInfo.CID)
|
||||||
|
if err = h.ape.SaveACLChains(reqInfo.Namespace, chains); err != nil {
|
||||||
target := engine.NamespaceTarget(reqInfo.Namespace)
|
h.logAndSendError(w, "failed to add morph rule chain", reqInfo, err)
|
||||||
for _, chainPolicy := range chainRules {
|
|
||||||
if err = h.ape.AddChain(target, chainPolicy); err != nil {
|
|
||||||
h.logAndSendError(w, "failed to add morph rule chain", reqInfo, err, zap.String("chain_id", string(chainPolicy.ID)))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
sp := &layer.PutSettingsParams{
|
sp := &layer.PutSettingsParams{
|
||||||
BktInfo: bktInfo,
|
BktInfo: bktInfo,
|
||||||
|
|
|
@ -2,9 +2,11 @@ package contract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/commonclient"
|
||||||
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
||||||
policyclient "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/policy"
|
policyclient "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/policy"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
||||||
|
@ -21,6 +23,7 @@ import (
|
||||||
type Client struct {
|
type Client struct {
|
||||||
actor *actor.Actor
|
actor *actor.Actor
|
||||||
policyContract *policyclient.Contract
|
policyContract *policyclient.Contract
|
||||||
|
contractHash util.Uint160
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -72,6 +75,7 @@ func New(ctx context.Context, cfg Config) (*Client, error) {
|
||||||
return &Client{
|
return &Client{
|
||||||
actor: act,
|
actor: act,
|
||||||
policyContract: policyclient.New(act, contractHash),
|
policyContract: policyclient.New(act, contractHash),
|
||||||
|
contractHash: contractHash,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,3 +134,87 @@ func (c *Client) Wait(tx util.Uint256, vub uint32, err error) error {
|
||||||
_, err = c.actor.Wait(tx, vub, err)
|
_, err = c.actor.Wait(tx, vub, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type multiTX struct {
|
||||||
|
contractHash util.Uint160
|
||||||
|
txs []*commonclient.Transaction
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *multiTX) AddChain(entity policycontract.Kind, entityName string, name []byte, chain []byte) {
|
||||||
|
m.wrapCall("addChain", []any{big.NewInt(int64(entity)), entityName, name, chain})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *multiTX) RemoveChain(entity policycontract.Kind, entityName string, name []byte) {
|
||||||
|
m.wrapCall("removeChain", []any{big.NewInt(int64(entity)), entityName, name})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *multiTX) Scripts() ([][]byte, error) {
|
||||||
|
if m.err != nil {
|
||||||
|
return nil, m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(m.txs) == 0 {
|
||||||
|
return nil, errors.New("tx isn't initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([][]byte, 0, len(m.txs))
|
||||||
|
for _, tx := range m.txs {
|
||||||
|
script, err := tx.Bytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res = append(res, script)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *multiTX) wrapCall(method string, args []any) {
|
||||||
|
if m.err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(m.txs) == 0 {
|
||||||
|
m.err = errors.New("multi tx isn't initialized")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := m.txs[len(m.txs)-1].WrapCall(method, args)
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !errors.Is(commonclient.ErrTransactionTooLarge, err) {
|
||||||
|
m.err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tx := commonclient.NewTransaction(m.contractHash)
|
||||||
|
m.err = tx.WrapCall(method, args)
|
||||||
|
if m.err == nil {
|
||||||
|
m.txs = append(m.txs, tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) StartTx() policy.MultiTransaction {
|
||||||
|
return &multiTX{
|
||||||
|
txs: []*commonclient.Transaction{commonclient.NewTransaction(c.contractHash)},
|
||||||
|
contractHash: c.contractHash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) SendTx(mtx policy.MultiTransaction) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
scripts, err := mtx.Scripts()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range scripts {
|
||||||
|
if _, err = c.actor.Wait(c.actor.SendRun(scripts[i])); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -83,6 +83,17 @@ func (c *InMemoryContract) Wait(_ util.Uint256, _ uint32, err error) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *InMemoryContract) StartTx() policy.MultiTransaction {
|
||||||
|
return &inMemoryTx{operations: make([]func(*InMemoryContract), 0)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *InMemoryContract) SendTx(tx policy.MultiTransaction) error {
|
||||||
|
for _, operation := range tx.(*inMemoryTx).operations {
|
||||||
|
operation(c)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *InMemoryContract) getMap(kind policycontract.Kind) *syncedMap {
|
func (c *InMemoryContract) getMap(kind policycontract.Kind) *syncedMap {
|
||||||
switch kind {
|
switch kind {
|
||||||
case policycontract.IAM:
|
case policycontract.IAM:
|
||||||
|
@ -95,3 +106,23 @@ func (c *InMemoryContract) getMap(kind policycontract.Kind) *syncedMap {
|
||||||
return &syncedMap{data: map[string][]byte{}}
|
return &syncedMap{data: map[string][]byte{}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type inMemoryTx struct {
|
||||||
|
operations []func(contract *InMemoryContract)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *inMemoryTx) AddChain(kind policycontract.Kind, entity string, name []byte, chain []byte) {
|
||||||
|
t.operations = append(t.operations, func(c *InMemoryContract) {
|
||||||
|
_, _, _ = c.AddChain(kind, entity, name, chain)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *inMemoryTx) RemoveChain(kind policycontract.Kind, entity string, name []byte) {
|
||||||
|
t.operations = append(t.operations, func(c *InMemoryContract) {
|
||||||
|
_, _, _ = c.RemoveChain(kind, entity, name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *inMemoryTx) Scripts() ([][]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
package policy
|
|
||||||
|
|
||||||
import (
|
|
||||||
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/handler"
|
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MorphPolicyStorage struct {
|
|
||||||
contract Contract
|
|
||||||
}
|
|
||||||
|
|
||||||
type MorphPolicyStorageConfig struct {
|
|
||||||
Contract Contract
|
|
||||||
Log *zap.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ handler.PolicyStorage = (*MorphPolicyStorage)(nil)
|
|
||||||
|
|
||||||
const policyStoragePrefix = 'b'
|
|
||||||
|
|
||||||
func NewMorphPolicyStorage(config *MorphPolicyStorageConfig) *MorphPolicyStorage {
|
|
||||||
return &MorphPolicyStorage{
|
|
||||||
contract: config.Contract,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MorphPolicyStorage) PutPolicy(namespace string, cnrID cid.ID, policy []byte) error {
|
|
||||||
name := getPolicyStorageName(cnrID)
|
|
||||||
return c.contract.Wait(c.contract.AddChain(policycontract.IAM, namespace, name, policy))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MorphPolicyStorage) GetPolicy(namespace string, cnrID cid.ID) ([]byte, error) {
|
|
||||||
name := getPolicyStorageName(cnrID)
|
|
||||||
return c.contract.GetChain(policycontract.IAM, namespace, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MorphPolicyStorage) DeletePolicy(namespace string, cnrID cid.ID) error {
|
|
||||||
name := getPolicyStorageName(cnrID)
|
|
||||||
return c.contract.Wait(c.contract.RemoveChain(policycontract.IAM, namespace, name))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPolicyStorageName(cnrID cid.ID) []byte {
|
|
||||||
return append([]byte{policyStoragePrefix}, cnrID[:]...)
|
|
||||||
}
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
|
|
||||||
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache"
|
"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/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -25,10 +25,9 @@ type MorphRuleChainStorageConfig struct {
|
||||||
Log *zap.Logger
|
Log *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var _ engine.MorphRuleChainStorage = (*MorphRuleChainStorage)(nil)
|
||||||
_ engine.MorphRuleChainStorage = (*MorphRuleChainStorage)(nil)
|
|
||||||
_ handler.MorphRuleChainStorage = (*MorphRuleChainStorage)(nil)
|
const bucketPolicyPrefix = 'b'
|
||||||
)
|
|
||||||
|
|
||||||
func NewMorphRuleChainStorage(config *MorphRuleChainStorageConfig) *MorphRuleChainStorage {
|
func NewMorphRuleChainStorage(config *MorphRuleChainStorageConfig) *MorphRuleChainStorage {
|
||||||
return &MorphRuleChainStorage{
|
return &MorphRuleChainStorage{
|
||||||
|
@ -38,26 +37,12 @@ func NewMorphRuleChainStorage(config *MorphRuleChainStorageConfig) *MorphRuleCha
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MorphRuleChainStorage) AddChain(target engine.Target, policyChain *chain.Chain) error {
|
func (c *MorphRuleChainStorage) AddMorphRuleChain(chain.Name, engine.Target, *chain.Chain) (util.Uint256, uint32, error) {
|
||||||
return c.contract.Wait(c.AddMorphRuleChain(chain.S3, target, policyChain))
|
panic("should never be called")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MorphRuleChainStorage) RemoveChain(target engine.Target, chainID chain.ID) error {
|
func (c *MorphRuleChainStorage) RemoveMorphRuleChain(chain.Name, engine.Target, chain.ID) (util.Uint256, uint32, error) {
|
||||||
return c.contract.Wait(c.RemoveMorphRuleChain(chain.S3, target, chainID))
|
panic("should never be called")
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MorphRuleChainStorage) ListChains(target engine.Target) ([]*chain.Chain, error) {
|
|
||||||
return c.ListMorphRuleChains(chain.S3, target)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MorphRuleChainStorage) AddMorphRuleChain(name chain.Name, target engine.Target, policyChain *chain.Chain) (util.Uint256, uint32, error) {
|
|
||||||
c.cache.Delete(cache.MorphPolicyCacheKey{Target: target, Name: name})
|
|
||||||
return c.contract.AddChain(getKind(target), target.Name, getName(name, policyChain.ID), policyChain.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MorphRuleChainStorage) RemoveMorphRuleChain(name chain.Name, target engine.Target, chainID chain.ID) (util.Uint256, uint32, error) {
|
|
||||||
c.cache.Delete(cache.MorphPolicyCacheKey{Target: target, Name: name})
|
|
||||||
return c.contract.RemoveChain(getKind(target), target.Name, getName(name, chainID))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MorphRuleChainStorage) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
func (c *MorphRuleChainStorage) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
||||||
|
@ -88,6 +73,42 @@ func (c *MorphRuleChainStorage) ListMorphRuleChains(name chain.Name, target engi
|
||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *MorphRuleChainStorage) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, s3Chain *chain.Chain) error {
|
||||||
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.S3})
|
||||||
|
|
||||||
|
tx := c.contract.StartTx()
|
||||||
|
tx.AddChain(policycontract.Namespace, ns, s3Chain.ID, s3Chain.Bytes())
|
||||||
|
tx.AddChain(policycontract.IAM, ns, getBucketPolicyName(cnrID), policy)
|
||||||
|
|
||||||
|
return c.contract.SendTx(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MorphRuleChainStorage) DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error {
|
||||||
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.S3})
|
||||||
|
|
||||||
|
tx := c.contract.StartTx()
|
||||||
|
tx.RemoveChain(policycontract.Namespace, ns, chainID)
|
||||||
|
tx.RemoveChain(policycontract.IAM, ns, getBucketPolicyName(cnrID))
|
||||||
|
|
||||||
|
return c.contract.SendTx(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MorphRuleChainStorage) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error) {
|
||||||
|
return c.contract.GetChain(policycontract.IAM, ns, getBucketPolicyName(cnrID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MorphRuleChainStorage) SaveACLChains(ns string, chains []*chain.Chain) error {
|
||||||
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.S3})
|
||||||
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: engine.NamespaceTarget(ns), Name: chain.Ingress})
|
||||||
|
|
||||||
|
tx := c.contract.StartTx()
|
||||||
|
for i := range chains {
|
||||||
|
tx.AddChain(policycontract.Namespace, ns, chains[i].ID, chains[i].Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.contract.SendTx(tx)
|
||||||
|
}
|
||||||
|
|
||||||
func getKind(target engine.Target) policycontract.Kind {
|
func getKind(target engine.Target) policycontract.Kind {
|
||||||
var kind policycontract.Kind = policycontract.Container
|
var kind policycontract.Kind = policycontract.Container
|
||||||
if target.Type != engine.Container {
|
if target.Type != engine.Container {
|
||||||
|
@ -96,6 +117,7 @@ func getKind(target engine.Target) policycontract.Kind {
|
||||||
|
|
||||||
return kind
|
return kind
|
||||||
}
|
}
|
||||||
func getName(name chain.Name, chainID chain.ID) []byte {
|
|
||||||
return append([]byte(name), []byte(chainID)...)
|
func getBucketPolicyName(cnrID cid.ID) []byte {
|
||||||
|
return append([]byte{bucketPolicyPrefix}, cnrID[:]...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,18 +9,15 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine/inmemory"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine/inmemory"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
router engine.ChainRouter
|
router engine.ChainRouter
|
||||||
|
|
||||||
morph handler.MorphRuleChainStorage
|
morph *MorphRuleChainStorage
|
||||||
|
|
||||||
local engine.LocalOverrideStorage
|
local engine.LocalOverrideStorage
|
||||||
|
|
||||||
policy handler.PolicyStorage
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type StorageConfig struct {
|
type StorageConfig struct {
|
||||||
|
@ -29,18 +26,23 @@ type StorageConfig struct {
|
||||||
Log *zap.Logger
|
Log *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MultiTransaction interface {
|
||||||
|
AddChain(entity policycontract.Kind, entityName string, name []byte, chain []byte)
|
||||||
|
RemoveChain(entity policycontract.Kind, entityName string, name []byte)
|
||||||
|
Scripts() ([][]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
type Contract interface {
|
type Contract interface {
|
||||||
AddChain(kind policycontract.Kind, entity string, name []byte, chain []byte) (util.Uint256, uint32, error)
|
GetChain(entity policycontract.Kind, entityName string, name []byte) ([]byte, error)
|
||||||
GetChain(kind policycontract.Kind, entity string, name []byte) ([]byte, error)
|
ListChains(entity policycontract.Kind, entityName string, prefix []byte) ([][]byte, error)
|
||||||
RemoveChain(kind policycontract.Kind, entity string, name []byte) (util.Uint256, uint32, error)
|
|
||||||
ListChains(kind policycontract.Kind, entity string, name []byte) ([][]byte, error)
|
StartTx() MultiTransaction
|
||||||
Wait(tx util.Uint256, vub uint32, err error) error
|
SendTx(transaction MultiTransaction) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ handler.APE = (*Storage)(nil)
|
var _ handler.APE = (*Storage)(nil)
|
||||||
|
|
||||||
func NewStorage(cfg StorageConfig) *Storage {
|
func NewStorage(cfg StorageConfig) *Storage {
|
||||||
// todo use thread safe inmemory https://git.frostfs.info/TrueCloudLab/policy-engine/issues/35
|
|
||||||
local := inmemory.NewInmemoryLocalStorage()
|
local := inmemory.NewInmemoryLocalStorage()
|
||||||
|
|
||||||
morph := NewMorphRuleChainStorage(&MorphRuleChainStorageConfig{
|
morph := NewMorphRuleChainStorage(&MorphRuleChainStorageConfig{
|
||||||
|
@ -49,16 +51,10 @@ func NewStorage(cfg StorageConfig) *Storage {
|
||||||
Log: cfg.Log,
|
Log: cfg.Log,
|
||||||
})
|
})
|
||||||
|
|
||||||
policyStorage := NewMorphPolicyStorage(&MorphPolicyStorageConfig{
|
|
||||||
Contract: cfg.Contract,
|
|
||||||
Log: cfg.Log,
|
|
||||||
})
|
|
||||||
|
|
||||||
return &Storage{
|
return &Storage{
|
||||||
router: engine.NewDefaultChainRouterWithLocalOverrides(morph, local),
|
router: engine.NewDefaultChainRouterWithLocalOverrides(morph, local),
|
||||||
morph: morph,
|
morph: morph,
|
||||||
local: local,
|
local: local,
|
||||||
policy: policyStorage,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,26 +66,23 @@ func (s *Storage) LocalStorage() engine.LocalOverrideStorage {
|
||||||
return s.local
|
return s.local
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) AddChain(target engine.Target, policyChain *chain.Chain) error {
|
func (s *Storage) PutBucketPolicy(ns string, cnrID cid.ID, policy []byte, s3Chain *chain.Chain) error {
|
||||||
return s.morph.AddChain(target, policyChain)
|
return s.morph.PutBucketPolicy(ns, cnrID, policy, s3Chain)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) RemoveChain(target engine.Target, chainID chain.ID) error {
|
func (s *Storage) DeleteBucketPolicy(ns string, cnrID cid.ID, chainID chain.ID) error {
|
||||||
return s.morph.RemoveChain(target, chainID)
|
return s.morph.DeleteBucketPolicy(ns, cnrID, chainID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) ListChains(target engine.Target) ([]*chain.Chain, error) {
|
func (s *Storage) GetBucketPolicy(ns string, cnrID cid.ID) ([]byte, error) {
|
||||||
return s.morph.ListChains(target)
|
return s.morph.GetBucketPolicy(ns, cnrID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) PutPolicy(namespace string, cnrID cid.ID, policy []byte) error {
|
func (s *Storage) SaveACLChains(ns string, chains []*chain.Chain) error {
|
||||||
return s.policy.PutPolicy(namespace, cnrID, policy)
|
return s.morph.SaveACLChains(ns, chains)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) GetPolicy(namespace string, cnrID cid.ID) ([]byte, error) {
|
//
|
||||||
return s.policy.GetPolicy(namespace, cnrID)
|
//func (s *Storage) ListChains(target engine.Target) ([]*chain.Chain, error) {
|
||||||
}
|
// return s.morph.ListMorphRuleChains(target)
|
||||||
|
//}
|
||||||
func (s *Storage) DeletePolicy(namespace string, cnrID cid.ID) error {
|
|
||||||
return s.policy.DeletePolicy(namespace, cnrID)
|
|
||||||
}
|
|
||||||
|
|
|
@ -145,4 +145,5 @@ const (
|
||||||
CouldNotCloseRequestBody = "could not close request body"
|
CouldNotCloseRequestBody = "could not close request body"
|
||||||
BucketOwnerKeyIsMissing = "bucket owner key is missing"
|
BucketOwnerKeyIsMissing = "bucket owner key is missing"
|
||||||
SettingsNodeInvalidOwnerKey = "settings node: invalid owner key"
|
SettingsNodeInvalidOwnerKey = "settings node: invalid owner key"
|
||||||
|
FailedToSendTransaction = "failed to send transaction"
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue