[#1607] adm/ape: Adopt policy reader
All checks were successful
Tests and linters / Run gofumpt (pull_request) Successful in 34s
DCO action / DCO (pull_request) Successful in 39s
Vulncheck / Vulncheck (pull_request) Successful in 1m11s
Pre-commit hooks / Pre-commit (pull_request) Successful in 1m23s
Build / Build Components (pull_request) Successful in 1m41s
Tests and linters / Staticcheck (pull_request) Successful in 2m4s
Tests and linters / Lint (pull_request) Successful in 3m9s
Tests and linters / Tests (pull_request) Successful in 3m52s
Tests and linters / Tests with -race (pull_request) Successful in 4m41s
Tests and linters / gopls check (pull_request) Successful in 4m44s

Embed https://git.frostfs.info/dkirillov/policy-reader
tool to 'frostfs-adm morph ape' command

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2025-01-19 21:25:19 +03:00
parent c98357606b
commit 98eeed2e74
10 changed files with 657 additions and 2 deletions

View file

@ -0,0 +1,99 @@
package chains
import (
"fmt"
"math/big"
"git.frostfs.info/TrueCloudLab/frostfs-contract/commonclient"
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/ape/raw/output"
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-sdk-go/container"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ns"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var listContainerCmd = &cobra.Command{
Use: "list-container",
Short: "List container related (namespace) policies",
Long: "List container related (namespace) policies along with filtering by service (s3/storage)",
Example: `chains list-container -r http://localhost:40332 list --container 7h7NcXcF6k6b1yidqEHc1jkyXUm1MfUDrrTuHAefhiDe
chains list-container -r http://localhost:40332 --policy-hash 81c1a41d09e08087a4b679418b12be5d3ab15742 list --container 7h7NcXcF6k6b1yidqEHc1jkyXUm1MfUDrrTuHAefhiDe --namespace test`,
PreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(containerFlag, cmd.Flags().Lookup(containerFlag))
_ = viper.BindPFlag(namespaceFlag, cmd.Flags().Lookup(namespaceFlag))
_ = viper.BindPFlag(decodeChainFlag, cmd.Flags().Lookup(decodeChainFlag))
_ = viper.BindPFlag(decodeIDFlag, cmd.Flags().Lookup(decodeIDFlag))
},
RunE: runListContainerCmd,
}
const (
containerFlag = "container"
)
func initListContainerCmd() {
listContainerCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
listContainerCmd.Flags().String(apeCmd.ChainNameFlag, "", apeCmd.ChainNameFlagDesc)
listContainerCmd.Flags().String(containerFlag, "", "Container id or bucket name in nns (if name is provided than 'namespace' should be set too)")
listContainerCmd.Flags().String(namespaceFlag, "", "Namespace where container name will be looked up")
listContainerCmd.Flags().Bool(decodeChainFlag, false, "Use this flag to decode chain")
listContainerCmd.Flags().Bool(decodeIDFlag, false, "Use this flag to additionally decode chain id (without --decode-chain no take effect)")
_ = listContainerCmd.MarkFlagRequired(containerFlag)
}
func runListContainerCmd(cmd *cobra.Command, _ []string) error {
chainName, err := parseChainName(viper.GetString(apeCmd.ChainNameFlag))
commonCmd.ExitOnErr(cmd, "can't parse chain-name: %w", err)
endpoint := viper.GetString(commonflags.EndpointFlag)
namespace := viper.GetString(namespaceFlag)
cnrID, err := ResolveContainerID(endpoint, namespace, viper.GetString(containerFlag))
commonCmd.ExitOnErr(cmd, "can't resolve container id: %w", err)
inv, policyHash, _ := initReaders(cmd)
res, err := commonclient.ReadIteratorItems(inv, 100, policyHash, methodIteratorChainsByPrefix, big.NewInt(int64(policycontract.Namespace)), namespace, string(chainName))
commonCmd.ExitOnErr(cmd, "can't read iterator: %w", err)
decodeChain := viper.GetBool(decodeChainFlag)
decodeID := viper.GetBool(decodeIDFlag)
cmd.Println("cid:", cnrID)
cmd.Printf("namespace '%s' policies: %d\n", namespace, len(res))
err = output.PrintChains(cmd, res, decodeChain, decodeID)
commonCmd.ExitOnErr(cmd, "can't print chains: %w", err)
res, err = commonclient.ReadIteratorItems(inv, 100, policyHash, methodIteratorChainsByPrefix, big.NewInt(int64(policycontract.Container)), cnrID.String(), string(chainName))
commonCmd.ExitOnErr(cmd, "can't read iterator: %w", err)
cmd.Printf("container policies: %d\n", len(res))
return output.PrintChains(cmd, res, decodeChain, decodeID)
}
// ResolveContainerID determine container id by resolving NNS name.
func ResolveContainerID(endpoint, namespace, containerName string) (cid.ID, error) {
var cnrID cid.ID
if err := cnrID.DecodeString(containerName); err == nil {
return cnrID, nil
}
var domain container.Domain
domain.SetName(containerName)
if namespace != "" {
domain.SetZone(namespace + ".ns")
}
var nns ns.NNS
if err := nns.Dial(endpoint); err != nil {
return cid.ID{}, fmt.Errorf("dial nns %s: %w", endpoint, err)
}
defer nns.Close()
return nns.ResolveContainerDomain(domain)
}

View file

@ -0,0 +1,177 @@
package chains
import (
"encoding/hex"
"errors"
"fmt"
"math/big"
"git.frostfs.info/TrueCloudLab/frostfs-contract/commonclient"
ffsidclient "git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/ape/raw/output"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
neoflags "github.com/nspcc-dev/neo-go/cli/flags"
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"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/nspcc-dev/neo-go/pkg/wallet"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var listUserCmd = &cobra.Command{
Use: "list-user",
Short: "List user related (groups/namespace) policies",
Long: "List user related (groups/namespace) policies along with filtering by service (s3/storage)",
Example: `policy-reader list-user -r http://localhost:40332 list --user NiGqBpUdMvAC68SxUeyYwVPyBCsqzNuof
policy-reader list-user -r http://localhost:40332 --policy-hash 81c1a41d09e08087a4b679418b12be5d3ab15742 list --user NiGqBpUdMvAC68SxUeyYwVPyBCsqzNuofL --service s3`,
PreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(userFlag, cmd.Flags().Lookup(userFlag))
_ = viper.BindPFlag(namespaceFlag, cmd.Flags().Lookup(namespaceFlag))
_ = viper.BindPFlag(decodeChainFlag, cmd.Flags().Lookup(decodeChainFlag))
_ = viper.BindPFlag(decodeIDFlag, cmd.Flags().Lookup(decodeIDFlag))
},
RunE: runListCmd,
}
var errUnknownServiceType = errors.New("unknown chain-name")
const (
userFlag = "user"
namespaceFlag = "namespace"
decodeChainFlag = "decode-chain"
decodeIDFlag = "decode-id"
)
const methodIteratorChainsByPrefix = "iteratorChainsByPrefix"
func initListUserCmd() {
listUserCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
listUserCmd.Flags().String(apeCmd.ChainNameFlag, "", apeCmd.ChainNameFlagDesc)
listUserCmd.Flags().String(userFlag, "", "User address or name in frostfsid contract (if name is provided than 'namespace' should be set too)")
listUserCmd.Flags().String(namespaceFlag, "", "Namespace where user name will be looked up")
listUserCmd.Flags().Bool(decodeChainFlag, false, "Use this flag to decode chain")
listUserCmd.Flags().Bool(decodeIDFlag, false, "Use this flag to additionally decode chain id (without --decode-chain no take effect)")
_ = listUserCmd.MarkFlagRequired(userFlag)
}
func runListCmd(cmd *cobra.Command, _ []string) error {
chainName, err := parseChainName(viper.GetString(apeCmd.ChainNameFlag))
commonCmd.ExitOnErr(cmd, "can't parse chain-name: %w", err)
inv, policyHash, ffsidCli := initReaders(cmd)
subj, err := resolveSubject(ffsidCli, viper.GetString(namespaceFlag), viper.GetString(userFlag))
commonCmd.ExitOnErr(cmd, "can't resolve frostfsid subject: %w", err)
printSubject(cmd, subj)
res, err := commonclient.ReadIteratorItems(inv, 100, policyHash, methodIteratorChainsByPrefix, big.NewInt(int64(policycontract.Namespace)), subj.Namespace, string(chainName))
commonCmd.ExitOnErr(cmd, "can't read iterator: %w", err)
decodeChain := viper.GetBool(decodeChainFlag)
decodeID := viper.GetBool(decodeIDFlag)
cmd.Printf("user namespace '%s' policies: %d\n", subj.Namespace, len(res))
err = output.PrintChains(cmd, res, decodeChain, decodeID)
commonCmd.ExitOnErr(cmd, "can't print chains: %w", err)
userEntity := big.NewInt(int64(policycontract.User))
userEntityName := fmt.Sprintf("%s:%s", subj.Namespace, subj.PrimaryKey.Address())
res, err = commonclient.ReadIteratorItems(inv, 100, policyHash, methodIteratorChainsByPrefix, userEntity, userEntityName, string(chainName))
commonCmd.ExitOnErr(cmd, "can't read iterator: %w", err)
cmd.Printf("user policies: %d\n", len(res))
err = output.PrintChains(cmd, res, decodeChain, decodeID)
commonCmd.ExitOnErr(cmd, "can't print chains: %w", err)
cmd.Printf("user group policies: %d\n", len(subj.Groups))
groupEntity := big.NewInt(int64(policycontract.Group))
for _, group := range subj.Groups {
groupEntityName := fmt.Sprintf("%s:%d", group.Namespace, group.ID)
res, err = commonclient.ReadIteratorItems(inv, 100, policyHash, methodIteratorChainsByPrefix, groupEntity, groupEntityName, string(chainName))
commonCmd.ExitOnErr(cmd, "can't read iterator: %w", err)
cmd.Printf("user group '%s' (id: %d) policies: %d\n", group.Name, group.ID, len(res))
err = output.PrintChains(cmd, res, decodeChain, decodeID)
commonCmd.ExitOnErr(cmd, "can't print chains: %w", err)
}
return nil
}
func resolveSubject(ffsid *ffsidclient.Client, namespace, userName string) (*ffsidclient.SubjectExtended, error) {
if userHash, err := neoflags.ParseAddress(userName); err == nil {
subj, err := ffsid.GetSubject(userHash)
if err != nil {
return nil, err
}
return ffsid.GetSubjectExtended(subj.PrimaryKey.GetScriptHash())
}
subj, err := ffsid.GetSubjectByName(namespace, userName)
if err != nil {
return nil, err
}
return ffsid.GetSubjectExtended(subj.PrimaryKey.GetScriptHash())
}
func parseChainName(service string) (apechain.Name, error) {
switch service {
case "":
return "", nil
case "s3":
return apechain.S3, nil
case "ingress":
return apechain.Ingress, nil
}
return "", errUnknownServiceType
}
func printSubject(cmd *cobra.Command, subj *ffsidclient.SubjectExtended) {
cmd.Println("ns:", subj.Namespace)
cmd.Println("name:", subj.Name)
cmd.Println("key:", hex.EncodeToString(subj.PrimaryKey.Bytes()))
cmd.Println("claims:")
for k, v := range subj.KV {
cmd.Println(k, v)
}
}
func initReaders(cmd *cobra.Command) (*invoker.Invoker, util.Uint160, *ffsidclient.Client) {
endpoint := viper.GetString(commonflags.EndpointFlag)
rpcCli, err := rpcclient.New(cmd.Context(), endpoint, rpcclient.Options{})
commonCmd.ExitOnErr(cmd, "can't init rpc client: %w", err)
inv := invoker.New(rpcCli, nil)
nnsCs, err := helper.GetContractByID(management.NewReader(inv), 1)
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
policyHash, err := helper.NNSResolveHash(inv, nnsCs.Hash, viper.GetString(policyHashFlag))
commonCmd.ExitOnErr(cmd, "can't resolve NNS policy contract: %w", err)
frostfsidHash, err := helper.NNSResolveHash(inv, nnsCs.Hash, viper.GetString(frostfsidHashFlag))
commonCmd.ExitOnErr(cmd, "can't resolve NNS frostfsid contract: %w", err)
acc, err := wallet.NewAccount()
commonCmd.ExitOnErr(cmd, "can't create new account: %w", err)
ffsidCli, err := ffsidclient.New(rpcCli, acc, frostfsidHash, ffsidclient.Options{})
commonCmd.ExitOnErr(cmd, "can't init frostfsid client: %w", err)
return inv, policyHash, ffsidCli
}

View file

@ -0,0 +1,36 @@
package chains
import (
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
apeCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common/ape"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var Cmd = &cobra.Command{
Use: "chains",
Short: "Chain related policy operations",
Long: "Chain related policy operations. Complex scenarios like: list all user chains (including groups, namespaces).",
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
_ = viper.BindPFlag(apeCmd.ChainNameFlag, cmd.Flags().Lookup(apeCmd.ChainNameFlag))
_ = viper.BindPFlag(policyHashFlag, cmd.Flags().Lookup(policyHashFlag))
_ = viper.BindPFlag(frostfsidHashFlag, cmd.Flags().Lookup(frostfsidHashFlag))
},
}
const (
policyHashFlag = "policy-hash"
frostfsidHashFlag = "frostfsid-hash"
)
func init() {
Cmd.PersistentFlags().String(policyHashFlag, "policy.frostfs", "NNS name or script hash of policy contract")
Cmd.PersistentFlags().String(frostfsidHashFlag, "frostfsid.frostfs", "NNS name or script hash of frostfsid contract")
Cmd.AddCommand(listUserCmd)
initListUserCmd()
Cmd.AddCommand(listContainerCmd)
initListContainerCmd()
}

View file

@ -0,0 +1,79 @@
package raw
import (
"encoding/base64"
"git.frostfs.info/TrueCloudLab/frostfs-contract/commonclient"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var listChainNamesCmd = &cobra.Command{
Use: "list-chain-names",
Short: "Invoke 'listChainNames' method",
Long: "Invoke 'listChainNames' method in policy contract and print results to stdout",
Example: `raw -r http://localhost:40332 list-chain-names --kind n --name ''
raw -r http://localhost:40332 --policy-hash 81c1a41d09e08087a4b679418b12be5d3ab15742 list-chain-names --kind c --name 7h7NcXcF6k6b1yidqEHc1jkyXUm1MfUDrrTuHAefhiDe`,
PreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(kindFlag, cmd.Flags().Lookup(kindFlag))
_ = viper.BindPFlag(nameFlag, cmd.Flags().Lookup(nameFlag))
_ = viper.BindPFlag(nameBase64Flag, cmd.Flags().Lookup(nameBase64Flag))
},
RunE: runListChainNamesCmd,
}
const (
nameFlag = "name"
nameBase64Flag = "name-base64"
)
func initListChainNamesCmd() {
listChainNamesCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
listChainNamesCmd.Flags().String(kindFlag, "n", "Target kind (1-byte) to list (n(namespace)/c(container)/g(group)/u(user)/i(iam))")
listChainNamesCmd.Flags().String(nameFlag, "", "Target name to list")
listChainNamesCmd.Flags().Bool(nameBase64Flag, false, "Use this flag if you provide name in base64 format")
_ = listChainNamesCmd.MarkFlagRequired(kindFlag)
_ = listChainNamesCmd.MarkFlagRequired(nameFlag)
}
func runListChainNamesCmd(cmd *cobra.Command, _ []string) error {
kind := viper.GetString(kindFlag)
entity, err := parseTargetKind(kind)
commonCmd.ExitOnErr(cmd, "can't parse target kind: %w", err)
entityName, err := parseEntityName()
commonCmd.ExitOnErr(cmd, "can't parse name: %w", err)
inv, policyHash := initPolicyReader(cmd)
res, err := commonclient.ReadIteratorItems(inv, 100, policyHash, methodListChainNames, entity, entityName)
commonCmd.ExitOnErr(cmd, "can't read iterator: %w", err)
cmd.Printf("%s target chain names: %d\n", kind, len(res))
for _, re := range res {
bytes, err := re.TryBytes()
commonCmd.ExitOnErr(cmd, "can't parse result: %w", err)
cmd.Printf("%s\t(base64: '%s')\n", string(bytes), base64.StdEncoding.EncodeToString(bytes))
}
return nil
}
func parseEntityName() ([]byte, error) {
entityNameStr := viper.GetString(nameFlag)
var entityName []byte
if viper.GetBool(nameBase64Flag) {
return base64.StdEncoding.DecodeString(entityNameStr)
}
if entityNameStr == "root" {
entityNameStr = ""
}
entityName = []byte(entityNameStr)
return entityName, nil
}

