Skip to content

Commit

Permalink
[feat]:add command bs recover volume
Browse files Browse the repository at this point in the history
Signed-off-by: kevin <[email protected]>
  • Loading branch information
CrystalAnalyst committed Dec 26, 2023
1 parent 35846be commit 3491478
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 1 deletion.
23 changes: 23 additions & 0 deletions tools-v2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ A tool for CurveFS & CurveBs.
- [snapshot copyset](#snapshot-copyset)
- [stop](#stop)
- [stop snapshot](#stop-snapshot)
- [recover](#recover)
- [recover volume](#recover-volume)
- [Comparison of old and new commands](#comparison-of-old-and-new-commands)
- [curve fs](#curve-fs)
- [curve bs](#curve-bs)
Expand Down Expand Up @@ -2037,6 +2039,27 @@ Output:
+--------------------------------------+--------------+---------+
```

#### recover

##### recover volume

recover volume from recycleBin

Usage:
```shell
curve bs recover volume --path /test/path --user root
```

Output:
```
+-----------+---------+
| FILENAME | RESULT |
+-----------+---------+
| test/path | success |
+-----------+---------+
```


## Comparison of old and new commands

### curve fs
Expand Down
4 changes: 3 additions & 1 deletion tools-v2/internal/error/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,9 @@ var (
ErrInvalidMetaServerAddr = func() *CmdError {
return NewInternalCmdError(80, "invalid metaserver external addr: %s")
}

ErrBsRecoverFile = func() *CmdError {
return NewInternalCmdError(81, "recover file fail, err: %s")
}
// http error
ErrHttpUnreadableResult = func() *CmdError {
return NewHttpResultCmdError(1, "http response is unreadable, the uri is: %s, the error is: %s")
Expand Down
50 changes: 50 additions & 0 deletions tools-v2/pkg/cli/command/curvebs/recover/recover.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*
* Project: CurveCli
* Created Date: 2023-11-15
* Author: CrystalAnalyst
*/
package recover

import (
basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command"
volume "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/recover/volume"
"github.com/spf13/cobra"
)

type RecoverCommand struct {
basecmd.MidCurveCmd
}

var _ basecmd.MidCurveCmdFunc = (*RecoverCommand)(nil)

func (rCmd *RecoverCommand) AddSubCommands() {
rCmd.Cmd.AddCommand(
volume.NewVolumeCommand(),
)
}

func NewRecoverCommand() *cobra.Command {
rCmd := &RecoverCommand{
basecmd.MidCurveCmd{
Use: "recover",
Short: "recover resources in curvebs cluster",
},
}
return basecmd.NewMidCurveCli(&rCmd.MidCurveCmd, rCmd)
}
174 changes: 174 additions & 0 deletions tools-v2/pkg/cli/command/curvebs/recover/volume/volume.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package volume

import (
"context"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"google.golang.org/grpc"

cmderror "github.com/opencurve/curve/tools-v2/internal/error"
cobrautil "github.com/opencurve/curve/tools-v2/internal/utils"
basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command"
"github.com/opencurve/curve/tools-v2/pkg/config"
"github.com/opencurve/curve/tools-v2/pkg/output"
"github.com/opencurve/curve/tools-v2/proto/proto/nameserver2"
)

const (
RecoverExample = ` $ curve bs recover volume --path /test/path --user username `
)

func NewVolumeCommand() *cobra.Command {
return NewRecoverFileCommand().Cmd
}

func NewRecoverFileCommand() *RecoverFileCommand {
RecoverFileCommand := &RecoverFileCommand{
FinalCurveCmd: basecmd.FinalCurveCmd{
Use: "volume",
Short: "recover volume in curvebs",
Example: RecoverExample,
},
}
basecmd.NewFinalCurveCli(&RecoverFileCommand.FinalCurveCmd, RecoverFileCommand)
return RecoverFileCommand
}

type RecoverCertainFileRPC struct {
Info *basecmd.Rpc
Request *nameserver2.RecoverFileRequest
mdsClient nameserver2.CurveFSServiceClient
}

var _ basecmd.RpcFunc = (*RecoverCertainFileRPC)(nil)

func (gRpc *RecoverCertainFileRPC) NewRpcClient(cc grpc.ClientConnInterface) {
gRpc.mdsClient = nameserver2.NewCurveFSServiceClient(cc)
}

func (gRpc *RecoverCertainFileRPC) Stub_Func(ctx context.Context) (interface{}, error) {
return gRpc.mdsClient.RecoverFile(ctx, gRpc.Request)
}

type RecoverFileCommand struct {
basecmd.FinalCurveCmd
Rpc *RecoverCertainFileRPC
Response *nameserver2.RecoverFileResponse
}

var _ basecmd.FinalCurveCmdFunc = (*RecoverFileCommand)(nil)

func (rCmd *RecoverFileCommand) Init(cmd *cobra.Command, args []string) error {
mdsAddrs, err := config.GetBsMdsAddrSlice(rCmd.Cmd)
if err.TypeCode() != cmderror.CODE_SUCCESS {
return err.ToError()
}

//get the default timeout and retrytimes
timeout := config.GetFlagDuration(rCmd.Cmd, config.RPCTIMEOUT)
retrytimes := config.GetFlagInt32(rCmd.Cmd, config.RPCRETRYTIMES)

//get the params needed from commandline
path := config.GetBsFlagString(rCmd.Cmd, config.CURVEBS_PATH)
username := config.GetBsFlagString(rCmd.Cmd, config.CURVEBS_USER)
password := config.GetBsFlagString(rCmd.Cmd, config.CURVEBS_PASSWORD)
fileId := config.GetBsFlagUint64(rCmd.Cmd, config.CURVEBS_FILE_ID)
date, errDat := cobrautil.GetTimeofDayUs()
if errDat.TypeCode() != cmderror.CODE_SUCCESS {
return errDat.ToError()
}

//add basic info
recoverRequest := nameserver2.RecoverFileRequest{
FileName: &path,
Owner: &username,
FileId: &fileId,
Date: &date,
}

//add signature
if username == viper.GetString(config.VIPER_CURVEBS_USER) && len(password) != 0 {
strSig := cobrautil.GetString2Signature(date, username)
sig := cobrautil.CalcString2Signature(strSig, password)
recoverRequest.Signature = &sig
}
rCmd.Rpc = &RecoverCertainFileRPC{
Info: basecmd.NewRpc(mdsAddrs, timeout, retrytimes, "recoverFile"),
Request: &recoverRequest,
}

//set headers
header := []string{
cobrautil.ROW_FILE_NAME,
cobrautil.ROW_RESULT,
}
rCmd.SetHeader(header)
out := make(map[string]string)
out[cobrautil.ROW_FILE_NAME] = *recoverRequest.FileName
list := cobrautil.Map2List(out, []string{cobrautil.ROW_FILE_NAME})
rCmd.TableNew.Append(list)
return nil
}

func (rCmd *RecoverFileCommand) AddFlags() {
config.AddRpcTimeoutFlag(rCmd.Cmd)
config.AddRpcRetryTimesFlag(rCmd.Cmd)
config.AddBsMdsFlagOption(rCmd.Cmd)

//file path and user name is required.
config.AddBsPathRequiredFlag(rCmd.Cmd)
config.AddBsUserRequireFlag(rCmd.Cmd)

//password and fileID is optional.
config.AddBsPasswordOptionFlag(rCmd.Cmd)
config.AddBsFileIdOptionFlag(rCmd.Cmd)
}

func (rCmd *RecoverFileCommand) RunCommand(cmd *cobra.Command, args []string) error {
result, err := basecmd.GetRpcResponse(rCmd.Rpc.Info, rCmd.Rpc)
if err.TypeCode() != cmderror.CODE_SUCCESS {
rCmd.Error = err
rCmd.Result = result
return err.ToError()
}
rCmd.Response = result.(*nameserver2.RecoverFileResponse)
if rCmd.Response.GetStatusCode() != nameserver2.StatusCode_kOK {
rCmd.Error = cmderror.ErrBsRecoverFile()
rCmd.Result = result
return rCmd.Error.ToError()
}
out := make(map[string]string)
out[cobrautil.ROW_RESULT] = cobrautil.ROW_VALUE_SUCCESS
list := cobrautil.Map2List(out, []string{cobrautil.ROW_RESULT})
rCmd.TableNew.Append(list)
rCmd.Result, rCmd.Error = result, cmderror.Success()
return nil
}

func (rCmd *RecoverFileCommand) Print(cmd *cobra.Command, args []string) error {
return output.FinalCmdOutput(&rCmd.FinalCurveCmd, rCmd)
}

func (rCmd *RecoverFileCommand) ResultPlainOutput() error {
return output.FinalCmdOutputPlain(&rCmd.FinalCurveCmd)
}

func RecoverFile(caller *cobra.Command) (*nameserver2.RecoverFileResponse, *cmderror.CmdError) {
rCmd := NewRecoverFileCommand()
config.AlignFlagsValue(caller, rCmd.Cmd, []string{
config.RPCRETRYTIMES, config.RPCTIMEOUT, config.CURVEBS_MDSADDR,
config.CURVEBS_PATH, config.CURVEBS_USER,
config.CURVEBS_PASSWORD, config.CURVEBS_FILE_ID,
})
rCmd.Cmd.SilenceErrors = true
rCmd.Cmd.SilenceUsage = true
rCmd.Cmd.SetArgs([]string{"--format", config.FORMAT_NOOUT})
err := rCmd.Cmd.Execute()
if err != nil {
retErr := cmderror.ErrBsRecoverFile()
retErr.Format(err.Error())
return rCmd.Response, retErr
}
return rCmd.Response, cmderror.Success()
}
14 changes: 14 additions & 0 deletions tools-v2/pkg/config/bs.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ const (
VIPER_CURVEBS_FILENAME = "curvebs.filename"
CURVEBS_SNAPSHOTNAME = "snapshotname"
VIPER_CURVEBS_SNAPSHOTNAME = "curvebs.snapshotname"
CURVEBS_FILE_ID = "fileId"
VIPER_CURVEBS_FILE_ID = "curvebs.fileId"
)

var (
Expand Down Expand Up @@ -557,6 +559,10 @@ func AddBsPathRequiredFlag(cmd *cobra.Command) {
AddBsStringRequiredFlag(cmd, CURVEBS_PATH, "file path")
}

func AddBsUserRequireFlag(cmd *cobra.Command) {
AddBsStringRequiredFlag(cmd, CURVEBS_USER, "user name")
}

func AddBsLogicalPoolIdRequiredFlag(cmd *cobra.Command) {
AddBsUint32RequiredFlag(cmd, CURVEBS_LOGIC_POOL_ID, "logical pool id")
}
Expand Down Expand Up @@ -693,6 +699,10 @@ func AddBsSnapshotNameRequiredFlag(cmd *cobra.Command) {
AddBsStringRequiredFlag(cmd, CURVEBS_SNAPSHOTNAME, "snapshot name")
}

func AddBsFileIdOptionFlag(cmd *cobra.Command) {
AddBsUint64OptionFlag(cmd, CURVEBS_FILE_ID, "recover fileId")
}

// get stingslice flag
func GetBsFlagStringSlice(cmd *cobra.Command, flagName string) []string {
var value []string
Expand Down Expand Up @@ -876,3 +886,7 @@ func GetBsChunkServerId(cmd *cobra.Command) []uint32 {
}
return chunkserveridSlice
}

func GetBsFileId(cmd *cobra.Command) uint64 {
return GetBsFlagUint64(cmd, CURVEBS_FILE_ID)
}

0 comments on commit 3491478

Please sign in to comment.