[#1501] cli: Refactor APE-related commands
All checks were successful
Tests and linters / Run gofumpt (pull_request) Successful in 1m32s
DCO action / DCO (pull_request) Successful in 1m46s
Vulncheck / Vulncheck (pull_request) Successful in 2m16s
Pre-commit hooks / Pre-commit (pull_request) Successful in 2m30s
Build / Build Components (pull_request) Successful in 2m47s
Tests and linters / gopls check (pull_request) Successful in 2m56s
Tests and linters / Staticcheck (pull_request) Successful in 3m4s
Tests and linters / Lint (pull_request) Successful in 3m52s
Tests and linters / Tests (pull_request) Successful in 4m40s
Tests and linters / Tests with -race (pull_request) Successful in 6m3s

* Move common rule parsing logic to a common package that
  also can be imported out of `frostfs-node`;
* Move common flags and commands to `cmd/internal/common/ape` package to
  avoid duplication. Since `frostfs-adm` and `frostfs-cli` subcommands
  are able to use commands, thee same flag names and their descriptions.

Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
Airat Arifullin 2024-11-15 15:05:37 +03:00
parent 46fef276b4
commit fdbeaeba7b
20 changed files with 434 additions and 560 deletions

View file

@ -5,8 +5,8 @@ import (
"encoding/json"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
apecmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/spf13/cobra"
@ -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)
target := parseTarget(cmd)
chain := apecmd.ParseChain(cmd)
target := apecmd.ParseTarget(cmd, false)
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)
@ -177,18 +160,18 @@ func addRuleChain(cmd *cobra.Command, _ []string) {
}
func removeRuleChain(cmd *cobra.Command, _ []string) {
target := parseTarget(cmd)
target := apecmd.ParseTarget(cmd, false)
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)
@ -197,9 +180,9 @@ func removeRuleChain(cmd *cobra.Command, _ []string) {
}
func listRuleChains(cmd *cobra.Command, _ []string) {
target := parseTarget(cmd)
target := apecmd.ParseTarget(cmd, false)
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
@ -210,7 +193,7 @@ func listRuleChains(cmd *cobra.Command, _ []string) {
prettyJSONFormat(cmd, chains)
} else {
for _, c := range chains {
parseutil.PrintHumanReadableAPEChain(cmd, c)
apecmd.PrintHumanReadableAPEChain(cmd, c)
}
}
}
@ -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)

View file

@ -1,154 +0,0 @@
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"
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
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"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/spf13/cobra"
"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")
)
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)
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:")
parseutil.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.
type invokerAdapter struct {
*invoker.Invoker
rpcActor invoker.RPCInvoke
}
func (n *invokerAdapter) GetRPCInvoker() invoker.RPCInvoke {
return n.rpcActor
}
func newPolicyContractReaderInterface(cmd *cobra.Command) (*morph.ContractStorageReader, *invoker.Invoker) {
c, err := helper.GetN3Client(viper.GetViper())
commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
inv := invoker.New(c, nil)
var ch util.Uint160
r := management.NewReader(inv)
nnsCs, err := helper.GetContractByID(r, 1)
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
ch, err = helper.NNSResolveHash(inv, nnsCs.Hash, helper.DomainOf(constants.PolicyContract))
commonCmd.ExitOnErr(cmd, "unable to resolve policy contract hash: %w", err)
invokerAdapter := &invokerAdapter{
Invoker: inv,
rpcActor: c,
}
return morph.NewContractStorageReader(invokerAdapter, ch), inv
}
func newPolicyContractInterface(cmd *cobra.Command) (*morph.ContractStorage, *helper.LocalActor) {
c, err := helper.GetN3Client(viper.GetViper())
commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
ac, err := helper.NewLocalActor(cmd, c, constants.ConsensusAccountName)
commonCmd.ExitOnErr(cmd, "can't create actor: %w", err)
var ch util.Uint160
r := management.NewReader(ac.Invoker)
nnsCs, err := helper.GetContractByID(r, 1)
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
ch, err = helper.NNSResolveHash(ac.Invoker, nnsCs.Hash, helper.DomainOf(constants.PolicyContract))
commonCmd.ExitOnErr(cmd, "unable to resolve policy contract hash: %w", err)
return morph.NewContractStorage(ac, ch), ac
}