View file

@ -0,0 +1,77 @@
package raw
import (
"encoding/base64"
"git.frostfs.info/TrueCloudLab/frostfs-contract/commonclient"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/ape/raw/output"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var listChainsByPrefixCmd = &cobra.Command{
Use: "list-chains-by-prefix",
Short: "Invoke 'iteratorChainsByPrefix' method",
Long: "Invoke 'iteratorChainsByPrefix' method in policy contract and print results to stdout",
Example: `raw -r http://localhost:40332 list-chains-by-prefix --kind n --name ''
raw -r http://localhost:40332 --policy-hash 81c1a41d09e08087a4b679418b12be5d3ab15742 list-chains-by-prefix --kind c --name 7h7NcXcF6k6b1yidqEHc1jkyXUm1MfUDrrTuHAefhiDe`,
PreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(kindFlag, cmd.Flags().Lookup(kindFlag))
_ = viper.BindPFlag(nameFlag, cmd.Flags().Lookup(nameFlag))
_ = viper.BindPFlag(prefixFlag, cmd.Flags().Lookup(prefixFlag))
_ = viper.BindPFlag(prefixBase64Flag, cmd.Flags().Lookup(prefixBase64Flag))
_ = viper.BindPFlag(nameBase64Flag, cmd.Flags().Lookup(nameBase64Flag))
_ = viper.BindPFlag(decodeChainFlag, cmd.Flags().Lookup(decodeChainFlag))
_ = viper.BindPFlag(decodeIDFlag, cmd.Flags().Lookup(decodeIDFlag))
},
RunE: runListChainsByPrefixCmd,
}
const (
prefixFlag = "prefix"
prefixBase64Flag = "prefix-base64"
decodeChainFlag = "decode-chain"
decodeIDFlag = "decode-id"
)
func initListChainsByPrefixCmd() {
listChainsByPrefixCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
listChainsByPrefixCmd.Flags().String(kindFlag, "n", "Target kind (1-byte) to list (n(namespace)/c(container)/g(group)/u(user)/i(iam))")
listChainsByPrefixCmd.Flags().String(nameFlag, "", "Target name to list")
listChainsByPrefixCmd.Flags().String(prefixFlag, "", "Prefix to list")
listChainsByPrefixCmd.Flags().Bool(prefixBase64Flag, false, "Use this flag if you provide prefix in base64 format")
listChainsByPrefixCmd.Flags().Bool(nameBase64Flag, false, "Use this flag if you provide name in base64 format")
listChainsByPrefixCmd.Flags().Bool(decodeChainFlag, false, "Use this flag to decode chain")
listChainsByPrefixCmd.Flags().Bool(decodeIDFlag, false, "Use this flag to additionally decode chain id (without --decode-chain no take effect)")
_ = listChainsByPrefixCmd.MarkFlagRequired(kindFlag)
_ = listChainsByPrefixCmd.MarkFlagRequired(nameFlag)
}
func runListChainsByPrefixCmd(cmd *cobra.Command, _ []string) error {
typ := viper.GetString(kindFlag)
entity, err := parseTargetKind(typ)
commonCmd.ExitOnErr(cmd, "can't parse target kind: %w", err)
entityName, err := parseEntityName()
commonCmd.ExitOnErr(cmd, "can't parse name: %w", err)
prefixStr := viper.GetString(prefixFlag)
var prefix []byte
if viper.GetBool(prefixBase64Flag) {
if prefix, err = base64.StdEncoding.DecodeString(prefixStr); err != nil {
return err
}
} else {
prefix = []byte(prefixStr)
}
inv, policyHash := initPolicyReader(cmd)
res, err := commonclient.ReadIteratorItems(inv, 100, policyHash, methodIteratorChainsByPrefix, entity, entityName, prefix)
commonCmd.ExitOnErr(cmd, "can't read iterator: %w", err)
cmd.Printf("%s target chains names: %d\n", typ, len(res))
return output.PrintChains(cmd, res, viper.GetBool(decodeChainFlag), viper.GetBool(decodeIDFlag))
}

