[#1607] adm/ape: Adopt policy reader

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 b959ce920a
commit a1154801d1
10 changed files with 689 additions and 1 deletions

View file

@ -0,0 +1,96 @@
package chains
import (
"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"
"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"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
"github.com/spf13/cobra"
)
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`,
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 := parseChainName(cmd)
namespace := parseNamespace(cmd)
inv, policyHash, _ := initReaders(cmd)
cnrID := parseContainer(cmd, inv, namespace)
printContainer(cmd, namespace, cnrID)
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, _ := cmd.Flags().GetBool(decodeChainFlag)
decodeID, _ := cmd.Flags().GetBool(decodeIDFlag)
cmd.Printf("\nnamespace policies: %d\n", 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.EncodeToString(), string(chainName))
commonCmd.ExitOnErr(cmd, "can't read iterator: %w", err)
cmd.Printf("\ncontainer policies: %d\n", len(res))
return output.PrintChains(cmd, res, decodeChain, decodeID)
}
func printContainer(cmd *cobra.Command, namespace string, cnrID cid.ID) {
cmd.Println("container:")
cmd.Printf("\tnamespace: '%s'\n", namespace)
cmd.Printf("\tCID: '%s'\n", cnrID.EncodeToString())
}
func parseContainer(cmd *cobra.Command, inv *invoker.Invoker, namespace string) cid.ID {
containerName, _ := cmd.Flags().GetString(containerFlag)
var cnrID cid.ID
if err := cnrID.DecodeString(containerName); err == nil {
return cnrID
}
var domain container.Domain
domain.SetName(containerName)
if namespace != "" {
domain.SetZone(namespace + ".ns")
}
nnsCs, err := helper.GetContractByID(management.NewReader(inv), 1)
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
cnrID, err = helper.NNSResolveContainerDomain(inv, nnsCs.Hash, domain.Name()+"."+domain.Zone())
commonCmd.ExitOnErr(cmd, "can't resolve container id: %w", err)
return cnrID
}

View file

@ -0,0 +1,197 @@
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`,
RunE: runListCmd,
}
var errUnknownChainNameType = 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 := parseChainName(cmd)
namespace := parseNamespace(cmd)
inv, policyHash, ffsidCli := initReaders(cmd)
user, _ := cmd.Flags().GetString(userFlag)
subj, err := resolveSubject(ffsidCli, namespace, user)
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, _ := cmd.Flags().GetBool(decodeChainFlag)
decodeID, _ := cmd.Flags().GetBool(decodeIDFlag)
cmd.Printf("\nnamespace policies: %d\n", 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("\nuser policies: %d\n", len(res))
err = output.PrintChains(cmd, res, decodeChain, decodeID)
commonCmd.ExitOnErr(cmd, "can't print chains: %w", err)
cmd.Printf("\ngroup 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(cmd *cobra.Command) apechain.Name {
chainName, _ := cmd.Flags().GetString(apeCmd.ChainNameFlag)
switch chainName {
case "":
return ""
case "s3":
return apechain.S3
case "ingress":
return apechain.Ingress
}
commonCmd.ExitOnErr(cmd, "can't parse chain-name: %w", errUnknownChainNameType)
panic("unreachable")
}
func parseNamespace(cmd *cobra.Command) string {
namespace, _ := cmd.Flags().GetString(namespaceFlag)
if namespace == "root" {
namespace = ""
}
return namespace
}
func printSubject(cmd *cobra.Command, subj *ffsidclient.SubjectExtended) {
cmd.Println("subject:")
cmd.Printf("\tnamespace: '%s'\n", subj.Namespace)
cmd.Printf("\tname: '%s'\n", subj.Name)
cmd.Printf("\tkey: '%s'\n", hex.EncodeToString(subj.PrimaryKey.Bytes()))
additionalKeys := make([]string, len(subj.AdditionalKeys))
for i, key := range subj.AdditionalKeys {
additionalKeys[i] = hex.EncodeToString(key.Bytes())
}
cmd.Printf("\tadditional keys: %v\n", additionalKeys)
cmd.Printf("\tclaims:\n")
for k, v := range subj.KV {
cmd.Printf("\t\t%s: '%s'\n", k, v)
}
cmd.Printf("\tgroups:\n")
for _, gr := range subj.Groups {
cmd.Printf("\t\t%d: '%s'\n", gr.ID, gr.Name)
}
}
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)
policyHashStr, _ := cmd.Flags().GetString(policyHashFlag)
policyHash, err := helper.NNSResolveHash(inv, nnsCs.Hash, policyHashStr)
commonCmd.ExitOnErr(cmd, "can't resolve NNS policy contract: %w", err)
frostfsidHashStr, _ := cmd.Flags().GetString(frostfsidHashFlag)
frostfsidHash, err := helper.NNSResolveHash(inv, nnsCs.Hash, frostfsidHashStr)
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,32 @@
package chains
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: "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))
},
}
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,74 @@
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`,
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, _ := cmd.Flags().GetString(kindFlag)
entity, err := parseTargetKind(kind)
commonCmd.ExitOnErr(cmd, "can't parse target kind: %w", err)
entityName, err := parseEntityName(cmd)
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(cmd *cobra.Command) ([]byte, error) {
entityNameStr, _ := cmd.Flags().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,71 @@
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"
)
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`,
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 {
kind, _ := cmd.Flags().GetString(kindFlag)
entity, err := parseTargetKind(kind)
commonCmd.ExitOnErr(cmd, "can't parse target kind: %w", err)
entityName, err := parseEntityName(cmd)
commonCmd.ExitOnErr(cmd, "can't parse name: %w", err)
prefixStr, _ := cmd.Flags().GetString(prefixFlag)
prefixBase64, _ := cmd.Flags().GetBool(prefixBase64Flag)
var prefix []byte
if prefixBase64 {
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", kind, len(res))
decodeChain, _ := cmd.Flags().GetBool(decodeChainFlag)
decodeID, _ := cmd.Flags().GetBool(decodeIDFlag)
return output.PrintChains(cmd, res, decodeChain, decodeID)
}

View file

@ -0,0 +1,88 @@
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`,
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, _ := cmd.Flags().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)
policyHashStr, _ := cmd.Flags().GetString(policyHashFlag)
policyHash, err := helper.NNSResolveHash(inv, nnsCs.Hash, policyHashStr)
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.Printf("\t%s\n", 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.Printf("\t%s - %s\n", printableID, string(raw))
} else {
cmd.Printf("\t%s\n", string(raw))
}
}
return nil
}

View file

@ -0,0 +1,32 @@
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",
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
},
}
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

@ -10,6 +10,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/config"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
@ -158,6 +159,40 @@ func NNSResolveHash(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (
return ParseNNSResolveResult(item)
}
// NNSResolveContainerDomain returns errMissingNNSRecord if invocation fault exception contains "token not found".
func NNSResolveContainerDomain(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (cid.ID, error) {
item, err := NNSResolve(inv, nnsHash, domain)
if err != nil {
return cid.ID{}, err
}
return parseNNSResolveResultCID(item)
}
func parseNNSResolveResultCID(res stackitem.Item) (cid.ID, error) {
arr, ok := res.Value().([]stackitem.Item)
if !ok {
arr = []stackitem.Item{res}
}
if _, ok := res.Value().(stackitem.Null); ok || len(arr) == 0 {
return cid.ID{}, errors.New("NNS record is missing")
}
var cnrID cid.ID
for i := range arr {
bs, err := arr[i].TryBytes()
if err != nil {
continue
}
if err = cnrID.DecodeString(string(bs)); err == nil {
return cnrID, nil
}
}
return cid.ID{}, errors.New("no valid CIDs are found")
}
func DomainOf(contract string) string {
return contract + ".frostfs"
}