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
|
name: Build
|
||||||
|
|
||||||
on: [pull_request]
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
name: Pre-commit hooks
|
name: Pre-commit hooks
|
||||||
on: [pull_request]
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
precommit:
|
precommit:
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
name: Tests and linters
|
name: Tests and linters
|
||||||
on: [pull_request]
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
name: Vulncheck
|
name: Vulncheck
|
||||||
on: [pull_request]
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
vulncheck:
|
vulncheck:
|
||||||
|
|
|
@ -14,26 +14,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
namespaceTarget = "namespace"
|
|
||||||
containerTarget = "container"
|
|
||||||
userTarget = "user"
|
|
||||||
groupTarget = "group"
|
|
||||||
jsonFlag = "json"
|
jsonFlag = "json"
|
||||||
jsonFlagDesc = "Output rule chains in JSON format"
|
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"
|
addrAdminFlag = "addr"
|
||||||
addrAdminDesc = "The address of the admins wallet"
|
addrAdminDesc = "The address of the admins wallet"
|
||||||
chainNameFlag = "chain-name"
|
|
||||||
chainNameFlagDesc = "Chain name(ingress|s3)"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -101,17 +85,17 @@ func initAddRuleChainCmd() {
|
||||||
addRuleChainCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
addRuleChainCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||||
addRuleChainCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
addRuleChainCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||||
|
|
||||||
addRuleChainCmd.Flags().String(targetTypeFlag, "", targetTypeDesc)
|
addRuleChainCmd.Flags().String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||||
_ = addRuleChainCmd.MarkFlagRequired(targetTypeFlag)
|
_ = addRuleChainCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||||
addRuleChainCmd.Flags().String(targetNameFlag, "", targetNameDesc)
|
addRuleChainCmd.Flags().String(apeCmd.TargetNameFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||||
_ = addRuleChainCmd.MarkFlagRequired(targetNameFlag)
|
_ = addRuleChainCmd.MarkFlagRequired(apeCmd.TargetNameFlag)
|
||||||
|
|
||||||
addRuleChainCmd.Flags().String(chainIDFlag, "", chainIDDesc)
|
addRuleChainCmd.Flags().String(apeCmd.ChainIDFlag, "", apeCmd.ChainIDFlagDesc)
|
||||||
_ = addRuleChainCmd.MarkFlagRequired(chainIDFlag)
|
_ = addRuleChainCmd.MarkFlagRequired(apeCmd.ChainIDFlag)
|
||||||
addRuleChainCmd.Flags().StringArray(ruleFlag, []string{}, ruleFlagDesc)
|
addRuleChainCmd.Flags().StringArray(apeCmd.RuleFlag, []string{}, apeCmd.RuleFlagDesc)
|
||||||
addRuleChainCmd.Flags().String(pathFlag, "", pathFlagDesc)
|
addRuleChainCmd.Flags().String(apeCmd.PathFlag, "", apeCmd.PathFlagDesc)
|
||||||
addRuleChainCmd.Flags().String(chainNameFlag, ingress, chainNameFlagDesc)
|
addRuleChainCmd.Flags().String(apeCmd.ChainNameFlag, apeCmd.Ingress, apeCmd.ChainNameFlagDesc)
|
||||||
addRuleChainCmd.MarkFlagsMutuallyExclusive(ruleFlag, pathFlag)
|
addRuleChainCmd.MarkFlagsMutuallyExclusive(apeCmd.RuleFlag, apeCmd.PathFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initRemoveRuleChainCmd() {
|
func initRemoveRuleChainCmd() {
|
||||||
|
@ -120,26 +104,25 @@ func initRemoveRuleChainCmd() {
|
||||||
removeRuleChainCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
removeRuleChainCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||||
removeRuleChainCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
removeRuleChainCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||||
|
|
||||||
removeRuleChainCmd.Flags().String(targetTypeFlag, "", targetTypeDesc)
|
removeRuleChainCmd.Flags().String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||||
_ = removeRuleChainCmd.MarkFlagRequired(targetTypeFlag)
|
_ = removeRuleChainCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||||
removeRuleChainCmd.Flags().String(targetNameFlag, "", targetNameDesc)
|
removeRuleChainCmd.Flags().String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||||
_ = removeRuleChainCmd.MarkFlagRequired(targetNameFlag)
|
_ = removeRuleChainCmd.MarkFlagRequired(apeCmd.TargetNameFlag)
|
||||||
removeRuleChainCmd.Flags().String(chainIDFlag, "", chainIDDesc)
|
removeRuleChainCmd.Flags().String(apeCmd.ChainIDFlag, "", apeCmd.ChainIDFlagDesc)
|
||||||
removeRuleChainCmd.Flags().String(chainNameFlag, ingress, chainNameFlagDesc)
|
removeRuleChainCmd.Flags().String(apeCmd.ChainNameFlag, apeCmd.Ingress, apeCmd.ChainNameFlagDesc)
|
||||||
removeRuleChainCmd.Flags().Bool(commonflags.AllFlag, false, "Remove all chains for target")
|
removeRuleChainCmd.Flags().Bool(commonflags.AllFlag, false, "Remove all chains for target")
|
||||||
removeRuleChainCmd.MarkFlagsMutuallyExclusive(commonflags.AllFlag, chainIDFlag)
|
removeRuleChainCmd.MarkFlagsMutuallyExclusive(commonflags.AllFlag, apeCmd.ChainIDFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initListRuleChainsCmd() {
|
func initListRuleChainsCmd() {
|
||||||
Cmd.AddCommand(listRuleChainsCmd)
|
Cmd.AddCommand(listRuleChainsCmd)
|
||||||
|
|
||||||
listRuleChainsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
listRuleChainsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||||
listRuleChainsCmd.Flags().StringP(targetTypeFlag, "t", "", targetTypeDesc)
|
listRuleChainsCmd.Flags().StringP(apeCmd.TargetTypeFlag, "t", "", apeCmd.TargetTypeFlagDesc)
|
||||||
_ = listRuleChainsCmd.MarkFlagRequired(targetTypeFlag)
|
_ = listRuleChainsCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||||
listRuleChainsCmd.Flags().String(targetNameFlag, "", targetNameDesc)
|
listRuleChainsCmd.Flags().String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||||
_ = listRuleChainsCmd.MarkFlagRequired(targetNameFlag)
|
|
||||||
listRuleChainsCmd.Flags().Bool(jsonFlag, false, jsonFlagDesc)
|
listRuleChainsCmd.Flags().Bool(jsonFlag, false, jsonFlagDesc)
|
||||||
listRuleChainsCmd.Flags().String(chainNameFlag, ingress, chainNameFlagDesc)
|
listRuleChainsCmd.Flags().String(apeCmd.ChainNameFlag, apeCmd.Ingress, apeCmd.ChainNameFlagDesc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSetAdminCmd() {
|
func initSetAdminCmd() {
|
||||||
|
@ -161,15 +144,15 @@ func initListTargetsCmd() {
|
||||||
Cmd.AddCommand(listTargetsCmd)
|
Cmd.AddCommand(listTargetsCmd)
|
||||||
|
|
||||||
listTargetsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
listTargetsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||||
listTargetsCmd.Flags().StringP(targetTypeFlag, "t", "", targetTypeDesc)
|
listTargetsCmd.Flags().StringP(apeCmd.TargetTypeFlag, "t", "", apeCmd.TargetTypeFlagDesc)
|
||||||
_ = listTargetsCmd.MarkFlagRequired(targetTypeFlag)
|
_ = listTargetsCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addRuleChain(cmd *cobra.Command, _ []string) {
|
func addRuleChain(cmd *cobra.Command, _ []string) {
|
||||||
chain := parseChain(cmd)
|
chain := apeCmd.ParseChain(cmd)
|
||||||
target := parseTarget(cmd)
|
target := parseTarget(cmd)
|
||||||
pci, ac := newPolicyContractInterface(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...")
|
cmd.Println("Waiting for transaction to persist...")
|
||||||
_, err = ac.Wait(h, vub, err)
|
_, err = ac.Wait(h, vub, err)
|
||||||
commonCmd.ExitOnErr(cmd, "add rule chain error: %w", err)
|
commonCmd.ExitOnErr(cmd, "add rule chain error: %w", err)
|
||||||
|
@ -181,14 +164,14 @@ func removeRuleChain(cmd *cobra.Command, _ []string) {
|
||||||
pci, ac := newPolicyContractInterface(cmd)
|
pci, ac := newPolicyContractInterface(cmd)
|
||||||
removeAll, _ := cmd.Flags().GetBool(commonflags.AllFlag)
|
removeAll, _ := cmd.Flags().GetBool(commonflags.AllFlag)
|
||||||
if removeAll {
|
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...")
|
cmd.Println("Waiting for transaction to persist...")
|
||||||
_, err = ac.Wait(h, vub, err)
|
_, err = ac.Wait(h, vub, err)
|
||||||
commonCmd.ExitOnErr(cmd, "remove rule chain error: %w", err)
|
commonCmd.ExitOnErr(cmd, "remove rule chain error: %w", err)
|
||||||
cmd.Println("All chains for target removed successfully")
|
cmd.Println("All chains for target removed successfully")
|
||||||
} else {
|
} else {
|
||||||
chainID := parseChainID(cmd)
|
chainID := apeCmd.ParseChainID(cmd)
|
||||||
h, vub, err := pci.RemoveMorphRuleChain(parseChainName(cmd), target, chainID)
|
h, vub, err := pci.RemoveMorphRuleChain(apeCmd.ParseChainName(cmd), target, chainID)
|
||||||
cmd.Println("Waiting for transaction to persist...")
|
cmd.Println("Waiting for transaction to persist...")
|
||||||
_, err = ac.Wait(h, vub, err)
|
_, err = ac.Wait(h, vub, err)
|
||||||
commonCmd.ExitOnErr(cmd, "remove rule chain error: %w", 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) {
|
func listRuleChains(cmd *cobra.Command, _ []string) {
|
||||||
target := parseTarget(cmd)
|
target := parseTarget(cmd)
|
||||||
pci, _ := newPolicyContractReaderInterface(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)
|
commonCmd.ExitOnErr(cmd, "list rule chains error: %w", err)
|
||||||
if len(chains) == 0 {
|
if len(chains) == 0 {
|
||||||
return
|
return
|
||||||
|
@ -235,8 +218,7 @@ func getAdmin(cmd *cobra.Command, _ []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func listTargets(cmd *cobra.Command, _ []string) {
|
func listTargets(cmd *cobra.Command, _ []string) {
|
||||||
typ, err := parseTargetType(cmd)
|
typ := apeCmd.ParseTargetType(cmd)
|
||||||
commonCmd.ExitOnErr(cmd, "parse target type error: %w", err)
|
|
||||||
pci, inv := newPolicyContractReaderInterface(cmd)
|
pci, inv := newPolicyContractReaderInterface(cmd)
|
||||||
|
|
||||||
sid, it, err := pci.ListTargetsIterator(typ)
|
sid, it, err := pci.ListTargetsIterator(typ)
|
||||||
|
|
|
@ -2,14 +2,12 @@ package ape
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"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/constants"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
|
||||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
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"
|
||||||
parseutil "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"
|
|
||||||
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
morph "git.frostfs.info/TrueCloudLab/policy-engine/pkg/morph/policy"
|
morph "git.frostfs.info/TrueCloudLab/policy-engine/pkg/morph/policy"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||||
|
@ -19,90 +17,29 @@ import (
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
var errUnknownTargetType = errors.New("unknown target type")
|
||||||
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")
|
|
||||||
)
|
|
||||||
|
|
||||||
func parseTarget(cmd *cobra.Command) policyengine.Target {
|
func parseTarget(cmd *cobra.Command) policyengine.Target {
|
||||||
name, _ := cmd.Flags().GetString(targetNameFlag)
|
typ := apeCmd.ParseTargetType(cmd)
|
||||||
typ, err := parseTargetType(cmd)
|
name, _ := cmd.Flags().GetString(apeCmd.TargetNameFlag)
|
||||||
|
switch typ {
|
||||||
// interpret "root" namespace as empty
|
case policyengine.Namespace:
|
||||||
if typ == policyengine.Namespace && name == "root" {
|
if name == "root" {
|
||||||
name = ""
|
name = ""
|
||||||
}
|
}
|
||||||
|
return policyengine.NamespaceTarget(name)
|
||||||
commonCmd.ExitOnErr(cmd, "read target type error: %w", err)
|
case policyengine.Container:
|
||||||
|
var cnr cid.ID
|
||||||
return policyengine.Target{
|
commonCmd.ExitOnErr(cmd, "can't decode container ID: %w", cnr.DecodeString(name))
|
||||||
Name: name,
|
return policyengine.ContainerTarget(name)
|
||||||
Type: typ,
|
case policyengine.User:
|
||||||
|
return policyengine.UserTarget(name)
|
||||||
|
case policyengine.Group:
|
||||||
|
return policyengine.GroupTarget(name)
|
||||||
|
default:
|
||||||
|
commonCmd.ExitOnErr(cmd, "read target type error: %w", errUnknownTargetType)
|
||||||
}
|
}
|
||||||
}
|
panic("unreachable")
|
||||||
|
|
||||||
func parseTargetType(cmd *cobra.Command) (policyengine.TargetType, error) {
|
|
||||||
typ, _ := cmd.Flags().GetString(targetTypeFlag)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// invokerAdapter adapats invoker.Invoker to ContractStorageInvoker interface.
|
// invokerAdapter adapats invoker.Invoker to ContractStorageInvoker interface.
|
||||||
|
|
|
@ -1,45 +1,19 @@
|
||||||
package apemanager
|
package apemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"fmt"
|
||||||
"errors"
|
|
||||||
|
|
||||||
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
|
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/commonflags"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
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"
|
||||||
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/ape"
|
|
||||||
apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||||
client_sdk "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
client_sdk "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
|
||||||
"github.com/spf13/cobra"
|
"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{
|
var addCmd = &cobra.Command{
|
||||||
Use: "add",
|
Use: "add",
|
||||||
Short: "Add rule chain for a target",
|
Short: "Add rule chain for a target",
|
||||||
|
@ -50,55 +24,28 @@ var addCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTarget(cmd *cobra.Command) (ct apeSDK.ChainTarget) {
|
func parseTarget(cmd *cobra.Command) (ct apeSDK.ChainTarget) {
|
||||||
typ, _ := cmd.Flags().GetString(targetTypeFlag)
|
t := apeCmd.ParseTarget(cmd)
|
||||||
name, _ := cmd.Flags().GetString(targetNameFlag)
|
|
||||||
|
|
||||||
ct.Name = name
|
ct.Name = t.Name
|
||||||
|
|
||||||
switch typ {
|
switch t.Type {
|
||||||
case namespaceTarget:
|
case engine.Namespace:
|
||||||
ct.TargetType = apeSDK.TargetTypeNamespace
|
ct.TargetType = apeSDK.TargetTypeNamespace
|
||||||
case containerTarget:
|
case engine.Container:
|
||||||
var cnr cid.ID
|
|
||||||
commonCmd.ExitOnErr(cmd, "can't decode container ID: %w", cnr.DecodeString(name))
|
|
||||||
ct.TargetType = apeSDK.TargetTypeContainer
|
ct.TargetType = apeSDK.TargetTypeContainer
|
||||||
case userTarget:
|
case engine.User:
|
||||||
ct.TargetType = apeSDK.TargetTypeUser
|
ct.TargetType = apeSDK.TargetTypeUser
|
||||||
case groupTarget:
|
case engine.Group:
|
||||||
ct.TargetType = apeSDK.TargetTypeGroup
|
ct.TargetType = apeSDK.TargetTypeGroup
|
||||||
default:
|
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
|
return ct
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseChain(cmd *cobra.Command) apeSDK.Chain {
|
func parseChain(cmd *cobra.Command) apeSDK.Chain {
|
||||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
c := apeCmd.ParseChain(cmd)
|
||||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
serialized := c.Bytes()
|
||||||
|
|
||||||
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()
|
|
||||||
return apeSDK.Chain{
|
return apeSDK.Chain{
|
||||||
Raw: serialized,
|
Raw: serialized,
|
||||||
}
|
}
|
||||||
|
@ -127,13 +74,13 @@ func initAddCmd() {
|
||||||
commonflags.Init(addCmd)
|
commonflags.Init(addCmd)
|
||||||
|
|
||||||
ff := addCmd.Flags()
|
ff := addCmd.Flags()
|
||||||
ff.StringArray(ruleFlag, []string{}, "Rule statement")
|
ff.StringArray(apeCmd.RuleFlag, []string{}, apeCmd.RuleFlagDesc)
|
||||||
ff.String(pathFlag, "", "Path to encoded chain in JSON or binary format")
|
ff.String(apeCmd.PathFlag, "", apeCmd.PathFlagDesc)
|
||||||
ff.String(chainIDFlag, "", "Assign ID to the parsed chain")
|
ff.String(apeCmd.ChainIDFlag, "", apeCmd.ChainIDFlagDesc)
|
||||||
ff.String(targetNameFlag, "", targetNameDesc)
|
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||||
_ = addCmd.MarkFlagRequired(targetTypeFlag)
|
_ = addCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
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)
|
commonflags.Init(listCmd)
|
||||||
|
|
||||||
ff := listCmd.Flags()
|
ff := listCmd.Flags()
|
||||||
ff.String(targetNameFlag, "", targetNameDesc)
|
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||||
_ = listCmd.MarkFlagRequired(targetTypeFlag)
|
_ = listCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,16 @@
|
||||||
package apemanager
|
package apemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
|
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/commonflags"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
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"
|
client_sdk "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var removeCmd = &cobra.Command{
|
||||||
errEmptyChainID = errors.New("chain id cannot be empty")
|
|
||||||
|
|
||||||
removeCmd = &cobra.Command{
|
|
||||||
Use: "remove",
|
Use: "remove",
|
||||||
Short: "Remove rule chain for a target",
|
Short: "Remove rule chain for a target",
|
||||||
Run: remove,
|
Run: remove,
|
||||||
|
@ -23,7 +18,6 @@ var (
|
||||||
commonflags.Bind(cmd)
|
commonflags.Bind(cmd)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
func remove(cmd *cobra.Command, _ []string) {
|
func remove(cmd *cobra.Command, _ []string) {
|
||||||
target := parseTarget(cmd)
|
target := parseTarget(cmd)
|
||||||
|
@ -31,19 +25,9 @@ func remove(cmd *cobra.Command, _ []string) {
|
||||||
key := key.Get(cmd)
|
key := key.Get(cmd)
|
||||||
cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC)
|
cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC)
|
||||||
|
|
||||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
chainID := apeCmd.ParseChainID(cmd)
|
||||||
if chainID == "" {
|
|
||||||
commonCmd.ExitOnErr(cmd, "read chain id error: %w", errEmptyChainID)
|
|
||||||
}
|
|
||||||
chainIDRaw := []byte(chainID)
|
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{
|
_, err := cli.APEManagerRemoveChain(cmd.Context(), client_sdk.PrmAPEManagerRemoveChain{
|
||||||
ChainTarget: target,
|
ChainTarget: target,
|
||||||
ChainID: chainIDRaw,
|
ChainID: chainIDRaw,
|
||||||
|
@ -58,9 +42,10 @@ func initRemoveCmd() {
|
||||||
commonflags.Init(removeCmd)
|
commonflags.Init(removeCmd)
|
||||||
|
|
||||||
ff := removeCmd.Flags()
|
ff := removeCmd.Flags()
|
||||||
ff.String(targetNameFlag, "", targetNameDesc)
|
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||||
_ = removeCmd.MarkFlagRequired(targetTypeFlag)
|
_ = removeCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||||
ff.String(chainIDFlag, "", "Chain id")
|
ff.String(apeCmd.ChainIDFlag, "", apeCmd.ChainIDFlagDesc)
|
||||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
_ = removeCmd.MarkFlagRequired(apeCmd.ChainIDFlag)
|
||||||
|
ff.Bool(apeCmd.ChainIDHexFlag, false, apeCmd.ChainIDHexFlagDesc)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,19 @@
|
||||||
package bearer
|
package bearer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
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"
|
||||||
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/ape"
|
|
||||||
apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
errChainIDCannotBeEmpty = errors.New("chain id cannot be empty")
|
|
||||||
errRuleIsNotParsed = errors.New("rule is not passed")
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
chainIDFlag = "chain-id"
|
|
||||||
chainIDHexFlag = "chain-id-hex"
|
|
||||||
ruleFlag = "rule"
|
|
||||||
pathFlag = "path"
|
|
||||||
outputFlag = "output"
|
outputFlag = "output"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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) {
|
func genereateAPEOverride(cmd *cobra.Command, _ []string) {
|
||||||
c := parseChain(cmd)
|
c := apeCmd.ParseChain(cmd)
|
||||||
|
|
||||||
targetCID, _ := cmd.Flags().GetString(commonflags.CIDFlag)
|
targetCID, _ := cmd.Flags().GetString(commonflags.CIDFlag)
|
||||||
var cid cidSDK.ID
|
var cid cidSDK.ID
|
||||||
|
@ -78,39 +66,11 @@ func init() {
|
||||||
ff.StringP(commonflags.CIDFlag, "", "", "Target container ID.")
|
ff.StringP(commonflags.CIDFlag, "", "", "Target container ID.")
|
||||||
_ = cobra.MarkFlagRequired(createCmd.Flags(), commonflags.CIDFlag)
|
_ = cobra.MarkFlagRequired(createCmd.Flags(), commonflags.CIDFlag)
|
||||||
|
|
||||||
ff.StringArray(ruleFlag, []string{}, "Rule statement")
|
ff.StringArray(apeCmd.RuleFlag, []string{}, "Rule statement")
|
||||||
ff.String(pathFlag, "", "Path to encoded chain in JSON or binary format")
|
ff.String(apeCmd.PathFlag, "", "Path to encoded chain in JSON or binary format")
|
||||||
ff.String(chainIDFlag, "", "Assign ID to the parsed chain")
|
ff.String(apeCmd.ChainIDFlag, "", "Assign ID to the parsed chain")
|
||||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
ff.Bool(apeCmd.ChainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||||
|
|
||||||
ff.String(outputFlag, "", "Output path to dump result JSON-encoded APE override")
|
ff.String(outputFlag, "", "Output path to dump result JSON-encoded APE override")
|
||||||
_ = cobra.MarkFlagFilename(createCmd.Flags(), outputFlag)
|
_ = 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
|
package control
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
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-node/pkg/services/control"
|
||||||
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/ape"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
ruleFlag = "rule"
|
|
||||||
pathFlag = "path"
|
|
||||||
)
|
|
||||||
|
|
||||||
var addRuleCmd = &cobra.Command{
|
var addRuleCmd = &cobra.Command{
|
||||||
Use: "add-rule",
|
Use: "add-rule",
|
||||||
Short: "Add local override",
|
Short: "Add local override",
|
||||||
|
@ -32,41 +22,12 @@ control add-rule --endpoint ... -w ... --address ... --chain-id ChainID --cid ..
|
||||||
Run: addRule,
|
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) {
|
func addRule(cmd *cobra.Command, _ []string) {
|
||||||
pk := key.Get(cmd)
|
pk := key.Get(cmd)
|
||||||
|
|
||||||
target := parseTarget(cmd)
|
target := parseTarget(cmd)
|
||||||
|
|
||||||
parsed := parseChain(cmd)
|
parsed := apeCmd.ParseChain(cmd)
|
||||||
|
|
||||||
req := &control.AddChainLocalOverrideRequest{
|
req := &control.AddChainLocalOverrideRequest{
|
||||||
Body: &control.AddChainLocalOverrideRequest_Body{
|
Body: &control.AddChainLocalOverrideRequest_Body{
|
||||||
|
@ -95,13 +56,13 @@ func initControlAddRuleCmd() {
|
||||||
initControlFlags(addRuleCmd)
|
initControlFlags(addRuleCmd)
|
||||||
|
|
||||||
ff := addRuleCmd.Flags()
|
ff := addRuleCmd.Flags()
|
||||||
ff.StringArray(ruleFlag, []string{}, "Rule statement")
|
ff.StringArray(apeCmd.RuleFlag, []string{}, "Rule statement")
|
||||||
ff.String(pathFlag, "", "Path to encoded chain in JSON or binary format")
|
ff.String(apeCmd.PathFlag, "", "Path to encoded chain in JSON or binary format")
|
||||||
ff.String(chainIDFlag, "", "Assign ID to the parsed chain")
|
ff.String(apeCmd.ChainIDFlag, "", "Assign ID to the parsed chain")
|
||||||
ff.String(targetNameFlag, "", targetNameDesc)
|
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||||
_ = addRuleCmd.MarkFlagRequired(targetTypeFlag)
|
_ = addRuleCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
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"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
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-node/pkg/services/control"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
@ -24,8 +24,8 @@ func getRule(cmd *cobra.Command, _ []string) {
|
||||||
|
|
||||||
target := parseTarget(cmd)
|
target := parseTarget(cmd)
|
||||||
|
|
||||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
chainID, _ := cmd.Flags().GetString(apecmd.ChainIDFlag)
|
||||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
hexEncoded, _ := cmd.Flags().GetBool(apecmd.ChainIDHexFlag)
|
||||||
|
|
||||||
if hexEncoded {
|
if hexEncoded {
|
||||||
chainIDBytes, err := hex.DecodeString(chainID)
|
chainIDBytes, err := hex.DecodeString(chainID)
|
||||||
|
@ -56,16 +56,16 @@ func getRule(cmd *cobra.Command, _ []string) {
|
||||||
|
|
||||||
var chain apechain.Chain
|
var chain apechain.Chain
|
||||||
commonCmd.ExitOnErr(cmd, "decode error: %w", chain.DecodeBytes(resp.GetBody().GetChain()))
|
commonCmd.ExitOnErr(cmd, "decode error: %w", chain.DecodeBytes(resp.GetBody().GetChain()))
|
||||||
apeCmd.PrintHumanReadableAPEChain(cmd, &chain)
|
apecmd.PrintHumanReadableAPEChain(cmd, &chain)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initControGetRuleCmd() {
|
func initControGetRuleCmd() {
|
||||||
initControlFlags(getRuleCmd)
|
initControlFlags(getRuleCmd)
|
||||||
|
|
||||||
ff := getRuleCmd.Flags()
|
ff := getRuleCmd.Flags()
|
||||||
ff.String(targetNameFlag, "", targetNameDesc)
|
ff.String(apecmd.TargetNameFlag, "", apecmd.TargetNameFlagDesc)
|
||||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
ff.String(apecmd.TargetTypeFlag, "", apecmd.TargetTypeFlagDesc)
|
||||||
_ = getRuleCmd.MarkFlagRequired(targetTypeFlag)
|
_ = getRuleCmd.MarkFlagRequired(apecmd.TargetTypeFlag)
|
||||||
ff.String(chainIDFlag, "", "Chain id")
|
ff.String(apecmd.ChainIDFlag, "", "Chain id")
|
||||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
ff.Bool(apecmd.ChainIDHexFlag, false, "Flag to parse chain ID as hex")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package control
|
package control
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -10,9 +9,8 @@ import (
|
||||||
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-node/pkg/services/control"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
"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"
|
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"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,65 +21,25 @@ var listRulesCmd = &cobra.Command{
|
||||||
Run: listRules,
|
Run: listRules,
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
var engineToControlSvcType = map[policyengine.TargetType]control.ChainTarget_TargetType{
|
||||||
defaultNamespace = "root"
|
policyengine.Namespace: control.ChainTarget_NAMESPACE,
|
||||||
namespaceTarget = "namespace"
|
policyengine.Container: control.ChainTarget_CONTAINER,
|
||||||
containerTarget = "container"
|
policyengine.User: control.ChainTarget_USER,
|
||||||
userTarget = "user"
|
policyengine.Group: control.ChainTarget_GROUP,
|
||||||
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")
|
|
||||||
)
|
|
||||||
|
|
||||||
func parseTarget(cmd *cobra.Command) *control.ChainTarget {
|
func parseTarget(cmd *cobra.Command) *control.ChainTarget {
|
||||||
typ, _ := cmd.Flags().GetString(targetTypeFlag)
|
target := apeCmd.ParseTarget(cmd)
|
||||||
name, _ := cmd.Flags().GetString(targetNameFlag)
|
|
||||||
switch typ {
|
typ, ok := engineToControlSvcType[target.Type]
|
||||||
case namespaceTarget:
|
if !ok {
|
||||||
if name == "" {
|
commonCmd.ExitOnErr(cmd, "%w", fmt.Errorf("unknown type '%c", target.Type))
|
||||||
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{
|
return &control.ChainTarget{
|
||||||
Name: name,
|
Name: target.Name,
|
||||||
Type: control.ChainTarget_NAMESPACE,
|
Type: typ,
|
||||||
}
|
}
|
||||||
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)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func listRules(cmd *cobra.Command, _ []string) {
|
func listRules(cmd *cobra.Command, _ []string) {
|
||||||
|
@ -125,7 +83,7 @@ func initControlListRulesCmd() {
|
||||||
initControlFlags(listRulesCmd)
|
initControlFlags(listRulesCmd)
|
||||||
|
|
||||||
ff := listRulesCmd.Flags()
|
ff := listRulesCmd.Flags()
|
||||||
ff.String(targetNameFlag, "", targetNameDesc)
|
ff.String(apeCmd.TargetNameFlag, "", apeCmd.TargetNameFlagDesc)
|
||||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
ff.String(apeCmd.TargetTypeFlag, "", apeCmd.TargetTypeFlagDesc)
|
||||||
_ = listRulesCmd.MarkFlagRequired(targetTypeFlag)
|
_ = listRulesCmd.MarkFlagRequired(apeCmd.TargetTypeFlag)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,26 +2,20 @@ package control
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha256"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
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-node/pkg/services/control"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
chainNameFlag = "chain-name"
|
|
||||||
chainNameFlagUsage = "Chain name(ingress|s3)"
|
|
||||||
)
|
|
||||||
|
|
||||||
var listTargetsCmd = &cobra.Command{
|
var listTargetsCmd = &cobra.Command{
|
||||||
Use: "list-targets",
|
Use: "list-targets",
|
||||||
Short: "List local targets",
|
Short: "List local targets",
|
||||||
|
@ -32,15 +26,11 @@ var listTargetsCmd = &cobra.Command{
|
||||||
func listTargets(cmd *cobra.Command, _ []string) {
|
func listTargets(cmd *cobra.Command, _ []string) {
|
||||||
pk := key.Get(cmd)
|
pk := key.Get(cmd)
|
||||||
|
|
||||||
var cnr cid.ID
|
chainName := apeCmd.ParseChainName(cmd)
|
||||||
chainName, _ := cmd.Flags().GetString(chainNameFlag)
|
|
||||||
|
|
||||||
rawCID := make([]byte, sha256.Size)
|
|
||||||
cnr.Encode(rawCID)
|
|
||||||
|
|
||||||
req := &control.ListTargetsLocalOverridesRequest{
|
req := &control.ListTargetsLocalOverridesRequest{
|
||||||
Body: &control.ListTargetsLocalOverridesRequest_Body{
|
Body: &control.ListTargetsLocalOverridesRequest_Body{
|
||||||
ChainName: chainName,
|
ChainName: string(chainName),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +72,7 @@ func initControlListTargetsCmd() {
|
||||||
initControlFlags(listTargetsCmd)
|
initControlFlags(listTargetsCmd)
|
||||||
|
|
||||||
ff := listTargetsCmd.Flags()
|
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"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||||
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
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-node/pkg/services/control"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
chainIDFlag = "chain-id"
|
|
||||||
chainIDHexFlag = "chain-id-hex"
|
|
||||||
allFlag = "all"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errEmptyChainID = errors.New("chain id cannot be empty")
|
errEmptyChainID = errors.New("chain id cannot be empty")
|
||||||
|
|
||||||
|
@ -30,8 +25,8 @@ var (
|
||||||
|
|
||||||
func removeRule(cmd *cobra.Command, _ []string) {
|
func removeRule(cmd *cobra.Command, _ []string) {
|
||||||
pk := key.Get(cmd)
|
pk := key.Get(cmd)
|
||||||
hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag)
|
hexEncoded, _ := cmd.Flags().GetBool(apecmd.ChainIDHexFlag)
|
||||||
removeAll, _ := cmd.Flags().GetBool(allFlag)
|
removeAll, _ := cmd.Flags().GetBool(apecmd.AllFlag)
|
||||||
if removeAll {
|
if removeAll {
|
||||||
req := &control.RemoveChainLocalOverridesByTargetRequest{
|
req := &control.RemoveChainLocalOverridesByTargetRequest{
|
||||||
Body: &control.RemoveChainLocalOverridesByTargetRequest_Body{
|
Body: &control.RemoveChainLocalOverridesByTargetRequest_Body{
|
||||||
|
@ -52,7 +47,7 @@ func removeRule(cmd *cobra.Command, _ []string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
chainID, _ := cmd.Flags().GetString(chainIDFlag)
|
chainID, _ := cmd.Flags().GetString(apecmd.ChainIDFlag)
|
||||||
if chainID == "" {
|
if chainID == "" {
|
||||||
commonCmd.ExitOnErr(cmd, "read chain id error: %w", errEmptyChainID)
|
commonCmd.ExitOnErr(cmd, "read chain id error: %w", errEmptyChainID)
|
||||||
}
|
}
|
||||||
|
@ -92,11 +87,11 @@ func initControlRemoveRuleCmd() {
|
||||||
initControlFlags(removeRuleCmd)
|
initControlFlags(removeRuleCmd)
|
||||||
|
|
||||||
ff := removeRuleCmd.Flags()
|
ff := removeRuleCmd.Flags()
|
||||||
ff.String(targetNameFlag, "", targetNameDesc)
|
ff.String(apecmd.TargetNameFlag, "", apecmd.TargetNameFlagDesc)
|
||||||
ff.String(targetTypeFlag, "", targetTypeDesc)
|
ff.String(apecmd.TargetTypeFlag, "", apecmd.TargetTypeFlagDesc)
|
||||||
_ = removeRuleCmd.MarkFlagRequired(targetTypeFlag)
|
_ = removeRuleCmd.MarkFlagRequired(apecmd.TargetTypeFlag)
|
||||||
ff.String(chainIDFlag, "", "Chain id")
|
ff.String(apecmd.ChainIDFlag, "", apecmd.ChainIDFlagDesc)
|
||||||
ff.Bool(chainIDHexFlag, false, "Flag to parse chain ID as hex")
|
ff.Bool(apecmd.ChainIDHexFlag, false, apecmd.ChainIDHexFlagDesc)
|
||||||
ff.Bool(allFlag, false, "Remove all chains")
|
ff.Bool(apecmd.AllFlag, false, "Remove all chains")
|
||||||
removeRuleCmd.MarkFlagsMutuallyExclusive(allFlag, chainIDFlag)
|
removeRuleCmd.MarkFlagsMutuallyExclusive(apecmd.AllFlag, apecmd.ChainIDFlag)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,43 @@
|
||||||
package ape
|
package ape
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"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"
|
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"
|
"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.
|
// PrintHumanReadableAPEChain print APE chain rules.
|
||||||
func PrintHumanReadableAPEChain(cmd *cobra.Command, chain *apechain.Chain) {
|
func PrintHumanReadableAPEChain(cmd *cobra.Command, chain *apechain.Chain) {
|
||||||
cmd.Println("Chain ID: " + string(chain.ID))
|
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
|
// It can tick the blocks and perform certain actions
|
||||||
// on block time intervals.
|
// on block time intervals.
|
||||||
type BlockTimer struct {
|
type BlockTimer struct {
|
||||||
rolledBack bool
|
|
||||||
|
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
|
|
||||||
dur BlockMeter
|
dur BlockMeter
|
||||||
|
|
||||||
baseDur uint32
|
baseDur uint32
|
||||||
|
|
||||||
mul, div uint32
|
|
||||||
|
|
||||||
cur, tgt uint32
|
cur, tgt uint32
|
||||||
|
|
||||||
last uint32
|
last uint32
|
||||||
|
|
||||||
h BlockTickHandler
|
h BlockTickHandler
|
||||||
|
|
||||||
ps []BlockTimer
|
|
||||||
|
|
||||||
once bool
|
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).
|
// StaticBlockMeter returns BlockMeters that always returns (d, nil).
|
||||||
|
@ -65,52 +43,19 @@ func StaticBlockMeter(d uint32) BlockMeter {
|
||||||
func NewBlockTimer(dur BlockMeter, h BlockTickHandler) *BlockTimer {
|
func NewBlockTimer(dur BlockMeter, h BlockTickHandler) *BlockTimer {
|
||||||
return &BlockTimer{
|
return &BlockTimer{
|
||||||
dur: dur,
|
dur: dur,
|
||||||
mul: 1,
|
|
||||||
div: 1,
|
|
||||||
h: h,
|
h: h,
|
||||||
deltaCfg: deltaCfg{
|
|
||||||
pulse: true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOneTickTimer creates a new BlockTimer that ticks only once.
|
// 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 {
|
func NewOneTickTimer(dur BlockMeter, h BlockTickHandler) *BlockTimer {
|
||||||
return &BlockTimer{
|
return &BlockTimer{
|
||||||
dur: dur,
|
dur: dur,
|
||||||
mul: 1,
|
|
||||||
div: 1,
|
|
||||||
h: h,
|
h: h,
|
||||||
once: true,
|
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.
|
// Reset resets previous ticks of the BlockTimer.
|
||||||
//
|
//
|
||||||
// Returns BlockMeter's error upon occurrence.
|
// Returns BlockMeter's error upon occurrence.
|
||||||
|
@ -124,29 +69,18 @@ func (t *BlockTimer) Reset() error {
|
||||||
|
|
||||||
t.resetWithBaseInterval(d)
|
t.resetWithBaseInterval(d)
|
||||||
|
|
||||||
for i := range t.ps {
|
|
||||||
t.ps[i].resetWithBaseInterval(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.mtx.Unlock()
|
t.mtx.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *BlockTimer) resetWithBaseInterval(d uint32) {
|
func (t *BlockTimer) resetWithBaseInterval(d uint32) {
|
||||||
t.rolledBack = false
|
|
||||||
t.baseDur = d
|
t.baseDur = d
|
||||||
t.reset()
|
t.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *BlockTimer) reset() {
|
func (t *BlockTimer) reset() {
|
||||||
mul, div := t.mul, t.div
|
delta := t.baseDur
|
||||||
|
|
||||||
if !t.pulse && t.rolledBack && mul < div {
|
|
||||||
mul, div = 1, 1
|
|
||||||
}
|
|
||||||
|
|
||||||
delta := mul * t.baseDur / div
|
|
||||||
if delta == 0 {
|
if delta == 0 {
|
||||||
delta = 1
|
delta = 1
|
||||||
}
|
}
|
||||||
|
@ -180,12 +114,7 @@ func (t *BlockTimer) tick(h uint32) {
|
||||||
|
|
||||||
if !t.once {
|
if !t.once {
|
||||||
t.cur = 0
|
t.cur = 0
|
||||||
t.rolledBack = true
|
|
||||||
t.reset()
|
t.reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range t.ps {
|
|
||||||
t.ps[i].tick(h)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package timer_test
|
package timer_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/timer"
|
"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`.
|
// "resetting" consists of ticking the current height as well and invoking `Reset`.
|
||||||
func TestIRBlockTimer_Reset(t *testing.T) {
|
func TestIRBlockTimer_Reset(t *testing.T) {
|
||||||
var baseCounter [2]int
|
var baseCounter [2]int
|
||||||
blockDur := uint32(3)
|
const blockDur = uint32(3)
|
||||||
|
|
||||||
bt1 := timer.NewBlockTimer(
|
bt1 := timer.NewBlockTimer(
|
||||||
func() (uint32, error) { return blockDur, nil },
|
func() (uint32, error) { return blockDur, nil },
|
||||||
|
@ -48,8 +49,40 @@ func TestIRBlockTimer_Reset(t *testing.T) {
|
||||||
require.Equal(t, baseCounter[0], baseCounter[1])
|
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) {
|
func TestBlockTimer(t *testing.T) {
|
||||||
blockDur := uint32(10)
|
const blockDur = uint32(10)
|
||||||
baseCallCounter := uint32(0)
|
baseCallCounter := uint32(0)
|
||||||
|
|
||||||
bt := timer.NewBlockTimer(timer.StaticBlockMeter(blockDur), func() {
|
bt := timer.NewBlockTimer(timer.StaticBlockMeter(blockDur), func() {
|
||||||
|
@ -63,85 +96,6 @@ func TestBlockTimer(t *testing.T) {
|
||||||
tickN(bt, intervalNum*blockDur)
|
tickN(bt, intervalNum*blockDur)
|
||||||
|
|
||||||
require.Equal(t, intervalNum, uint32(baseCallCounter))
|
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) {
|
func TestNewOneTickTimer(t *testing.T) {
|
||||||
|
@ -168,82 +122,51 @@ func TestNewOneTickTimer(t *testing.T) {
|
||||||
tickN(bt, 10)
|
tickN(bt, 10)
|
||||||
require.Equal(t, 1, baseCallCounter)
|
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) {
|
func TestBlockTimer_TickSameHeight(t *testing.T) {
|
||||||
var baseCounter, deltaCounter int
|
var baseCounter int
|
||||||
|
|
||||||
blockDur := uint32(2)
|
blockDur := uint32(2)
|
||||||
bt := timer.NewBlockTimer(
|
bt := timer.NewBlockTimer(
|
||||||
func() (uint32, error) { return blockDur, nil },
|
func() (uint32, error) { return blockDur, nil },
|
||||||
func() { baseCounter++ })
|
func() { baseCounter++ })
|
||||||
bt.OnDelta(2, 1, func() {
|
|
||||||
deltaCounter++
|
|
||||||
})
|
|
||||||
require.NoError(t, bt.Reset())
|
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) {
|
for range 2 * int(blockDur) {
|
||||||
bt.Tick(h)
|
bt.Tick(h)
|
||||||
require.Equal(t, base, baseCounter)
|
require.Equal(t, base, baseCounter)
|
||||||
require.Equal(t, delta, deltaCounter)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check(t, 1, 0, 0)
|
check(t, 1, 0)
|
||||||
check(t, 2, 1, 0)
|
check(t, 2, 1)
|
||||||
check(t, 3, 1, 0)
|
check(t, 3, 1)
|
||||||
check(t, 4, 2, 1)
|
check(t, 4, 2)
|
||||||
|
|
||||||
t.Run("works the same way after `Reset()`", func(t *testing.T) {
|
t.Run("works the same way after `Reset()`", func(t *testing.T) {
|
||||||
t.Run("same block duration", func(t *testing.T) {
|
t.Run("same block duration", func(t *testing.T) {
|
||||||
require.NoError(t, bt.Reset())
|
require.NoError(t, bt.Reset())
|
||||||
baseCounter = 0
|
baseCounter = 0
|
||||||
deltaCounter = 0
|
|
||||||
|
|
||||||
check(t, 1, 0, 0)
|
check(t, 1, 0)
|
||||||
check(t, 2, 1, 0)
|
check(t, 2, 1)
|
||||||
check(t, 3, 1, 0)
|
check(t, 3, 1)
|
||||||
check(t, 4, 2, 1)
|
check(t, 4, 2)
|
||||||
})
|
})
|
||||||
t.Run("different block duration", func(t *testing.T) {
|
t.Run("different block duration", func(t *testing.T) {
|
||||||
blockDur = 3
|
blockDur = 3
|
||||||
|
|
||||||
require.NoError(t, bt.Reset())
|
require.NoError(t, bt.Reset())
|
||||||
baseCounter = 0
|
baseCounter = 0
|
||||||
deltaCounter = 0
|
|
||||||
|
|
||||||
check(t, 1, 0, 0)
|
check(t, 1, 0)
|
||||||
check(t, 2, 0, 0)
|
check(t, 2, 0)
|
||||||
check(t, 3, 1, 0)
|
check(t, 3, 1)
|
||||||
check(t, 4, 1, 0)
|
check(t, 4, 1)
|
||||||
check(t, 5, 1, 0)
|
check(t, 5, 1)
|
||||||
check(t, 6, 2, 1)
|
check(t, 6, 2)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,14 +111,18 @@ func NewTraverser(opts ...Option) (*Traverser, error) {
|
||||||
var rem []int
|
var rem []int
|
||||||
if len(cfg.metrics) > 0 && cfg.nodeState != nil {
|
if len(cfg.metrics) > 0 && cfg.nodeState != nil {
|
||||||
rem = defaultCopiesVector(cfg.policy)
|
rem = defaultCopiesVector(cfg.policy)
|
||||||
var unsortedVector []netmap.NodeInfo
|
var unsortedVector, regularVector []netmap.NodeInfo
|
||||||
var regularVector []netmap.NodeInfo
|
|
||||||
for i := range rem {
|
for i := range rem {
|
||||||
|
if len(ns[i]) < rem[i] {
|
||||||
|
unsortedVector = append(unsortedVector, ns[i]...)
|
||||||
|
} else {
|
||||||
unsortedVector = append(unsortedVector, ns[i][:rem[i]]...)
|
unsortedVector = append(unsortedVector, ns[i][:rem[i]]...)
|
||||||
|
if len(ns[i]) > rem[i] {
|
||||||
regularVector = append(regularVector, ns[i][rem[i]:]...)
|
regularVector = append(regularVector, ns[i][rem[i]:]...)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
rem = []int{-1, -1}
|
rem = []int{-1, -1}
|
||||||
|
|
||||||
sortedVector, err := sortVector(cfg, unsortedVector)
|
sortedVector, err := sortVector(cfg, unsortedVector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -356,6 +356,52 @@ func TestTraverserPriorityMetrics(t *testing.T) {
|
||||||
require.Nil(t, next)
|
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) {
|
t.Run("two reps two metrics", func(t *testing.T) {
|
||||||
selectors := []int{3, 3}
|
selectors := []int{3, 3}
|
||||||
replicas := []int{2, 2}
|
replicas := []int{2, 2}
|
||||||
|
|
Loading…
Reference in a new issue