From 37dfbf3a1c92a61f9bf10e5250d1721e213309da Mon Sep 17 00:00:00 2001 From: Ekaterina Pavlova Date: Mon, 28 Aug 2023 19:12:40 +0400 Subject: [PATCH] neofs-adm: add new command morph netmap-candidates This command lists netmap candidates in the netmap contract. It allows checking if a node has been bootstrapped successfully. Closes #1889. Signed-off-by: Ekaterina Pavlova --- CHANGELOG.md | 1 + .../modules/morph/netmap-candidates.go | 80 +++++++++++++++++++ cmd/neofs-adm/internal/modules/morph/root.go | 11 +++ pkg/morph/client/netmap/netmap.go | 6 +- pkg/morph/client/netmap/snapshot.go | 2 +- 5 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 cmd/neofs-adm/internal/modules/morph/netmap-candidates.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d0283f7654..cac16d7ad74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ minor release, the component will be purged, so be prepared (see `Updating` sect - Validation of excessive positional arguments to `neofs-cli` commands (#1941) - `--lifetime` flag to `bearer create` and `object put` CLI commands (#1574) - `--expired-at` flag to `session create` and `storagegroup put` CLI commands (#1574) +- `neofs-adm morph netmap-candidates` command (#1889) ### Fixed - `neo-go` RPC connection loss handling (#1337) diff --git a/cmd/neofs-adm/internal/modules/morph/netmap-candidates.go b/cmd/neofs-adm/internal/modules/morph/netmap-candidates.go new file mode 100644 index 00000000000..413ec4c7ef4 --- /dev/null +++ b/cmd/neofs-adm/internal/modules/morph/netmap-candidates.go @@ -0,0 +1,80 @@ +package morph + +import ( + "encoding/hex" + "fmt" + + "github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker" + "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap" + neofsnetmap "github.com/nspcc-dev/neofs-sdk-go/netmap" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func listNetmapCandidatesNodes(cmd *cobra.Command, _ []string) error { + c, err := getN3Client(viper.GetViper()) + if err != nil { + return err + } + + inv := invoker.New(c, nil) + + nnsCs, err := c.GetContractStateByID(1) + if err != nil { + return fmt.Errorf("can't get NNS contract info: %w", err) + } + + nmHash, err := nnsResolveHash(inv, nnsCs.Hash, netmapContract+".neofs") + if err != nil { + return fmt.Errorf("can't get netmap contract hash: %w", err) + } + + res, err := inv.Call(nmHash, "netmapCandidates") + if err != nil { + return fmt.Errorf("can't fetch list of network config keys from the netmap contract: %w", err) + } + + nm, err := netmap.DecodeNetMap(res.Stack) + + if err != nil { + return fmt.Errorf("unable to decode netmap: %w", err) + } + cmd.Println("Epoch:", nm.Epoch()) + + nodes := nm.Nodes() + for i := range nodes { + PrettyPrintNodeInfo(cmd, nodes[i], i, "", false) + } + return nil +} + +// PrettyPrintNodeInfo and PrettyPrintNetMap copied from +// "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common", can be imported but new package is needed. +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) + + neofsnetmap.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) + }) + } +} diff --git a/cmd/neofs-adm/internal/modules/morph/root.go b/cmd/neofs-adm/internal/modules/morph/root.go index bbbc8f71ad4..27f237ccd71 100644 --- a/cmd/neofs-adm/internal/modules/morph/root.go +++ b/cmd/neofs-adm/internal/modules/morph/root.go @@ -245,6 +245,15 @@ var ( }, RunE: depositNotary, } + netmapCandidatesCmd = &cobra.Command{ + Use: "netmap-candidates", + Short: "List netmap candidates nodes", + PreRun: func(cmd *cobra.Command, _ []string) { + _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) + //_ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) + }, + RunE: listNetmapCandidatesNodes, + } ) func init() { @@ -350,4 +359,6 @@ func init() { depositNotaryCmd.Flags().String(walletAccountFlag, "", "Wallet account address") depositNotaryCmd.Flags().String(refillGasAmountFlag, "", "Amount of GAS to deposit") depositNotaryCmd.Flags().String(notaryDepositTillFlag, "", "Notary deposit duration in blocks") + RootCmd.AddCommand(netmapCandidatesCmd) + netmapCandidatesCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") } diff --git a/pkg/morph/client/netmap/netmap.go b/pkg/morph/client/netmap/netmap.go index d2222162367..921cf280ceb 100644 --- a/pkg/morph/client/netmap/netmap.go +++ b/pkg/morph/client/netmap/netmap.go @@ -22,7 +22,7 @@ func (c *Client) GetNetMapByEpoch(epoch uint64) (*netmap.NetMap, error) { epochSnapshotMethod, err) } - nm, err := decodeNetMap(res) + nm, err := DecodeNetMap(res) if err != nil { return nil, err } @@ -61,10 +61,10 @@ func (c *Client) NetMap() (*netmap.NetMap, error) { netMapMethod, err) } - return decodeNetMap(res) + return DecodeNetMap(res) } -func decodeNetMap(resStack []stackitem.Item) (*netmap.NetMap, error) { +func DecodeNetMap(resStack []stackitem.Item) (*netmap.NetMap, error) { var nm netmap.NetMap if len(resStack) > 0 { diff --git a/pkg/morph/client/netmap/snapshot.go b/pkg/morph/client/netmap/snapshot.go index 1896225a27a..f5e93ea43a1 100644 --- a/pkg/morph/client/netmap/snapshot.go +++ b/pkg/morph/client/netmap/snapshot.go @@ -16,5 +16,5 @@ func (c *Client) GetNetMap(diff uint64) (*netmap.NetMap, error) { return nil, err } - return decodeNetMap(res) + return DecodeNetMap(res) }