forked from TrueCloudLab/frostfs-node
[#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>
This commit is contained in:
parent
6557f5d249
commit
5e493b7f1c
10 changed files with 157 additions and 64 deletions
|
@ -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)
|
||||
|
|
49
cmd/neofs-cli/internal/common/netmap.go
Normal file
49
cmd/neofs-cli/internal/common/netmap.go
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
)
|
||||
|
|
62
cmd/neofs-cli/modules/container/nodes.go
Normal file
62
cmd/neofs-cli/modules/container/nodes.go
Normal 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")
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue