diff --git a/tools-v2/internal/error/error.go b/tools-v2/internal/error/error.go index 23f9849f33..930cc3d237 100644 --- a/tools-v2/internal/error/error.go +++ b/tools-v2/internal/error/error.go @@ -366,6 +366,10 @@ var ( return NewInternalCmdError(39, "list zone fail. the error is %s") } + ErrBsDeleteFile = func() *CmdError { + return NewInternalCmdError(40, "delete file fail. the error is %s") + } + // http error ErrHttpUnreadableResult = func() *CmdError { return NewHttpResultCmdError(1, "http response is unreadable, the uri is: %s, the error is: %s") @@ -433,7 +437,7 @@ var ( case mds.FSStatusCode_S3_INFO_ERROR: message = "s3 info is not available" case mds.FSStatusCode_FSNAME_INVALID: - message = "fsname should match regex: ^([a-z0-9]+\\-?)+$" + message = "fsname should match regex: ^([a-z0-9]+\\-?)+$" default: message = fmt.Sprintf("delete fs failed!, error is %s", mds.FSStatusCode_name[int32(code)]) } diff --git a/tools-v2/internal/utils/row.go b/tools-v2/internal/utils/row.go index 3e82d12664..f387004819 100644 --- a/tools-v2/internal/utils/row.go +++ b/tools-v2/internal/utils/row.go @@ -97,6 +97,7 @@ const ( ROW_ZONE = "zone" ROW_IP = "ip" ROW_PORT = "port" + ROW_REASON = "reason" // s3 ROW_S3CHUNKINFO_CHUNKID = "s3ChunkId" diff --git a/tools-v2/pkg/cli/command/curvebs/bs.go b/tools-v2/pkg/cli/command/curvebs/bs.go index 729e6e35e3..0e763ac769 100644 --- a/tools-v2/pkg/cli/command/curvebs/bs.go +++ b/tools-v2/pkg/cli/command/curvebs/bs.go @@ -24,6 +24,7 @@ package curvebs import ( basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/delete" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/list" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/query" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/status" @@ -41,6 +42,7 @@ func (bsCmd *CurveBsCommand) AddSubCommands() { list.NewListCommand(), query.NewQueryCommand(), status.NewStatusCommand(), + delete.NewDeleteCommand(), ) } diff --git a/tools-v2/pkg/cli/command/curvebs/delete/delete.go b/tools-v2/pkg/cli/command/curvebs/delete/delete.go new file mode 100644 index 0000000000..2cd5c253cf --- /dev/null +++ b/tools-v2/pkg/cli/command/curvebs/delete/delete.go @@ -0,0 +1,137 @@ +/* + * Project: tools-v2 + * Created Date: 2022-11-14 + * Author: shentupenghui@gmail.com + */ + +package delete + +import ( + "context" + 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" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "google.golang.org/grpc" +) + +const ( + deleteCliExample = `curve bs delete --filename /curvebs-file-name --username username [--password password] [--forcedelete true]` +) + +type DeleteCertainFileRpc struct { + Info *basecmd.Rpc + Request *nameserver2.DeleteFileRequest + mdsClient nameserver2.CurveFSServiceClient +} + +// DeleteCommand definition +type DeleteCommand struct { + basecmd.FinalCurveCmd + Rpc *DeleteCertainFileRpc + Response *nameserver2.DeleteFileResponse +} + +var _ basecmd.FinalCurveCmdFunc = (*DeleteCommand)(nil) + +func (gRpc *DeleteCertainFileRpc) NewRpcClient(cc grpc.ClientConnInterface) { + gRpc.mdsClient = nameserver2.NewCurveFSServiceClient(cc) + +} + +func (gRpc *DeleteCertainFileRpc) Stub_Func(ctx context.Context) (interface{}, error) { + return gRpc.mdsClient.DeleteFile(ctx, gRpc.Request) +} + +func (deleteCommand *DeleteCommand) Init(cmd *cobra.Command, args []string) error { + mdsAddrs, err := config.GetBsMdsAddrSlice(deleteCommand.Cmd) + if err.TypeCode() != cmderror.CODE_SUCCESS { + return err.ToError() + } + //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) + username := config.GetBsFlagString(deleteCommand.Cmd, config.CURVEBS_USER) + password := config.GetBsFlagString(deleteCommand.Cmd, config.CURVEBS_PASSWORD) + forcedelete := config.GetFlagBool(deleteCommand.Cmd, config.CURVEBS_FORCEDELETE) + date, errDat := cobrautil.GetTimeofDayUs() + if errDat.TypeCode() != cmderror.CODE_SUCCESS { + return errDat.ToError() + } + deleteRequest := nameserver2.DeleteFileRequest{ + FileName: &filename, + Owner: &username, + Date: &date, + ForceDelete: &forcedelete, + } + if username == viper.GetString(config.VIPER_CURVEBS_USER) && len(password) != 0 { + strSig := cobrautil.GetString2Signature(date, username) + sig := cobrautil.CalcString2Signature(strSig, password) + deleteRequest.Signature = &sig + } + deleteCommand.Rpc = &DeleteCertainFileRpc{ + Info: basecmd.NewRpc(mdsAddrs, timeout, retrytimes, "DeleteFile"), + Request: &deleteRequest, + } + header := []string{cobrautil.ROW_RESULT, cobrautil.ROW_REASON} + deleteCommand.SetHeader(header) + deleteCommand.TableNew.SetAutoMergeCellsByColumnIndex(cobrautil.GetIndexSlice( + deleteCommand.Header, header, + )) + return nil +} + +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.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 + } + out[cobrautil.ROW_RESULT] = "success" + out[cobrautil.ROW_REASON] = "" + list := cobrautil.Map2List(out, []string{cobrautil.ROW_RESULT, cobrautil.ROW_REASON}) + deleteCommand.TableNew.Append(list) + return nil +} + +func (deleteCommand *DeleteCommand) Print(cmd *cobra.Command, args []string) error { + return output.FinalCmdOutput(&deleteCommand.FinalCurveCmd, deleteCommand) +} + +func (deleteCommand *DeleteCommand) ResultPlainOutput() error { + return output.FinalCmdOutputPlain(&deleteCommand.FinalCurveCmd) +} + +func (deleteCommand *DeleteCommand) AddFlags() { + config.AddBsFilenameRequiredFlag(deleteCommand.Cmd) + config.AddBsUsernameRequiredFlag(deleteCommand.Cmd) + config.AddBsPasswordOptionFlag(deleteCommand.Cmd) + config.AddBsForceDeleteOptionFlag(deleteCommand.Cmd) +} + +// NewDeleteCommand return the mid cli +func NewDeleteCommand() *cobra.Command { + deleteCommand := &DeleteCommand{ + FinalCurveCmd: basecmd.FinalCurveCmd{ + Use: "delete", + Short: "delete certain file in curvebs", + Example: deleteCliExample, + }, + } + basecmd.NewFinalCurveCli(&deleteCommand.FinalCurveCmd, deleteCommand) + return basecmd.NewFinalCurveCli(&deleteCommand.FinalCurveCmd, deleteCommand) +} diff --git a/tools-v2/pkg/config/bs.go b/tools-v2/pkg/config/bs.go index 1e373b5b13..e85a4bb625 100644 --- a/tools-v2/pkg/config/bs.go +++ b/tools-v2/pkg/config/bs.go @@ -33,22 +33,26 @@ import ( const ( // curvebs - CURVEBS_MDSADDR = "mdsaddr" - VIPER_CURVEBS_MDSADDR = "curvebs.mdsAddr" - CURVEBS_MDSDUMMYADDR = "mdsdummyaddr" - VIPER_CURVEBS_MDSDUMMYADDR = "curvebs.mdsDummyAddr" - CURVEBS_ETCDADDR = "etcdaddr" - VIPER_CURVEBS_ETCDADDR = "curvebs.etcdAddr" - CURVEBS_PATH = "path" - VIPER_CURVEBS_PATH = "curvebs.path" - CURVEBS_USER = "user" - VIPER_CURVEBS_USER = "curvebs.root.user" - CURVEBS_DEFAULT_USER = "root" - CURVEBS_PASSWORD = "password" - VIPER_CURVEBS_PASSWORD = "curvebs.root.password" - CURVEBS_DEFAULT_PASSWORD = "root_password" - CURVEBS_DIR = "dir" - VIPER_CURVEBS_DIR = "curvebs.dir" + CURVEBS_MDSADDR = "mdsaddr" + VIPER_CURVEBS_MDSADDR = "curvebs.mdsAddr" + CURVEBS_MDSDUMMYADDR = "mdsdummyaddr" + VIPER_CURVEBS_MDSDUMMYADDR = "curvebs.mdsDummyAddr" + CURVEBS_ETCDADDR = "etcdaddr" + VIPER_CURVEBS_ETCDADDR = "curvebs.etcdAddr" + CURVEBS_PATH = "path" + VIPER_CURVEBS_PATH = "curvebs.path" + CURVEBS_USER = "user" + VIPER_CURVEBS_USER = "curvebs.root.user" + CURVEBS_DEFAULT_USER = "root" + CURVEBS_PASSWORD = "password" + VIPER_CURVEBS_PASSWORD = "curvebs.root.password" + CURVEBS_DEFAULT_PASSWORD = "root_password" + CURVEBS_FILENAME = "filename" + VIPER_CURVEBS_FILENAME = "curvebs.filename" + CURVEBS_FORCEDELETE = "forcedelete" + CURVEBS_DEFAULT_FORCEDELETE = "false" + CURVEBS_DIR = "dir" + VIPER_CURVEBS_DIR = "curvebs.dir" ) var ( @@ -69,8 +73,9 @@ var ( BSFLAG2DEFAULT = map[string]interface{}{ // bs - CURVEBS_USER: CURVEBS_DEFAULT_USER, - CURVEBS_PASSWORD: CURVEBS_DEFAULT_PASSWORD, + CURVEBS_USER: CURVEBS_DEFAULT_USER, + CURVEBS_PASSWORD: CURVEBS_DEFAULT_PASSWORD, + CURVEBS_FORCEDELETE: CURVEBS_DEFAULT_FORCEDELETE, } ) @@ -110,6 +115,18 @@ func AddBsStringRequiredFlag(cmd *cobra.Command, name string, usage string) { } } +func AddBsBoolOptionFlag(cmd *cobra.Command, name string, usage string) { + defaultValue := FLAG2DEFAULT[name] + if defaultValue == nil { + defaultValue = false + } + cmd.Flags().Bool(name, defaultValue.(bool), usage) + err := viper.BindPFlag(FLAG2VIPER[name], cmd.Flags().Lookup(name)) + if err != nil { + cobra.CheckErr(err) + } +} + // add flag option // bs mds[option] func AddBsMdsFlagOption(cmd *cobra.Command) { @@ -145,6 +162,18 @@ 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 AddBsForceDeleteOptionFlag(cmd *cobra.Command) { + AddBsBoolOptionFlag(cmd, CURVEBS_FORCEDELETE, "whether to force delete the file") +} + // get stingslice flag func GetBsFlagStringSlice(cmd *cobra.Command, flagName string) []string { var value []string