View file

@ -0,0 +1,90 @@
package raw
import (
"encoding/base64"
"fmt"
"math/big"
"git.frostfs.info/TrueCloudLab/frostfs-contract/commonclient"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"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"
)
var listTargetsCmd = &cobra.Command{
Use: "list-targets",
Short: "Invoke 'listTargets' method",
Long: "Invoke 'listTargets' method in policy contract and print results to stdout",
Example: `raw -r http://localhost:40332 list-targets
raw -r http://localhost:40332 --policy-hash 81c1a41d09e08087a4b679418b12be5d3ab15742 list-targets --kind c`,
PreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(kindFlag, cmd.Flags().Lookup(kindFlag))
},
RunE: runListTargetsCmd,
}
const (
kindFlag = "kind"
)
const (
methodIteratorChainsByPrefix = "iteratorChainsByPrefix"
methodListTargets = "listTargets"
methodListChainNames = "listChainNames"
)
func initListTargetsCmd() {
listTargetsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
listTargetsCmd.Flags().String(kindFlag, "n", "Target kind (1-byte) to list (n(namespace)/c(container)/g(group)/u(user)/i(iam))")
}
func runListTargetsCmd(cmd *cobra.Command, _ []string) error {
kind := viper.GetString(kindFlag)
entity, err := parseTargetKind(kind)
commonCmd.ExitOnErr(cmd, "can't parse target kind: %w", err)
inv, policyHash := initPolicyReader(cmd)
res, err := commonclient.ReadIteratorItems(inv, 100, policyHash, methodListTargets, entity)
commonCmd.ExitOnErr(cmd, "can't read iterator: %w", err)
cmd.Printf("%s targets: %d\n", kind, len(res))
for _, re := range res {
bytes, err := re.TryBytes()
commonCmd.ExitOnErr(cmd, "can't parse result: %w", err)
cmd.Printf("%s\t(base64: '%s')\n", string(bytes), base64.StdEncoding.EncodeToString(bytes))
}
return nil
}
func parseTargetKind(typ string) (*big.Int, error) {
if len(typ) != 1 {
return nil, fmt.Errorf("invalid type: %s", typ)
}
return big.NewInt(int64(typ[0])), nil
}
func initPolicyReader(cmd *cobra.Command) (*invoker.Invoker, util.Uint160) {
endpoint := viper.GetString(commonflags.EndpointFlag)
rpcCli, err := rpcclient.New(cmd.Context(), endpoint, rpcclient.Options{})
commonCmd.ExitOnErr(cmd, "can't init rpc client: %w", err)
inv := invoker.New(rpcCli, nil)
nnsCs, err := helper.GetContractByID(management.NewReader(inv), 1)
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
policyHash, err := helper.NNSResolveHash(inv, nnsCs.Hash, viper.GetString(policyHashFlag))
commonCmd.ExitOnErr(cmd, "can't resolve NNS policy contract: %w", err)
return inv, policyHash
}