View file

@ -0,0 +1,62 @@
package ape
import (
"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"
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/management"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// invokerAdapter adapats invoker.Invoker to ContractStorageInvoker interface.
type invokerAdapter struct {
*invoker.Invoker
rpcActor invoker.RPCInvoke
}
func (n *invokerAdapter) GetRPCInvoker() invoker.RPCInvoke {
return n.rpcActor
}
func newPolicyContractReaderInterface(cmd *cobra.Command) (*morph.ContractStorageReader, *invoker.Invoker) {
c, err := helper.GetN3Client(viper.GetViper())
commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
inv := invoker.New(c, nil)
var ch util.Uint160
r := management.NewReader(inv)
nnsCs, err := helper.GetContractByID(r, 1)
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
ch, err = helper.NNSResolveHash(inv, nnsCs.Hash, helper.DomainOf(constants.PolicyContract))
commonCmd.ExitOnErr(cmd, "unable to resolve policy contract hash: %w", err)
invokerAdapter := &invokerAdapter{
Invoker: inv,
rpcActor: c,
}
return morph.NewContractStorageReader(invokerAdapter, ch), inv
}
func newPolicyContractInterface(cmd *cobra.Command) (*morph.ContractStorage, *helper.LocalActor) {
c, err := helper.GetN3Client(viper.GetViper())
commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
ac, err := helper.NewLocalActor(cmd, c, constants.ConsensusAccountName)
commonCmd.ExitOnErr(cmd, "can't create actor: %w", err)
var ch util.Uint160
r := management.NewReader(ac.Invoker)
nnsCs, err := helper.GetContractByID(r, 1)
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
ch, err = helper.NNSResolveHash(ac.Invoker, nnsCs.Hash, helper.DomainOf(constants.PolicyContract))
commonCmd.ExitOnErr(cmd, "unable to resolve policy contract hash: %w", err)
return morph.NewContractStorage(ac, ch), ac
}

View file

@ -0,0 +1,20 @@
package commonflags
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"
AllFlagDesc = "Remove all chains"
)

View file

@ -1,44 +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"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
apecmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/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",
@ -49,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, false)
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", util.ParseAPEChain(chain, rules))
} else if encPath, _ := cmd.Flags().GetString(pathFlag); encPath != "" {
commonCmd.ExitOnErr(cmd, "decode binary or json error: %w", util.ParseAPEChainBinaryOrJSON(chain, encPath))
} else {
commonCmd.ExitOnErr(cmd, "parser error: %w", errors.New("rule is not passed"))
}
cmd.Println("Parsed chain:")
util.PrintHumanReadableAPEChain(cmd, chain)
serialized := chain.Bytes()
c := apecmd.ParseChain(cmd)
serialized := c.Bytes()
return apeSDK.Chain{
Raw: serialized,
}
@ -126,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)
}

View file

@ -4,8 +4,8 @@ import (
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"
apeutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
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"
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
"github.com/spf13/cobra"
@ -35,7 +35,7 @@ func list(cmd *cobra.Command, _ []string) {
for _, respChain := range resp.Chains {
var chain apechain.Chain
commonCmd.ExitOnErr(cmd, "decode error: %w", chain.DecodeBytes(respChain.Raw))
apeutil.PrintHumanReadableAPEChain(cmd, &chain)
apecmd.PrintHumanReadableAPEChain(cmd, &chain)
}
}
@ -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)
}

View file

@ -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,9 @@ 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)
ff.Bool(apecmd.ChainIDHexFlag, false, apecmd.ChainIDHexFlagDesc)
}

View file

