diff --git a/tools-v2/README.md b/tools-v2/README.md index f275e5455a..f45aaa83eb 100644 --- a/tools-v2/README.md +++ b/tools-v2/README.md @@ -77,6 +77,7 @@ A tool for CurveFS & CurveBs. - [delete volume](#delete-volume) - [delete volume clone](#delete-volume-clone) - [delete volume recover](#delete-volume-recover) + - [delete snapshot](#delete-snapshot) - [update](#update) - [update peer](#update-peer) - [update leader](#update-leader) @@ -1693,6 +1694,28 @@ Output: +------+--------------------------------------+--------------------------------------+-------+---------+--------+ ``` +##### delete snapshot + +delete the snapshot in curvebs + +Usage: + +```shell +curve bs delete snapshot --path /test111/test222 --user root --snapshotFailed=false +``` + +Output: + +```shell ++--------------------------------------+--------------+---------+--------+ +| SNAPSHOTID | SNAPSHOTNAME | RESULT | REASON | ++--------------------------------------+--------------+---------+--------+ +| 3b9d14c2-79a2-4454-9b0a-6cb7477956db | testsnap1 | success | null | ++--------------------------------------+--------------+---------+--------+ +| 2a94fb51-e985-4e98-a34c-f02aef8e97b5 | testsnap2 | success | null | ++--------------------------------------+--------------+---------+--------+ +``` + #### update ##### update peer @@ -2030,13 +2053,13 @@ curve bs stop snapshot Output: ```shell -+--------------------------------------+--------------+---------+ -| SNAPSHOTID | SNAPSHOTNAME | RESULT | -+--------------------------------------+--------------+---------+ -| 9aa2b4c5-f27b-40a2-82c9-4e0ad6093567 | testsnap | success | -+--------------------------------------+--------------+---------+ -| 0171a33b-17b7-4215-9f00-6d8de2686f77 | testsnap1 | success | -+--------------------------------------+--------------+---------+ ++--------------------------------------+--------------+---------+--------+ +| SNAPSHOTID | SNAPSHOTNAME | RESULT | REASON | ++--------------------------------------+--------------+---------+--------+ +| 3b9d14c2-79a2-4454-9b0a-6cb7477956db | testsnap1 | success | null | ++--------------------------------------+--------------+---------+--------+ +| 2a94fb51-e985-4e98-a34c-f02aef8e97b5 | testsnap2 | success | null | ++--------------------------------------+--------------+---------+--------+ ``` #### recover diff --git a/tools-v2/internal/utils/snapshot/const.go b/tools-v2/internal/utils/snapshot/const.go index c5b202dac5..3b60d770fe 100644 --- a/tools-v2/internal/utils/snapshot/const.go +++ b/tools-v2/internal/utils/snapshot/const.go @@ -55,4 +55,7 @@ const ( ResultSuccess = "0" Limit = "100" Offset = "0" + + ErrSnaphshot = "5" + DefaultSnapID = "*" ) diff --git a/tools-v2/pkg/cli/command/curvebs/delete/delete.go b/tools-v2/pkg/cli/command/curvebs/delete/delete.go index fe57b58ef0..a8b7f14642 100644 --- a/tools-v2/pkg/cli/command/curvebs/delete/delete.go +++ b/tools-v2/pkg/cli/command/curvebs/delete/delete.go @@ -12,6 +12,7 @@ import ( 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/delete/peer" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/delete/snapshot" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/delete/volume" ) @@ -26,6 +27,7 @@ func (dCmd *DeleteCommand) AddSubCommands() { file.NewFileCommand(), peer.NewCommand(), volume.NewVolumeCommand(), + snapshot.NewSnapShotCommand(), ) } diff --git a/tools-v2/pkg/cli/command/curvebs/delete/snapshot/snapshot.go b/tools-v2/pkg/cli/command/curvebs/delete/snapshot/snapshot.go new file mode 100644 index 0000000000..9609791f11 --- /dev/null +++ b/tools-v2/pkg/cli/command/curvebs/delete/snapshot/snapshot.go @@ -0,0 +1,177 @@ +/* + * 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-10 + * Author: ZackSoul + */ +package snapshot + +import ( + "time" + + cmderror "github.com/opencurve/curve/tools-v2/internal/error" + cobrautil "github.com/opencurve/curve/tools-v2/internal/utils" + snapshotutil "github.com/opencurve/curve/tools-v2/internal/utils/snapshot" + basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command" + listSnapshot "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/list/snapshot" + stopSnapShot "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/stop/snapshot" + "github.com/opencurve/curve/tools-v2/pkg/config" + "github.com/opencurve/curve/tools-v2/pkg/output" + "github.com/spf13/cobra" +) + +const ( + snapshotExample = `$ curve bs delete snapshot --path /test111/test222 --user root --snapshotFailed=false` +) + +type SnapShotCommand struct { + basecmd.FinalCurveCmd + snapshotAddrs []string + timeout time.Duration + + user string + file string + uuid string + failed bool +} + +var _ basecmd.FinalCurveCmdFunc = (*SnapShotCommand)(nil) + +func NewSnapShotCommand() *cobra.Command { + return NewDeleteSnapShotCommand().Cmd +} + +func NewDeleteSnapShotCommand() *SnapShotCommand { + snapShotCommand := &SnapShotCommand{ + FinalCurveCmd: basecmd.FinalCurveCmd{ + Use: "snapshot", + Short: "delete snapshot in curvebs", + Example: snapshotExample, + }, + } + + basecmd.NewFinalCurveCli(&snapShotCommand.FinalCurveCmd, snapShotCommand) + return snapShotCommand +} + +func (sCmd *SnapShotCommand) AddFlags() { + config.AddBsSnapshotCloneFlagOption(sCmd.Cmd) + config.AddHttpTimeoutFlag(sCmd.Cmd) + config.AddBsUserOptionFlag(sCmd.Cmd) + config.AddBsSnapshotIDOptionFlag(sCmd.Cmd) + config.AddBsPathOptionFlag(sCmd.Cmd) + config.AddBsSnapshotFailedOptionFlag(sCmd.Cmd) +} + +func (sCmd *SnapShotCommand) Init(cmd *cobra.Command, args []string) error { + snapshotAddrs, err := config.GetBsSnapshotAddrSlice(sCmd.Cmd) + if err.TypeCode() != cmderror.CODE_SUCCESS { + sCmd.Error = err + return err.ToError() + } + sCmd.snapshotAddrs = snapshotAddrs + sCmd.timeout = config.GetFlagDuration(sCmd.Cmd, config.HTTPTIMEOUT) + sCmd.user = config.GetBsFlagString(sCmd.Cmd, config.CURVEBS_USER) + sCmd.file = config.GetBsFlagString(sCmd.Cmd, config.CURVEBS_PATH) + sCmd.uuid = config.GetBsFlagString(sCmd.Cmd, config.CURVEBS_SNAPSHOT_ID) + sCmd.failed = config.GetBsFlagBool(sCmd.Cmd, config.CURVEBS_SNAPSHOT_FAILED) + header := []string{ + cobrautil.ROW_SNAPSHOT_ID, + cobrautil.ROW_SNAPSHOT_NAME, + cobrautil.ROW_RESULT, + cobrautil.ROW_REASON, + } + sCmd.TableNew.SetAutoMergeCellsByColumnIndex(cobrautil.GetIndexSlice( + sCmd.Header, []string{cobrautil.ROW_FILE}, + )) + sCmd.SetHeader(header) + return nil +} + +func (sCmd *SnapShotCommand) Print(cmd *cobra.Command, args []string) error { + return output.FinalCmdOutput(&sCmd.FinalCurveCmd, sCmd) +} + +func (sCmd *SnapShotCommand) RunCommand(cmd *cobra.Command, args []string) error { + params := map[string]any{ + snapshotutil.QueryAction: snapshotutil.ActionGetFileSnapshotList, + snapshotutil.QueryUser: sCmd.user, + snapshotutil.QueryFile: sCmd.file, + snapshotutil.QueryLimit: snapshotutil.Limit, + snapshotutil.QueryOffset: snapshotutil.Offset, + } + if sCmd.failed { + params[snapshotutil.QueryStatus] = snapshotutil.ErrSnaphshot + } + if sCmd.uuid != snapshotutil.DefaultSnapID { + params[snapshotutil.QueryUUID] = sCmd.uuid + } + snapshotsList, err := listSnapshot.ListSnapShot(sCmd.snapshotAddrs, sCmd.timeout, params) + if err != nil { + sCmd.Error = err + return sCmd.Error.ToError() + } + rows := make([]map[string]string, 0) + if len(snapshotsList) == 0 { + rows = append(rows, stopSnapShot.EmptyOutPut()) + } else { + for _, snapshot := range snapshotsList { + row := make(map[string]string) + err := DeleteSnapShot(sCmd.snapshotAddrs, sCmd.timeout, snapshot) + row[cobrautil.ROW_SNAPSHOT_ID] = snapshot.UUID + row[cobrautil.ROW_SNAPSHOT_NAME] = snapshot.Name + if err.TypeCode() == cmderror.CODE_SUCCESS { + row[cobrautil.ROW_RESULT] = cobrautil.ROW_VALUE_SUCCESS + row[cobrautil.ROW_REASON] = "null" + } else { + row[cobrautil.ROW_RESULT] = cobrautil.ROW_VALUE_FAILED + row[cobrautil.ROW_REASON] = err.ToError().Error() + } + rows = append(rows, row) + } + } + list := cobrautil.ListMap2ListSortByKeys(rows, sCmd.Header, []string{cobrautil.ROW_SNAPSHOT_NAME, cobrautil.ROW_SNAPSHOT_ID}) + var emptyList [][]string = [][]string{} + if len(snapshotsList) == 0 { + sCmd.TableNew.AppendBulk(emptyList) + sCmd.Result = rows + sCmd.Error = cmderror.Success() + return nil + } + sCmd.TableNew.AppendBulk(list) + sCmd.Result = rows + sCmd.Error = cmderror.Success() + return nil +} + +func (sCmd *SnapShotCommand) ResultPlainOutput() error { + return output.FinalCmdOutputPlain(&sCmd.FinalCurveCmd) +} + +func DeleteSnapShot(addrs []string, timeout time.Duration, snapshot *snapshotutil.SnapshotInfo) *cmderror.CmdError { + params := map[string]any{ + snapshotutil.QueryAction: snapshotutil.ActionDeleteSnapshot, + snapshotutil.QueryUser: snapshot.User, + snapshotutil.QueryUUID: snapshot.UUID, + snapshotutil.QueryFile: snapshot.File, + } + subUri := snapshotutil.NewQuerySubUri(params) + metric := basecmd.NewMetric(addrs, subUri, timeout) + _, err := basecmd.QueryMetric(metric) + return err +} diff --git a/tools-v2/pkg/cli/command/curvebs/stop/snapshot/snapshot.go b/tools-v2/pkg/cli/command/curvebs/stop/snapshot/snapshot.go index 7dd826f392..e574983af7 100644 --- a/tools-v2/pkg/cli/command/curvebs/stop/snapshot/snapshot.go +++ b/tools-v2/pkg/cli/command/curvebs/stop/snapshot/snapshot.go @@ -89,7 +89,11 @@ func (sCmd *SnapShotCommand) Init(cmd *cobra.Command, args []string) error { cobrautil.ROW_SNAPSHOT_ID, cobrautil.ROW_SNAPSHOT_NAME, cobrautil.ROW_RESULT, + cobrautil.ROW_REASON, } + sCmd.TableNew.SetAutoMergeCellsByColumnIndex(cobrautil.GetIndexSlice( + sCmd.Header, []string{cobrautil.ROW_FILE}, + )) sCmd.SetHeader(header) return nil } @@ -115,17 +119,23 @@ func (sCmd *SnapShotCommand) RunCommand(cmd *cobra.Command, args []string) error return sCmd.Error.ToError() } rows := make([]map[string]string, 0) - for _, snapshot := range snapshotsList { - row := make(map[string]string) - err := StopSnapShot(sCmd.snapshotAddrs, sCmd.timeout, snapshot) - row[cobrautil.ROW_SNAPSHOT_ID] = snapshot.UUID - row[cobrautil.ROW_SNAPSHOT_NAME] = snapshot.Name - if err.TypeCode() == cmderror.CODE_SUCCESS { - row[cobrautil.ROW_RESULT] = cobrautil.ROW_VALUE_SUCCESS - } else { - row[cobrautil.ROW_RESULT] = cobrautil.ROW_VALUE_FAILED + if len(snapshotsList) == 0 { + rows = append(rows, EmptyOutPut()) + } else { + for _, snapshot := range snapshotsList { + row := make(map[string]string) + err := StopSnapShot(sCmd.snapshotAddrs, sCmd.timeout, snapshot) + row[cobrautil.ROW_SNAPSHOT_ID] = snapshot.UUID + row[cobrautil.ROW_SNAPSHOT_NAME] = snapshot.Name + if err.TypeCode() == cmderror.CODE_SUCCESS { + row[cobrautil.ROW_RESULT] = cobrautil.ROW_VALUE_SUCCESS + row[cobrautil.ROW_REASON] = "null" + } else { + row[cobrautil.ROW_RESULT] = cobrautil.ROW_VALUE_FAILED + row[cobrautil.ROW_REASON] = err.ToError().Error() + } + rows = append(rows, row) } - rows = append(rows, row) } list := cobrautil.ListMap2ListSortByKeys(rows, sCmd.Header, []string{cobrautil.ROW_SNAPSHOT_NAME, cobrautil.ROW_SNAPSHOT_ID}) sCmd.TableNew.AppendBulk(list) @@ -150,3 +160,18 @@ func StopSnapShot(addrs []string, timeout time.Duration, snapshot *snapshotutil. _, err := basecmd.QueryMetric(metric) return err } + +func EmptyOutPut() map[string]string { + emptyResult := "-" + keys := []string{ + cobrautil.ROW_SNAPSHOT_ID, + cobrautil.ROW_SNAPSHOT_NAME, + cobrautil.ROW_RESULT, + cobrautil.ROW_REASON, + } + row := make(map[string]string) + for _, key := range keys { + row[key] = emptyResult + } + return row +} diff --git a/tools-v2/pkg/config/bs.go b/tools-v2/pkg/config/bs.go index 4fad5d2306..24980c88dc 100644 --- a/tools-v2/pkg/config/bs.go +++ b/tools-v2/pkg/config/bs.go @@ -145,6 +145,9 @@ const ( CURVEBS_SNAPSHOT_ID = "snapshotid" VIPER_CURVEBS_SNAPSHOT_ID = "curvebs.snapshotqid" CURVEBS_DEFAULT_SNAPSHOT_ID = "*" + CURVEBS_SNAPSHOT_FAILED = "snapshotFailed" + VIPER_CURVEBS_SNAPSHOT_FAILED = "curvebs.snapshotFailed" + CURVEBS_DEFAULT_SNAPSHOT_FAILED = false CURVEBS_FAILED = "failed" VIPER_CURVEBS_FAILED = "curvebs.failed" CURVEBS_CHUNK_SIZE = "chunksize" @@ -217,31 +220,33 @@ var ( CURVEBS_CHECK_HASH: VIPER_CURVEBS_CHECK_HASH, CURVEBS_FILENAME: VIPER_CURVEBS_FILENAME, CURVEBS_SNAPSHOTNAME: VIPER_CURVEBS_SNAPSHOTNAME, + CURVEBS_SNAPSHOT_FAILED: VIPER_CURVEBS_SNAPSHOT_FAILED, } BSFLAG2DEFAULT = map[string]interface{}{ // bs - CURVEBS_USER: CURVEBS_DEFAULT_USER, - CURVEBS_PASSWORD: CURVEBS_DEFAULT_PASSWORD, - 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, - CURVEBS_MARGIN: CURVEBS_DEFAULT_MARGIN, - CURVEBS_OP: CURVEBS_DEFAULT_OP, - CURVEBS_CHECK_TIME: CURVEBS_DEFAULT_CHECK_TIME, - CURVEBS_SCAN: CURVEBS_DEFAULT_SCAN, - CURVEBS_CHUNKSERVER_ID: CURVEBS_DEFAULT_CHUNKSERVER_ID, - CURVEBS_DRYRUN: CURVEBS_DEFAULT_DRYRUN, - CURVEBS_FIlTER: CURVEBS_DEFAULT_FILTER, - 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_SNAPSHOT_ID: CURVEBS_DEFAULT_SNAPSHOT_ID, + CURVEBS_USER: CURVEBS_DEFAULT_USER, + CURVEBS_PASSWORD: CURVEBS_DEFAULT_PASSWORD, + 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, + CURVEBS_MARGIN: CURVEBS_DEFAULT_MARGIN, + CURVEBS_OP: CURVEBS_DEFAULT_OP, + CURVEBS_CHECK_TIME: CURVEBS_DEFAULT_CHECK_TIME, + CURVEBS_SCAN: CURVEBS_DEFAULT_SCAN, + CURVEBS_CHUNKSERVER_ID: CURVEBS_DEFAULT_CHUNKSERVER_ID, + CURVEBS_DRYRUN: CURVEBS_DEFAULT_DRYRUN, + CURVEBS_FIlTER: CURVEBS_DEFAULT_FILTER, + 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_SNAPSHOT_ID: CURVEBS_DEFAULT_SNAPSHOT_ID, + CURVEBS_SNAPSHOT_FAILED: CURVEBS_DEFAULT_SNAPSHOT_FAILED, } ) @@ -687,6 +692,10 @@ func AddBsSnapshotIDOptionFlag(cmd *cobra.Command) { AddBsStringOptionFlag(cmd, CURVEBS_SNAPSHOT_ID, "snapshot seqId") } +func AddBsSnapshotFailedOptionFlag(cmd *cobra.Command) { + AddBsBoolOptionFlag(cmd, CURVEBS_SNAPSHOT_FAILED, "snapshot failed(error)") +} + func AddBsTaskTypeOptionFlag(cmd *cobra.Command) { AddBsStringOptionFlag(cmd, CURVEBS_TYPE, "only query target type (clone or recover)") }