Skip to content

Commit

Permalink
add curve bs recover volume and its readme.
Browse files Browse the repository at this point in the history
Signed-off-by: kevin <[email protected]>
  • Loading branch information
CrystalAnalyst committed Dec 19, 2023
1 parent c16555e commit 5a4c6bd
Show file tree
Hide file tree
Showing 6 changed files with 303 additions and 9 deletions.
23 changes: 23 additions & 0 deletions tools-v2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,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 @@ -1997,6 +1999,27 @@ Output:
+--------------------------------------+--------------+---------+
```

#### recover

##### recover volume

recover volume from recycleBin

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

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


## 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 NewVolumeCommand() *cobra.Command {
rCmd := &RecoverCommand{
basecmd.MidCurveCmd{
Use: "recover",
Short: "recover resources in curvebs cluster",
},
}
return basecmd.NewMidCurveCli(&rCmd.MidCurveCmd, rCmd)
}
142 changes: 142 additions & 0 deletions tools-v2/pkg/cli/command/curvebs/recover/volume/recover.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
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"
)

// NewCommand return the mid cli
func NewRecoverFileCommand() *RecoverFileCommand {
RecoverFileCommand := &RecoverFileCommand{
FinalCurveCmd: basecmd.FinalCurveCmd{},
}
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 (recoverCommand *RecoverFileCommand) Init(cmd *cobra.Command, args []string) error {
mdsAddrs, err := config.GetBsMdsAddrSlice(recoverCommand.Cmd)
if err.TypeCode() != cmderror.CODE_SUCCESS {
return err.ToError()
}
//get the default timeout and retrytimes
timeout := config.GetFlagDuration(recoverCommand.Cmd, config.RPCTIMEOUT)
retrytimes := config.GetFlagInt32(recoverCommand.Cmd, config.RPCRETRYTIMES)
//get the params needed from commandline
path := config.GetBsFlagString(recoverCommand.Cmd, config.CURVEBS_PATH)
username := config.GetBsFlagString(recoverCommand.Cmd, config.CURVEBS_USER)
password := config.GetBsFlagString(recoverCommand.Cmd, config.CURVEBS_PASSWORD)
fileId := config.GetBsFlagUint64(recoverCommand.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
}
recoverCommand.Rpc = &RecoverCertainFileRPC{
Info: basecmd.NewRpc(mdsAddrs, timeout, retrytimes, "recoverFile"),
Request: &recoverRequest,
}
return nil
}

func (recoverCommand *RecoverFileCommand) AddFlags() {
config.AddRpcTimeoutFlag(recoverCommand.Cmd)
config.AddRpcRetryTimesFlag(recoverCommand.Cmd)
config.AddBsMdsFlagOption(recoverCommand.Cmd)
//file path and user name is required.
config.AddBsPathRequiredFlag(recoverCommand.Cmd)
config.AddBsUserRequireFlag(recoverCommand.Cmd)
//password and fileID is optional.
config.AddBsPasswordOptionFlag(recoverCommand.Cmd)
config.AddBsFileIdOptionFlag(recoverCommand.Cmd)
}

func (recoverCommand *RecoverFileCommand) RunCommand(cmd *cobra.Command, args []string) error {
result, err := basecmd.GetRpcResponse(recoverCommand.Rpc.Info, recoverCommand.Rpc)
if err.TypeCode() != cmderror.CODE_SUCCESS {
recoverCommand.Error = err
recoverCommand.Result = result
return err.ToError()
}
recoverCommand.Response = result.(*nameserver2.RecoverFileResponse)
if recoverCommand.Response.GetStatusCode() != nameserver2.StatusCode_kOK {
recoverCommand.Error = cmderror.ErrBsRecoverFile()
recoverCommand.Result = result
return recoverCommand.Error.ToError()
}
return nil
}

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

func (recoverCommand *RecoverFileCommand) ResultPlainOutput() error {
return output.FinalCmdOutputPlain(&recoverCommand.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()
}
67 changes: 67 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,67 @@
package volume

import (
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/spf13/cobra"
)

const (
RecoverExample = `curve bs recover volume --path /curvebs-volume-path
--user username [--password password] [--fileid fileid]`
)

// RecoverCommand
type RecoverCommand struct {
basecmd.FinalCurveCmd
}

var _ basecmd.FinalCurveCmdFunc = (*RecoverCommand)(nil) // check interface

// new RecoverCommand function
func NewVolumeCommand() *cobra.Command {
rCmd := &RecoverCommand{
FinalCurveCmd: basecmd.FinalCurveCmd{
Use: "curve bs recover volume",
Short: "recover volumes from the RecycleBin",
Example: RecoverExample,
},
}
return basecmd.NewFinalCurveCli(&rCmd.FinalCurveCmd, rCmd)
}

func (rCmd *RecoverCommand) Init(cmd *cobra.Command, args []string) error {
header := []string{cobrautil.ROW_RESULT}
rCmd.SetHeader(header)
return nil
}

func (rCmd *RecoverCommand) RunCommand(cmd *cobra.Command, args []string) error {
rCmd.Result, rCmd.Error = RecoverFile(rCmd.Cmd)
if rCmd.Error.TypeCode() != cmderror.CODE_SUCCESS {
return rCmd.Error.ToError()
}
rCmd.TableNew.Append([]string{rCmd.Error.Message})
return nil
}

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

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

func (rCmd *RecoverCommand) AddFlags() {
config.AddRpcRetryTimesFlag(rCmd.Cmd)
config.AddRpcTimeoutFlag(rCmd.Cmd)
config.AddBsMdsFlagOption(rCmd.Cmd)
config.AddBsPathRequiredFlag(rCmd.Cmd)
config.AddBsUserRequireFlag(rCmd.Cmd)
config.AddBsPasswordOptionFlag(rCmd.Cmd)
config.AddBsFileIdOptionFlag(rCmd.Cmd)
}
26 changes: 18 additions & 8 deletions tools-v2/pkg/config/bs.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,13 @@ const (
CURVEBS_DEFAULT_SNAPSHOT_ID = "*"
CURVEBS_FAILED = "failed"
VIPER_CURVEBS_FAILED = "curvebs.failed"
CURVEBS_CHUNK_SIZE = "chunksize"
VIPER_CURVEBS_CHUNK_SIZE = "curvebs.chunksize"
CURVEBS_CHECK_HASH = "checkhash"
VIPER_CURVEBS_CHECK_HASH = "curvebs.checkhash"
CURVEBS_DEFAULT_CHECK_HASH = false
CURVEBS_CHUNK_SIZE = "chunksize"
VIPER_CURVEBS_CHUNK_SIZE = "curvebs.chunksize"
CURVEBS_CHECK_HASH = "checkhash"
VIPER_CURVEBS_CHECK_HASH = "curvebs.checkhash"
CURVEBS_DEFAULT_CHECK_HASH = false
CURVEBS_FILE_ID = "fileId"
VIPER_CURVEBS_FILE_ID = "curvebs.fileId"
)

var (
Expand Down Expand Up @@ -207,8 +209,8 @@ var (
CURVEBS_TASKID: VIPER_CURVEBS_TASKID,
CURVEBS_SNAPSHOT_ID: VIPER_CURVEBS_SNAPSHOT_ID,
CURVEBS_FAILED: VIPER_CURVEBS_FAILED,
CURVEBS_CHUNK_SIZE: VIPER_CURVEBS_CHUNK_SIZE,
CURVEBS_CHECK_HASH: VIPER_CURVEBS_CHECK_HASH,
CURVEBS_CHUNK_SIZE: VIPER_CURVEBS_CHUNK_SIZE,
CURVEBS_CHECK_HASH: VIPER_CURVEBS_CHECK_HASH,
}

BSFLAG2DEFAULT = map[string]interface{}{
Expand All @@ -232,7 +234,7 @@ var (
CURVEBS_ALL: CURVEBS_DEFAULT_ALL,
CURVEBS_LOGIC_POOL_ID: CURVEBS_DEFAULT_LOGIC_POOL_ID,
CURVEBS_COPYSET_ID: CURVEBS_DEFAULT_COPYSET_ID,
CURVEBS_CHECK_HASH: CURVEBS_DEFAULT_CHECK_HASH,
CURVEBS_CHECK_HASH: CURVEBS_DEFAULT_CHECK_HASH,
CURVEBS_SNAPSHOT_ID: CURVEBS_DEFAULT_SNAPSHOT_ID,
}
)
Expand Down Expand Up @@ -679,6 +681,10 @@ func AddBsTaskTypeOptionFlag(cmd *cobra.Command) {
AddBsStringOptionFlag(cmd, CURVEBS_TYPE, "only query target type (clone or recover)")
}

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 @@ -862,3 +868,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 5a4c6bd

Please sign in to comment.