diff --git a/tools-v2/internal/error/error.go b/tools-v2/internal/error/error.go index 280054f3aa..70181abb87 100644 --- a/tools-v2/internal/error/error.go +++ b/tools-v2/internal/error/error.go @@ -880,4 +880,15 @@ var ( } return NewRpcReultCmdError(code, message) } + ErrCreateCloneFile = func(statusCode nameserver2.StatusCode, path string) *CmdError { + var message string + code := int(statusCode) + switch statusCode { + case nameserver2.StatusCode_kOK: + message = "Created successfully" + default: + message = fmt.Sprintf("failed to create clone file[%s], err: %s", path, statusCode.String()) + } + return NewRpcReultCmdError(code, message) + } ) diff --git a/tools-v2/pkg/cli/command/curvebs/create/create.go b/tools-v2/pkg/cli/command/curvebs/create/create.go index 947385d113..b736d3e04a 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" + clone "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(), + clone.NewCloneCommand(), ) } diff --git a/tools-v2/pkg/cli/command/curvebs/create/volume/clone.go b/tools-v2/pkg/cli/command/curvebs/create/volume/clone.go new file mode 100644 index 0000000000..6fb786ae9f --- /dev/null +++ b/tools-v2/pkg/cli/command/curvebs/create/volume/clone.go @@ -0,0 +1,105 @@ +/* +* 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: curve +* Created Date: 2023-08-23 +* Author: lng2020 + */ + +package volume + +import ( + "time" + + "github.com/spf13/cobra" + + cmderror "github.com/opencurve/curve/tools-v2/internal/error" + 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" +) + +const ( + cloneExample = `$ curve bs create volume clone` +) + +type CloneCmd struct { + basecmd.FinalCurveCmd + snapshotAddrs []string + timeout time.Duration + + user string + src string + dest string + lazy bool +} + +var _ basecmd.FinalCurveCmdFunc = (*CloneCmd)(nil) + +func (cCmd *CloneCmd) Init(cmd *cobra.Command, args []string) error { + snapshotAddrs, err := config.GetBsSnapshotAddrSlice(cCmd.Cmd) + if err.TypeCode() != cmderror.CODE_SUCCESS || len(snapshotAddrs) == 0 { + return err.ToError() + } + cCmd.snapshotAddrs = snapshotAddrs + cCmd.timeout = config.GetFlagDuration(cCmd.Cmd, config.HTTPTIMEOUT) + cCmd.user = config.GetBsFlagString(cCmd.Cmd, config.CURVEBS_USER) + cCmd.src = config.GetBsFlagString(cCmd.Cmd, config.CURVEBS_SRC) + cCmd.dest = config.GetBsFlagString(cCmd.Cmd, config.CURVEBS_DEST) + cCmd.lazy = config.GetBsFlagBool(cCmd.Cmd, config.CURVEBS_LAZY) + return nil +} + +func (cCmd *CloneCmd) RunCommand(cmd *cobra.Command, args []string) error { + c := newCloneOrRecover(cCmd.snapshotAddrs, cCmd.timeout, cCmd.user, cCmd.src, cCmd.dest, cCmd.lazy) + if err := c.CreateClone(); err != nil { + return err + } + return nil +} + +func (cCmd *CloneCmd) Print(cmd *cobra.Command, args []string) error { + return output.FinalCmdOutput(&cCmd.FinalCurveCmd, cCmd) +} + +func (cCmd *CloneCmd) ResultPlainOutput() error { + return output.FinalCmdOutputPlain(&cCmd.FinalCurveCmd) +} + +func (cCmd *CloneCmd) AddFlags() { + config.AddBsSnapshotCloneFlagOption(cCmd.Cmd) + config.AddHttpTimeoutFlag(cCmd.Cmd) + config.AddBsUserOptionFlag(cCmd.Cmd) + config.AddBsSrcOptionFlag(cCmd.Cmd) + config.AddBsDestOptionFlag(cCmd.Cmd) + config.AddBsLazyOptionFlag(cCmd.Cmd) +} + +func NewCreateVolumeCloneCommand() *CloneCmd { + cCmd := &CloneCmd{ + FinalCurveCmd: basecmd.FinalCurveCmd{ + Use: "clone", + Short: "create volume clone tasks in curvebs cluster", + Example: cloneExample, + }, + } + basecmd.NewFinalCurveCli(&cCmd.FinalCurveCmd, cCmd) + return cCmd +} + +func NewCloneCommand() *cobra.Command { + return NewCreateVolumeCloneCommand().Cmd +} diff --git a/tools-v2/pkg/cli/command/curvebs/create/volume/clone_or_recover.go b/tools-v2/pkg/cli/command/curvebs/create/volume/clone_or_recover.go new file mode 100644 index 0000000000..7449ef6d1b --- /dev/null +++ b/tools-v2/pkg/cli/command/curvebs/create/volume/clone_or_recover.go @@ -0,0 +1,148 @@ +/* +* 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: curve +* Created Date: 2023-08-23 +* Author: lng2020 + */ + +package volume + +import ( + "encoding/json" + "fmt" + "net/url" + "strconv" + "time" + + cmderror "github.com/opencurve/curve/tools-v2/internal/error" + basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command" +) + +const ( + version = "0.0.6" +) + +type CloneOrRecover struct { + serverAddress []string + timeout time.Duration + + User string + Src string + Dest string + Lazy bool +} + +func newCloneOrRecover(serverAddress []string, timeout time.Duration, user, src, dest string, lazy bool) *CloneOrRecover { + return &CloneOrRecover{ + serverAddress: serverAddress, + timeout: timeout, + User: user, + Src: src, + Dest: dest, + Lazy: lazy, + } +} + +type QueryParams struct { + Action string `json:"Action"` + Version string `json:"Version"` + User string `json:"User"` + Source string `json:"Source"` + Destination string `json:"Destination"` + Lazy string `json:"Lazy"` +} + +func (c *CloneOrRecover) CreateRecover() error { + params := QueryParams{ + Action: "Recover", + Version: version, + User: c.User, + Source: c.Src, + Destination: c.Dest, + Lazy: strconv.FormatBool(c.Lazy), + } + + var resp struct { + Code string + } + err := c.query(params, &resp) + if err != nil || resp.Code != "0" { + return fmt.Errorf("create recover failed, error=%s", err) + } + + return nil +} + +func (c *CloneOrRecover) CreateClone() error { + params := QueryParams{ + Action: "Clone", + Version: version, + User: c.User, + Source: c.Src, + Destination: c.Dest, + Lazy: strconv.FormatBool(c.Lazy), + } + + var resp struct { + Code string + } + err := c.query(params, &resp) + if err != nil || resp.Code != "0" { + return fmt.Errorf("create clone failed, error=%s", err) + } + + return nil +} + +func (c *CloneOrRecover) query(params QueryParams, data interface{}) error { + encodedParams := c.encodeParam(params) + + subUri := fmt.Sprintf("/SnapshotCloneService?%s", encodedParams) + + metric := basecmd.NewMetric(c.serverAddress, subUri, c.timeout) + + result, err := basecmd.QueryMetric(metric) + if err.TypeCode() != cmderror.CODE_SUCCESS { + return err.ToError() + } + + if err := json.Unmarshal([]byte(result), &data); err != nil { + return err + } + + return nil +} + +func (c *CloneOrRecover) encodeParam(params QueryParams) string { + values := url.Values{} + paramsMap := map[string]string{ + "Action": params.Action, + "Version": params.Version, + "User": params.User, + "Source": params.Source, + "Destination": params.Destination, + "Lazy": params.Lazy, + } + + for key, value := range paramsMap { + if value != "" { + values.Add(key, value) + } + } + + return values.Encode() +} diff --git a/tools-v2/pkg/cli/command/curvebs/create/volume/recover.go b/tools-v2/pkg/cli/command/curvebs/create/volume/recover.go new file mode 100644 index 0000000000..772cccf1cb --- /dev/null +++ b/tools-v2/pkg/cli/command/curvebs/create/volume/recover.go @@ -0,0 +1,105 @@ +/* +* 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: curve +* Created Date: 2023-08-23 +* Author: lng2020 + */ + +package volume + +import ( + "time" + + "github.com/spf13/cobra" + + cmderror "github.com/opencurve/curve/tools-v2/internal/error" + 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" +) + +const ( + recoverExample = `$ curve bs create volume recover` +) + +type RecoverCmd struct { + basecmd.FinalCurveCmd + snapshotAddrs []string + timeout time.Duration + + user string + src string + dest string + lazy bool +} + +var _ basecmd.FinalCurveCmdFunc = (*RecoverCmd)(nil) + +func (rCmd *RecoverCmd) Init(cmd *cobra.Command, args []string) error { + snapshotAddrs, err := config.GetBsSnapshotAddrSlice(rCmd.Cmd) + if err.TypeCode() != cmderror.CODE_SUCCESS || len(snapshotAddrs) == 0 { + return err.ToError() + } + rCmd.snapshotAddrs = snapshotAddrs + rCmd.timeout = config.GetFlagDuration(rCmd.Cmd, config.HTTPTIMEOUT) + rCmd.user = config.GetBsFlagString(rCmd.Cmd, config.CURVEBS_USER) + rCmd.src = config.GetBsFlagString(rCmd.Cmd, config.CURVEBS_SRC) + rCmd.dest = config.GetBsFlagString(rCmd.Cmd, config.CURVEBS_DEST) + rCmd.lazy = config.GetBsFlagBool(rCmd.Cmd, config.CURVEBS_LAZY) + return nil +} + +func (rCmd *RecoverCmd) RunCommand(cmd *cobra.Command, args []string) error { + c := newCloneOrRecover(rCmd.snapshotAddrs, rCmd.timeout, rCmd.user, rCmd.src, rCmd.dest, rCmd.lazy) + if err := c.CreateRecover(); err != nil { + return err + } + return nil +} + +func (rCmd *RecoverCmd) Print(cmd *cobra.Command, args []string) error { + return output.FinalCmdOutput(&rCmd.FinalCurveCmd, rCmd) +} + +func (rCmd *RecoverCmd) ResultPlainOutput() error { + return output.FinalCmdOutputPlain(&rCmd.FinalCurveCmd) +} + +func (rCmd *RecoverCmd) AddFlags() { + config.AddBsSnapshotCloneFlagOption(rCmd.Cmd) + config.AddHttpTimeoutFlag(rCmd.Cmd) + config.AddBsUserOptionFlag(rCmd.Cmd) + config.AddBsSrcOptionFlag(rCmd.Cmd) + config.AddBsDestOptionFlag(rCmd.Cmd) + config.AddBsLazyOptionFlag(rCmd.Cmd) +} + +func NewCreateVolumeRecoverCommand() *RecoverCmd { + rCmd := &RecoverCmd{ + FinalCurveCmd: basecmd.FinalCurveCmd{ + Use: "recover", + Short: "create volume recover tasks in curvebs cluster", + Example: recoverExample, + }, + } + basecmd.NewFinalCurveCli(&rCmd.FinalCurveCmd, rCmd) + return rCmd +} + +func NewRecoverCommand() *cobra.Command { + return NewCreateVolumeRecoverCommand().Cmd +} 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..86b888068c --- /dev/null +++ b/tools-v2/pkg/cli/command/curvebs/create/volume/volume.go @@ -0,0 +1,51 @@ +/* +* 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: curve +* Created Date: 2023-08-23 +* Author: lng2020 + */ + +package volume + +import ( + "github.com/spf13/cobra" + + basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command" +) + +type RecoverCommand struct { + basecmd.MidCurveCmd +} + +var _ basecmd.MidCurveCmdFunc = (*RecoverCommand)(nil) // check interface + +func (dCmd *RecoverCommand) AddSubCommands() { + dCmd.Cmd.AddCommand( + NewRecoverCommand(), + NewCloneCommand(), + ) +} + +func NewVolumeCommand() *cobra.Command { + dCmd := &RecoverCommand{ + basecmd.MidCurveCmd{ + Use: "volume", + Short: "delete resources in the curvebs", + }, + } + return basecmd.NewMidCurveCli(&dCmd.MidCurveCmd, dCmd) +} diff --git a/tools-v2/pkg/config/bs.go b/tools-v2/pkg/config/bs.go index 574a263088..5919bc8632 100644 --- a/tools-v2/pkg/config/bs.go +++ b/tools-v2/pkg/config/bs.go @@ -144,6 +144,8 @@ const ( VIPER_CURVEBS_TASKID = "curvebs.taskid" CURVEBS_FAILED = "failed" VIPER_CURVEBS_FAILED = "curvebs.failed" + CURVEBS_LAZY = "lazy" + VIPER_CURVEBS_LAZY = "curvebs.lazy" ) var ( @@ -198,6 +200,7 @@ var ( CURVEBS_DEST: VIPER_CURVEBS_DEST, CURVEBS_TASKID: VIPER_CURVEBS_TASKID, CURVEBS_FAILED: VIPER_CURVEBS_FAILED, + CURVEBS_LAZY: VIPER_CURVEBS_LAZY, } BSFLAG2DEFAULT = map[string]interface{}{ @@ -618,14 +621,6 @@ func AddBsChunkServerAddressSliceRequiredFlag(cmd *cobra.Command) { AddBsStringSliceRequiredFlag(cmd, CURVEBS_CHUNKSERVER_ADDRESS, "chunk server address") } -func AddBsSrcOptionFlag(cmd *cobra.Command) { - AddBsStringOptionFlag(cmd, CURVEBS_SRC, "source") -} - -func AddBsDestOptionFlag(cmd *cobra.Command) { - AddBsStringOptionFlag(cmd, CURVEBS_DEST, "destination") -} - func AddBsTaskIDOptionFlag(cmd *cobra.Command) { AddBsStringOptionFlag(cmd, CURVEBS_TASKID, "task id") } @@ -817,3 +812,15 @@ func GetBsChunkServerId(cmd *cobra.Command) []uint32 { } return chunkserveridSlice } + +func AddBsSrcOptionFlag(cmd *cobra.Command) { + AddBsStringOptionFlag(cmd, CURVEBS_SRC, "source") +} + +func AddBsDestOptionFlag(cmd *cobra.Command) { + AddBsStringOptionFlag(cmd, CURVEBS_DEST, "destination") +} + +func AddBsLazyOptionFlag(cmd *cobra.Command) { + AddBsBoolOptionFlag(cmd, CURVEBS_LAZY, "lazy") +}