[#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
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:
parent
c98357606b
commit
98eeed2e74
10 changed files with 657 additions and 2 deletions
|
@ -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)
|
||||
}
|
177
cmd/frostfs-adm/internal/modules/morph/ape/chains/list_user.go
Normal file
177
cmd/frostfs-adm/internal/modules/morph/ape/chains/list_user.go
Normal 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
|
||||
}
|
36
cmd/frostfs-adm/internal/modules/morph/ape/chains/root.go
Normal file
36
cmd/frostfs-adm/internal/modules/morph/ape/chains/root.go
Normal 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()
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
34
cmd/frostfs-adm/internal/modules/morph/ape/raw/root.go
Normal file
34
cmd/frostfs-adm/internal/modules/morph/ape/raw/root.go
Normal 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()
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue