forked from TrueCloudLab/frostfs-node
[#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:
parent
b959ce920a
commit
a1154801d1
10 changed files with 689 additions and 1 deletions
|
@ -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
|
||||
}
|
197
cmd/frostfs-adm/internal/modules/morph/ape/chains/list_user.go
Normal file
197
cmd/frostfs-adm/internal/modules/morph/ape/chains/list_user.go
Normal 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
|
||||
}
|
32
cmd/frostfs-adm/internal/modules/morph/ape/chains/root.go
Normal file
32
cmd/frostfs-adm/internal/modules/morph/ape/chains/root.go
Normal 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()
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
32
cmd/frostfs-adm/internal/modules/morph/ape/raw/root.go
Normal file
32
cmd/frostfs-adm/internal/modules/morph/ape/raw/root.go
Normal 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()
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue