forked from TrueCloudLab/frostfs-node
[#979] adm/subnet: Add commands to add/remove nodes
Implement `ManageNodes` operation on morph subnet client. Add `node add` and `node remove` commands to `subnet` section. Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
579c3717a5
commit
98e0792b08
2 changed files with 179 additions and 0 deletions
|
@ -646,6 +646,117 @@ var cmdSubnetClientRemove = &cobra.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cmdSubnetNode flags.
|
||||||
|
const (
|
||||||
|
// node ID
|
||||||
|
flagSubnetNode = "id"
|
||||||
|
// ID of the subnet to be managed
|
||||||
|
flagSubnetNodeSubnet = flagSubnet
|
||||||
|
)
|
||||||
|
|
||||||
|
// common executor cmdSubnetNodeAdd and cmdSubnetNodeRemove commands.
|
||||||
|
func manageSubnetNodes(cmd *cobra.Command, rm bool) error {
|
||||||
|
// read private key
|
||||||
|
var key keys.PrivateKey
|
||||||
|
|
||||||
|
err := readSubnetKey(&key)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("read private key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// read ID and encode it
|
||||||
|
var id subnetid.ID
|
||||||
|
|
||||||
|
err = id.UnmarshalText([]byte(viper.GetString(flagSubnetNodeSubnet)))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("decode ID text: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if subnetid.IsZero(id) {
|
||||||
|
return errZeroSubnet
|
||||||
|
}
|
||||||
|
|
||||||
|
binID, err := id.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("marshal subnet ID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// read node ID and encode it
|
||||||
|
binNodeID, err := hex.DecodeString(viper.GetString(flagSubnetNode))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("decode node ID text: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var pubkey keys.PublicKey
|
||||||
|
if err = pubkey.DecodeBytes(binNodeID); err != nil {
|
||||||
|
return fmt.Errorf("node ID format: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var prm morphsubnet.ManageNodesPrm
|
||||||
|
|
||||||
|
prm.SetSubnet(binID)
|
||||||
|
prm.SetNode(binNodeID)
|
||||||
|
|
||||||
|
if rm {
|
||||||
|
prm.SetRemove()
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize morph subnet client
|
||||||
|
var cSubnet morphsubnet.Client
|
||||||
|
|
||||||
|
err = initSubnetClient(&cSubnet, &key)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("init subnet client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = cSubnet.ManageNodes(prm)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("morph call: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var op string
|
||||||
|
|
||||||
|
if rm {
|
||||||
|
op = "Remove"
|
||||||
|
} else {
|
||||||
|
op = "Add"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Printf("%s node request sent successfully.\n", op)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// command to manage subnet nodes.
|
||||||
|
var cmdSubnetNode = &cobra.Command{
|
||||||
|
Use: "node",
|
||||||
|
Short: "Manage nodes of the NeoFS subnet.",
|
||||||
|
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
viperBindFlags(cmd,
|
||||||
|
flagSubnetNode,
|
||||||
|
flagSubnetNodeSubnet,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// command to add subnet node.
|
||||||
|
var cmdSubnetNodeAdd = &cobra.Command{
|
||||||
|
Use: "add",
|
||||||
|
Short: "Add node to the NeoFS subnet.",
|
||||||
|
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||||
|
return manageSubnetNodes(cmd, false)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// command to remove subnet node.
|
||||||
|
var cmdSubnetNodeRemove = &cobra.Command{
|
||||||
|
Use: "remove",
|
||||||
|
Short: "Remove node from the NeoFS subnet.",
|
||||||
|
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||||
|
return manageSubnetNodes(cmd, true)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// returns function which calls PreRun on parent if it exists.
|
// returns function which calls PreRun on parent if it exists.
|
||||||
func inheritPreRun(preRun func(*cobra.Command, []string)) func(*cobra.Command, []string) {
|
func inheritPreRun(preRun func(*cobra.Command, []string)) func(*cobra.Command, []string) {
|
||||||
return func(cmd *cobra.Command, args []string) {
|
return func(cmd *cobra.Command, args []string) {
|
||||||
|
@ -718,6 +829,19 @@ func init() {
|
||||||
cmdSubnetClientRemove,
|
cmdSubnetClientRemove,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// subnet node flags
|
||||||
|
nodeFlags := cmdSubnetNode.PersistentFlags()
|
||||||
|
nodeFlags.String(flagSubnetNode, "", "Hex-encoded public key of the node")
|
||||||
|
_ = cmdSubnetAdmin.MarkFlagRequired(flagSubnetNode)
|
||||||
|
nodeFlags.String(flagSubnetNodeSubnet, "", "ID of the subnet to manage nodes")
|
||||||
|
_ = cmdSubnetNode.MarkFlagRequired(flagSubnetNodeSubnet)
|
||||||
|
|
||||||
|
// add all node managing commands to corresponding command section
|
||||||
|
addCommandInheritPreRun(cmdSubnetNode,
|
||||||
|
cmdSubnetNodeAdd,
|
||||||
|
cmdSubnetNodeRemove,
|
||||||
|
)
|
||||||
|
|
||||||
// subnet global flags
|
// subnet global flags
|
||||||
cmdSubnetFlags := cmdSubnet.PersistentFlags()
|
cmdSubnetFlags := cmdSubnet.PersistentFlags()
|
||||||
cmdSubnetFlags.StringP(flagSubnetEndpoint, "r", "", "N3 RPC node endpoint")
|
cmdSubnetFlags.StringP(flagSubnetEndpoint, "r", "", "N3 RPC node endpoint")
|
||||||
|
@ -735,5 +859,6 @@ func init() {
|
||||||
cmdSubnetGet,
|
cmdSubnetGet,
|
||||||
cmdSubnetAdmin,
|
cmdSubnetAdmin,
|
||||||
cmdSubnetClient,
|
cmdSubnetClient,
|
||||||
|
cmdSubnetNode,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
54
pkg/morph/client/subnet/nodes.go
Normal file
54
pkg/morph/client/subnet/nodes.go
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package morphsubnet
|
||||||
|
|
||||||
|
import "github.com/nspcc-dev/neofs-node/pkg/morph/client"
|
||||||
|
|
||||||
|
// ManageNodesPrm groups parameters of node management in Subnet contract.
|
||||||
|
//
|
||||||
|
// Zero value adds node to subnet. Subnet and node IDs must be specified via setters.
|
||||||
|
type ManageNodesPrm struct {
|
||||||
|
// remove or add node
|
||||||
|
rm bool
|
||||||
|
|
||||||
|
args [2]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRemove marks node to be removed. By default, node is added.
|
||||||
|
func (x *ManageNodesPrm) SetRemove() {
|
||||||
|
x.rm = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSubnet sets identifier of the subnet in a binary NeoFS API protocol format.
|
||||||
|
func (x *ManageNodesPrm) SetSubnet(id []byte) {
|
||||||
|
x.args[0] = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNode sets node's public key in a binary format.
|
||||||
|
func (x *ManageNodesPrm) SetNode(id []byte) {
|
||||||
|
x.args[1] = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// ManageNodesRes groups resulting values of node management methods of Subnet contract.
|
||||||
|
type ManageNodesRes struct{}
|
||||||
|
|
||||||
|
// ManageNodes manages node list of the NeoFS subnet through Subnet contract calls.
|
||||||
|
func (x Client) ManageNodes(prm ManageNodesPrm) (*ManageNodesRes, error) {
|
||||||
|
var method string
|
||||||
|
|
||||||
|
if prm.rm {
|
||||||
|
method = "removeNode"
|
||||||
|
} else {
|
||||||
|
method = "addNode"
|
||||||
|
}
|
||||||
|
|
||||||
|
var prmInvoke client.InvokePrm
|
||||||
|
|
||||||
|
prmInvoke.SetMethod(method)
|
||||||
|
prmInvoke.SetArgs(prm.args[:]...)
|
||||||
|
|
||||||
|
err := x.client.Invoke(prmInvoke)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return new(ManageNodesRes), nil
|
||||||
|
}
|
Loading…
Reference in a new issue