diff --git a/tools-v2/README.md b/tools-v2/README.md index 4fac551ebf..40bc272ad7 100644 --- a/tools-v2/README.md +++ b/tools-v2/README.md @@ -63,6 +63,7 @@ A tool for CurveFS & CurveBs. - [create](#create-1) - [create file](#create-file) - [create dir](#create-dir) + - [clean-recycle](#clean-recycle) - [Comparison of old and new commands](#comparison-of-old-and-new-commands) - [curve fs](#curve-fs) - [curve bs](#curve-bs) @@ -936,6 +937,26 @@ Output: +------+------+----------------+-------+--------+---------+--------+-----+---------------------+--------------+---------+-----------------+----------+ ``` +### clean-recycle + +clean the recycle bin + +Usage: + +```bash +curve bs clean-recycle --recycleprefix=/test --expiredtime=1h +``` + +Output: + +```bash ++---------+ +| RESULT | ++---------+ +| success | ++---------+ +``` + ##### query chunk query the location of the chunk corresponding to the offset diff --git a/tools-v2/internal/error/error.go b/tools-v2/internal/error/error.go index 0ecdd521ce..f57c23c975 100644 --- a/tools-v2/internal/error/error.go +++ b/tools-v2/internal/error/error.go @@ -411,6 +411,9 @@ var ( ErrBsUnknownThrottleType = func() *CmdError { return NewInternalCmdError(50, "unknown throttle type[%s], only support: iops_total|iops_read|iops_write|bps_total|bps_read|bps_write") } + ErrBsListDir = func() *CmdError { + return NewInternalCmdError(51, "list directory fail, err: %s") + } // http error ErrHttpUnreadableResult = func() *CmdError { diff --git a/tools-v2/internal/utils/string.go b/tools-v2/internal/utils/string.go index 2a88e4a657..9f7f856a55 100644 --- a/tools-v2/internal/utils/string.go +++ b/tools-v2/internal/utils/string.go @@ -41,6 +41,7 @@ const ( IP_PORT_REGEX = "((\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5]):([0-9]|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{4}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5]))|(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])" PATH_REGEX = `^(/[^/ ]*)+/?$` FS_NAME_REGEX = "^([a-z0-9]+\\-?)+$" + K_STRING_TRUE = "true" ROOT_PATH = "/" RECYCLEBIN_PATH = "/RecycleBin" diff --git a/tools-v2/pkg/cli/command/curvebs/bs.go b/tools-v2/pkg/cli/command/curvebs/bs.go index deb52faa85..0c6f533260 100644 --- a/tools-v2/pkg/cli/command/curvebs/bs.go +++ b/tools-v2/pkg/cli/command/curvebs/bs.go @@ -26,6 +26,7 @@ import ( "github.com/spf13/cobra" basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/clean_recycle" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/create" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/delete" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/list" @@ -48,6 +49,7 @@ func (bsCmd *CurveBsCommand) AddSubCommands() { delete.NewDeleteCommand(), create.NewCreateCmd(), update.NewUpdateCommand(), + clean_recycle.NewCleanRecycleCommand(), ) } diff --git a/tools-v2/pkg/cli/command/curvebs/clean_recycle/clean_recycle.go b/tools-v2/pkg/cli/command/curvebs/clean_recycle/clean_recycle.go new file mode 100644 index 0000000000..dad824d9bf --- /dev/null +++ b/tools-v2/pkg/cli/command/curvebs/clean_recycle/clean_recycle.go @@ -0,0 +1,134 @@ +/* + * Project: tools-v2 + * Created Date: 2023-4-6 + * Author: nanguanlin6@gmail.com + */ + +package clean_recycle + +import ( + "strings" + "time" + + 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/cli/command/curvebs/delete/file" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/list/dir" + "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" + "github.com/spf13/cobra" +) + +const ( + cleanRecycleBinExample = `$ curve bs clean-recycle --expiredtime=1h --recycleprefix=/test` + RECYCLEBINDIR = "/RecycleBin" +) + +// CleanRecycleCommand +type CleanRecycleCommand struct { + basecmd.FinalCurveCmd + recyclePrefix string + expireTime time.Duration +} + +var _ basecmd.FinalCurveCmdFunc = (*CleanRecycleCommand)(nil) // check interface + +// new CleanRecycleCommand function +func NewCleanRecycleCommand() *cobra.Command { + crCmd := &CleanRecycleCommand{ + FinalCurveCmd: basecmd.FinalCurveCmd{ + Use: "clean-recycle", + Short: "clean recycle bin", + Example: cleanRecycleBinExample, + }, + } + return basecmd.NewFinalCurveCli(&crCmd.FinalCurveCmd, crCmd) +} + +// method of CleanRecycleCommand struct +func (crCmd *CleanRecycleCommand) Init(cmd *cobra.Command, args []string) error { + crCmd.recyclePrefix = config.GetBsRecyclePrefix(crCmd.Cmd) + crCmd.expireTime = config.GetBsExpireTime(crCmd.Cmd) + header := []string{cobrautil.ROW_RESULT} + crCmd.SetHeader(header) + crCmd.TableNew.SetAutoMergeCellsByColumnIndex(cobrautil.GetIndexSlice( + crCmd.Header, header, + )) + return nil +} + +func (crCmd *CleanRecycleCommand) Print(cmd *cobra.Command, args []string) error { + return output.FinalCmdOutput(&crCmd.FinalCurveCmd, crCmd) +} + +func (crCmd *CleanRecycleCommand) RunCommand(cmd *cobra.Command, args []string) error { + // Get the file infos in recycle bin + crCmd.Cmd.Flags().Set(config.CURVEBS_PATH, RECYCLEBINDIR) + resp, err := dir.ListDir(crCmd.Cmd) + if err.TypeCode() != cmderror.CODE_SUCCESS { + crCmd.Error = err + crCmd.Result = cobrautil.ROW_VALUE_FAILED + return err.ToError() + } + + // Define the needDelete function + needDelete := func(fileInfo *nameserver2.FileInfo, now time.Time, expireTime time.Duration) bool { + createTime := time.Unix(int64(fileInfo.GetCtime()/1000000), 0) + return createTime.Add(expireTime).Before(now) + } + + // Iterate through files and delete if necessary + now := time.Now() + + var errs []*cmderror.CmdError + infos := resp.GetFileInfo() + for _, fileInfo := range infos { + originPath := fileInfo.GetOriginalFullPathName() + if !strings.HasPrefix(originPath, crCmd.recyclePrefix) || !needDelete(fileInfo, now, crCmd.expireTime) { + continue + } + + filename := RECYCLEBINDIR + "/" + fileInfo.GetFileName() + crCmd.Cmd.Flags().Set(config.CURVEBS_PATH, filename) + crCmd.Cmd.Flags().Set(config.CURVEBS_FORCE, cobrautil.K_STRING_TRUE) + deleteResult, err := file.DeleteFile(crCmd.Cmd) + if deleteResult.GetStatusCode() != nameserver2.StatusCode_kOK { + errs = append(errs, err) + continue + } + } + + if len(errs) != 0 { + crCmd.Result = cobrautil.ROW_VALUE_FAILED + crCmd.Error = cmderror.MergeCmdError(errs) + return crCmd.Error.ToError() + } + + out := make(map[string]string) + out[cobrautil.ROW_RESULT] = cobrautil.ROW_VALUE_SUCCESS + list := cobrautil.Map2List(out, []string{cobrautil.ROW_RESULT}) + crCmd.TableNew.Append(list) + + crCmd.Result = out + crCmd.Error = cmderror.ErrSuccess() + return nil +} + +func (crCmd *CleanRecycleCommand) ResultPlainOutput() error { + return output.FinalCmdOutputPlain(&crCmd.FinalCurveCmd) +} + +func (crCmd *CleanRecycleCommand) AddFlags() { + config.AddBsMdsFlagOption(crCmd.Cmd) + config.AddRpcRetryTimesFlag(crCmd.Cmd) + config.AddRpcTimeoutFlag(crCmd.Cmd) + config.AddBsUserOptionFlag(crCmd.Cmd) + config.AddBsPasswordOptionFlag(crCmd.Cmd) + + config.AddBsForceDeleteOptionFlag(crCmd.Cmd) + config.AddBsPathOptionFlag(crCmd.Cmd) + config.AddBsRecyclePrefixOptionFlag(crCmd.Cmd) + config.AddBsExpireTimeOptionFlag(crCmd.Cmd) +} diff --git a/tools-v2/pkg/cli/command/curvebs/delete/delete.go b/tools-v2/pkg/cli/command/curvebs/delete/delete.go index 265aa378ef..e65312fb41 100644 --- a/tools-v2/pkg/cli/command/curvebs/delete/delete.go +++ b/tools-v2/pkg/cli/command/curvebs/delete/delete.go @@ -22,7 +22,7 @@ var _ basecmd.MidCurveCmdFunc = (*DeleteCommand)(nil) // check interface func (dCmd *DeleteCommand) AddSubCommands() { dCmd.Cmd.AddCommand( - file.NewCommand(), + file.NewFileCommand(), peer.NewCommand(), ) } diff --git a/tools-v2/pkg/cli/command/curvebs/delete/file/file.go b/tools-v2/pkg/cli/command/curvebs/delete/file/file.go index 96c8f7d16d..ec95bacaf0 100644 --- a/tools-v2/pkg/cli/command/curvebs/delete/file/file.go +++ b/tools-v2/pkg/cli/command/curvebs/delete/file/file.go @@ -16,7 +16,7 @@ import ( ) const ( - deleteCliExample = `curve bs delete file --filename /curvebs-file-name --username username [--password password] [--forcedelete true]` + deleteCliExample = `curve bs delete file --path /curvebs-file-path --user username [--password password] [--force true]` ) type DeleteCertainFileRpc struct { @@ -51,16 +51,16 @@ func (deleteCommand *DeleteCommand) Init(cmd *cobra.Command, args []string) erro //get the default timeout and retrytimes timeout := config.GetFlagDuration(deleteCommand.Cmd, config.RPCTIMEOUT) retrytimes := config.GetFlagInt32(deleteCommand.Cmd, config.RPCRETRYTIMES) - filename := config.GetBsFlagString(deleteCommand.Cmd, config.CURVEBS_FILENAME) + path := config.GetBsFlagString(deleteCommand.Cmd, config.CURVEBS_PATH) username := config.GetBsFlagString(deleteCommand.Cmd, config.CURVEBS_USER) password := config.GetBsFlagString(deleteCommand.Cmd, config.CURVEBS_PASSWORD) - forcedelete := config.GetFlagBool(deleteCommand.Cmd, config.CURVEBS_FORCEDELETE) + forcedelete := config.GetBsFlagBool(deleteCommand.Cmd, config.CURVEBS_FORCE) date, errDat := cobrautil.GetTimeofDayUs() if errDat.TypeCode() != cmderror.CODE_SUCCESS { return errDat.ToError() } deleteRequest := nameserver2.DeleteFileRequest{ - FileName: &filename, + FileName: &path, Owner: &username, Date: &date, ForceDelete: &forcedelete, @@ -74,7 +74,7 @@ func (deleteCommand *DeleteCommand) Init(cmd *cobra.Command, args []string) erro Info: basecmd.NewRpc(mdsAddrs, timeout, retrytimes, "DeleteFile"), Request: &deleteRequest, } - header := []string{cobrautil.ROW_RESULT, cobrautil.ROW_REASON} + header := []string{cobrautil.ROW_RESULT} deleteCommand.SetHeader(header) deleteCommand.TableNew.SetAutoMergeCellsByColumnIndex(cobrautil.GetIndexSlice( deleteCommand.Header, header, @@ -83,24 +83,24 @@ func (deleteCommand *DeleteCommand) Init(cmd *cobra.Command, args []string) erro } func (deleteCommand *DeleteCommand) RunCommand(cmd *cobra.Command, args []string) error { - out := make(map[string]string) result, err := basecmd.GetRpcResponse(deleteCommand.Rpc.Info, deleteCommand.Rpc) if err.TypeCode() != cmderror.CODE_SUCCESS { - out[cobrautil.ROW_RESULT] = "failed" - out[cobrautil.ROW_REASON] = err.Message - return nil + deleteCommand.Error = err + deleteCommand.Result = result + return err.ToError() } deleteCommand.Response = result.(*nameserver2.DeleteFileResponse) if deleteCommand.Response.GetStatusCode() != nameserver2.StatusCode_kOK { - err = cmderror.ErrBsDeleteFile() - out[cobrautil.ROW_RESULT] = "failed" - out[cobrautil.ROW_REASON] = err.Message - return nil + deleteCommand.Error = cmderror.ErrBsDeleteFile() + deleteCommand.Result = result + return deleteCommand.Error.ToError() } - out[cobrautil.ROW_RESULT] = "success" - out[cobrautil.ROW_REASON] = "" - list := cobrautil.Map2List(out, []string{cobrautil.ROW_RESULT, cobrautil.ROW_REASON}) + out := make(map[string]string) + out[cobrautil.ROW_RESULT] = cobrautil.ROW_VALUE_SUCCESS + list := cobrautil.Map2List(out, []string{cobrautil.ROW_RESULT}) deleteCommand.TableNew.Append(list) + + deleteCommand.Result, deleteCommand.Error = result, cmderror.Success() return nil } @@ -113,18 +113,18 @@ func (deleteCommand *DeleteCommand) ResultPlainOutput() error { } func (deleteCommand *DeleteCommand) AddFlags() { - config.AddFsMdsAddrFlag(deleteCommand.Cmd) + config.AddBsMdsFlagOption(deleteCommand.Cmd) config.AddRpcTimeoutFlag(deleteCommand.Cmd) config.AddRpcRetryTimesFlag(deleteCommand.Cmd) - config.AddBsFilenameRequiredFlag(deleteCommand.Cmd) - config.AddBsUsernameRequiredFlag(deleteCommand.Cmd) + config.AddBsPathRequiredFlag(deleteCommand.Cmd) + config.AddBsUserOptionFlag(deleteCommand.Cmd) config.AddBsPasswordOptionFlag(deleteCommand.Cmd) config.AddBsForceDeleteOptionFlag(deleteCommand.Cmd) } // NewCommand return the mid cli -func NewCommand() *cobra.Command { +func NewDeleteFileCommand() *DeleteCommand { deleteCommand := &DeleteCommand{ FinalCurveCmd: basecmd.FinalCurveCmd{ Use: "file", @@ -133,5 +133,29 @@ func NewCommand() *cobra.Command { }, } basecmd.NewFinalCurveCli(&deleteCommand.FinalCurveCmd, deleteCommand) - return basecmd.NewFinalCurveCli(&deleteCommand.FinalCurveCmd, deleteCommand) + return deleteCommand +} + +func NewFileCommand() *cobra.Command { + return NewDeleteFileCommand().Cmd +} + +// DeleteFile function wraps the DeleteCertainFile rpc +func DeleteFile(caller *cobra.Command) (*nameserver2.DeleteFileResponse, *cmderror.CmdError) { + delCmd := NewDeleteFileCommand() + config.AlignFlagsValue(caller, delCmd.Cmd, []string{ + config.RPCRETRYTIMES, config.RPCTIMEOUT, config.CURVEBS_MDSADDR, + config.CURVEBS_PATH, config.CURVEBS_USER, config.CURVEBS_PASSWORD, + config.CURVEBS_FORCE, + }) + delCmd.Cmd.SilenceErrors = true + delCmd.Cmd.SilenceUsage = true + delCmd.Cmd.SetArgs([]string{"--format", config.FORMAT_NOOUT}) + err := delCmd.Cmd.Execute() + if err != nil { + retErr := cmderror.ErrBsDeleteFile() + retErr.Format(err.Error()) + return delCmd.Response, retErr + } + return delCmd.Response, cmderror.Success() } diff --git a/tools-v2/pkg/cli/command/curvebs/list/dir/dir.go b/tools-v2/pkg/cli/command/curvebs/list/dir/dir.go index e5b4074297..35c54fcafd 100644 --- a/tools-v2/pkg/cli/command/curvebs/list/dir/dir.go +++ b/tools-v2/pkg/cli/command/curvebs/list/dir/dir.go @@ -25,7 +25,6 @@ package dir import ( "context" "fmt" - "log" "time" "github.com/dustin/go-humanize" @@ -55,7 +54,8 @@ var _ basecmd.RpcFunc = (*ListDirRpc)(nil) // check interface type DirCommand struct { basecmd.FinalCurveCmd - Rpc []*ListDirRpc + Rpc *ListDirRpc + Response *nameserver2.ListDirResponse } var _ basecmd.FinalCurveCmdFunc = (*DirCommand)(nil) // check interface @@ -104,16 +104,16 @@ func (pCmd *DirCommand) Init(cmd *cobra.Command, args []string) error { timeout := config.GetFlagDuration(pCmd.Cmd, config.RPCTIMEOUT) retrytimes := config.GetFlagInt32(pCmd.Cmd, config.RPCRETRYTIMES) - fileName := config.GetBsFlagString(pCmd.Cmd, config.CURVEBS_PATH) + path := config.GetBsFlagString(pCmd.Cmd, config.CURVEBS_PATH) owner := config.GetBsFlagString(pCmd.Cmd, config.CURVEBS_USER) date, errDat := cobrautil.GetTimeofDayUs() if errDat.TypeCode() != cmderror.CODE_SUCCESS { return errDat.ToError() } - rpc := &ListDirRpc{ + pCmd.Rpc = &ListDirRpc{ Request: &nameserver2.ListDirRequest{ - FileName: &fileName, + FileName: &path, Owner: &owner, Date: &date, }, @@ -124,9 +124,9 @@ func (pCmd *DirCommand) Init(cmd *cobra.Command, args []string) error { if owner == viper.GetString(config.VIPER_CURVEBS_USER) && len(password) != 0 { strSig := cobrautil.GetString2Signature(date, owner) sig := cobrautil.CalcString2Signature(strSig, password) - rpc.Request.Signature = &sig + pCmd.Rpc.Request.Signature = &sig } - pCmd.Rpc = append(pCmd.Rpc, rpc) + header := []string{ cobrautil.ROW_ID, cobrautil.ROW_FILE_NAME, @@ -151,69 +151,63 @@ func (pCmd *DirCommand) Print(cmd *cobra.Command, args []string) error { // RunCommand implements basecmd.FinalCurveCmdFunc func (pCmd *DirCommand) RunCommand(cmd *cobra.Command, args []string) error { - var infos []*basecmd.Rpc - var funcs []basecmd.RpcFunc - for _, rpc := range pCmd.Rpc { - infos = append(infos, rpc.Info) - funcs = append(funcs, rpc) - } - results, errs := basecmd.GetRpcListResponse(infos, funcs) - if len(errs) == len(infos) { - mergeErr := cmderror.MergeCmdErrorExceptSuccess(errs) - return mergeErr.ToError() + result, err := basecmd.GetRpcResponse(pCmd.Rpc.Info, pCmd.Rpc) + if err.TypeCode() != cmderror.CODE_SUCCESS { + pCmd.Error = err + pCmd.Result = result + return err.ToError() } - var errors []*cmderror.CmdError + pCmd.Response = result.(*nameserver2.ListDirResponse) + infos := pCmd.Response.GetFileInfo() rows := make([]map[string]string, 0) - for _, res := range results { - infos := res.(*nameserver2.ListDirResponse).GetFileInfo() - for _, info := range infos { - row := make(map[string]string) - dirName := config.GetBsFlagString(pCmd.Cmd, config.CURVEBS_PATH) - var fileName string - if dirName == "/" { - fileName = dirName + info.GetFileName() - } else { - fileName = dirName + "/" + info.GetFileName() - } - row[cobrautil.ROW_ID] = fmt.Sprintf("%d", info.GetId()) - row[cobrautil.ROW_FILE_NAME] = fileName - row[cobrautil.ROW_PARENT_ID] = fmt.Sprintf("%d", info.GetParentId()) - row[cobrautil.ROW_FILE_TYPE] = fmt.Sprintf("%v", info.GetFileType()) - row[cobrautil.ROW_OWNER] = info.GetOwner() - row[cobrautil.ROW_CTIME] = time.Unix(int64(info.GetCtime()/1000000), 0).Format("2006-01-02 15:04:05") - - // generate a query file command - fInfoCmd := file.NewQueryFileCommand() - config.AlignFlagsValue(pCmd.Cmd, fInfoCmd.Cmd, []string{ - config.RPCRETRYTIMES, config.RPCTIMEOUT, config.CURVEBS_MDSADDR, - config.CURVEBS_PATH, - }) - fInfoCmd.Cmd.Flags().Set("path", fileName) - - // Get file size - sizeRes, err := file.GetFileSize(fInfoCmd.Cmd) - if err.TypeCode() != cmderror.CODE_SUCCESS { - // TODO handle err - log.Printf("%s failed to get file size: %v", info.GetFileName(), err) - //return err.ToError() - } - row[cobrautil.ROW_FILE_SIZE] = fmt.Sprintf("%s", humanize.IBytes(sizeRes.GetFileSize())) - // Get allocated size - allocRes, err := file.GetAllocatedSize(fInfoCmd.Cmd) - if err.TypeCode() != cmderror.CODE_SUCCESS { - // TODO handle err - log.Printf("%s failed to get allocated size: %v", info.GetFileName(), err) - //return err.ToError() - } - row[cobrautil.ROW_ALLOC_SIZE] = fmt.Sprintf("%s", humanize.IBytes(allocRes.GetAllocatedSize())) - rows = append(rows, row) + var errs []*cmderror.CmdError + for _, info := range infos { + row := make(map[string]string) + var fileName string + path := config.GetBsFlagString(pCmd.Cmd, config.CURVEBS_PATH) + if path[len(path)-1] == '/' { + fileName = path + info.GetFileName() + } else { + fileName = path + "/" + info.GetFileName() + } + row[cobrautil.ROW_ID] = fmt.Sprintf("%d", info.GetId()) + row[cobrautil.ROW_FILE_NAME] = fileName + row[cobrautil.ROW_PARENT_ID] = fmt.Sprintf("%d", info.GetParentId()) + row[cobrautil.ROW_FILE_TYPE] = fmt.Sprintf("%v", info.GetFileType()) + row[cobrautil.ROW_OWNER] = info.GetOwner() + row[cobrautil.ROW_CTIME] = time.Unix(int64(info.GetCtime()/1000000), 0).Format("2006-01-02 15:04:05") + + // generate a query file command + fInfoCmd := file.NewQueryFileCommand() + config.AlignFlagsValue(pCmd.Cmd, fInfoCmd.Cmd, []string{ + config.RPCRETRYTIMES, config.RPCTIMEOUT, config.CURVEBS_MDSADDR, + }) + fInfoCmd.Cmd.Flags().Set("path", fileName) + + // Get file size + sizeRes, err := file.GetFileSize(fInfoCmd.Cmd) + if err.TypeCode() != cmderror.CODE_SUCCESS { + errs = append(errs, err) + continue } + row[cobrautil.ROW_FILE_SIZE] = fmt.Sprintf("%s", humanize.IBytes(sizeRes.GetFileSize())) + // Get allocated size + allocRes, err := file.GetAllocatedSize(fInfoCmd.Cmd) + if err.TypeCode() != cmderror.CODE_SUCCESS { + errs = append(errs, err) + continue + } + row[cobrautil.ROW_ALLOC_SIZE] = fmt.Sprintf("%s", humanize.IBytes(allocRes.GetAllocatedSize())) + rows = append(rows, row) } list := cobrautil.ListMap2ListSortByKeys(rows, pCmd.Header, []string{cobrautil.ROW_OWNER, cobrautil.ROW_FILE_TYPE, cobrautil.ROW_PARENT_ID}) pCmd.TableNew.AppendBulk(list) - errRet := cmderror.MergeCmdError(errors) - pCmd.Error = errRet - pCmd.Result = results + if len(errs) != 0 { + mergeErr := cmderror.MergeCmdError(errs) + pCmd.Result, pCmd.Error = result, mergeErr + return mergeErr.ToError() + } + pCmd.Result, pCmd.Error = result, cmderror.Success() return nil } @@ -221,3 +215,21 @@ func (pCmd *DirCommand) RunCommand(cmd *cobra.Command, args []string) error { func (pCmd *DirCommand) ResultPlainOutput() error { return output.FinalCmdOutputPlain(&pCmd.FinalCurveCmd) } + +func ListDir(caller *cobra.Command) (*nameserver2.ListDirResponse, *cmderror.CmdError) { + lsCmd := NewListDirCommand() + config.AlignFlagsValue(caller, lsCmd.Cmd, []string{ + config.RPCRETRYTIMES, config.RPCTIMEOUT, config.CURVEBS_MDSADDR, + config.CURVEBS_PATH, config.CURVEBS_USER, config.CURVEBS_PASSWORD, + }) + lsCmd.Cmd.SilenceErrors = true + lsCmd.Cmd.SilenceUsage = true + lsCmd.Cmd.SetArgs([]string{"--format", config.FORMAT_NOOUT}) + err := lsCmd.Cmd.Execute() + if err != nil { + retErr := cmderror.ErrBsListDir() + retErr.Format(err.Error()) + return lsCmd.Response, retErr + } + return lsCmd.Response, cmderror.Success() +} diff --git a/tools-v2/pkg/config/bs.go b/tools-v2/pkg/config/bs.go index f2ce148ec3..064ed7f02a 100644 --- a/tools-v2/pkg/config/bs.go +++ b/tools-v2/pkg/config/bs.go @@ -53,10 +53,9 @@ const ( CURVEBS_DEFAULT_PASSWORD = "root_password" CURVEBS_CLUSTERMAP = "clustermap" VIPER_CURVEBS_CLUSTERMAP = "curvebs.clustermap" - CURVEBS_FILENAME = "filename" - VIPER_CURVEBS_FILENAME = "curvebs.filename" - CURVEBS_FORCEDELETE = "forcedelete" - CURVEBS_DEFAULT_FORCEDELETE = false + CURVEBS_FORCE = "force" + VIPER_CURVEBS_FORCE = "curvebs.force" + CURVEBS_DEFAULT_FORCE = false CURVEBS_LOGIC_POOL_ID = "logicalpoolid" VIPER_CURVEBS_LOGIC_POOL_ID = "curvebs.logicalpoolid" CURVEBS_COPYSET_ID = "copysetid" @@ -76,6 +75,10 @@ const ( CURVEBS_STRIPE_COUNT = "stripecount" VIPER_CURVEBS_STRIPE_COUNT = "curvebs.stripecount" CURVEBS_DEFAULT_STRIPE_COUNT = uint64(32) + CURVEBS_RECYCLE_PREFIX = "recycleprefix" + VIPER_RECYCLE_PREFIX = "curvebs.recycleprefix" + CURVE_EXPIRED_TIME = "expiredtime" + VIPER_CURVE_EXPIRED_TIME = "curvebs.expiredtime" CURVEBS_LIMIT = "limit" VIPER_CURVEBS_LIMIT = "curvebs.limit" CURVEBS_BURST = "burst" @@ -93,36 +96,40 @@ var ( RPCRETRYTIMES: VIPER_GLOBALE_RPCRETRYTIMES, // bs - CURVEBS_MDSADDR: VIPER_CURVEBS_MDSADDR, - CURVEBS_MDSDUMMYADDR: VIPER_CURVEBS_MDSDUMMYADDR, - CURVEBS_PATH: VIPER_CURVEBS_PATH, - CURVEBS_USER: VIPER_CURVEBS_USER, - CURVEBS_PASSWORD: VIPER_CURVEBS_PASSWORD, - CURVEBS_ETCDADDR: VIPER_CURVEBS_ETCDADDR, - CURVEBS_LOGIC_POOL_ID: VIPER_CURVEBS_LOGIC_POOL_ID, - CURVEBS_COPYSET_ID: VIPER_CURVEBS_COPYSET_ID, - CURVEBS_PEERS_ADDRESS: VIPER_CURVEBS_PEERS_ADDRESS, - CURVEBS_CLUSTERMAP: VIPER_CURVEBS_CLUSTERMAP, - CURVEBS_OFFSET: VIPER_CURVEBS_OFFSET, - CURVEBS_SIZE: VIPER_CURVEBS_SIZE, - CURVEBS_STRIPE_UNIT: VIPER_CURVEBS_STRIPE_UNIT, - CURVEBS_STRIPE_COUNT: VIPER_CURVEBS_STRIPE_COUNT, - CURVEBS_LIMIT: VIPER_CURVEBS_LIMIT, - CURVEBS_BURST: VIPER_CURVEBS_BURST, - CURVEBS_BURST_LENGTH: VIPER_CURVEBS_BURST_LENGTH, + CURVEBS_MDSADDR: VIPER_CURVEBS_MDSADDR, + CURVEBS_MDSDUMMYADDR: VIPER_CURVEBS_MDSDUMMYADDR, + CURVEBS_PATH: VIPER_CURVEBS_PATH, + CURVEBS_USER: VIPER_CURVEBS_USER, + CURVEBS_PASSWORD: VIPER_CURVEBS_PASSWORD, + CURVEBS_ETCDADDR: VIPER_CURVEBS_ETCDADDR, + CURVEBS_LOGIC_POOL_ID: VIPER_CURVEBS_LOGIC_POOL_ID, + CURVEBS_COPYSET_ID: VIPER_CURVEBS_COPYSET_ID, + CURVEBS_PEERS_ADDRESS: VIPER_CURVEBS_PEERS_ADDRESS, + CURVEBS_CLUSTERMAP: VIPER_CURVEBS_CLUSTERMAP, + CURVEBS_OFFSET: VIPER_CURVEBS_OFFSET, + CURVEBS_SIZE: VIPER_CURVEBS_SIZE, + CURVEBS_STRIPE_UNIT: VIPER_CURVEBS_STRIPE_UNIT, + CURVEBS_STRIPE_COUNT: VIPER_CURVEBS_STRIPE_COUNT, + CURVEBS_LIMIT: VIPER_CURVEBS_LIMIT, + CURVEBS_BURST: VIPER_CURVEBS_BURST, + CURVEBS_BURST_LENGTH: VIPER_CURVEBS_BURST_LENGTH, + CURVEBS_FORCE: VIPER_CURVEBS_FORCE, + CURVEBS_TYPE: VIPER_CURVEBS_TYPE, + CURVE_EXPIRED_TIME: VIPER_CURVE_EXPIRED_TIME, + CURVEBS_RECYCLE_PREFIX: VIPER_RECYCLE_PREFIX, } BSFLAG2DEFAULT = map[string]interface{}{ // bs CURVEBS_USER: CURVEBS_DEFAULT_USER, CURVEBS_PASSWORD: CURVEBS_DEFAULT_PASSWORD, - CURVEBS_FORCEDELETE: CURVEBS_DEFAULT_FORCEDELETE, CURVEBS_SIZE: CURVEBS_DEFAULT_SIZE, CURVEBS_STRIPE_UNIT: CURVEBS_DEFAULT_STRIPE_UNIT, CURVEBS_STRIPE_COUNT: CURVEBS_DEFAULT_STRIPE_COUNT, CURVEBS_BURST: CURVEBS_DEFAULT_BURST, CURVEBS_BURST_LENGTH: CURVEBS_DEFAULT_BURST_LENGTH, CURVEBS_PATH: CURVEBS_DEFAULT_PATH, + CURVEBS_FORCE: CURVEBS_DEFAULT_FORCE, } ) @@ -244,7 +251,6 @@ func AddBsPasswordOptionFlag(cmd *cobra.Command) { AddBsStringOptionFlag(cmd, CURVEBS_PASSWORD, "user password") } - // etcd func AddBsEtcdAddrFlag(cmd *cobra.Command) { AddBsStringOptionFlag(cmd, CURVEBS_ETCDADDR, "etcd address, should be like 127.0.0.1:8700,127.0.0.1:8701,127.0.0.1:8702") @@ -280,14 +286,6 @@ func AddBsPathRequiredFlag(cmd *cobra.Command) { AddBsStringRequiredFlag(cmd, CURVEBS_PATH, "file path") } -func AddBsUsernameRequiredFlag(cmd *cobra.Command) { - AddBsStringRequiredFlag(cmd, CURVEBS_USER, "username") -} - -func AddBsFilenameRequiredFlag(cmd *cobra.Command) { - AddBsStringRequiredFlag(cmd, CURVEBS_FILENAME, "the full path of file") -} - func AddBSLogicalPoolIdRequiredFlag(cmd *cobra.Command) { AddBsUint32RequiredFlag(cmd, CURVEBS_LOGIC_POOL_ID, "logical pool id") } @@ -305,7 +303,7 @@ func AddBSPeersConfFlag(cmd *cobra.Command) { } func AddBsForceDeleteOptionFlag(cmd *cobra.Command) { - AddBsBoolOptionFlag(cmd, CURVEBS_FORCEDELETE, "whether to force delete the file") + AddBsBoolOptionFlag(cmd, CURVEBS_FORCE, "whether to force delete the file") } func AddBsOffsetRequiredFlag(cmd *cobra.Command) { @@ -450,3 +448,20 @@ func GetBsFlagInt32(cmd *cobra.Command, flagName string) int32 { } return value } + +// flag for clean recycle bin +func AddBsRecyclePrefixOptionFlag(cmd *cobra.Command) { + AddBsStringOptionFlag(cmd, CURVEBS_RECYCLE_PREFIX, "recycle prefix (default \"\")") +} + +func AddBsExpireTimeOptionFlag(cmd *cobra.Command) { + AddBsStringOptionFlag(cmd, CURVE_EXPIRED_TIME, "expire time (default 0s)") +} + +func GetBsRecyclePrefix(cmd *cobra.Command) string { + return GetBsFlagString(cmd, CURVEBS_RECYCLE_PREFIX) +} + +func GetBsExpireTime(cmd *cobra.Command) time.Duration { + return GetBsFlagDuration(cmd, CURVE_EXPIRED_TIME) +}