forked from TrueCloudLab/frostfs-node
Compare commits
10 commits
ffe9906266
...
afacc86f35
Author | SHA1 | Date | |
---|---|---|---|
afacc86f35 | |||
6ae8667fb4 | |||
49a4e727fd | |||
2e974f734c | |||
3042490340 | |||
a339b52a60 | |||
4ab4ed6f96 | |||
3b1364e4cf | |||
daff77b273 | |||
7a7ee71a4d |
21 changed files with 428 additions and 647 deletions
|
@ -1,6 +1,10 @@
|
|||
name: Build
|
||||
|
||||
on: [pull_request]
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
name: Pre-commit hooks
|
||||
on: [pull_request]
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
precommit:
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
name: Tests and linters
|
||||
on: [pull_request]
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
name: Vulncheck
|
||||
on: [pull_request]
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
vulncheck:
|
||||
|
|
|
@ -14,26 +14,10 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
namespaceTarget = "namespace"
|
||||
containerTarget = "container"
|
||||
userTarget = "user"
|
||||
groupTarget = "group"
|
||||
jsonFlag = "json"
|
||||
jsonFlagDesc = "Output rule chains in JSON format"
|
||||
chainIDFlag = "chain-id"
|
||||
chainIDDesc = "Rule chain ID"
|
||||
ruleFlag = "rule"
|
||||
ruleFlagDesc = "Rule chain in text format"
|
||||
pathFlag = "path"
|
||||
pathFlagDesc = "path to encoded chain in JSON or binary format"
|
||||
targetNameFlag = "target-name"
|
||||
targetNameDesc = "Resource name in APE resource name format"
|
||||
targetTypeFlag = "target-type"
|
||||
targetTypeDesc = "Resource type(container/namespace)"
|
||||
addrAdminFlag = "addr"
|
||||
addrAdminDesc = "The address of the admins wallet"
|
||||
chainNameFlag = "chain-name"
|
||||
chainNameFlagDesc = "Chain name(ingress|s3)"
|
||||
jsonFlag = "json"
|
||||
jsonFlagDesc = "Output rule chains in JSON format"
|
||||
addrAdminFlag = "addr"
|
||||
addrAdminDesc = "The address of the admins wallet"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -101,17 +85,17 @@ func initAddRuleChainCmd() {
|
|||
addRuleChainCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
addRuleChainCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||
|
||||
addRuleChainCmd.Flags().String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = addRuleChainCmd.MarkFlagRequired(targetTypeFlag)
|
||||
addRuleChainCmd.Flags().String(targetNameFlag, "", targetNameDesc)
|
||||
_ = addRuleChainCmd.MarkFlagRequired(targetNameFlag)
|
||||
addRuleChainCmd.Flags().String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = addRuleChainCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
addRuleChainCmd.Flags().String(apeCmd.TargetNameFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = addRuleChainCmd.MarkFlagRequired(apeCmd.TargetNameFlag)
|
||||
|
||||
addRuleChainCmd.Flags().String(chainIDFlag, "", chainIDDesc)
|
||||
_ = addRuleChainCmd.MarkFlagRequired(chainIDFlag)
|
||||
addRuleChainCmd.Flags().StringArray(ruleFlag, []string{}, ruleFlagDesc)
|
||||
addRuleChainCmd.Flags().String(pathFlag, "", pathFlagDesc)
|
||||
addRuleChainCmd.Flags().String(chainNameFlag, ingress, chainNameFlagDesc)
|
||||
addRuleChainCmd.MarkFlagsMutuallyExclusive(ruleFlag, pathFlag)
|
||||
addRuleChainCmd.Flags().String(apeCmd.ChainIDFlag, "", apeCmd.ChainIDFlagDesc)
|
||||
_ = addRuleChainCmd.MarkFlagRequired(apeCmd.ChainIDFlag)
|
||||
addRuleChainCmd.Flags().StringArray(apeCmd.RuleFlag, []string{}, apeCmd.RuleFlagDesc)
|
||||
addRuleChainCmd.Flags().String(apeCmd.PathFlag, "", apeCmd.PathFlagDesc)
|
||||
addRuleChainCmd.Flags().String(apeCmd.ChainNameFlag, apeCmd.Ingress, apeCmd.ChainNameFlagDesc)
|
||||
addRuleChainCmd.MarkFlagsMutuallyExclusive(apeCmd.RuleFlag, apeCmd.PathFlag)
|
||||
}
|
||||
|
||||
func initRemoveRuleChainCmd() {
|
||||
|
@ -120,26 +104,25 @@ func initRemoveRuleChainCmd() {
|
|||
removeRuleChainCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
removeRuleChainCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||
|
||||
removeRuleChainCmd.Flags().String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = removeRuleChainCmd.MarkFlagRequired(targetTypeFlag)
|
||||
removeRuleChainCmd.Flags().String(targetNameFlag, "", targetNameDesc)
|
||||
_ = removeRuleChainCmd.MarkFlagRequired(targetNameFlag)
|
||||
removeRuleChainCmd.Flags().String(chainIDFlag, "", chainIDDesc)
|
||||
removeRuleChainCmd.Flags().String(chainNameFlag, ingress, chainNameFlagDesc)
|
||||
removeRuleChainCmd.Flags().String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = removeRuleChainCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
removeRuleChainCmd.Flags().String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
_ = removeRuleChainCmd.MarkFlagRequired(apeCmd.TargetNameFlag)
|
||||
removeRuleChainCmd.Flags().String(apeCmd.ChainIDFlag, "", apeCmd.ChainIDFlagDesc)
|
||||
removeRuleChainCmd.Flags().String(apeCmd.ChainNameFlag, apeCmd.Ingress, apeCmd.ChainNameFlagDesc)
|
||||
removeRuleChainCmd.Flags().Bool(commonflags.AllFlag, false, "Remove all chains for target")
|
||||
removeRuleChainCmd.MarkFlagsMutuallyExclusive(commonflags.AllFlag, chainIDFlag)
|
||||
removeRuleChainCmd.MarkFlagsMutuallyExclusive(commonflags.AllFlag, apeCmd.ChainIDFlag)
|
||||
}
|
||||
|
||||
func initListRuleChainsCmd() {
|
||||
Cmd.AddCommand(listRuleChainsCmd)
|
||||
|
||||
listRuleChainsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
listRuleChainsCmd.Flags().StringP(targetTypeFlag, "t", "", targetTypeDesc)
|
||||
_ = listRuleChainsCmd.MarkFlagRequired(targetTypeFlag)
|
||||
listRuleChainsCmd.Flags().String(targetNameFlag, "", targetNameDesc)
|
||||
_ = listRuleChainsCmd.MarkFlagRequired(targetNameFlag)
|
||||
listRuleChainsCmd.Flags().StringP(apeCmd.TargetTypeFlag, "t", "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = listRuleChainsCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
listRuleChainsCmd.Flags().String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
listRuleChainsCmd.Flags().Bool(jsonFlag, false, jsonFlagDesc)
|
||||
listRuleChainsCmd.Flags().String(chainNameFlag, ingress, chainNameFlagDesc)
|
||||
listRuleChainsCmd.Flags().String(apeCmd.ChainNameFlag, apeCmd.Ingress, apeCmd.ChainNameFlagDesc)
|
||||
}
|
||||
|
||||
func initSetAdminCmd() {
|
||||
|
@ -161,15 +144,15 @@ func initListTargetsCmd() {
|
|||
Cmd.AddCommand(listTargetsCmd)
|
||||
|
||||
listTargetsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||
listTargetsCmd.Flags().StringP(targetTypeFlag, "t", "", targetTypeDesc)
|
||||
_ = listTargetsCmd.MarkFlagRequired(targetTypeFlag)
|
||||
listTargetsCmd.Flags().StringP(apeCmd.TargetTypeFlag, "t", "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = listTargetsCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
}
|
||||
|
||||
func addRuleChain(cmd *cobra.Command, _ []string) {
|
||||
chain := parseChain(cmd)
|
||||
chain := apeCmd.ParseChain(cmd)
|
||||
target := parseTarget(cmd)
|
||||
pci, ac := newPolicyContractInterface(cmd)
|
||||
h, vub, err := pci.AddMorphRuleChain(parseChainName(cmd), target, chain)
|
||||
h, vub, err := pci.AddMorphRuleChain(apeCmd.ParseChainName(cmd), target, chain)
|
||||
cmd.Println("Waiting for transaction to persist...")
|
||||
_, err = ac.Wait(h, vub, err)
|
||||
commonCmd.ExitOnErr(cmd, "add rule chain error: %w", err)
|
||||
|
@ -181,14 +164,14 @@ func removeRuleChain(cmd *cobra.Command, _ []string) {
|
|||
pci, ac := newPolicyContractInterface(cmd)
|
||||
removeAll, _ := cmd.Flags().GetBool(commonflags.AllFlag)
|
||||
if removeAll {
|
||||
h, vub, err := pci.RemoveMorphRuleChainsByTarget(parseChainName(cmd), target)
|
||||
h, vub, err := pci.RemoveMorphRuleChainsByTarget(apeCmd.ParseChainName(cmd), target)
|
||||
cmd.Println("Waiting for transaction to persist...")
|
||||
_, err = ac.Wait(h, vub, err)
|
||||
commonCmd.ExitOnErr(cmd, "remove rule chain error: %w", err)
|
||||
cmd.Println("All chains for target removed successfully")
|
||||
} else {
|
||||
chainID := parseChainID(cmd)
|
||||
h, vub, err := pci.RemoveMorphRuleChain(parseChainName(cmd), target, chainID)
|
||||
chainID := apeCmd.ParseChainID(cmd)
|
||||
h, vub, err := pci.RemoveMorphRuleChain(apeCmd.ParseChainName(cmd), target, chainID)
|
||||
cmd.Println("Waiting for transaction to persist...")
|
||||
_, err = ac.Wait(h, vub, err)
|
||||
commonCmd.ExitOnErr(cmd, "remove rule chain error: %w", err)
|
||||
|
@ -199,7 +182,7 @@ func removeRuleChain(cmd *cobra.Command, _ []string) {
|
|||
func listRuleChains(cmd *cobra.Command, _ []string) {
|
||||
target := parseTarget(cmd)
|
||||
pci, _ := newPolicyContractReaderInterface(cmd)
|
||||
chains, err := pci.ListMorphRuleChains(parseChainName(cmd), target)
|
||||
chains, err := pci.ListMorphRuleChains(apeCmd.ParseChainName(cmd), target)
|
||||
commonCmd.ExitOnErr(cmd, "list rule chains error: %w", err)
|
||||
if len(chains) == 0 {
|
||||
return
|
||||
|
@ -235,8 +218,7 @@ func getAdmin(cmd *cobra.Command, _ []string) {
|
|||
}
|
||||
|
||||
func listTargets(cmd *cobra.Command, _ []string) {
|
||||
typ, err := parseTargetType(cmd)
|
||||
commonCmd.ExitOnErr(cmd, "parse target type error: %w", err)
|
||||
typ := apeCmd.ParseTargetType(cmd)
|
||||
pci, inv := newPolicyContractReaderInterface(cmd)
|
||||
|
||||
sid, it, err := pci.ListTargetsIterator(typ)
|
||||
|
|
|
@ -2,14 +2,12 @@ package ape
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/ape"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||
morph "git.frostfs.info/TrueCloudLab/policy-engine/pkg/morph/policy"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||
|
@ -19,90 +17,29 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
ingress = "ingress"
|
||||
s3 = "s3"
|
||||
)
|
||||
|
||||
var mChainName = map[string]apechain.Name{
|
||||
ingress: apechain.Ingress,
|
||||
s3: apechain.S3,
|
||||
}
|
||||
|
||||
var (
|
||||
errUnknownTargetType = errors.New("unknown target type")
|
||||
errChainIDCannotBeEmpty = errors.New("chain id cannot be empty")
|
||||
errRuleIsNotParsed = errors.New("rule is not passed")
|
||||
errUnsupportedChainName = errors.New("unsupported chain name")
|
||||
)
|
||||
var errUnknownTargetType = errors.New("unknown target type")
|
||||
|
||||
func parseTarget(cmd *cobra.Command) policyengine.Target {
|
||||
name, _ := cmd.Flags().GetString(targetNameFlag)
|
||||
typ, err := parseTargetType(cmd)
|
||||
|
||||
// interpret "root" namespace as empty
|
||||
if typ == policyengine.Namespace && name == "root" {
|
||||
name = ""
|
||||
}
|
||||
|
||||
commonCmd.ExitOnErr(cmd, "read target type error: %w", err)
|
||||
|
||||
return policyengine.Target{
|
||||
Name: name,
|
||||
Type: typ,
|
||||
}
|
||||
}
|
||||
|
||||
func parseTargetType(cmd *cobra.Command) (policyengine.TargetType, error) {
|
||||
typ, _ := cmd.Flags().GetString(targetTypeFlag)
|
||||
typ := apeCmd.ParseTargetType(cmd)
|
||||
name, _ := cmd.Flags().GetString(apeCmd.TargetNameFlag)
|
||||
switch typ {
|
||||
case namespaceTarget:
|
||||
return policyengine.Namespace, nil
|
||||
case containerTarget:
|
||||
return policyengine.Container, nil
|
||||
case userTarget:
|
||||
return policyengine.User, nil
|
||||
case groupTarget:
|
||||
return policyengine.Group, nil
|
||||
case policyengine.Namespace:
|
||||
if name == "root" {
|
||||
name = ""
|
||||
}
|
||||
return policyengine.NamespaceTarget(name)
|
||||
case policyengine.Container:
|
||||
var cnr cid.ID
|
||||
commonCmd.ExitOnErr(cmd, "can't decode container ID: %w", cnr.DecodeString(name))
|
||||
return policyengine.ContainerTarget(name)
|
||||
case policyengine.User:
|
||||
return policyengine.UserTarget(name)
|
||||
case policyengine.Group:
|
||||
return policyengine.GroupTarget(name)
|
||||
default:
|
||||
commonCmd.ExitOnErr(cmd, "read target type error: %w", errUnknownTargetType)
|
||||
}
|
||||
return -1, errUnknownTargetType
|
||||
}
|
||||
|
||||
func parseChainID(cmd *cobra.Command) apechain.ID {
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
if chainID == "" {
|
||||
commonCmd.ExitOnErr(cmd, "read chain id error: %w",
|
||||
errChainIDCannotBeEmpty)
|
||||
}
|
||||
return apechain.ID(chainID)
|
||||
}
|
||||
|
||||
func parseChain(cmd *cobra.Command) *apechain.Chain {
|
||||
chain := new(apechain.Chain)
|
||||
|
||||
if rules, _ := cmd.Flags().GetStringArray(ruleFlag); len(rules) > 0 {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", parseutil.ParseAPEChain(chain, rules))
|
||||
} else if encPath, _ := cmd.Flags().GetString(pathFlag); encPath != "" {
|
||||
commonCmd.ExitOnErr(cmd, "decode binary or json error: %w", parseutil.ParseAPEChainBinaryOrJSON(chain, encPath))
|
||||
} else {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", errRuleIsNotParsed)
|
||||
}
|
||||
|
||||
chain.ID = parseChainID(cmd)
|
||||
|
||||
cmd.Println("Parsed chain:")
|
||||
apeCmd.PrintHumanReadableAPEChain(cmd, chain)
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
func parseChainName(cmd *cobra.Command) apechain.Name {
|
||||
chainName, _ := cmd.Flags().GetString(chainNameFlag)
|
||||
apeChainName, ok := mChainName[strings.ToLower(chainName)]
|
||||
if !ok {
|
||||
commonCmd.ExitOnErr(cmd, "", errUnsupportedChainName)
|
||||
}
|
||||
return apeChainName
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// invokerAdapter adapats invoker.Invoker to ContractStorageInvoker interface.
|
||||
|
|
|
@ -1,45 +1,19 @@
|
|||
package apemanager
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/ape"
|
||||
apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||
client_sdk "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
chainIDFlag = "chain-id"
|
||||
chainIDHexFlag = "chain-id-hex"
|
||||
ruleFlag = "rule"
|
||||
pathFlag = "path"
|
||||
)
|
||||
|
||||
const (
|
||||
targetNameFlag = "target-name"
|
||||
targetNameDesc = "Resource name in APE resource name format"
|
||||
targetTypeFlag = "target-type"
|
||||
targetTypeDesc = "Resource type(container/namespace)"
|
||||
)
|
||||
|
||||
const (
|
||||
namespaceTarget = "namespace"
|
||||
containerTarget = "container"
|
||||
userTarget = "user"
|
||||
groupTarget = "group"
|
||||
)
|
||||
|
||||
var errUnknownTargetType = errors.New("unknown target type")
|
||||
|
||||
var addCmd = &cobra.Command{
|
||||
Use: "add",
|
||||
Short: "Add rule chain for a target",
|
||||
|
@ -50,55 +24,28 @@ var addCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
func parseTarget(cmd *cobra.Command) (ct apeSDK.ChainTarget) {
|
||||
typ, _ := cmd.Flags().GetString(targetTypeFlag)
|
||||
name, _ := cmd.Flags().GetString(targetNameFlag)
|
||||
t := apeCmd.ParseTarget(cmd)
|
||||
|
||||
ct.Name = name
|
||||
ct.Name = t.Name
|
||||
|
||||
switch typ {
|
||||
case namespaceTarget:
|
||||
switch t.Type {
|
||||
case engine.Namespace:
|
||||
ct.TargetType = apeSDK.TargetTypeNamespace
|
||||
case containerTarget:
|
||||
var cnr cid.ID
|
||||
commonCmd.ExitOnErr(cmd, "can't decode container ID: %w", cnr.DecodeString(name))
|
||||
case engine.Container:
|
||||
ct.TargetType = apeSDK.TargetTypeContainer
|
||||
case userTarget:
|
||||
case engine.User:
|
||||
ct.TargetType = apeSDK.TargetTypeUser
|
||||
case groupTarget:
|
||||
case engine.Group:
|
||||
ct.TargetType = apeSDK.TargetTypeGroup
|
||||
default:
|
||||
commonCmd.ExitOnErr(cmd, "read target type error: %w", errUnknownTargetType)
|
||||
commonCmd.ExitOnErr(cmd, "conversion error: %w", fmt.Errorf("unknown type '%c'", t.Type))
|
||||
}
|
||||
return ct
|
||||
}
|
||||
|
||||
func parseChain(cmd *cobra.Command) apeSDK.Chain {
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
||||
|
||||
chainIDRaw := []byte(chainID)
|
||||
|
||||
if hexEncoded {
|
||||
var err error
|
||||
chainIDRaw, err = hex.DecodeString(chainID)
|
||||
commonCmd.ExitOnErr(cmd, "can't decode chain ID as hex: %w", err)
|
||||
}
|
||||
|
||||
chain := new(apechain.Chain)
|
||||
chain.ID = apechain.ID(chainIDRaw)
|
||||
|
||||
if rules, _ := cmd.Flags().GetStringArray(ruleFlag); len(rules) > 0 {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", parseutil.ParseAPEChain(chain, rules))
|
||||
} else if encPath, _ := cmd.Flags().GetString(pathFlag); encPath != "" {
|
||||
commonCmd.ExitOnErr(cmd, "decode binary or json error: %w", parseutil.ParseAPEChainBinaryOrJSON(chain, encPath))
|
||||
} else {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", errors.New("rule is not passed"))
|
||||
}
|
||||
|
||||
cmd.Println("Parsed chain:")
|
||||
apeCmd.PrintHumanReadableAPEChain(cmd, chain)
|
||||
|
||||
serialized := chain.Bytes()
|
||||
c := apeCmd.ParseChain(cmd)
|
||||
serialized := c.Bytes()
|
||||
return apeSDK.Chain{
|
||||
Raw: serialized,
|
||||
}
|
||||
|
@ -127,13 +74,13 @@ func initAddCmd() {
|
|||
commonflags.Init(addCmd)
|
||||
|
||||
ff := addCmd.Flags()
|
||||
ff.StringArray(ruleFlag, []string{}, "Rule statement")
|
||||
ff.String(pathFlag, "", "Path to encoded chain in JSON or binary format")
|
||||
ff.String(chainIDFlag, "", "Assign ID to the parsed chain")
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = addCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
ff.StringArray(apeCmd.RuleFlag, []string{}, apeCmd.RuleFlagDesc)
|
||||
ff.String(apeCmd.PathFlag, "", apeCmd.PathFlagDesc)
|
||||
ff.String(apeCmd.ChainIDFlag, "", apeCmd.ChainIDFlagDesc)
|
||||
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = addCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
ff.Bool(apeCmd.ChainIDHexFlag, false, apeCmd.ChainIDHexFlagDesc)
|
||||
|
||||
addCmd.MarkFlagsMutuallyExclusive(pathFlag, ruleFlag)
|
||||
addCmd.MarkFlagsMutuallyExclusive(apeCmd.PathFlag, apeCmd.RuleFlag)
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ func initListCmd() {
|
|||
commonflags.Init(listCmd)
|
||||
|
||||
ff := listCmd.Flags()
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = listCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = listCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
}
|
||||
|
|
|
@ -1,29 +1,23 @@
|
|||
package apemanager
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
||||
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
client_sdk "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
errEmptyChainID = errors.New("chain id cannot be empty")
|
||||
|
||||
removeCmd = &cobra.Command{
|
||||
Use: "remove",
|
||||
Short: "Remove rule chain for a target",
|
||||
Run: remove,
|
||||
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
|
||||
commonflags.Bind(cmd)
|
||||
},
|
||||
}
|
||||
)
|
||||
var removeCmd = &cobra.Command{
|
||||
Use: "remove",
|
||||
Short: "Remove rule chain for a target",
|
||||
Run: remove,
|
||||
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
|
||||
commonflags.Bind(cmd)
|
||||
},
|
||||
}
|
||||
|
||||
func remove(cmd *cobra.Command, _ []string) {
|
||||
target := parseTarget(cmd)
|
||||
|
@ -31,19 +25,9 @@ func remove(cmd *cobra.Command, _ []string) {
|
|||
key := key.Get(cmd)
|
||||
cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC)
|
||||
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
if chainID == "" {
|
||||
commonCmd.ExitOnErr(cmd, "read chain id error: %w", errEmptyChainID)
|
||||
}
|
||||
chainID := apeCmd.ParseChainID(cmd)
|
||||
chainIDRaw := []byte(chainID)
|
||||
|
||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
||||
if hexEncoded {
|
||||
var err error
|
||||
chainIDRaw, err = hex.DecodeString(chainID)
|
||||
commonCmd.ExitOnErr(cmd, "can't decode chain ID as hex: %w", err)
|
||||
}
|
||||
|
||||
_, err := cli.APEManagerRemoveChain(cmd.Context(), client_sdk.PrmAPEManagerRemoveChain{
|
||||
ChainTarget: target,
|
||||
ChainID: chainIDRaw,
|
||||
|
@ -58,9 +42,10 @@ func initRemoveCmd() {
|
|||
commonflags.Init(removeCmd)
|
||||
|
||||
ff := removeCmd.Flags()
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = removeCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.String(chainIDFlag, "", "Chain id")
|
||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = removeCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
ff.String(apeCmd.ChainIDFlag, "", apeCmd.ChainIDFlagDesc)
|
||||
_ = removeCmd.MarkFlagRequired(apeCmd.ChainIDFlag)
|
||||
ff.Bool(apeCmd.ChainIDHexFlag, false, apeCmd.ChainIDHexFlagDesc)
|
||||
}
|
||||
|
|
|
@ -1,32 +1,20 @@
|
|||
package bearer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/ape"
|
||||
apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
errChainIDCannotBeEmpty = errors.New("chain id cannot be empty")
|
||||
errRuleIsNotParsed = errors.New("rule is not passed")
|
||||
)
|
||||
|
||||
const (
|
||||
chainIDFlag = "chain-id"
|
||||
chainIDHexFlag = "chain-id-hex"
|
||||
ruleFlag = "rule"
|
||||
pathFlag = "path"
|
||||
outputFlag = "output"
|
||||
outputFlag = "output"
|
||||
)
|
||||
|
||||
var generateAPEOverrideCmd = &cobra.Command{
|
||||
|
@ -41,7 +29,7 @@ Generated APE override can be dumped to a file in JSON format that is passed to
|
|||
}
|
||||
|
||||
func genereateAPEOverride(cmd *cobra.Command, _ []string) {
|
||||
c := parseChain(cmd)
|
||||
c := apeCmd.ParseChain(cmd)
|
||||
|
||||
targetCID, _ := cmd.Flags().GetString(commonflags.CIDFlag)
|
||||
var cid cidSDK.ID
|
||||
|
@ -78,39 +66,11 @@ func init() {
|
|||
ff.StringP(commonflags.CIDFlag, "", "", "Target container ID.")
|
||||
_ = cobra.MarkFlagRequired(createCmd.Flags(), commonflags.CIDFlag)
|
||||
|
||||
ff.StringArray(ruleFlag, []string{}, "Rule statement")
|
||||
ff.String(pathFlag, "", "Path to encoded chain in JSON or binary format")
|
||||
ff.String(chainIDFlag, "", "Assign ID to the parsed chain")
|
||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
ff.StringArray(apeCmd.RuleFlag, []string{}, "Rule statement")
|
||||
ff.String(apeCmd.PathFlag, "", "Path to encoded chain in JSON or binary format")
|
||||
ff.String(apeCmd.ChainIDFlag, "", "Assign ID to the parsed chain")
|
||||
ff.Bool(apeCmd.ChainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
|
||||
ff.String(outputFlag, "", "Output path to dump result JSON-encoded APE override")
|
||||
_ = cobra.MarkFlagFilename(createCmd.Flags(), outputFlag)
|
||||
}
|
||||
|
||||
func parseChainID(cmd *cobra.Command) apechain.ID {
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
if chainID == "" {
|
||||
commonCmd.ExitOnErr(cmd, "read chain id error: %w",
|
||||
errChainIDCannotBeEmpty)
|
||||
}
|
||||
return apechain.ID(chainID)
|
||||
}
|
||||
|
||||
func parseChain(cmd *cobra.Command) *apechain.Chain {
|
||||
chain := new(apechain.Chain)
|
||||
|
||||
if rules, _ := cmd.Flags().GetStringArray(ruleFlag); len(rules) > 0 {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", parseutil.ParseAPEChain(chain, rules))
|
||||
} else if encPath, _ := cmd.Flags().GetString(pathFlag); encPath != "" {
|
||||
commonCmd.ExitOnErr(cmd, "decode binary or json error: %w", parseutil.ParseAPEChainBinaryOrJSON(chain, encPath))
|
||||
} else {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", errRuleIsNotParsed)
|
||||
}
|
||||
|
||||
chain.ID = parseChainID(cmd)
|
||||
|
||||
cmd.Println("Parsed chain:")
|
||||
apeCmd.PrintHumanReadableAPEChain(cmd, chain)
|
||||
|
||||
return chain
|
||||
}
|
||||
|
|
|
@ -1,24 +1,14 @@
|
|||
package control
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
|
||||
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
ruleFlag = "rule"
|
||||
pathFlag = "path"
|
||||
)
|
||||
|
||||
var addRuleCmd = &cobra.Command{
|
||||
Use: "add-rule",
|
||||
Short: "Add local override",
|
||||
|
@ -32,41 +22,12 @@ control add-rule --endpoint ... -w ... --address ... --chain-id ChainID --cid ..
|
|||
Run: addRule,
|
||||
}
|
||||
|
||||
func parseChain(cmd *cobra.Command) *apechain.Chain {
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
||||
|
||||
chainIDRaw := []byte(chainID)
|
||||
|
||||
if hexEncoded {
|
||||
var err error
|
||||
chainIDRaw, err = hex.DecodeString(chainID)
|
||||
commonCmd.ExitOnErr(cmd, "can't decode chain ID as hex: %w", err)
|
||||
}
|
||||
|
||||
chain := new(apechain.Chain)
|
||||
chain.ID = apechain.ID(chainIDRaw)
|
||||
|
||||
if rules, _ := cmd.Flags().GetStringArray(ruleFlag); len(rules) > 0 {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", parseutil.ParseAPEChain(chain, rules))
|
||||
} else if encPath, _ := cmd.Flags().GetString(pathFlag); encPath != "" {
|
||||
commonCmd.ExitOnErr(cmd, "decode binary or json error: %w", parseutil.ParseAPEChainBinaryOrJSON(chain, encPath))
|
||||
} else {
|
||||
commonCmd.ExitOnErr(cmd, "parser error", errors.New("rule is not passed"))
|
||||
}
|
||||
|
||||
cmd.Println("Parsed chain:")
|
||||
apeCmd.PrintHumanReadableAPEChain(cmd, chain)
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
func addRule(cmd *cobra.Command, _ []string) {
|
||||
pk := key.Get(cmd)
|
||||
|
||||
target := parseTarget(cmd)
|
||||
|
||||
parsed := parseChain(cmd)
|
||||
parsed := apeCmd.ParseChain(cmd)
|
||||
|
||||
req := &control.AddChainLocalOverrideRequest{
|
||||
Body: &control.AddChainLocalOverrideRequest_Body{
|
||||
|
@ -95,13 +56,13 @@ func initControlAddRuleCmd() {
|
|||
initControlFlags(addRuleCmd)
|
||||
|
||||
ff := addRuleCmd.Flags()
|
||||
ff.StringArray(ruleFlag, []string{}, "Rule statement")
|
||||
ff.String(pathFlag, "", "Path to encoded chain in JSON or binary format")
|
||||
ff.String(chainIDFlag, "", "Assign ID to the parsed chain")
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = addRuleCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
ff.StringArray(apeCmd.RuleFlag, []string{}, "Rule statement")
|
||||
ff.String(apeCmd.PathFlag, "", "Path to encoded chain in JSON or binary format")
|
||||
ff.String(apeCmd.ChainIDFlag, "", "Assign ID to the parsed chain")
|
||||
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = addRuleCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
ff.Bool(apeCmd.ChainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
|
||||
addRuleCmd.MarkFlagsMutuallyExclusive(pathFlag, ruleFlag)
|
||||
addRuleCmd.MarkFlagsMutuallyExclusive(apeCmd.PathFlag, apeCmd.RuleFlag)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
apecmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
|
@ -24,8 +24,8 @@ func getRule(cmd *cobra.Command, _ []string) {
|
|||
|
||||
target := parseTarget(cmd)
|
||||
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
||||
chainID, _ := cmd.Flags().GetString(apecmd.ChainIDFlag)
|
||||
hexEncoded, _ := cmd.Flags().GetBool(apecmd.ChainIDHexFlag)
|
||||
|
||||
if hexEncoded {
|
||||
chainIDBytes, err := hex.DecodeString(chainID)
|
||||
|
@ -56,16 +56,16 @@ func getRule(cmd *cobra.Command, _ []string) {
|
|||
|
||||
var chain apechain.Chain
|
||||
commonCmd.ExitOnErr(cmd, "decode error: %w", chain.DecodeBytes(resp.GetBody().GetChain()))
|
||||
apeCmd.PrintHumanReadableAPEChain(cmd, &chain)
|
||||
apecmd.PrintHumanReadableAPEChain(cmd, &chain)
|
||||
}
|
||||
|
||||
func initControGetRuleCmd() {
|
||||
initControlFlags(getRuleCmd)
|
||||
|
||||
ff := getRuleCmd.Flags()
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = getRuleCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.String(chainIDFlag, "", "Chain id")
|
||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
ff.String(apecmd.TargetNameFlag, "", apecmd.TargetNameFlagDesc)
|
||||
ff.String(apecmd.TargetTypeFlag, "", apecmd.TargetTypeFlagDesc)
|
||||
_ = getRuleCmd.MarkFlagRequired(apecmd.TargetTypeFlag)
|
||||
ff.String(apecmd.ChainIDFlag, "", "Chain id")
|
||||
ff.Bool(apecmd.ChainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package control
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
@ -10,9 +9,8 @@ import (
|
|||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"github.com/nspcc-dev/neo-go/cli/input"
|
||||
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -23,65 +21,25 @@ var listRulesCmd = &cobra.Command{
|
|||
Run: listRules,
|
||||
}
|
||||
|
||||
const (
|
||||
defaultNamespace = "root"
|
||||
namespaceTarget = "namespace"
|
||||
containerTarget = "container"
|
||||
userTarget = "user"
|
||||
groupTarget = "group"
|
||||
)
|
||||
|
||||
const (
|
||||
targetNameFlag = "target-name"
|
||||
targetNameDesc = "Resource name in APE resource name format"
|
||||
targetTypeFlag = "target-type"
|
||||
targetTypeDesc = "Resource type(container/namespace)"
|
||||
)
|
||||
|
||||
var (
|
||||
errSettingDefaultValueWasDeclined = errors.New("setting default value was declined")
|
||||
errUnknownTargetType = errors.New("unknown target type")
|
||||
)
|
||||
var engineToControlSvcType = map[policyengine.TargetType]control.ChainTarget_TargetType{
|
||||
policyengine.Namespace: control.ChainTarget_NAMESPACE,
|
||||
policyengine.Container: control.ChainTarget_CONTAINER,
|
||||
policyengine.User: control.ChainTarget_USER,
|
||||
policyengine.Group: control.ChainTarget_GROUP,
|
||||
}
|
||||
|
||||
func parseTarget(cmd *cobra.Command) *control.ChainTarget {
|
||||
typ, _ := cmd.Flags().GetString(targetTypeFlag)
|
||||
name, _ := cmd.Flags().GetString(targetNameFlag)
|
||||
switch typ {
|
||||
case namespaceTarget:
|
||||
if name == "" {
|
||||
ln, err := input.ReadLine(fmt.Sprintf("Target name is not set. Confirm to use %s namespace (n|Y)> ", defaultNamespace))
|
||||
commonCmd.ExitOnErr(cmd, "read line error: %w", err)
|
||||
ln = strings.ToLower(ln)
|
||||
if len(ln) > 0 && (ln[0] == 'n') {
|
||||
commonCmd.ExitOnErr(cmd, "read namespace error: %w", errSettingDefaultValueWasDeclined)
|
||||
}
|
||||
name = defaultNamespace
|
||||
}
|
||||
return &control.ChainTarget{
|
||||
Name: name,
|
||||
Type: control.ChainTarget_NAMESPACE,
|
||||
}
|
||||
case containerTarget:
|
||||
var cnr cid.ID
|
||||
commonCmd.ExitOnErr(cmd, "can't decode container ID: %w", cnr.DecodeString(name))
|
||||
return &control.ChainTarget{
|
||||
Name: name,
|
||||
Type: control.ChainTarget_CONTAINER,
|
||||
}
|
||||
case userTarget:
|
||||
return &control.ChainTarget{
|
||||
Name: name,
|
||||
Type: control.ChainTarget_USER,
|
||||
}
|
||||
case groupTarget:
|
||||
return &control.ChainTarget{
|
||||
Name: name,
|
||||
Type: control.ChainTarget_GROUP,
|
||||
}
|
||||
default:
|
||||
commonCmd.ExitOnErr(cmd, "read target type error: %w", errUnknownTargetType)
|
||||
target := apeCmd.ParseTarget(cmd)
|
||||
|
||||
typ, ok := engineToControlSvcType[target.Type]
|
||||
if !ok {
|
||||
commonCmd.ExitOnErr(cmd, "%w", fmt.Errorf("unknown type '%c", target.Type))
|
||||
}
|
||||
|
||||
return &control.ChainTarget{
|
||||
Name: target.Name,
|
||||
Type: typ,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func listRules(cmd *cobra.Command, _ []string) {
|
||||
|
@ -125,7 +83,7 @@ func initControlListRulesCmd() {
|
|||
initControlFlags(listRulesCmd)
|
||||
|
||||
ff := listRulesCmd.Flags()
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = listRulesCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||
_ = listRulesCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||
}
|
||||
|
|
|
@ -2,26 +2,20 @@ package control
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"text/tabwriter"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const (
|
||||
chainNameFlag = "chain-name"
|
||||
chainNameFlagUsage = "Chain name(ingress|s3)"
|
||||
)
|
||||
|
||||
var listTargetsCmd = &cobra.Command{
|
||||
Use: "list-targets",
|
||||
Short: "List local targets",
|
||||
|
@ -32,15 +26,11 @@ var listTargetsCmd = &cobra.Command{
|
|||
func listTargets(cmd *cobra.Command, _ []string) {
|
||||
pk := key.Get(cmd)
|
||||
|
||||
var cnr cid.ID
|
||||
chainName, _ := cmd.Flags().GetString(chainNameFlag)
|
||||
|
||||
rawCID := make([]byte, sha256.Size)
|
||||
cnr.Encode(rawCID)
|
||||
chainName := apeCmd.ParseChainName(cmd)
|
||||
|
||||
req := &control.ListTargetsLocalOverridesRequest{
|
||||
Body: &control.ListTargetsLocalOverridesRequest_Body{
|
||||
ChainName: chainName,
|
||||
ChainName: string(chainName),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -82,7 +72,7 @@ func initControlListTargetsCmd() {
|
|||
initControlFlags(listTargetsCmd)
|
||||
|
||||
ff := listTargetsCmd.Flags()
|
||||
ff.String(chainNameFlag, "", chainNameFlagUsage)
|
||||
ff.String(apeCmd.ChainNameFlag, "", apeCmd.ChainNameFlagDesc)
|
||||
|
||||
_ = cobra.MarkFlagRequired(ff, chainNameFlag)
|
||||
_ = cobra.MarkFlagRequired(ff, apeCmd.ChainNameFlag)
|
||||
}
|
||||
|
|
|
@ -6,17 +6,12 @@ import (
|
|||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apecmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
chainIDFlag = "chain-id"
|
||||
chainIDHexFlag = "chain-id-hex"
|
||||
allFlag = "all"
|
||||
)
|
||||
|
||||
var (
|
||||
errEmptyChainID = errors.New("chain id cannot be empty")
|
||||
|
||||
|
@ -30,8 +25,8 @@ var (
|
|||
|
||||
func removeRule(cmd *cobra.Command, _ []string) {
|
||||
pk := key.Get(cmd)
|
||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
||||
removeAll, _ := cmd.Flags().GetBool(allFlag)
|
||||
hexEncoded, _ := cmd.Flags().GetBool(apecmd.ChainIDHexFlag)
|
||||
removeAll, _ := cmd.Flags().GetBool(apecmd.AllFlag)
|
||||
if removeAll {
|
||||
req := &control.RemoveChainLocalOverridesByTargetRequest{
|
||||
Body: &control.RemoveChainLocalOverridesByTargetRequest_Body{
|
||||
|
@ -52,7 +47,7 @@ func removeRule(cmd *cobra.Command, _ []string) {
|
|||
return
|
||||
}
|
||||
|
||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
||||
chainID, _ := cmd.Flags().GetString(apecmd.ChainIDFlag)
|
||||
if chainID == "" {
|
||||
commonCmd.ExitOnErr(cmd, "read chain id error: %w", errEmptyChainID)
|
||||
}
|
||||
|
@ -92,11 +87,11 @@ func initControlRemoveRuleCmd() {
|
|||
initControlFlags(removeRuleCmd)
|
||||
|
||||
ff := removeRuleCmd.Flags()
|
||||
ff.String(targetNameFlag, "", targetNameDesc)
|
||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
||||
_ = removeRuleCmd.MarkFlagRequired(targetTypeFlag)
|
||||
ff.String(chainIDFlag, "", "Chain id")
|
||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||
ff.Bool(allFlag, false, "Remove all chains")
|
||||
removeRuleCmd.MarkFlagsMutuallyExclusive(allFlag, chainIDFlag)
|
||||
ff.String(apecmd.TargetNameFlag, "", apecmd.TargetNameFlagDesc)
|
||||
ff.String(apecmd.TargetTypeFlag, "", apecmd.TargetTypeFlagDesc)
|
||||
_ = removeRuleCmd.MarkFlagRequired(apecmd.TargetTypeFlag)
|
||||
ff.String(apecmd.ChainIDFlag, "", apecmd.ChainIDFlagDesc)
|
||||
ff.Bool(apecmd.ChainIDHexFlag, false, apecmd.ChainIDHexFlagDesc)
|
||||
ff.Bool(apecmd.AllFlag, false, "Remove all chains")
|
||||
removeRuleCmd.MarkFlagsMutuallyExclusive(apecmd.AllFlag, apecmd.ChainIDFlag)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,43 @@
|
|||
package ape
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||
apeutil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/ape"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||
"github.com/nspcc-dev/neo-go/cli/input"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultNamespace = "root"
|
||||
namespaceTarget = "namespace"
|
||||
containerTarget = "container"
|
||||
userTarget = "user"
|
||||
groupTarget = "group"
|
||||
|
||||
Ingress = "ingress"
|
||||
S3 = "s3"
|
||||
)
|
||||
|
||||
var mChainName = map[string]apechain.Name{
|
||||
Ingress: apechain.Ingress,
|
||||
S3: apechain.S3,
|
||||
}
|
||||
|
||||
var (
|
||||
errSettingDefaultValueWasDeclined = errors.New("setting default value was declined")
|
||||
errUnknownTargetType = errors.New("unknown target type")
|
||||
errUnsupportedChainName = errors.New("unsupported chain name")
|
||||
)
|
||||
|
||||
// PrintHumanReadableAPEChain print APE chain rules.
|
||||
func PrintHumanReadableAPEChain(cmd *cobra.Command, chain *apechain.Chain) {
|
||||
cmd.Println("Chain ID: " + string(chain.ID))
|
||||
|
@ -39,3 +69,99 @@ func PrintHumanReadableAPEChain(cmd *cobra.Command, chain *apechain.Chain) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ParseTarget handles target parsing of an APE chain.
|
||||
func ParseTarget(cmd *cobra.Command) engine.Target {
|
||||
typ := ParseTargetType(cmd)
|
||||
name, _ := cmd.Flags().GetString(TargetNameFlag)
|
||||
switch typ {
|
||||
case engine.Namespace:
|
||||
if name == "" {
|
||||
ln, err := input.ReadLine(fmt.Sprintf("Target name is not set. Confirm to use %s namespace (n|Y)> ", defaultNamespace))
|
||||
commonCmd.ExitOnErr(cmd, "read line error: %w", err)
|
||||
ln = strings.ToLower(ln)
|
||||
if len(ln) > 0 && (ln[0] == 'n') {
|
||||
commonCmd.ExitOnErr(cmd, "read namespace error: %w", errSettingDefaultValueWasDeclined)
|
||||
}
|
||||
name = defaultNamespace
|
||||
}
|
||||
return engine.NamespaceTarget(name)
|
||||
case engine.Container:
|
||||
var cnr cid.ID
|
||||
commonCmd.ExitOnErr(cmd, "can't decode container ID: %w", cnr.DecodeString(name))
|
||||
return engine.ContainerTarget(name)
|
||||
case engine.User:
|
||||
return engine.UserTarget(name)
|
||||
case engine.Group:
|
||||
return engine.GroupTarget(name)
|
||||
default:
|
||||
commonCmd.ExitOnErr(cmd, "read target type error: %w", errUnknownTargetType)
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// ParseTargetType handles target type parsing of an APE chain.
|
||||
func ParseTargetType(cmd *cobra.Command) engine.TargetType {
|
||||
typ, _ := cmd.Flags().GetString(TargetTypeFlag)
|
||||
switch typ {
|
||||
case namespaceTarget:
|
||||
return engine.Namespace
|
||||
case containerTarget:
|
||||
return engine.Container
|
||||
case userTarget:
|
||||
return engine.User
|
||||
case groupTarget:
|
||||
return engine.Group
|
||||
default:
|
||||
commonCmd.ExitOnErr(cmd, "parse target type error: %w", errUnknownTargetType)
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// ParseChainID handles the parsing of APE-chain identifier.
|
||||
// For some subcommands, chain ID is optional as an input parameter and should be generated by
|
||||
// the service instead.
|
||||
func ParseChainID(cmd *cobra.Command) (id apechain.ID) {
|
||||
chainID, _ := cmd.Flags().GetString(ChainIDFlag)
|
||||
id = apechain.ID(chainID)
|
||||
|
||||
hexEncoded, _ := cmd.Flags().GetBool(ChainIDHexFlag)
|
||||
if !hexEncoded {
|
||||
return
|
||||
}
|
||||
|
||||
chainIDRaw, err := hex.DecodeString(chainID)
|
||||
commonCmd.ExitOnErr(cmd, "can't decode chain ID as hex: %w", err)
|
||||
id = apechain.ID(chainIDRaw)
|
||||
return
|
||||
}
|
||||
|
||||
// ParseChain parses an APE chain which can be provided either as a rule statement
|
||||
// or loaded from a binary/JSON file path.
|
||||
func ParseChain(cmd *cobra.Command) *apechain.Chain {
|
||||
chain := new(apechain.Chain)
|
||||
chain.ID = ParseChainID(cmd)
|
||||
|
||||
if rules, _ := cmd.Flags().GetStringArray(RuleFlag); len(rules) > 0 {
|
||||
commonCmd.ExitOnErr(cmd, "parser error: %w", apeutil.ParseAPEChain(chain, rules))
|
||||
} else if encPath, _ := cmd.Flags().GetString(PathFlag); encPath != "" {
|
||||
commonCmd.ExitOnErr(cmd, "decode binary or json error: %w", apeutil.ParseAPEChainBinaryOrJSON(chain, encPath))
|
||||
} else {
|
||||
commonCmd.ExitOnErr(cmd, "parser error", errors.New("rule is not passed"))
|
||||
}
|
||||
|
||||
cmd.Println("Parsed chain:")
|
||||
PrintHumanReadableAPEChain(cmd, chain)
|
||||
|
||||
return chain
|
||||
}
|
||||
|
||||
// ParseChainName parses chain name: the place in the request lifecycle where policy is applied.
|
||||
func ParseChainName(cmd *cobra.Command) apechain.Name {
|
||||
chainName, _ := cmd.Flags().GetString(ChainNameFlag)
|
||||
apeChainName, ok := mChainName[strings.ToLower(chainName)]
|
||||
if !ok {
|
||||
commonCmd.ExitOnErr(cmd, "", errUnsupportedChainName)
|
||||
}
|
||||
return apeChainName
|
||||
}
|
||||
|
|
19
cmd/internal/common/ape/flags.go
Normal file
19
cmd/internal/common/ape/flags.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package ape
|
||||
|
||||
const (
|
||||
RuleFlag = "rule"
|
||||
RuleFlagDesc = "Rule statement"
|
||||
PathFlag = "path"
|
||||
PathFlagDesc = "Path to encoded chain in JSON or binary format"
|
||||
TargetNameFlag = "target-name"
|
||||
TargetNameFlagDesc = "Resource name in APE resource name format"
|
||||
TargetTypeFlag = "target-type"
|
||||
TargetTypeFlagDesc = "Resource type(container/namespace)"
|
||||
ChainIDFlag = "chain-id"
|
||||
ChainIDFlagDesc = "Chain id"
|
||||
ChainIDHexFlag = "chain-id-hex"
|
||||
ChainIDHexFlagDesc = "Flag to parse chain ID as hex"
|
||||
ChainNameFlag = "chain-name"
|
||||
ChainNameFlagDesc = "Chain name(ingress|s3)"
|
||||
AllFlag = "all"
|
||||
)
|
|
@ -15,41 +15,19 @@ type BlockTickHandler func()
|
|||
// It can tick the blocks and perform certain actions
|
||||
// on block time intervals.
|
||||
type BlockTimer struct {
|
||||
rolledBack bool
|
||||
|
||||
mtx sync.Mutex
|
||||
|
||||
dur BlockMeter
|
||||
|
||||
baseDur uint32
|
||||
|
||||
mul, div uint32
|
||||
|
||||
cur, tgt uint32
|
||||
|
||||
last uint32
|
||||
|
||||
h BlockTickHandler
|
||||
|
||||
ps []BlockTimer
|
||||
|
||||
once bool
|
||||
|
||||
deltaCfg
|
||||
}
|
||||
|
||||
// DeltaOption is an option of delta-interval handler.
|
||||
type DeltaOption func(*deltaCfg)
|
||||
|
||||
type deltaCfg struct {
|
||||
pulse bool
|
||||
}
|
||||
|
||||
// WithPulse returns option to call delta-interval handler multiple times.
|
||||
func WithPulse() DeltaOption {
|
||||
return func(c *deltaCfg) {
|
||||
c.pulse = true
|
||||
}
|
||||
}
|
||||
|
||||
// StaticBlockMeter returns BlockMeters that always returns (d, nil).
|
||||
|
@ -65,52 +43,19 @@ func StaticBlockMeter(d uint32) BlockMeter {
|
|||
func NewBlockTimer(dur BlockMeter, h BlockTickHandler) *BlockTimer {
|
||||
return &BlockTimer{
|
||||
dur: dur,
|
||||
mul: 1,
|
||||
div: 1,
|
||||
h: h,
|
||||
deltaCfg: deltaCfg{
|
||||
pulse: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewOneTickTimer creates a new BlockTimer that ticks only once.
|
||||
//
|
||||
// Do not use delta handlers with pulse in this timer.
|
||||
func NewOneTickTimer(dur BlockMeter, h BlockTickHandler) *BlockTimer {
|
||||
return &BlockTimer{
|
||||
dur: dur,
|
||||
mul: 1,
|
||||
div: 1,
|
||||
h: h,
|
||||
once: true,
|
||||
}
|
||||
}
|
||||
|
||||
// OnDelta registers handler which is executed on (mul / div * BlockMeter()) block
|
||||
// after basic interval reset.
|
||||
//
|
||||
// If WithPulse option is provided, handler is executed (mul / div * BlockMeter()) block
|
||||
// during base interval.
|
||||
func (t *BlockTimer) OnDelta(mul, div uint32, h BlockTickHandler, opts ...DeltaOption) {
|
||||
c := deltaCfg{
|
||||
pulse: false,
|
||||
}
|
||||
|
||||
for i := range opts {
|
||||
opts[i](&c)
|
||||
}
|
||||
|
||||
t.ps = append(t.ps, BlockTimer{
|
||||
mul: mul,
|
||||
div: div,
|
||||
h: h,
|
||||
once: t.once,
|
||||
|
||||
deltaCfg: c,
|
||||
})
|
||||
}
|
||||
|
||||
// Reset resets previous ticks of the BlockTimer.
|
||||
//
|
||||
// Returns BlockMeter's error upon occurrence.
|
||||
|
@ -124,29 +69,18 @@ func (t *BlockTimer) Reset() error {
|
|||
|
||||
t.resetWithBaseInterval(d)
|
||||
|
||||
for i := range t.ps {
|
||||
t.ps[i].resetWithBaseInterval(d)
|
||||
}
|
||||
|
||||
t.mtx.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *BlockTimer) resetWithBaseInterval(d uint32) {
|
||||
t.rolledBack = false
|
||||
t.baseDur = d
|
||||
t.reset()
|
||||
}
|
||||
|
||||
func (t *BlockTimer) reset() {
|
||||
mul, div := t.mul, t.div
|
||||
|
||||
if !t.pulse && t.rolledBack && mul < div {
|
||||
mul, div = 1, 1
|
||||
}
|
||||
|
||||
delta := mul * t.baseDur / div
|
||||
delta := t.baseDur
|
||||
if delta == 0 {
|
||||
delta = 1
|
||||
}
|
||||
|
@ -180,12 +114,7 @@ func (t *BlockTimer) tick(h uint32) {
|
|||
|
||||
if !t.once {
|
||||
t.cur = 0
|
||||
t.rolledBack = true
|
||||
t.reset()
|
||||
}
|
||||
}
|
||||
|
||||
for i := range t.ps {
|
||||
t.ps[i].tick(h)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package timer_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/timer"
|
||||
|
@ -17,7 +18,7 @@ func tickN(t *timer.BlockTimer, n uint32) {
|
|||
// "resetting" consists of ticking the current height as well and invoking `Reset`.
|
||||
func TestIRBlockTimer_Reset(t *testing.T) {
|
||||
var baseCounter [2]int
|
||||
blockDur := uint32(3)
|
||||
const blockDur = uint32(3)
|
||||
|
||||
bt1 := timer.NewBlockTimer(
|
||||
func() (uint32, error) { return blockDur, nil },
|
||||
|
@ -48,8 +49,40 @@ func TestIRBlockTimer_Reset(t *testing.T) {
|
|||
require.Equal(t, baseCounter[0], baseCounter[1])
|
||||
}
|
||||
|
||||
func TestBlockTimer_ResetChangeDuration(t *testing.T) {
|
||||
var dur uint32 = 2
|
||||
var err error
|
||||
var counter int
|
||||
|
||||
bt := timer.NewBlockTimer(
|
||||
func() (uint32, error) { return dur, err },
|
||||
func() { counter++ })
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
tickN(bt, 2)
|
||||
require.Equal(t, 1, counter)
|
||||
|
||||
t.Run("return error", func(t *testing.T) {
|
||||
dur = 5
|
||||
err = errors.New("my awesome error")
|
||||
require.ErrorIs(t, bt.Reset(), err)
|
||||
|
||||
tickN(bt, 2)
|
||||
require.Equal(t, 2, counter)
|
||||
})
|
||||
t.Run("change duration", func(t *testing.T) {
|
||||
dur = 5
|
||||
err = nil
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
tickN(bt, 5)
|
||||
require.Equal(t, 3, counter)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBlockTimer(t *testing.T) {
|
||||
blockDur := uint32(10)
|
||||
const blockDur = uint32(10)
|
||||
baseCallCounter := uint32(0)
|
||||
|
||||
bt := timer.NewBlockTimer(timer.StaticBlockMeter(blockDur), func() {
|
||||
|
@ -63,85 +96,6 @@ func TestBlockTimer(t *testing.T) {
|
|||
tickN(bt, intervalNum*blockDur)
|
||||
|
||||
require.Equal(t, intervalNum, uint32(baseCallCounter))
|
||||
|
||||
// add half-interval handler
|
||||
halfCallCounter := uint32(0)
|
||||
|
||||
bt.OnDelta(1, 2, func() {
|
||||
halfCallCounter++
|
||||
})
|
||||
|
||||
// add double interval handler
|
||||
doubleCallCounter := uint32(0)
|
||||
|
||||
bt.OnDelta(2, 1, func() {
|
||||
doubleCallCounter++
|
||||
})
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
baseCallCounter = 0
|
||||
intervalNum = 20
|
||||
|
||||
tickN(bt, intervalNum*blockDur)
|
||||
|
||||
require.Equal(t, intervalNum, uint32(halfCallCounter))
|
||||
require.Equal(t, intervalNum, uint32(baseCallCounter))
|
||||
require.Equal(t, intervalNum/2, uint32(doubleCallCounter))
|
||||
}
|
||||
|
||||
func TestDeltaPulse(t *testing.T) {
|
||||
blockDur := uint32(9)
|
||||
baseCallCounter := uint32(0)
|
||||
|
||||
bt := timer.NewBlockTimer(timer.StaticBlockMeter(blockDur), func() {
|
||||
baseCallCounter++
|
||||
})
|
||||
|
||||
deltaCallCounter := uint32(0)
|
||||
|
||||
div := uint32(3)
|
||||
|
||||
bt.OnDelta(1, div, func() {
|
||||
deltaCallCounter++
|
||||
}, timer.WithPulse())
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
intervalNum := uint32(7)
|
||||
|
||||
tickN(bt, intervalNum*blockDur)
|
||||
|
||||
require.Equal(t, intervalNum, uint32(baseCallCounter))
|
||||
require.Equal(t, intervalNum*div, uint32(deltaCallCounter))
|
||||
}
|
||||
|
||||
func TestDeltaReset(t *testing.T) {
|
||||
blockDur := uint32(6)
|
||||
baseCallCounter := 0
|
||||
|
||||
bt := timer.NewBlockTimer(timer.StaticBlockMeter(blockDur), func() {
|
||||
baseCallCounter++
|
||||
})
|
||||
|
||||
detlaCallCounter := 0
|
||||
|
||||
bt.OnDelta(1, 3, func() {
|
||||
detlaCallCounter++
|
||||
})
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
tickN(bt, 6)
|
||||
|
||||
require.Equal(t, 1, baseCallCounter)
|
||||
require.Equal(t, 1, detlaCallCounter)
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
tickN(bt, 3)
|
||||
|
||||
require.Equal(t, 2, detlaCallCounter)
|
||||
}
|
||||
|
||||
func TestNewOneTickTimer(t *testing.T) {
|
||||
|
@ -168,82 +122,51 @@ func TestNewOneTickTimer(t *testing.T) {
|
|||
tickN(bt, 10)
|
||||
require.Equal(t, 1, baseCallCounter)
|
||||
})
|
||||
|
||||
t.Run("delta without pulse", func(t *testing.T) {
|
||||
blockDur = uint32(10)
|
||||
baseCallCounter = 0
|
||||
|
||||
bt = timer.NewOneTickTimer(timer.StaticBlockMeter(blockDur), func() {
|
||||
baseCallCounter++
|
||||
})
|
||||
|
||||
detlaCallCounter := 0
|
||||
|
||||
bt.OnDelta(1, 10, func() {
|
||||
detlaCallCounter++
|
||||
})
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
tickN(bt, 10)
|
||||
require.Equal(t, 1, baseCallCounter)
|
||||
require.Equal(t, 1, detlaCallCounter)
|
||||
|
||||
tickN(bt, 10) // 10 more ticks must not affect counters
|
||||
require.Equal(t, 1, baseCallCounter)
|
||||
require.Equal(t, 1, detlaCallCounter)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBlockTimer_TickSameHeight(t *testing.T) {
|
||||
var baseCounter, deltaCounter int
|
||||
var baseCounter int
|
||||
|
||||
blockDur := uint32(2)
|
||||
bt := timer.NewBlockTimer(
|
||||
func() (uint32, error) { return blockDur, nil },
|
||||
func() { baseCounter++ })
|
||||
bt.OnDelta(2, 1, func() {
|
||||
deltaCounter++
|
||||
})
|
||||
require.NoError(t, bt.Reset())
|
||||
|
||||
check := func(t *testing.T, h uint32, base, delta int) {
|
||||
check := func(t *testing.T, h uint32, base int) {
|
||||
for range 2 * int(blockDur) {
|
||||
bt.Tick(h)
|
||||
require.Equal(t, base, baseCounter)
|
||||
require.Equal(t, delta, deltaCounter)
|
||||
}
|
||||
}
|
||||
|
||||
check(t, 1, 0, 0)
|
||||
check(t, 2, 1, 0)
|
||||
check(t, 3, 1, 0)
|
||||
check(t, 4, 2, 1)
|
||||
check(t, 1, 0)
|
||||
check(t, 2, 1)
|
||||
check(t, 3, 1)
|
||||
check(t, 4, 2)
|
||||
|
||||
t.Run("works the same way after `Reset()`", func(t *testing.T) {
|
||||
t.Run("same block duration", func(t *testing.T) {
|
||||
require.NoError(t, bt.Reset())
|
||||
baseCounter = 0
|
||||
deltaCounter = 0
|
||||
|
||||
check(t, 1, 0, 0)
|
||||
check(t, 2, 1, 0)
|
||||
check(t, 3, 1, 0)
|
||||
check(t, 4, 2, 1)
|
||||
check(t, 1, 0)
|
||||
check(t, 2, 1)
|
||||
check(t, 3, 1)
|
||||
check(t, 4, 2)
|
||||
})
|
||||
t.Run("different block duration", func(t *testing.T) {
|
||||
blockDur = 3
|
||||
|
||||
require.NoError(t, bt.Reset())
|
||||
baseCounter = 0
|
||||
deltaCounter = 0
|
||||
|
||||
check(t, 1, 0, 0)
|
||||
check(t, 2, 0, 0)
|
||||
check(t, 3, 1, 0)
|
||||
check(t, 4, 1, 0)
|
||||
check(t, 5, 1, 0)
|
||||
check(t, 6, 2, 1)
|
||||
check(t, 1, 0)
|
||||
check(t, 2, 0)
|
||||
check(t, 3, 1)
|
||||
check(t, 4, 1)
|
||||
check(t, 5, 1)
|
||||
check(t, 6, 2)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -111,14 +111,18 @@ func NewTraverser(opts ...Option) (*Traverser, error) {
|
|||
var rem []int
|
||||
if len(cfg.metrics) > 0 && cfg.nodeState != nil {
|
||||
rem = defaultCopiesVector(cfg.policy)
|
||||
var unsortedVector []netmap.NodeInfo
|
||||
var regularVector []netmap.NodeInfo
|
||||
var unsortedVector, regularVector []netmap.NodeInfo
|
||||
for i := range rem {
|
||||
unsortedVector = append(unsortedVector, ns[i][:rem[i]]...)
|
||||
regularVector = append(regularVector, ns[i][rem[i]:]...)
|
||||
if len(ns[i]) < rem[i] {
|
||||
unsortedVector = append(unsortedVector, ns[i]...)
|
||||
} else {
|
||||
unsortedVector = append(unsortedVector, ns[i][:rem[i]]...)
|
||||
if len(ns[i]) > rem[i] {
|
||||
regularVector = append(regularVector, ns[i][rem[i]:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
rem = []int{-1, -1}
|
||||
|
||||
sortedVector, err := sortVector(cfg, unsortedVector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -356,6 +356,52 @@ func TestTraverserPriorityMetrics(t *testing.T) {
|
|||
require.Nil(t, next)
|
||||
})
|
||||
|
||||
t.Run("one rep one metric fewer nodes", func(t *testing.T) {
|
||||
selectors := []int{2}
|
||||
replicas := []int{3}
|
||||
|
||||
nodes, cnr := testPlacement(selectors, replicas)
|
||||
|
||||
// Node_0, PK - ip4/0.0.0.0/tcp/0
|
||||
nodes[0][0].SetAttribute("ClusterName", "A")
|
||||
// Node_1, PK - ip4/0.0.0.0/tcp/1
|
||||
nodes[0][1].SetAttribute("ClusterName", "B")
|
||||
|
||||
sdkNode := testNode(5)
|
||||
sdkNode.SetAttribute("ClusterName", "B")
|
||||
|
||||
nodesCopy := copyVectors(nodes)
|
||||
|
||||
m := []Metric{NewAttributeMetric("ClusterName")}
|
||||
|
||||
tr, err := NewTraverser(
|
||||
ForContainer(cnr),
|
||||
UseBuilder(&testBuilder{
|
||||
vectors: nodesCopy,
|
||||
}),
|
||||
WithoutSuccessTracking(),
|
||||
WithPriorityMetrics(m),
|
||||
WithNodeState(&nodeState{
|
||||
node: &sdkNode,
|
||||
}),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Without priority metric `ClusterName` the order will be:
|
||||
// [ {Node_0 A}, {Node_1 A} ]
|
||||
// With priority metric `ClusterName` and current node in cluster B
|
||||
// the order should be:
|
||||
// [ {Node_1 B}, {Node_0 A} ]
|
||||
next := tr.Next()
|
||||
require.NotNil(t, next)
|
||||
require.Equal(t, 2, len(next))
|
||||
require.Equal(t, "/ip4/0.0.0.0/tcp/1", string(next[0].PublicKey()))
|
||||
require.Equal(t, "/ip4/0.0.0.0/tcp/0", string(next[1].PublicKey()))
|
||||
|
||||
next = tr.Next()
|
||||
require.Nil(t, next)
|
||||
})
|
||||
|
||||
t.Run("two reps two metrics", func(t *testing.T) {
|
||||
selectors := []int{3, 3}
|
||||
replicas := []int{2, 2}
|
||||
|
|
Loading…
Reference in a new issue