View file

@ -0,0 +1,56 @@
package output
import (
"encoding/base64"
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/spf13/cobra"
)
const (
minPrintable = 32
maxPrintable = 127
)
func PrintChains(cmd *cobra.Command, list []stackitem.Item, decodeChain, decodeID bool) error {
for _, item := range list {
bytes, err := item.TryBytes()
if err != nil {
return err
}
if !decodeChain {
cmd.Println(string(bytes))
continue
}
var chain apechain.Chain
if err = chain.DecodeBytes(bytes); err != nil {
cmd.PrintErrf("invalid chain format: %s\n", base64.StdEncoding.EncodeToString(bytes))
continue
}
raw, err := chain.MarshalJSON()
if err != nil {
return err
}
if decodeID {
var printableID string
for _, r := range string(chain.ID) {
if minPrintable <= r && r <= maxPrintable {
printableID += string(r)
} else {
printableID += "."
}
}
cmd.Println(printableID, string(raw))
} else {
cmd.Println(string(raw))
}
}
return nil
}

View file

@ -0,0 +1,34 @@
package raw
import (
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var Cmd = &cobra.Command{
Use: "raw",
Short: "FrostFS policy contract raw reader",
Long: "Helps reading policy information from contact in FrostFS network",
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
_ = viper.BindPFlag(policyHashFlag, cmd.Flags().Lookup(policyHashFlag))
},
}
const (
policyHashFlag = "policy-hash"
)
func init() {
Cmd.PersistentFlags().String(policyHashFlag, "policy.frostfs", "NNS name or script hash of policy contract")
Cmd.AddCommand(listTargetsCmd)
initListTargetsCmd()
Cmd.AddCommand(listChainNamesCmd)
initListChainNamesCmd()
Cmd.AddCommand(listChainsByPrefixCmd)
initListChainsByPrefixCmd()
}

View file

@ -1,6 +1,10 @@
package ape
import "github.com/spf13/cobra"
import (
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/ape/chains"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/ape/raw"
"github.com/spf13/cobra"
)
var Cmd = &cobra.Command{
Use: "ape",
@ -8,6 +12,9 @@ var Cmd = &cobra.Command{
}
func init() {
Cmd.AddCommand(raw.Cmd)
Cmd.AddCommand(chains.Cmd)
initAddRuleChainCmd()
initRemoveRuleChainCmd()
initListRuleChainsCmd()

View file

@ -7,7 +7,7 @@ const (
TargetNameFlag = "target-name"
TargetNameFlagDesc = "Resource name in APE resource name format"
TargetTypeFlag = "target-type"
TargetTypeFlagDesc = "Resource type(container/namespace)"
TargetTypeFlagDesc = "Resource type(container/namespace/group/user)"
ChainIDFlag = "chain-id"
ChainIDFlagDesc = "Chain id"
ChainIDHexFlag = "chain-id-hex"