[#390] cli: Support more tree service API calls in CLI #488
10 changed files with 455 additions and 20 deletions
|
@ -50,24 +50,29 @@ func add(cmd *cobra.Command, _ []string) {
|
||||||
ctx := cmd.Context()
|
ctx := cmd.Context()
|
||||||
|
|
||||||
cli, err := _client(ctx)
|
cli, err := _client(ctx)
|
||||||
commonCmd.ExitOnErr(cmd, "client: %w", err)
|
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||||
|
|
||||||
rawCID := make([]byte, sha256.Size)
|
rawCID := make([]byte, sha256.Size)
|
||||||
cnr.Encode(rawCID)
|
cnr.Encode(rawCID)
|
||||||
|
|
||||||
|
var bt []byte
|
||||||
|
if t := common.ReadBearerToken(cmd, bearerFlagKey); t != nil {
|
||||||
|
bt = t.Marshal()
|
||||||
|
}
|
||||||
|
|
||||||
req := new(tree.AddRequest)
|
req := new(tree.AddRequest)
|
||||||
req.Body = &tree.AddRequest_Body{
|
req.Body = &tree.AddRequest_Body{
|
||||||
ContainerId: rawCID,
|
ContainerId: rawCID,
|
||||||
TreeId: tid,
|
TreeId: tid,
|
||||||
ParentId: pid,
|
ParentId: pid,
|
||||||
Meta: meta,
|
Meta: meta,
|
||||||
BearerToken: common.ReadBearerToken(cmd, bearerFlagKey).Marshal(),
|
BearerToken: bt,
|
||||||
}
|
}
|
||||||
|
|
||||||
commonCmd.ExitOnErr(cmd, "message signing: %w", tree.SignMessage(req, pk))
|
commonCmd.ExitOnErr(cmd, "signing message: %w", tree.SignMessage(req, pk))
|
||||||
|
|
||||||
resp, err := cli.Add(ctx, req)
|
resp, err := cli.Add(ctx, req)
|
||||||
commonCmd.ExitOnErr(cmd, "rpc call: %w", err)
|
commonCmd.ExitOnErr(cmd, "failed to cal add: %w", err)
|
||||||
|
|
||||||
cmd.Println("Node ID: ", resp.Body.NodeId)
|
cmd.Println("Node ID: ", resp.Body.NodeId)
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ func addByPath(cmd *cobra.Command, _ []string) {
|
||||||
ctx := cmd.Context()
|
ctx := cmd.Context()
|
||||||
|
|
||||||
cli, err := _client(ctx)
|
cli, err := _client(ctx)
|
||||||
commonCmd.ExitOnErr(cmd, "client: %w", err)
|
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||||
|
|
||||||
rawCID := make([]byte, sha256.Size)
|
rawCID := make([]byte, sha256.Size)
|
||||||
cnr.Encode(rawCID)
|
cnr.Encode(rawCID)
|
||||||
|
@ -62,7 +62,11 @@ func addByPath(cmd *cobra.Command, _ []string) {
|
||||||
commonCmd.ExitOnErr(cmd, "meta data parsing: %w", err)
|
commonCmd.ExitOnErr(cmd, "meta data parsing: %w", err)
|
||||||
|
|
||||||
path, _ := cmd.Flags().GetString(pathFlagKey)
|
path, _ := cmd.Flags().GetString(pathFlagKey)
|
||||||
// pAttr, _ := cmd.Flags().GetString(pathAttributeFlagKey)
|
|
||||||
|
var bt []byte
|
||||||
|
if t := common.ReadBearerToken(cmd, bearerFlagKey); t != nil {
|
||||||
|
bt = t.Marshal()
|
||||||
|
}
|
||||||
|
|
||||||
req := new(tree.AddByPathRequest)
|
req := new(tree.AddByPathRequest)
|
||||||
req.Body = &tree.AddByPathRequest_Body{
|
req.Body = &tree.AddByPathRequest_Body{
|
||||||
|
@ -72,13 +76,13 @@ func addByPath(cmd *cobra.Command, _ []string) {
|
||||||
// PathAttribute: pAttr,
|
// PathAttribute: pAttr,
|
||||||
Path: strings.Split(path, "/"),
|
Path: strings.Split(path, "/"),
|
||||||
Meta: meta,
|
Meta: meta,
|
||||||
BearerToken: common.ReadBearerToken(cmd, bearerFlagKey).Marshal(),
|
BearerToken: bt,
|
||||||
}
|
}
|
||||||
|
|
||||||
commonCmd.ExitOnErr(cmd, "message signing: %w", tree.SignMessage(req, pk))
|
commonCmd.ExitOnErr(cmd, "signing message: %w", tree.SignMessage(req, pk))
|
||||||
|
|
||||||
resp, err := cli.AddByPath(ctx, req)
|
resp, err := cli.AddByPath(ctx, req)
|
||||||
commonCmd.ExitOnErr(cmd, "rpc call: %w", err)
|
commonCmd.ExitOnErr(cmd, "failed to addByPath %w", err)
|
||||||
|
|
||||||
cmd.Printf("Parent ID: %d\n", resp.GetBody().GetParentId())
|
cmd.Printf("Parent ID: %d\n", resp.GetBody().GetParentId())
|
||||||
|
|
||||||
|
|
|
@ -53,14 +53,18 @@ func getByPath(cmd *cobra.Command, _ []string) {
|
||||||
ctx := cmd.Context()
|
ctx := cmd.Context()
|
||||||
|
|
||||||
cli, err := _client(ctx)
|
cli, err := _client(ctx)
|
||||||
commonCmd.ExitOnErr(cmd, "client: %w", err)
|
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||||
|
|
||||||
rawCID := make([]byte, sha256.Size)
|
rawCID := make([]byte, sha256.Size)
|
||||||
cnr.Encode(rawCID)
|
cnr.Encode(rawCID)
|
||||||
|
|
||||||
latestOnly, _ := cmd.Flags().GetBool(latestOnlyFlagKey)
|
latestOnly, _ := cmd.Flags().GetBool(latestOnlyFlagKey)
|
||||||
path, _ := cmd.Flags().GetString(pathFlagKey)
|
path, _ := cmd.Flags().GetString(pathFlagKey)
|
||||||
// pAttr, _ := cmd.Flags().GetString(pathAttributeFlagKey)
|
|
||||||
|
var bt []byte
|
||||||
|
if t := common.ReadBearerToken(cmd, bearerFlagKey); t != nil {
|
||||||
|
bt = t.Marshal()
|
||||||
|
}
|
||||||
|
|
||||||
req := new(tree.GetNodeByPathRequest)
|
req := new(tree.GetNodeByPathRequest)
|
||||||
req.Body = &tree.GetNodeByPathRequest_Body{
|
req.Body = &tree.GetNodeByPathRequest_Body{
|
||||||
|
@ -71,15 +75,13 @@ func getByPath(cmd *cobra.Command, _ []string) {
|
||||||
Path: strings.Split(path, "/"),
|
Path: strings.Split(path, "/"),
|
||||||
LatestOnly: latestOnly,
|
LatestOnly: latestOnly,
|
||||||
AllAttributes: true,
|
AllAttributes: true,
|
||||||
}
|
BearerToken: bt,
|
||||||
if btok := common.ReadBearerToken(cmd, bearerFlagKey); btok != nil {
|
|
||||||
req.Body.BearerToken = btok.Marshal()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
commonCmd.ExitOnErr(cmd, "message signing: %w", tree.SignMessage(req, pk))
|
commonCmd.ExitOnErr(cmd, "signing message: %w", tree.SignMessage(req, pk))
|
||||||
|
|
||||||
resp, err := cli.GetNodeByPath(ctx, req)
|
resp, err := cli.GetNodeByPath(ctx, req)
|
||||||
commonCmd.ExitOnErr(cmd, "rpc call: %w", err)
|
commonCmd.ExitOnErr(cmd, "failed to call getNodeByPath: %w", err)
|
||||||
|
|
||||||
nn := resp.GetBody().GetNodes()
|
nn := resp.GetBody().GetNodes()
|
||||||
if len(nn) == 0 {
|
if len(nn) == 0 {
|
||||||
|
|
83
cmd/frostfs-cli/modules/tree/get_op_log.go
Normal file
83
cmd/frostfs-cli/modules/tree/get_op_log.go
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package tree
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/tree"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var getOpLogCmd = &cobra.Command{
|
||||||
|
Use: "get-op-log",
|
||||||
|
Short: "Get logged operations starting with some height",
|
||||||
|
Run: getOpLog,
|
||||||
|
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
commonflags.Bind(cmd)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func initGetOpLogCmd() {
|
||||||
|
commonflags.Init(getOpLogCmd)
|
||||||
|
initCTID(getOpLogCmd)
|
||||||
|
|
||||||
|
ff := getOpLogCmd.Flags()
|
||||||
|
ff.Uint64(heightFlagKey, 0, "Height to start with")
|
||||||
|
ff.Uint64(countFlagKey, 10, "Logged operations count")
|
||||||
|
|
||||||
|
_ = cobra.MarkFlagRequired(ff, commonflags.RPC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOpLog(cmd *cobra.Command, _ []string) {
|
||||||
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
|
cidRaw, _ := cmd.Flags().GetString(commonflags.CIDFlag)
|
||||||
|
|
||||||
|
var cnr cid.ID
|
||||||
|
err := cnr.DecodeString(cidRaw)
|
||||||
|
commonCmd.ExitOnErr(cmd, "decode container ID string: %w", err)
|
||||||
|
|
||||||
|
tid, _ := cmd.Flags().GetString(treeIDFlagKey)
|
||||||
|
ctx := cmd.Context()
|
||||||
|
|
||||||
|
cli, err := _client(ctx)
|
||||||
|
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||||
|
|
||||||
|
rawCID := make([]byte, sha256.Size)
|
||||||
|
cnr.Encode(rawCID)
|
||||||
|
|
||||||
|
height, _ := cmd.Flags().GetUint64(heightFlagKey)
|
||||||
|
count, _ := cmd.Flags().GetUint64(countFlagKey)
|
||||||
|
|
||||||
|
req := &tree.GetOpLogRequest{
|
||||||
|
Body: &tree.GetOpLogRequest_Body{
|
||||||
|
ContainerId: rawCID,
|
||||||
|
TreeId: tid,
|
||||||
|
Height: height,
|
||||||
|
Count: count,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
commonCmd.ExitOnErr(cmd, "signing message: %w", tree.SignMessage(req, pk))
|
||||||
|
|
||||||
|
resp, err := cli.GetOpLog(ctx, req)
|
||||||
|
commonCmd.ExitOnErr(cmd, "get op log: %w", err)
|
||||||
|
|
||||||
|
opLogResp, err := resp.Recv()
|
||||||
|
for ; err == nil; opLogResp, err = resp.Recv() {
|
||||||
|
o := opLogResp.GetBody().GetOperation()
|
||||||
|
|
||||||
|
cmd.Println("Parent ID: ", o.GetParentId())
|
||||||
|
|
||||||
|
cmd.Println("\tChild ID: ", o.GetChildId())
|
||||||
|
cmd.Printf("\tMeta: %s\n", o.GetMeta())
|
||||||
|
}
|
||||||
|
if !errors.Is(err, io.EOF) {
|
||||||
|
commonCmd.ExitOnErr(cmd, "get op log response stream: %w", err)
|
||||||
|
}
|
||||||
|
}
|
43
cmd/frostfs-cli/modules/tree/healthcheck.go
Normal file
43
cmd/frostfs-cli/modules/tree/healthcheck.go
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package tree
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/tree"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var healthcheckCmd = &cobra.Command{
|
||||||
|
Use: "healthcheck",
|
||||||
|
Short: "Check tree service availability",
|
||||||
|
Run: healthcheck,
|
||||||
|
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
commonflags.Bind(cmd)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func initHealthcheckCmd() {
|
||||||
|
commonflags.Init(healthcheckCmd)
|
||||||
|
ff := healthcheckCmd.Flags()
|
||||||
|
_ = cobra.MarkFlagRequired(ff, commonflags.RPC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func healthcheck(cmd *cobra.Command, _ []string) {
|
||||||
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
ctx := cmd.Context()
|
||||||
|
|
||||||
|
cli, err := _client(ctx)
|
||||||
|
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||||
|
|
||||||
|
req := &tree.HealthcheckRequest{
|
||||||
|
Body: &tree.HealthcheckRequest_Body{},
|
||||||
|
}
|
||||||
|
commonCmd.ExitOnErr(cmd, "signing message: %w", tree.SignMessage(req, pk))
|
||||||
|
|
||||||
|
_, err = cli.Healthcheck(ctx, req)
|
||||||
|
commonCmd.ExitOnErr(cmd, "failed to call healthcheck: %w", err)
|
||||||
|
|
||||||
|
common.PrintVerbose(cmd, "Successful healthcheck invocation.")
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ func list(cmd *cobra.Command, _ []string) {
|
||||||
ctx := cmd.Context()
|
ctx := cmd.Context()
|
||||||
|
|
||||||
cli, err := _client(ctx)
|
cli, err := _client(ctx)
|
||||||
commonCmd.ExitOnErr(cmd, "client: %w", err)
|
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||||
|
|
||||||
rawCID := make([]byte, sha256.Size)
|
rawCID := make([]byte, sha256.Size)
|
||||||
cnr.Encode(rawCID)
|
cnr.Encode(rawCID)
|
||||||
|
@ -52,10 +52,10 @@ func list(cmd *cobra.Command, _ []string) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
commonCmd.ExitOnErr(cmd, "message signing: %w", tree.SignMessage(req, pk))
|
commonCmd.ExitOnErr(cmd, "signing message: %w", tree.SignMessage(req, pk))
|
||||||
|
|
||||||
resp, err := cli.TreeList(ctx, req)
|
resp, err := cli.TreeList(ctx, req)
|
||||||
commonCmd.ExitOnErr(cmd, "rpc call: %w", err)
|
commonCmd.ExitOnErr(cmd, "failed to call treeList %w", err)
|
||||||
|
|
||||||
for _, treeID := range resp.GetBody().GetIds() {
|
for _, treeID := range resp.GetBody().GetIds() {
|
||||||
cmd.Println(treeID)
|
cmd.Println(treeID)
|
||||||
|
|
107
cmd/frostfs-cli/modules/tree/move.go
Normal file
107
cmd/frostfs-cli/modules/tree/move.go
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
package tree
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/tree"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var moveCmd = &cobra.Command{
|
||||||
|
Use: "move",
|
||||||
|
Short: "Move node",
|
||||||
|
Run: move,
|
||||||
|
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
commonflags.Bind(cmd)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func initMoveCmd() {
|
||||||
|
commonflags.Init(moveCmd)
|
||||||
|
initCTID(moveCmd)
|
||||||
|
|
||||||
|
ff := moveCmd.Flags()
|
||||||
|
ff.Uint64(nodeIDFlagKey, 0, "Node ID.")
|
||||||
|
ff.Uint64(parentIDFlagKey, 0, "Parent ID.")
|
||||||
|
|
||||||
|
_ = getSubtreeCmd.MarkFlagRequired(nodeIDFlagKey)
|
||||||
|
_ = getSubtreeCmd.MarkFlagRequired(parentIDFlagKey)
|
||||||
|
|
||||||
|
_ = cobra.MarkFlagRequired(ff, commonflags.RPC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func move(cmd *cobra.Command, _ []string) {
|
||||||
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
cidString, _ := cmd.Flags().GetString(commonflags.CIDFlag)
|
||||||
|
|
||||||
|
var cnr cid.ID
|
||||||
|
err := cnr.DecodeString(cidString)
|
||||||
|
commonCmd.ExitOnErr(cmd, "decode container ID string: %w", err)
|
||||||
|
|
||||||
|
ctx := cmd.Context()
|
||||||
|
|
||||||
|
cli, err := _client(ctx)
|
||||||
|
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||||
|
|
||||||
|
rawCID := make([]byte, sha256.Size)
|
||||||
|
cnr.Encode(rawCID)
|
||||||
|
|
||||||
|
tid, _ := cmd.Flags().GetString(treeIDFlagKey)
|
||||||
|
pid, _ := cmd.Flags().GetUint64(parentIDFlagKey)
|
||||||
|
nid, _ := cmd.Flags().GetUint64(nodeIDFlagKey)
|
||||||
|
|
||||||
|
var bt []byte
|
||||||
|
if t := common.ReadBearerToken(cmd, bearerFlagKey); t != nil {
|
||||||
|
bt = t.Marshal()
|
||||||
|
}
|
||||||
|
|
||||||
|
subTreeReq := &tree.GetSubTreeRequest{
|
||||||
|
Body: &tree.GetSubTreeRequest_Body{
|
||||||
|
ContainerId: rawCID,
|
||||||
|
TreeId: tid,
|
||||||
|
RootId: nid,
|
||||||
|
Depth: 1,
|
||||||
|
BearerToken: bt,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
commonCmd.ExitOnErr(cmd, "signing message: %w", tree.SignMessage(subTreeReq, pk))
|
||||||
|
resp, err := cli.GetSubTree(ctx, subTreeReq)
|
||||||
|
commonCmd.ExitOnErr(cmd, "rpc call: %w", err)
|
||||||
|
|
||||||
|
var meta []*tree.KeyValue
|
||||||
|
subtreeResp, err := resp.Recv()
|
||||||
|
for ; err == nil; subtreeResp, err = resp.Recv() {
|
||||||
|
meta = subtreeResp.GetBody().GetMeta()
|
||||||
|
}
|
||||||
|
if !errors.Is(err, io.EOF) {
|
||||||
|
commonCmd.ExitOnErr(cmd, "failed to read getSubTree response stream: %w", err)
|
||||||
|
}
|
||||||
|
var metaErr error
|
||||||
|
if len(meta) == 0 {
|
||||||
|
metaErr = errors.New("no meta for given node ID")
|
||||||
|
}
|
||||||
|
commonCmd.ExitOnErr(cmd, "unexpected rpc call result: %w", metaErr)
|
||||||
|
|
||||||
|
req := &tree.MoveRequest{
|
||||||
|
Body: &tree.MoveRequest_Body{
|
||||||
|
ContainerId: rawCID,
|
||||||
|
TreeId: tid,
|
||||||
|
ParentId: pid,
|
||||||
|
NodeId: nid,
|
||||||
|
Meta: meta,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
commonCmd.ExitOnErr(cmd, "signing message: %w", tree.SignMessage(req, pk))
|
||||||
|
|
||||||
|
_, err = cli.Move(ctx, req)
|
||||||
|
commonCmd.ExitOnErr(cmd, "failed to call move: %w", err)
|
||||||
|
common.PrintVerbose(cmd, "Successful move invocation.")
|
||||||
|
}
|
74
cmd/frostfs-cli/modules/tree/remove.go
Normal file
74
cmd/frostfs-cli/modules/tree/remove.go
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package tree
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/tree"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var removeCmd = &cobra.Command{
|
||||||
|
Use: "remove",
|
||||||
|
Short: "Remove node",
|
||||||
|
Run: remove,
|
||||||
|
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
commonflags.Bind(cmd)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func initRemoveCmd() {
|
||||||
|
commonflags.Init(removeCmd)
|
||||||
|
initCTID(removeCmd)
|
||||||
|
|
||||||
|
ff := removeCmd.Flags()
|
||||||
|
ff.Uint64(nodeIDFlagKey, 0, "Node ID.")
|
||||||
|
|
||||||
|
_ = getSubtreeCmd.MarkFlagRequired(nodeIDFlagKey)
|
||||||
|
|
||||||
|
_ = cobra.MarkFlagRequired(ff, commonflags.RPC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func remove(cmd *cobra.Command, _ []string) {
|
||||||
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
cidString, _ := cmd.Flags().GetString(commonflags.CIDFlag)
|
||||||
|
|
||||||
|
var cnr cid.ID
|
||||||
|
err := cnr.DecodeString(cidString)
|
||||||
|
commonCmd.ExitOnErr(cmd, "decode container ID string: %w", err)
|
||||||
|
|
||||||
|
ctx := cmd.Context()
|
||||||
|
|
||||||
|
cli, err := _client(ctx)
|
||||||
|
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||||
|
|
||||||
|
rawCID := make([]byte, sha256.Size)
|
||||||
|
cnr.Encode(rawCID)
|
||||||
|
|
||||||
|
tid, _ := cmd.Flags().GetString(treeIDFlagKey)
|
||||||
|
|
||||||
|
nid, _ := cmd.Flags().GetUint64(nodeIDFlagKey)
|
||||||
|
|
||||||
|
var bt []byte
|
||||||
|
if t := common.ReadBearerToken(cmd, bearerFlagKey); t != nil {
|
||||||
|
bt = t.Marshal()
|
||||||
|
}
|
||||||
|
req := &tree.RemoveRequest{
|
||||||
|
Body: &tree.RemoveRequest_Body{
|
||||||
|
ContainerId: rawCID,
|
||||||
|
TreeId: tid,
|
||||||
|
NodeId: nid,
|
||||||
|
BearerToken: bt,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
commonCmd.ExitOnErr(cmd, "signing message: %w", tree.SignMessage(req, pk))
|
||||||
|
|
||||||
|
_, err = cli.Remove(ctx, req)
|
||||||
|
commonCmd.ExitOnErr(cmd, "failed to call remove: %w", err)
|
||||||
|
common.PrintVerbose(cmd, "Successful remove invocation.")
|
||||||
|
}
|
|
@ -15,16 +15,28 @@ func init() {
|
||||||
Cmd.AddCommand(getByPathCmd)
|
Cmd.AddCommand(getByPathCmd)
|
||||||
Cmd.AddCommand(addByPathCmd)
|
Cmd.AddCommand(addByPathCmd)
|
||||||
Cmd.AddCommand(listCmd)
|
Cmd.AddCommand(listCmd)
|
||||||
|
Cmd.AddCommand(healthcheckCmd)
|
||||||
|
Cmd.AddCommand(moveCmd)
|
||||||
|
Cmd.AddCommand(removeCmd)
|
||||||
|
Cmd.AddCommand(getSubtreeCmd)
|
||||||
|
Cmd.AddCommand(getOpLogCmd)
|
||||||
|
|
||||||
initAddCmd()
|
initAddCmd()
|
||||||
initGetByPathCmd()
|
initGetByPathCmd()
|
||||||
initAddByPathCmd()
|
initAddByPathCmd()
|
||||||
initListCmd()
|
initListCmd()
|
||||||
|
initHealthcheckCmd()
|
||||||
|
initMoveCmd()
|
||||||
|
initRemoveCmd()
|
||||||
|
initGetSubtreeCmd()
|
||||||
|
initGetOpLogCmd()
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
treeIDFlagKey = "tid"
|
treeIDFlagKey = "tid"
|
||||||
parentIDFlagKey = "pid"
|
parentIDFlagKey = "pid"
|
||||||
|
nodeIDFlagKey = "nid"
|
||||||
|
rootIDFlagKey = "root"
|
||||||
|
|
||||||
metaFlagKey = "meta"
|
metaFlagKey = "meta"
|
||||||
|
|
||||||
|
@ -34,6 +46,10 @@ const (
|
||||||
latestOnlyFlagKey = "latest"
|
latestOnlyFlagKey = "latest"
|
||||||
|
|
||||||
bearerFlagKey = "bearer"
|
bearerFlagKey = "bearer"
|
||||||
|
|
||||||
|
heightFlagKey = "height"
|
||||||
|
countFlagKey = "count"
|
||||||
|
depthFlagKey = "depth"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initCTID(cmd *cobra.Command) {
|
func initCTID(cmd *cobra.Command) {
|
||||||
|
@ -45,5 +61,5 @@ func initCTID(cmd *cobra.Command) {
|
||||||
ff.String(treeIDFlagKey, "", "Tree ID")
|
ff.String(treeIDFlagKey, "", "Tree ID")
|
||||||
_ = cmd.MarkFlagRequired(treeIDFlagKey)
|
_ = cmd.MarkFlagRequired(treeIDFlagKey)
|
||||||
|
|
||||||
ff.StringP(bearerFlagKey, "", "", "Path to bearer token")
|
ff.String(bearerFlagKey, "", "Path to bearer token")
|
||||||
}
|
}
|
||||||
|
|
101
cmd/frostfs-cli/modules/tree/subtree.go
Normal file
101
cmd/frostfs-cli/modules/tree/subtree.go
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
package tree
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/tree"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var getSubtreeCmd = &cobra.Command{
|
||||||
|
Use: "get-subtree",
|
||||||
|
Short: "Get subtree",
|
||||||
|
Run: getSubTree,
|
||||||
|
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
commonflags.Bind(cmd)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func initGetSubtreeCmd() {
|
||||||
|
commonflags.Init(getSubtreeCmd)
|
||||||
|
initCTID(getSubtreeCmd)
|
||||||
|
|
||||||
|
ff := getSubtreeCmd.Flags()
|
||||||
|
ff.Uint64(rootIDFlagKey, 0, "Root ID to traverse from.")
|
||||||
|
ff.Uint32(depthFlagKey, 10, "Traversal depth.")
|
||||||
|
|
||||||
|
_ = getSubtreeCmd.MarkFlagRequired(commonflags.CIDFlag)
|
||||||
|
_ = getSubtreeCmd.MarkFlagRequired(treeIDFlagKey)
|
||||||
|
|
||||||
|
_ = cobra.MarkFlagRequired(ff, commonflags.RPC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSubTree(cmd *cobra.Command, _ []string) {
|
||||||
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
cidString, _ := cmd.Flags().GetString(commonflags.CIDFlag)
|
||||||
|
|
||||||
|
var cnr cid.ID
|
||||||
|
err := cnr.DecodeString(cidString)
|
||||||
|
commonCmd.ExitOnErr(cmd, "decode container ID string: %w", err)
|
||||||
|
|
||||||
|
ctx := cmd.Context()
|
||||||
|
|
||||||
|
cli, err := _client(ctx)
|
||||||
|
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||||
|
|
||||||
|
rawCID := make([]byte, sha256.Size)
|
||||||
|
cnr.Encode(rawCID)
|
||||||
|
|
||||||
|
tid, _ := cmd.Flags().GetString(treeIDFlagKey)
|
||||||
|
|
||||||
|
rid, _ := cmd.Flags().GetUint64(rootIDFlagKey)
|
||||||
|
|
||||||
|
depth, _ := cmd.Flags().GetUint32(depthFlagKey)
|
||||||
|
|
||||||
|
var bt []byte
|
||||||
|
if t := common.ReadBearerToken(cmd, bearerFlagKey); t != nil {
|
||||||
|
bt = t.Marshal()
|
||||||
|
}
|
||||||
|
|
||||||
|
req := &tree.GetSubTreeRequest{
|
||||||
|
Body: &tree.GetSubTreeRequest_Body{
|
||||||
|
ContainerId: rawCID,
|
||||||
|
TreeId: tid,
|
||||||
|
RootId: rid,
|
||||||
|
Depth: depth,
|
||||||
|
BearerToken: bt,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
commonCmd.ExitOnErr(cmd, "signing message: %w", tree.SignMessage(req, pk))
|
||||||
|
|
||||||
|
resp, err := cli.GetSubTree(ctx, req)
|
||||||
|
commonCmd.ExitOnErr(cmd, "failed to call getSubTree: %w", err)
|
||||||
|
|
||||||
|
subtreeResp, err := resp.Recv()
|
||||||
|
for ; err == nil; subtreeResp, err = resp.Recv() {
|
||||||
|
b := subtreeResp.GetBody()
|
||||||
|
|
||||||
|
cmd.Printf("Node ID: %d\n", b.GetNodeId())
|
||||||
|
|
||||||
|
cmd.Println("\tParent ID: ", b.GetParentId())
|
||||||
|
cmd.Println("\tTimestamp: ", b.GetTimestamp())
|
||||||
|
|
||||||
|
if meta := b.GetMeta(); len(meta) > 0 {
|
||||||
|
cmd.Println("\tMeta pairs: ")
|
||||||
|
for _, kv := range meta {
|
||||||
|
cmd.Printf("\t\t%s: %s\n", kv.GetKey(), string(kv.GetValue()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !errors.Is(err, io.EOF) {
|
||||||
|
commonCmd.ExitOnErr(cmd, "rpc call: %w", err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue