From 5466e884447401fa8d7441683111ac0b5a13608c Mon Sep 17 00:00:00 2001
From: Dmitrii Stepanov <d.stepanov@yadro.com>
Date: Tue, 7 Nov 2023 17:35:09 +0300
Subject: [PATCH] [#787] cli: Add `vub` for `control ir` commands

Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
---
 cmd/frostfs-cli/modules/control/ir.go             | 15 ++++++++++++++-
 .../modules/control/ir_remove_container.go        |  6 +++++-
 cmd/frostfs-cli/modules/control/ir_remove_node.go |  4 +++-
 cmd/frostfs-cli/modules/control/ir_tick_epoch.go  |  7 +++++--
 cmd/frostfs-cli/modules/control/util.go           | 11 +++++++++++
 5 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/cmd/frostfs-cli/modules/control/ir.go b/cmd/frostfs-cli/modules/control/ir.go
index ac1371db7..2a38f1e97 100644
--- a/cmd/frostfs-cli/modules/control/ir.go
+++ b/cmd/frostfs-cli/modules/control/ir.go
@@ -1,6 +1,9 @@
 package control
 
-import "github.com/spf13/cobra"
+import (
+	commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
+	"github.com/spf13/cobra"
+)
 
 var irCmd = &cobra.Command{
 	Use:   "ir",
@@ -19,3 +22,13 @@ func initControlIRCmd() {
 	initControlIRHealthCheckCmd()
 	initControlIRRemoveContainerCmd()
 }
+
+func printVUB(cmd *cobra.Command, vub uint32) {
+	cmd.Printf("Transaction's valid until block is %d\n", vub)
+}
+
+func parseVUB(cmd *cobra.Command) uint32 {
+	vub, err := cmd.Flags().GetUint32(irFlagNameVUB)
+	commonCmd.ExitOnErr(cmd, "invalid valid until block value: %w", err)
+	return vub
+}
diff --git a/cmd/frostfs-cli/modules/control/ir_remove_container.go b/cmd/frostfs-cli/modules/control/ir_remove_container.go
index 43173bcaa..52eaa574d 100644
--- a/cmd/frostfs-cli/modules/control/ir_remove_container.go
+++ b/cmd/frostfs-cli/modules/control/ir_remove_container.go
@@ -29,7 +29,7 @@ To check removal status "frostfs-cli container list" command can be used.`,
 }
 
 func initControlIRRemoveContainerCmd() {
-	initControlFlags(removeContainerCmd)
+	initControlIRFlags(removeContainerCmd)
 
 	flags := removeContainerCmd.Flags()
 	flags.String(commonflags.CIDFlag, "", commonflags.CIDFlagUsage)
@@ -60,6 +60,7 @@ func removeContainer(cmd *cobra.Command, _ []string) {
 	} else {
 		cmd.Println("User containers sheduled to removal")
 	}
+	printVUB(cmd, resp.GetBody().GetVub())
 }
 
 func prepareRemoveContainerRequest(cmd *cobra.Command) *ircontrol.RemoveContainerRequest {
@@ -90,5 +91,8 @@ func prepareRemoveContainerRequest(cmd *cobra.Command) *ircontrol.RemoveContaine
 		commonCmd.ExitOnErr(cmd, "invalid container ID: %w", containerID.DecodeString(cidStr))
 		req.Body.ContainerId = containerID[:]
 	}
+
+	req.Body.Vub = parseVUB(cmd)
+
 	return req
 }
diff --git a/cmd/frostfs-cli/modules/control/ir_remove_node.go b/cmd/frostfs-cli/modules/control/ir_remove_node.go
index f5b968b7f..412dc7934 100644
--- a/cmd/frostfs-cli/modules/control/ir_remove_node.go
+++ b/cmd/frostfs-cli/modules/control/ir_remove_node.go
@@ -20,7 +20,7 @@ var removeNodeCmd = &cobra.Command{
 }
 
 func initControlIRRemoveNodeCmd() {
-	initControlFlags(removeNodeCmd)
+	initControlIRFlags(removeNodeCmd)
 
 	flags := removeNodeCmd.Flags()
 	flags.String("node", "", "Node public key as a hex string")
@@ -41,6 +41,7 @@ func removeNode(cmd *cobra.Command, _ []string) {
 	req := new(ircontrol.RemoveNodeRequest)
 	req.SetBody(&ircontrol.RemoveNodeRequest_Body{
 		Key: nodeKey,
+		Vub: parseVUB(cmd),
 	})
 
 	commonCmd.ExitOnErr(cmd, "could not sign request: %w", ircontrolsrv.SignMessage(pk, req))
@@ -55,4 +56,5 @@ func removeNode(cmd *cobra.Command, _ []string) {
 	verifyResponse(cmd, resp.GetSignature(), resp.GetBody())
 
 	cmd.Println("Node removed")
+	printVUB(cmd, resp.GetBody().GetVub())
 }
diff --git a/cmd/frostfs-cli/modules/control/ir_tick_epoch.go b/cmd/frostfs-cli/modules/control/ir_tick_epoch.go
index 3e6af0081..6965b5dca 100644
--- a/cmd/frostfs-cli/modules/control/ir_tick_epoch.go
+++ b/cmd/frostfs-cli/modules/control/ir_tick_epoch.go
@@ -17,7 +17,7 @@ var tickEpochCmd = &cobra.Command{
 }
 
 func initControlIRTickEpochCmd() {
-	initControlFlags(tickEpochCmd)
+	initControlIRFlags(tickEpochCmd)
 }
 
 func tickEpoch(cmd *cobra.Command, _ []string) {
@@ -25,7 +25,9 @@ func tickEpoch(cmd *cobra.Command, _ []string) {
 	c := getClient(cmd, pk)
 
 	req := new(ircontrol.TickEpochRequest)
-	req.SetBody(new(ircontrol.TickEpochRequest_Body))
+	req.SetBody(&ircontrol.TickEpochRequest_Body{
+		Vub: parseVUB(cmd),
+	})
 
 	err := ircontrolsrv.SignMessage(pk, req)
 	commonCmd.ExitOnErr(cmd, "could not sign request: %w", err)
@@ -40,4 +42,5 @@ func tickEpoch(cmd *cobra.Command, _ []string) {
 	verifyResponse(cmd, resp.GetSignature(), resp.GetBody())
 
 	cmd.Println("Epoch tick requested")
+	printVUB(cmd, resp.GetBody().GetVub())
 }
diff --git a/cmd/frostfs-cli/modules/control/util.go b/cmd/frostfs-cli/modules/control/util.go
index 5ad675c0e..ffaceff13 100644
--- a/cmd/frostfs-cli/modules/control/util.go
+++ b/cmd/frostfs-cli/modules/control/util.go
@@ -14,6 +14,10 @@ import (
 	"github.com/spf13/cobra"
 )
 
+const (
+	irFlagNameVUB = "vub"
+)
+
 func initControlFlags(cmd *cobra.Command) {
 	ff := cmd.Flags()
 	ff.StringP(commonflags.WalletPath, commonflags.WalletPathShorthand, commonflags.WalletPathDefault, commonflags.WalletPathUsage)
@@ -22,6 +26,13 @@ func initControlFlags(cmd *cobra.Command) {
 	ff.DurationP(commonflags.Timeout, commonflags.TimeoutShorthand, commonflags.TimeoutDefault, commonflags.TimeoutUsage)
 }
 
+func initControlIRFlags(cmd *cobra.Command) {
+	initControlFlags(cmd)
+
+	ff := cmd.Flags()
+	ff.Uint32(irFlagNameVUB, 0, "Valid until block value for notary transaction")
+}
+
 func signRequest(cmd *cobra.Command, pk *ecdsa.PrivateKey, req controlSvc.SignedMessage) {
 	err := controlSvc.SignMessage(pk, req)
 	commonCmd.ExitOnErr(cmd, "could not sign request: %w", err)