@ -1,31 +1,20 @@
package bearer
import (
"errors"
"fmt"
"os"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
apecmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/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{
@ -40,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
@ -77,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:")
parseutil.PrintHumanReadableAPEChain(cmd, chain)
return chain
}

View file

@ -1,23 +1,14 @@
package control
import (
"encoding/hex"
"errors"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
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"
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",
@ -31,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", util.ParseAPEChain(chain, rules))
} else if encPath, _ := cmd.Flags().GetString(pathFlag); encPath != "" {
commonCmd.ExitOnErr(cmd, "decode binary or json error: %w", util.ParseAPEChainBinaryOrJSON(chain, encPath))
} else {
commonCmd.ExitOnErr(cmd, "parser error", errors.New("rule is not passed"))
}
cmd.Println("Parsed chain:")
util.PrintHumanReadableAPEChain(cmd, chain)
return chain
}
func addRule(cmd *cobra.Command, _ []string) {
pk := key.Get(cmd)
target := parseTarget(cmd)
target := parseLocalOverrideTarget(cmd)
parsed := parseChain(cmd)
parsed := apecmd.ParseChain(cmd)
req := &control.AddChainLocalOverrideRequest{
Body: &control.AddChainLocalOverrideRequest_Body{
@ -94,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)
}

View file

@ -4,8 +4,8 @@ import (
"encoding/hex"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
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"
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
@ -22,10 +22,10 @@ var getRuleCmd = &cobra.Command{
func getRule(cmd *cobra.Command, _ []string) {
pk := key.Get(cmd)
target := parseTarget(cmd)
target := parseLocalOverrideTarget(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()))
util.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")
}

View file

@ -1,18 +1,16 @@
package control
import (
"errors"
"fmt"
"strings"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
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"
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,71 +21,31 @@ var listRulesCmd = &cobra.Command{
Run: listRules,
}
const (
defaultNamespace = "root"
namespaceTarget = "namespace"
containerTarget = "container"
userTarget = "user"
groupTarget = "group"
)
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,
}
const (
targetNameFlag = "target-name"
targetNameDesc = "Resource name in APE resource name format"
targetTypeFlag = "target-type"
targetTypeDesc = "Resource type(container/namespace)"
)
func parseLocalOverrideTarget(cmd *cobra.Command) *control.ChainTarget {
target := apecmd.ParseTarget(cmd, true)
var (
errSettingDefaultValueWasDeclined = errors.New("setting default value was declined")
errUnknownTargetType = errors.New("unknown target type")
)
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)
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) {
pk := key.Get(cmd)
target := parseTarget(cmd)
target := parseLocalOverrideTarget(cmd)
req := &control.ListChainLocalOverridesRequest{
Body: &control.ListChainLocalOverridesRequest_Body{
Target: target,
@ -117,7 +75,7 @@ func listRules(cmd *cobra.Command, _ []string) {
for _, c := range chains {
var chain apechain.Chain
commonCmd.ExitOnErr(cmd, "decode error: %w", chain.DecodeBytes(c))
util.PrintHumanReadableAPEChain(cmd, &chain)
apecmd.PrintHumanReadableAPEChain(cmd, &chain)
}
}
@ -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)
}

View file

@ -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)
}

View file

@ -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,12 +25,12 @@ 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{
Target: parseTarget(cmd),
Target: parseLocalOverrideTarget(cmd),
},
}
signRequest(cmd, pk, req)
@ -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)
}
@ -66,7 +61,7 @@ func removeRule(cmd *cobra.Command, _ []string) {
req := &control.RemoveChainLocalOverrideRequest{
Body: &control.RemoveChainLocalOverrideRequest_Body{
Target: parseTarget(cmd),
Target: parseLocalOverrideTarget(cmd),
ChainId: chainIDRaw,
},
}
@ -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)
}

View file

@ -6,7 +6,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
apeutil "git.frostfs.info/TrueCloudLab/frostfs-node/internal/ape"
apeutil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/ape"
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
"github.com/spf13/cobra"
)

View file

@ -0,0 +1,181 @@
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")
errChainIDCannotBeEmpty = errors.New("chain id cannot be empty")
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))
cmd.Printf(" HEX: %x\n", chain.ID)
cmd.Println("Rules:")
for _, rule := range chain.Rules {
cmd.Println("\n\tStatus: " + rule.Status.String())
cmd.Println("\tAny: " + strconv.FormatBool(rule.Any))
cmd.Println("\tConditions:")
for _, c := range rule.Condition {
var ot string
switch c.Kind {
case apechain.KindResource:
ot = "Resource"
case apechain.KindRequest:
ot = "Request"
default:
panic("unknown object type")
}
cmd.Println(fmt.Sprintf("\t\t%s %s %s %s", ot, c.Key, c.Op, c.Value))
}
cmd.Println("\tActions:\tInverted:" + strconv.FormatBool(rule.Actions.Inverted))
for _, name := range rule.Actions.Names {
cmd.Println("\t\t" + name)
}
cmd.Println("\tResources:\tInverted:" + strconv.FormatBool(rule.Resources.Inverted))
for _, name := range rule.Resources.Names {
cmd.Println("\t\t" + name)
}
}
}
// ParseTarget handles target parsing of an APE chain. Names are optional for certain
// target types. When prompt is enabled, the parser will request confirmation
// for empty inputs.
func ParseTarget(cmd *cobra.Command, promptRequired bool) engine.Target {
typ := ParseTargetType(cmd)
name, _ := cmd.Flags().GetString(TargetNameFlag)
switch typ {
case engine.Namespace:
if promptRequired && 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)
}
return engine.Target{}
}
// 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
}
commonCmd.ExitOnErr(cmd, "parse target type error: %w", errUnknownTargetType)
return engine.TargetType(0)
}
func wasMarkedAsRequired(cmd *cobra.Command, flagName string) bool {
if flag := cmd.Flags().Lookup(flagName); flag != nil {
if required, ok := flag.Annotations[cobra.BashCompOneRequiredFlag]; ok {
return len(required) > 0
}
}
return false
}
// ParseChainID parses a chain id of an APE chain. It fails
// when `chainID` is not set, but `allowEmpty` is false.
func ParseChainID(cmd *cobra.Command) (id apechain.ID) {
chainID, _ := cmd.Flags().GetString(ChainIDFlag)
if chainID == "" && wasMarkedAsRequired(cmd, ChainIDFlag) {
commonCmd.ExitOnErr(cmd, "read chain id error: %w",
errChainIDCannotBeEmpty)
}
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
}

View 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"
)

View file

@ -1,16 +1,14 @@
package util
package ape
import (
"errors"
"fmt"
"os"
"strconv"
"strings"
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
"github.com/flynn-archive/go-shlex"
"github.com/spf13/cobra"
)
var (
@ -27,38 +25,6 @@ var (
errFailedToParseAllAny = errors.New("any/all is not parsed")
)
// PrintHumanReadableAPEChain print APE chain rules.
func PrintHumanReadableAPEChain(cmd *cobra.Command, chain *apechain.Chain) {
cmd.Println("Chain ID: " + string(chain.ID))
cmd.Printf(" HEX: %x\n", chain.ID)
cmd.Println("Rules:")
for _, rule := range chain.Rules {
cmd.Println("\n\tStatus: " + rule.Status.String())
cmd.Println("\tAny: " + strconv.FormatBool(rule.Any))
cmd.Println("\tConditions:")
for _, c := range rule.Condition {
var ot string
switch c.Kind {
case apechain.KindResource:
ot = "Resource"
case apechain.KindRequest:
ot = "Request"
default:
panic("unknown object type")
}
cmd.Println(fmt.Sprintf("\t\t%s %s %s %s", ot, c.Key, c.Op, c.Value))
}
cmd.Println("\tActions:\tInverted:" + strconv.FormatBool(rule.Actions.Inverted))
for _, name := range rule.Actions.Names {
cmd.Println("\t\t" + name)
}
cmd.Println("\tResources:\tInverted:" + strconv.FormatBool(rule.Resources.Inverted))
for _, name := range rule.Resources.Names {
cmd.Println("\t\t" + name)
}
}
}
func ParseAPEChainBinaryOrJSON(chain *apechain.Chain, path string) error {
data, err := os.ReadFile(path)
if err != nil {

View file

@ -1,4 +1,4 @@
package util
package ape
import (
"fmt"