diff --git a/cmd/neofs-cli/modules/control/root.go b/cmd/neofs-cli/modules/control/root.go index 07041a1ab..31459d030 100644 --- a/cmd/neofs-cli/modules/control/root.go +++ b/cmd/neofs-cli/modules/control/root.go @@ -32,6 +32,7 @@ func init() { dropObjectsCmd, snapshotCmd, shardsCmd, + synchronizeTreeCmd, ) initControlHealthCheckCmd() @@ -39,4 +40,5 @@ func init() { initControlDropObjectsCmd() initControlSnapshotCmd() initControlShardsCmd() + initControlSynchronizeTreeCmd() } diff --git a/cmd/neofs-cli/modules/control/synchronize_tree.go b/cmd/neofs-cli/modules/control/synchronize_tree.go new file mode 100644 index 000000000..07696a0e9 --- /dev/null +++ b/cmd/neofs-cli/modules/control/synchronize_tree.go @@ -0,0 +1,79 @@ +package control + +import ( + "crypto/sha256" + "errors" + + rawclient "github.com/nspcc-dev/neofs-api-go/v2/rpc/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-node/pkg/services/control" + controlSvc "github.com/nspcc-dev/neofs-node/pkg/services/control/server" + cid "github.com/nspcc-dev/neofs-sdk-go/container/id" + "github.com/spf13/cobra" +) + +const ( + synchronizeTreeIDFlag = "tree-id" + synchronizeTreeHeightFlag = "height" +) + +var synchronizeTreeCmd = &cobra.Command{ + Use: "synchronize-tree", + Short: "Synchronize log for the tree", + Long: "Synchronize log for the tree in an object tree service.", + Run: synchronizeTree, +} + +func initControlSynchronizeTreeCmd() { + commonflags.InitWithoutRPC(synchronizeTreeCmd) + + flags := synchronizeTreeCmd.Flags() + flags.String(controlRPC, controlRPCDefault, controlRPCUsage) + flags.String("cid", "", "Container ID") + flags.String(synchronizeTreeIDFlag, "", "Tree ID") + flags.Uint64(synchronizeTreeHeightFlag, 0, "Starting height") +} + +func synchronizeTree(cmd *cobra.Command, _ []string) { + pk := key.Get(cmd) + + var cnr cid.ID + cidStr, _ := cmd.Flags().GetString("cid") + common.ExitOnErr(cmd, "can't decode container ID: %w", cnr.DecodeString(cidStr)) + + treeID, _ := cmd.Flags().GetString("tree-id") + if treeID == "" { + common.ExitOnErr(cmd, "", errors.New("tree ID must not be empty")) + } + + height, _ := cmd.Flags().GetUint64("height") + + rawCID := make([]byte, sha256.Size) + cnr.Encode(rawCID) + + req := &control.SynchronizeTreeRequest{ + Body: &control.SynchronizeTreeRequest_Body{ + ContainerId: rawCID, + TreeId: treeID, + Height: height, + }, + } + + err := controlSvc.SignMessage(pk, req) + common.ExitOnErr(cmd, "could not sign request: %w", err) + + cli := getClient(cmd, pk) + + var resp *control.SynchronizeTreeResponse + err = cli.ExecRaw(func(client *rawclient.Client) error { + resp, err = control.SynchronizeTree(client, req) + return err + }) + common.ExitOnErr(cmd, "rpc error: %w", err) + + verifyResponse(cmd, resp.GetSignature(), resp.GetBody()) + + cmd.Println("Tree has been synchronized successfully.") +}