[#1704] Add command `container nodes` to output list of nodes for container, grouped by replica (#1704)

Signed-off-by: Anton Nikiforov <an.nikiforov@yadro.com>
remotes/fyrchik/neofs-adm-fix-commands
Anton Nikiforov 2022-10-05 16:52:46 +03:00 committed by fyrchik
parent 6557f5d249
commit 5e493b7f1c
10 changed files with 157 additions and 64 deletions

View File

@ -15,6 +15,7 @@ Changelog for NeoFS Node
- `wallet-address` flag in `neofs-adm morph refill-gas` command (#1820)
- Validate policy before container creation (#1704)
- `--timeout` flag in `neofs-cli` subcommands (#1837)
- `container nodes` command to output list of nodes for container, grouped by replica (#1704)
### Changed
- Allow to evacuate shard data with `EvacuateShard` control RPC (#1800)

View File

@ -0,0 +1,49 @@
package common
import (
"encoding/hex"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/spf13/cobra"
)
// PrettyPrintNodeInfo print information about network node with given indent and index.
// To avoid printing attribute list use short parameter.
func PrettyPrintNodeInfo(cmd *cobra.Command, node netmap.NodeInfo,
index int, indent string, short bool) {
var strState string
switch {
default:
strState = "STATE_UNSUPPORTED"
case node.IsOnline():
strState = "ONLINE"
case node.IsOffline():
strState = "OFFLINE"
case node.IsMaintenance():
strState = "MAINTENANCE"
}
cmd.Printf("%sNode %d: %s %s ", indent, index+1, hex.EncodeToString(node.PublicKey()), strState)
netmap.IterateNetworkEndpoints(node, func(endpoint string) {
cmd.Printf("%s ", endpoint)
})
cmd.Println()
if !short {
node.IterateAttributes(func(key, value string) {
cmd.Printf("%s\t%s: %s\n", indent, key, value)
})
}
}
// PrettyPrintNetMap print information about network map
func PrettyPrintNetMap(cmd *cobra.Command, nm netmap.NetMap) {
cmd.Println("Epoch:", nm.Epoch())
nodes := nm.Nodes()
for i := range nodes {
PrettyPrintNodeInfo(cmd, nodes[i], i, "", false)
}
}

View File

@ -96,7 +96,7 @@ func initContainerDeleteCmd() {
flags.StringP(commonflags.Account, commonflags.AccountShorthand, commonflags.AccountDefault, commonflags.AccountUsage)
flags.StringP(commonflags.RPC, commonflags.RPCShorthand, commonflags.RPCDefault, commonflags.RPCUsage)
flags.StringVar(&containerID, "cid", "", "container ID")
flags.StringVar(&containerID, cidFlag, "", cidFlagUsage)
flags.BoolVar(&containerAwait, "await", false, "block execution until container is removed")
flags.BoolP(commonflags.ForceFlag, commonflags.ForceFlagShorthand, false, "do not check whether container contains locks and remove immediately")
}

View File

@ -2,6 +2,7 @@ package container
import (
"bytes"
"crypto/ecdsa"
"encoding/json"
"os"
@ -15,6 +16,14 @@ import (
"github.com/spf13/cobra"
)
const (
cidFlag = "cid"
cidFlagUsage = "container ID"
fromFlag = "from"
fromFlagUsage = "path to file with encoded container"
)
var (
containerID string
containerPathFrom string
@ -27,28 +36,7 @@ var getContainerInfoCmd = &cobra.Command{
Short: "Get container field info",
Long: `Get container field info`,
Run: func(cmd *cobra.Command, args []string) {
var cnr container.Container
if containerPathFrom != "" {
data, err := os.ReadFile(containerPathFrom)
common.ExitOnErr(cmd, "can't read file: %w", err)
err = cnr.Unmarshal(data)
common.ExitOnErr(cmd, "can't unmarshal container: %w", err)
} else {
id := parseContainerID(cmd)
pk := key.GetOrGenerate(cmd)
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC)
var prm internalclient.GetContainerPrm
prm.SetClient(cli)
prm.SetContainer(id)
res, err := internalclient.GetContainer(prm)
common.ExitOnErr(cmd, "rpc error: %w", err)
cnr = res.Container()
}
cnr, _ := getContainer(cmd)
prettyPrintContainer(cmd, cnr, containerJSON)
@ -76,9 +64,9 @@ func initContainerInfoCmd() {
flags := getContainerInfoCmd.Flags()
flags.StringVar(&containerID, "cid", "", "container ID")
flags.StringVar(&containerID, cidFlag, "", cidFlagUsage)
flags.StringVar(&containerPathTo, "to", "", "path to dump encoded container")
flags.StringVar(&containerPathFrom, "from", "", "path to file with encoded container")
flags.StringVar(&containerPathFrom, fromFlag, "", fromFlagUsage)
flags.BoolVar(&containerJSON, commonflags.JSON, false, "print or dump container in JSON format")
}
@ -157,3 +145,29 @@ func prettyPrintBasicACL(cmd *cobra.Command, basicACL acl.Basic) {
cmd.Println()
}
func getContainer(cmd *cobra.Command) (container.Container, *ecdsa.PrivateKey) {
var cnr container.Container
var pk *ecdsa.PrivateKey
if containerPathFrom != "" {
data, err := os.ReadFile(containerPathFrom)
common.ExitOnErr(cmd, "can't read file: %w", err)
err = cnr.Unmarshal(data)
common.ExitOnErr(cmd, "can't unmarshal container: %w", err)
} else {
id := parseContainerID(cmd)
pk = key.GetOrGenerate(cmd)
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC)
var prm internalclient.GetContainerPrm
prm.SetClient(cli)
prm.SetContainer(id)
res, err := internalclient.GetContainer(prm)
common.ExitOnErr(cmd, "rpc error: %w", err)
cnr = res.Container()
}
return cnr, pk
}

View File

@ -57,7 +57,7 @@ func initContainerGetEACLCmd() {
flags := getExtendedACLCmd.Flags()
flags.StringVar(&containerID, "cid", "", "container ID")
flags.StringVar(&containerID, cidFlag, "", cidFlagUsage)
flags.StringVar(&containerPathTo, "to", "", "path to dump encoded container (default: binary encoded)")
flags.BoolVar(&containerJSON, commonflags.JSON, false, "encode EACL table in json format")
}

View File

@ -89,7 +89,7 @@ func initContainerListObjectsCmd() {
flags := listContainerObjectsCmd.Flags()
flags.StringVar(&containerID, "cid", "", "container ID")
flags.StringVar(&containerID, cidFlag, "", cidFlagUsage)
flags.BoolVar(&flagVarListObjectsPrintAttr, flagListObjectPrintAttr, false,
"request and print user attributes of each object",
)

View File

@ -0,0 +1,62 @@
package container
import (
"crypto/sha256"
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
containerAPI "github.com/nspcc-dev/neofs-sdk-go/container"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/spf13/cobra"
)
var short bool
var containerNodesCmd = &cobra.Command{
Use: "nodes",
Short: "Show nodes for container",
Long: "Show nodes taking part in a container at the current epoch.",
Run: func(cmd *cobra.Command, args []string) {
var cnr, pkey = getContainer(cmd)
if pkey == nil {
pkey = key.GetOrGenerate(cmd)
}
cli := internalclient.GetSDKClientByFlag(cmd, pkey, commonflags.RPC)
var prm internalclient.NetMapSnapshotPrm
prm.SetClient(cli)
resmap, err := internalclient.NetMapSnapshot(prm)
common.ExitOnErr(cmd, "unable to get netmap snapshot", err)
var id cid.ID
containerAPI.CalculateID(&id, cnr)
binCnr := make([]byte, sha256.Size)
id.Encode(binCnr)
var cnrNodes [][]netmap.NodeInfo
cnrNodes, err = resmap.NetMap().ContainerNodes(cnr.PlacementPolicy(), binCnr)
common.ExitOnErr(cmd, "could not build container nodes for given container: %w", err)
for i := range cnrNodes {
cmd.Printf("Rep %d\n", i+1)
for j := range cnrNodes[i] {
common.PrettyPrintNodeInfo(cmd, cnrNodes[i][j], j, "\t", short)
}
}
},
}
func initContainerNodesCmd() {
commonflags.Init(containerNodesCmd)
flags := containerNodesCmd.Flags()
flags.StringVar(&containerID, cidFlag, "", cidFlagUsage)
flags.StringVar(&containerPathFrom, fromFlag, "", fromFlagUsage)
flags.BoolVar(&short, "short", false, "Shortens output of node info")
}

View File

@ -27,6 +27,7 @@ func init() {
getContainerInfoCmd,
getExtendedACLCmd,
setExtendedACLCmd,
containerNodesCmd,
}
Cmd.AddCommand(containerChildCommand...)
@ -38,6 +39,7 @@ func init() {
initContainerInfoCmd()
initContainerGetEACLCmd()
initContainerSetEACLCmd()
initContainerNodesCmd()
for _, containerCommand := range containerChildCommand {
commonflags.InitAPI(containerCommand)

View File

@ -103,7 +103,7 @@ func initContainerSetEACLCmd() {
commonflags.Init(setExtendedACLCmd)
flags := setExtendedACLCmd.Flags()
flags.StringVar(&containerID, "cid", "", "container ID")
flags.StringVar(&containerID, cidFlag, "", cidFlagUsage)
flags.StringVar(&flagVarsSetEACL.srcPath, "table", "", "path to file with JSON or binary encoded EACL table")
flags.BoolVar(&containerAwait, "await", false, "block execution until EACL is persisted")
flags.BoolVar(&flagVarsSetEACL.noPreCheck, "no-precheck", false, "do not pre-check the extensibility of the container ACL")

View File

@ -1,13 +1,10 @@
package netmap
import (
"encoding/hex"
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/spf13/cobra"
)
@ -25,7 +22,7 @@ var snapshotCmd = &cobra.Command{
res, err := internalclient.NetMapSnapshot(prm)
common.ExitOnErr(cmd, "rpc error: %w", err)
prettyPrintNetMap(cmd, res.NetMap())
common.PrettyPrintNetMap(cmd, res.NetMap())
},
}
@ -33,35 +30,3 @@ func initSnapshotCmd() {
commonflags.Init(snapshotCmd)
commonflags.InitAPI(snapshotCmd)
}
func prettyPrintNetMap(cmd *cobra.Command, nm netmap.NetMap) {
cmd.Println("Epoch:", nm.Epoch())
nodes := nm.Nodes()
for i := range nodes {
var strState string
switch {
default:
strState = "STATE_UNSUPPORTED"
case nodes[i].IsOnline():
strState = "ONLINE"
case nodes[i].IsOffline():
strState = "OFFLINE"
case nodes[i].IsMaintenance():
strState = "MAINTENANCE"
}
cmd.Printf("Node %d: %s %s ", i+1, hex.EncodeToString(nodes[i].PublicKey()), strState)
netmap.IterateNetworkEndpoints(nodes[i], func(endpoint string) {
cmd.Printf("%s ", endpoint)
})
cmd.Println()
nodes[i].IterateAttributes(func(key, value string) {
cmd.Printf("\t%s: %s\n", key, value)
})
}
}