diff --git a/tools-v2/README.md b/tools-v2/README.md index eb29d05730..d716711eb4 100644 --- a/tools-v2/README.md +++ b/tools-v2/README.md @@ -1737,6 +1737,24 @@ Output: +---------+ ``` +##### create snapshot + +create snapshot + +Usage: +```bash +curve bs create volume snapshot --user root --filename test --snapshotname snap-test +``` + +Output: +``` ++------+----------+--------------+---------+ +| USER | FILENAME | SNAPSHOTNAME | RESULT | ++------+----------+------------------------+ +| root | test | snap-test | success | ++------+----------+--------------+---------+ +``` + #### check ##### check copyset diff --git a/tools-v2/internal/utils/row.go b/tools-v2/internal/utils/row.go index 8b94801f37..b3cdce8edd 100644 --- a/tools-v2/internal/utils/row.go +++ b/tools-v2/internal/utils/row.go @@ -128,6 +128,7 @@ const ( ROW_UNHEALTHY_COUNT = "unhealthyCount" ROW_HEALTHY_RATIO = "ratio" ROW_UNHEALTHY_RATIO = "unhealthy-Ratio" + ROW_SNAPSHOTNAME = "snapshotName" ROW_RW_STATUS = "rwStatus" ROW_DISK_STATE = "diskState" diff --git a/tools-v2/internal/utils/snapshot.go b/tools-v2/internal/utils/snapshot.go index 9010ada75a..1aefdeb3ee 100644 --- a/tools-v2/internal/utils/snapshot.go +++ b/tools-v2/internal/utils/snapshot.go @@ -42,6 +42,8 @@ const ( QueryOffset = "Offset" QueryStatus = "Status" QueryType = "Type" + QueryFile = "File" + QueryName = "Name" ActionClone = "Clone" ActionRecover = "Recover" diff --git a/tools-v2/pkg/cli/command/curvebs/create/create.go b/tools-v2/pkg/cli/command/curvebs/create/create.go index 947385d113..8c0971b2c7 100644 --- a/tools-v2/pkg/cli/command/curvebs/create/create.go +++ b/tools-v2/pkg/cli/command/curvebs/create/create.go @@ -27,6 +27,7 @@ import ( "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/create/cluster" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/create/dir" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/create/file" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/create/volume" "github.com/spf13/cobra" ) @@ -41,6 +42,7 @@ func (createCmd *CreateCmd) AddSubCommands() { cluster.NewClusterTopoCmd(), dir.NewDirectoryCommand(), file.NewFileCommand(), + volume.NewVolumeCommand(), ) } diff --git a/tools-v2/pkg/cli/command/curvebs/create/volume/snapshot/snapshot.go b/tools-v2/pkg/cli/command/curvebs/create/volume/snapshot/snapshot.go new file mode 100644 index 0000000000..e2833fb702 --- /dev/null +++ b/tools-v2/pkg/cli/command/curvebs/create/volume/snapshot/snapshot.go @@ -0,0 +1,128 @@ +/* +* 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-09-23 +* Author: baytan0720 + */ + +package snapshot + +import ( + "encoding/json" + "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/config" + "github.com/opencurve/curve/tools-v2/pkg/output" + "github.com/spf13/cobra" +) + +const ( + snapshotExample = `$ curve bs create volume snapshot --user root --filename test --snapshotname snap-test` +) + +type SnapshotCmd struct { + basecmd.FinalCurveCmd + snapshotAddrs []string + timeout time.Duration + + user string + fileName string + snapshotName string +} + +var _ basecmd.FinalCurveCmdFunc = (*SnapshotCmd)(nil) + +func NewCommand() *cobra.Command { + return NewSnapshotCmd().Cmd +} + +func NewSnapshotCmd() *SnapshotCmd { + sCmd := &SnapshotCmd{ + FinalCurveCmd: basecmd.FinalCurveCmd{ + Use: "snapshot", + Short: "create volume snapshot in curvebs cluster", + Example: snapshotExample, + }, + } + basecmd.NewFinalCurveCli(&sCmd.FinalCurveCmd, sCmd) + return sCmd +} + +func (sCmd *SnapshotCmd) AddFlags() { + config.AddBsSnapshotCloneFlagOption(sCmd.Cmd) + config.AddHttpTimeoutFlag(sCmd.Cmd) + config.AddBsUserRequiredFlag(sCmd.Cmd) + config.AddBsFileNameRequiredFlag(sCmd.Cmd) + config.AddBsSnapshotNameRequiredFlag(sCmd.Cmd) +} + +func (sCmd *SnapshotCmd) Init(cmd *cobra.Command, args []string) error { + snapshotAddrs, err := config.GetBsSnapshotAddrSlice(sCmd.Cmd) + if err.TypeCode() != cmderror.CODE_SUCCESS || len(snapshotAddrs) == 0 { + return err.ToError() + } + sCmd.snapshotAddrs = snapshotAddrs + sCmd.timeout = config.GetFlagDuration(sCmd.Cmd, config.HTTPTIMEOUT) + sCmd.user = config.GetBsFlagString(sCmd.Cmd, config.CURVEBS_USER) + sCmd.fileName = config.GetBsFlagString(sCmd.Cmd, config.CURVEBS_FILENAME) + sCmd.snapshotName = config.GetBsFlagString(sCmd.Cmd, config.CURVEBS_SNAPSHOTNAME) + sCmd.SetHeader([]string{cobrautil.ROW_USER, cobrautil.ROW_FILE_NAME, cobrautil.ROW_SNAPSHOTNAME, cobrautil.ROW_RESULT}) + return nil +} + +func (sCmd *SnapshotCmd) RunCommand(cmd *cobra.Command, args []string) error { + params := map[string]any{ + cobrautil.QueryAction: cobrautil.ActionCreateSnapshot, + cobrautil.QueryUser: sCmd.user, + cobrautil.QueryFile: sCmd.fileName, + cobrautil.QueryName: sCmd.snapshotName, + } + subUri := cobrautil.NewSnapshotQuerySubUri(params) + metric := basecmd.NewMetric(sCmd.snapshotAddrs, subUri, sCmd.timeout) + result, err := basecmd.QueryMetric(metric) + if err.TypeCode() != cmderror.CODE_SUCCESS { + return err.ToError() + } + payload := map[string]any{} + if err := json.Unmarshal([]byte(result), &payload); err != nil { + return err + } + row := make(map[string]string) + row[cobrautil.ROW_USER] = sCmd.user + row[cobrautil.ROW_FILE_NAME] = sCmd.fileName + row[cobrautil.ROW_SNAPSHOTNAME] = sCmd.snapshotName + + if payload["Code"] != "0" { + row[cobrautil.ROW_RESULT] = cobrautil.ROW_VALUE_FAILED + } else { + row[cobrautil.ROW_RESULT] = cobrautil.ROW_VALUE_SUCCESS + } + + sCmd.Result = row + return nil +} + +func (sCmd *SnapshotCmd) Print(cmd *cobra.Command, args []string) error { + return output.FinalCmdOutput(&sCmd.FinalCurveCmd, sCmd) +} + +func (sCmd *SnapshotCmd) ResultPlainOutput() error { + return output.FinalCmdOutputPlain(&sCmd.FinalCurveCmd) +} diff --git a/tools-v2/pkg/cli/command/curvebs/create/volume/volume.go b/tools-v2/pkg/cli/command/curvebs/create/volume/volume.go new file mode 100644 index 0000000000..a0f2ea41ef --- /dev/null +++ b/tools-v2/pkg/cli/command/curvebs/create/volume/volume.go @@ -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-09-23 +* Author: baytan0720 + */ + +package volume + +import ( + basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/create/volume/snapshot" + "github.com/spf13/cobra" +) + +type VolumeCommand struct { + basecmd.MidCurveCmd +} + +var _ basecmd.MidCurveCmdFunc = (*VolumeCommand)(nil) // check interface + +func (vCmd *VolumeCommand) AddSubCommands() { + vCmd.Cmd.AddCommand( + snapshot.NewCommand(), + ) +} + +func NewVolumeCommand() *cobra.Command { + vCmd := &VolumeCommand{ + basecmd.MidCurveCmd{ + Use: "volume", + Short: "create resources in the curvebs", + }, + } + return basecmd.NewMidCurveCli(&vCmd.MidCurveCmd, vCmd) +} diff --git a/tools-v2/pkg/config/bs.go b/tools-v2/pkg/config/bs.go index 574a263088..c812545c40 100644 --- a/tools-v2/pkg/config/bs.go +++ b/tools-v2/pkg/config/bs.go @@ -144,6 +144,10 @@ const ( VIPER_CURVEBS_TASKID = "curvebs.taskid" CURVEBS_FAILED = "failed" VIPER_CURVEBS_FAILED = "curvebs.failed" + CURVEBS_FILENAME = "filename" + VIPER_CURVEBS_FILENAME = "curvebs.filename" + CURVEBS_SNAPSHOTNAME = "snapshotname" + VIPER_CURVEBS_SNAPSHOTNAME = "curvebs.snapshotname" ) var ( @@ -198,6 +202,8 @@ var ( CURVEBS_DEST: VIPER_CURVEBS_DEST, CURVEBS_TASKID: VIPER_CURVEBS_TASKID, CURVEBS_FAILED: VIPER_CURVEBS_FAILED, + CURVEBS_FILENAME: VIPER_CURVEBS_FILENAME, + CURVEBS_SNAPSHOTNAME: VIPER_CURVEBS_SNAPSHOTNAME, } BSFLAG2DEFAULT = map[string]interface{}{ @@ -634,6 +640,18 @@ func AddBsFailedOptionFlag(cmd *cobra.Command) { AddBsBoolOptionFlag(cmd, CURVEBS_FAILED, "failed") } +func AddBsUserRequiredFlag(cmd *cobra.Command) { + AddBsStringRequiredFlag(cmd, CURVEBS_USER, "user name") +} + +func AddBsFileNameRequiredFlag(cmd *cobra.Command) { + AddBsStringRequiredFlag(cmd, CURVEBS_FILENAME, "file name") +} + +func AddBsSnapshotNameRequiredFlag(cmd *cobra.Command) { + AddBsStringRequiredFlag(cmd, CURVEBS_SNAPSHOTNAME, "snapshot name") +} + // get stingslice flag func GetBsFlagStringSlice(cmd *cobra.Command, flagName string) []string { var value []string