[#390] cli: Support more tree service API calls in CLI #488
|
@ -50,24 +50,29 @@ func add(cmd *cobra.Command, _ []string) {
|
|||
ctx := cmd.Context()
|
||||
|
||||
cli, err := _client(ctx)
|
||||
commonCmd.ExitOnErr(cmd, "client: %w", err)
|
||||
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||
|
||||
|
||||
rawCID := make([]byte, sha256.Size)
|
||||
cnr.Encode(rawCID)
|
||||
|
||||
var bt []byte
|
||||
fyrchik
commented
This also seems like a separate commit with bearer addition to existing methods. This also seems like a separate commit with bearer addition to existing methods.
|
||||
if t := common.ReadBearerToken(cmd, bearerFlagKey); t != nil {
|
||||
bt = t.Marshal()
|
||||
}
|
||||
|
||||
req := new(tree.AddRequest)
|
||||
req.Body = &tree.AddRequest_Body{
|
||||
ContainerId: rawCID,
|
||||
TreeId: tid,
|
||||
ParentId: pid,
|
||||
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))
|
||||
dstepanov-yadro
commented
`signing message` -> `failed to sign request` and so on. I think error messages must be clear for user, not only for developer. Or am I bothering too much? @fyrchik what do you think?
ale64bit
commented
IMHO, it's shorter/easier to structure it this way (i.e. present/past continuous form: actual error). This usually matches well and intuitively looks like IMHO, it's shorter/easier to structure it this way (i.e. present/past continuous form: actual error). This usually matches well and intuitively looks like `what was happening: what went wrong while doing that`.
|
||||
|
||||
resp, err := cli.Add(ctx, req)
|
||||
commonCmd.ExitOnErr(cmd, "rpc call: %w", err)
|
||||
commonCmd.ExitOnErr(cmd, "failed to cal add: %w", err)
|
||||
fyrchik
commented
Please, could you move all wording-only changes to a separate commit? Please, could you move all wording-only changes to a separate commit?
aarifullin
commented
Ofc Ofc
aarifullin
commented
I have splitted the PR into 3 commits. Check this out, please! I have splitted the PR into 3 commits. Check this out, please!
|
||||
|
||||
cmd.Println("Node ID: ", resp.Body.NodeId)
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ func addByPath(cmd *cobra.Command, _ []string) {
|
|||
ctx := cmd.Context()
|
||||
|
||||
cli, err := _client(ctx)
|
||||
commonCmd.ExitOnErr(cmd, "client: %w", err)
|
||||
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||
|
||||
rawCID := make([]byte, sha256.Size)
|
||||
cnr.Encode(rawCID)
|
||||
|
@ -62,7 +62,11 @@ func addByPath(cmd *cobra.Command, _ []string) {
|
|||
commonCmd.ExitOnErr(cmd, "meta data parsing: %w", err)
|
||||
|
||||
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.Body = &tree.AddByPathRequest_Body{
|
||||
|
@ -72,13 +76,13 @@ func addByPath(cmd *cobra.Command, _ []string) {
|
|||
// PathAttribute: pAttr,
|
||||
Path: strings.Split(path, "/"),
|
||||
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)
|
||||
commonCmd.ExitOnErr(cmd, "rpc call: %w", err)
|
||||
commonCmd.ExitOnErr(cmd, "failed to addByPath %w", err)
|
||||
|
||||
cmd.Printf("Parent ID: %d\n", resp.GetBody().GetParentId())
|
||||
|
||||
|
|
|
@ -53,14 +53,18 @@ func getByPath(cmd *cobra.Command, _ []string) {
|
|||
ctx := cmd.Context()
|
||||
|
||||
cli, err := _client(ctx)
|
||||
commonCmd.ExitOnErr(cmd, "client: %w", err)
|
||||
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||
|
||||
rawCID := make([]byte, sha256.Size)
|
||||
cnr.Encode(rawCID)
|
||||
|
||||
latestOnly, _ := cmd.Flags().GetBool(latestOnlyFlagKey)
|
||||
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.Body = &tree.GetNodeByPathRequest_Body{
|
||||
|
@ -71,15 +75,13 @@ func getByPath(cmd *cobra.Command, _ []string) {
|
|||
Path: strings.Split(path, "/"),
|
||||
LatestOnly: latestOnly,
|
||||
AllAttributes: true,
|
||||
}
|
||||
if btok := common.ReadBearerToken(cmd, bearerFlagKey); btok != nil {
|
||||
req.Body.BearerToken = btok.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.GetNodeByPath(ctx, req)
|
||||
commonCmd.ExitOnErr(cmd, "rpc call: %w", err)
|
||||
commonCmd.ExitOnErr(cmd, "failed to call getNodeByPath: %w", err)
|
||||
|
||||
nn := resp.GetBody().GetNodes()
|
||||
if len(nn) == 0 {
|
||||
|
|
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)
|
||||
dstepanov-yadro
commented
`failed to create clietn' will be better, I think. `failed to create clietn' will be better, I think.
|
||||
|
||||
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
|
@ -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",
|
||||
ale64bit marked this conversation as resolved
Outdated
|
||||
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()
|
||||
|
||||
cli, err := _client(ctx)
|
||||
commonCmd.ExitOnErr(cmd, "client: %w", err)
|
||||
commonCmd.ExitOnErr(cmd, "failed to create client: %w", err)
|
||||
|
||||
rawCID := make([]byte, sha256.Size)
|
||||
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)
|
||||
commonCmd.ExitOnErr(cmd, "rpc call: %w", err)
|
||||
commonCmd.ExitOnErr(cmd, "failed to call treeList %w", err)
|
||||
|
||||
for _, treeID := range resp.GetBody().GetIds() {
|
||||
cmd.Println(treeID)
|
||||
|
|
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)
|
||||
ale64bit marked this conversation as resolved
Outdated
ale64bit
commented
it's harder to understand what went wrong if all errors say it's harder to understand what went wrong if all errors say `"rpc call: %w"`. Maybe use more specific error messages? e.g. `"getting subtree: %v"` and so on.
aarifullin
commented
Okay. I'll make these errors more verbose 👍 Okay. I'll make these errors more verbose 👍
aarifullin
commented
Fixed Fixed
|
||||
|
||||
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))
|
||||
ale64bit marked this conversation as resolved
Outdated
ale64bit
commented
`"signing message: %w"`?
|
||||
|
||||
_, err = cli.Move(ctx, req)
|
||||
commonCmd.ExitOnErr(cmd, "failed to call move: %w", err)
|
||||
common.PrintVerbose(cmd, "Successful move invocation.")
|
||||
fyrchik
commented
Maybe Maybe `common.PrintVerbose`?
|
||||
}
|
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(addByPathCmd)
|
||||
Cmd.AddCommand(listCmd)
|
||||
Cmd.AddCommand(healthcheckCmd)
|
||||
Cmd.AddCommand(moveCmd)
|
||||
Cmd.AddCommand(removeCmd)
|
||||
Cmd.AddCommand(getSubtreeCmd)
|
||||
Cmd.AddCommand(getOpLogCmd)
|
||||
|
||||
initAddCmd()
|
||||
initGetByPathCmd()
|
||||
initAddByPathCmd()
|
||||
initListCmd()
|
||||
initHealthcheckCmd()
|
||||
initMoveCmd()
|
||||
initRemoveCmd()
|
||||
initGetSubtreeCmd()
|
||||
initGetOpLogCmd()
|
||||
}
|
||||
|
||||
const (
|
||||
treeIDFlagKey = "tid"
|
||||
parentIDFlagKey = "pid"
|
||||
nodeIDFlagKey = "nid"
|
||||
rootIDFlagKey = "root"
|
||||
fyrchik marked this conversation as resolved
Outdated
fyrchik
commented
What about What about `--root`? It is easy to get lost in 3-letter words.
aarifullin
commented
Good point Good point
|
||||
|
||||
metaFlagKey = "meta"
|
||||
|
||||
|
@ -34,6 +46,10 @@ const (
|
|||
latestOnlyFlagKey = "latest"
|
||||
|
||||
bearerFlagKey = "bearer"
|
||||
|
||||
heightFlagKey = "height"
|
||||
countFlagKey = "count"
|
||||
depthFlagKey = "depth"
|
||||
)
|
||||
|
||||
func initCTID(cmd *cobra.Command) {
|
||||
|
@ -45,5 +61,5 @@ func initCTID(cmd *cobra.Command) {
|
|||
ff.String(treeIDFlagKey, "", "Tree ID")
|
||||
_ = 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
|
@ -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)
|
||||
}
|
||||
}
|
Unrelated to the commit.