From 9611710e190b260a9067d57f64f3678da721e78c Mon Sep 17 00:00:00 2001 From: Airat Arifullin Date: Fri, 16 Feb 2024 12:36:42 +0300 Subject: [PATCH] [#989] cli: Read and parse chains from file * Introduce path flag to make add-rule command read and parse chain from file. File is binary/JSON-encoded chain. Signed-off-by: Airat Arifullin --- cmd/frostfs-cli/modules/control/add_rule.go | 37 +++++++++++++++------ cmd/frostfs-cli/modules/util/ape.go | 18 ++++++++++ 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/cmd/frostfs-cli/modules/control/add_rule.go b/cmd/frostfs-cli/modules/control/add_rule.go index 0f5ac11f..45b36bfb 100644 --- a/cmd/frostfs-cli/modules/control/add_rule.go +++ b/cmd/frostfs-cli/modules/control/add_rule.go @@ -2,6 +2,7 @@ package control import ( "encoding/hex" + "errors" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key" @@ -14,6 +15,7 @@ import ( const ( ruleFlag = "rule" + pathFlag = "path" ) var addRuleCmd = &cobra.Command{ @@ -23,15 +25,13 @@ var addRuleCmd = &cobra.Command{ Example: `control add-rule --endpoint ... -w ... --address ... --chain-id ChainID --cid ... --rule "allow Object.Get *" --rule "deny Object.Get EbxzAdz5LB4uqxuz6crWKAumBNtZyK2rKsqQP7TdZvwr/*" --rule "deny:QuotaLimitReached Object.Put Object.Resource:Department=HR *" + +control add-rule --endpoint ... -w ... --address ... --chain-id ChainID --cid ... --path some_chain.json `, Run: addRule, } -func addRule(cmd *cobra.Command, _ []string) { - pk := key.Get(cmd) - - target := parseTarget(cmd) - +func parseChain(cmd *cobra.Command) *apechain.Chain { chainID, _ := cmd.Flags().GetString(chainIDFlag) hexEncoded, _ := cmd.Flags().GetBool(chainIDHexFlag) @@ -43,20 +43,34 @@ func addRule(cmd *cobra.Command, _ []string) { commonCmd.ExitOnErr(cmd, "can't decode chain ID as hex: %w", err) } - rule, _ := cmd.Flags().GetStringArray(ruleFlag) - chain := new(apechain.Chain) - commonCmd.ExitOnErr(cmd, "parser error: %w", util.ParseAPEChain(chain, rule)) chain.ID = apechain.ID(chainIDRaw) - serializedChain := chain.Bytes() + + 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) + + parsed := parseChain(cmd) + req := &control.AddChainLocalOverrideRequest{ Body: &control.AddChainLocalOverrideRequest_Body{ Target: target, - Chain: serializedChain, + Chain: parsed.Bytes(), }, } @@ -81,9 +95,12 @@ func initControlAddRuleCmd() { 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") + + addRuleCmd.MarkFlagsMutuallyExclusive(pathFlag, ruleFlag) } diff --git a/cmd/frostfs-cli/modules/util/ape.go b/cmd/frostfs-cli/modules/util/ape.go index 6a7eca94..dfe70e7d 100644 --- a/cmd/frostfs-cli/modules/util/ape.go +++ b/cmd/frostfs-cli/modules/util/ape.go @@ -3,6 +3,7 @@ package util import ( "errors" "fmt" + "os" "strconv" "strings" @@ -57,6 +58,23 @@ func PrintHumanReadableAPEChain(cmd *cobra.Command, chain *apechain.Chain) { } } +func ParseAPEChainBinaryOrJSON(chain *apechain.Chain, path string) error { + data, err := os.ReadFile(path) + if err != nil { + return fmt.Errorf("read file <%s>: %w", path, err) + } + + err = chain.UnmarshalBinary(data) + if err != nil { + err = chain.UnmarshalJSON(data) + if err != nil { + return fmt.Errorf("invalid format: %w", err) + } + } + + return nil +} + // ParseAPEChain parses APE chain rules. func ParseAPEChain(chain *apechain.Chain, rules []string) error { if len(rules) == 0 {