From b9b6bfdfebb7cad2331dc39c8126bc3f7961d345 Mon Sep 17 00:00:00 2001 From: Cyber-SiKu Date: Mon, 24 Apr 2023 20:45:49 +0800 Subject: [PATCH] [feat] add bs update throttle Signed-off-by: Cyber-SiKu --- tools-v2/internal/error/error.go | 14 ++ tools-v2/internal/utils/proto.go | 23 ++- .../pkg/cli/command/curvebs/list/dir/dir.go | 8 +- .../curvebs/update/throttle/throttle.go | 168 ++++++++++++++++++ .../pkg/cli/command/curvebs/update/update.go | 2 + tools-v2/pkg/config/bs.go | 64 ++++++- tools-v2/pkg/config/config.go | 8 + 7 files changed, 275 insertions(+), 12 deletions(-) create mode 100644 tools-v2/pkg/cli/command/curvebs/update/throttle/throttle.go diff --git a/tools-v2/internal/error/error.go b/tools-v2/internal/error/error.go index e1b2dc5a49..0ecdd521ce 100644 --- a/tools-v2/internal/error/error.go +++ b/tools-v2/internal/error/error.go @@ -408,6 +408,9 @@ var ( ErrBsListLogicalPoolInfo = func() *CmdError { return NewInternalCmdError(49, "list logical pool info fail, the error is: %s") } + ErrBsUnknownThrottleType = func() *CmdError { + return NewInternalCmdError(50, "unknown throttle type[%s], only support: iops_total|iops_read|iops_write|bps_total|bps_read|bps_write") + } // http error ErrHttpUnreadableResult = func() *CmdError { @@ -751,4 +754,15 @@ var ( } return NewRpcReultCmdError(code, message) } + ErrUpdateFileThrottle = func(statusCode nameserver2.StatusCode, path string) *CmdError { + var message string + code := int(statusCode) + switch statusCode { + case nameserver2.StatusCode_kOK: + message = "successfully update the file throttle" + default: + message = fmt.Sprintf("failed to update file[%s] throttle, err: %s", path, statusCode.String()) + } + return NewRpcReultCmdError(code, message) + } ) diff --git a/tools-v2/internal/utils/proto.go b/tools-v2/internal/utils/proto.go index d40f484e34..0a0d325302 100644 --- a/tools-v2/internal/utils/proto.go +++ b/tools-v2/internal/utils/proto.go @@ -196,7 +196,7 @@ func Topology2Map(topo *topology.ListTopologyResponse) (map[string]interface{}, } const ( - TYPE_DIR = "dir" + TYPE_DIR = "dir" TYPE_FILE = "file" ) @@ -211,3 +211,24 @@ func TranslateFileType(fileType string) (nameserver2.FileType, *cmderror.CmdErro retErr.Format(fileType) return nameserver2.FileType_INODE_DIRECTORY, retErr } + +const ( + IOPS_TOTAL = "iops_total" + IOPS_READ = "iops_read" + IOPS_WRITE = "iops_write" + BPS_TOTAL = "bps_total" + BPS_READ = "bps_read" + BPS_WRITE = "bps_write" +) + +func ParseThrottleType(typeStr string) (nameserver2.ThrottleType, *cmderror.CmdError) { + throttleType := nameserver2.ThrottleType_value[strings.ToUpper(typeStr)] + var retErr *cmderror.CmdError + if throttleType == 0 { + retErr = cmderror.ErrBsUnknownThrottleType() + retErr.Format(typeStr) + } else { + retErr = cmderror.ErrSuccess() + } + return nameserver2.ThrottleType(throttleType), retErr +} 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 f66e0d11c4..e5b4074297 100644 --- a/tools-v2/pkg/cli/command/curvebs/list/dir/dir.go +++ b/tools-v2/pkg/cli/command/curvebs/list/dir/dir.go @@ -42,7 +42,7 @@ import ( ) const ( - dirExample = `$ curve bs list dir --dir /` + dirExample = `$ curve bs list dir --path /` ) type ListDirRpc struct { @@ -90,7 +90,7 @@ func (pCmd *DirCommand) AddFlags() { config.AddBsMdsFlagOption(pCmd.Cmd) config.AddRpcRetryTimesFlag(pCmd.Cmd) config.AddRpcTimeoutFlag(pCmd.Cmd) - config.AddBsDirOptionFlag(pCmd.Cmd) + config.AddBsPathOptionFlag(pCmd.Cmd) config.AddBsUserOptionFlag(pCmd.Cmd) config.AddBsPasswordOptionFlag(pCmd.Cmd) } @@ -104,7 +104,7 @@ 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_DIR) + fileName := 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 { @@ -168,7 +168,7 @@ func (pCmd *DirCommand) RunCommand(cmd *cobra.Command, args []string) error { infos := res.(*nameserver2.ListDirResponse).GetFileInfo() for _, info := range infos { row := make(map[string]string) - dirName := config.GetBsFlagString(pCmd.Cmd, config.CURVEBS_DIR) + dirName := config.GetBsFlagString(pCmd.Cmd, config.CURVEBS_PATH) var fileName string if dirName == "/" { fileName = dirName + info.GetFileName() diff --git a/tools-v2/pkg/cli/command/curvebs/update/throttle/throttle.go b/tools-v2/pkg/cli/command/curvebs/update/throttle/throttle.go new file mode 100644 index 0000000000..a9b533e256 --- /dev/null +++ b/tools-v2/pkg/cli/command/curvebs/update/throttle/throttle.go @@ -0,0 +1,168 @@ +/* +* 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-04-24 +* Author: chengyi01 + */ + +package throttle + +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 ( + throttleExample = `$ curve bs update throttle --path /test --throttleType iops_total|iops_read|iops_write|bps_total|bps_read|bps_write --limit 20000 [--burst 30000] [--burstlength 10]` +) + +type UpdateFileThrottleRpc struct { + Info *basecmd.Rpc + Request *nameserver2.UpdateFileThrottleParamsRequest + mdsClient nameserver2.CurveFSServiceClient +} + +var _ basecmd.RpcFunc = (*UpdateFileThrottleRpc)(nil) // check interface + +func (uRpc *UpdateFileThrottleRpc) NewRpcClient(cc grpc.ClientConnInterface) { + uRpc.mdsClient = nameserver2.NewCurveFSServiceClient(cc) +} + +func (uRpc *UpdateFileThrottleRpc) Stub_Func(ctx context.Context) (interface{}, error) { + return uRpc.mdsClient.UpdateFileThrottleParams(ctx, uRpc.Request) +} + +type ThrottleCommand struct { + basecmd.FinalCurveCmd + Rpc *UpdateFileThrottleRpc + Response *nameserver2.UpdateFileThrottleParamsResponse +} + +var _ basecmd.FinalCurveCmdFunc = (*ThrottleCommand)(nil) // check interface + +func NewUpdateThrottleCommand() *ThrottleCommand { + throttleCmd := &ThrottleCommand{ + FinalCurveCmd: basecmd.FinalCurveCmd{ + Use: "throttle", + Short: "update file throttle params", + Example: throttleExample, + }, + } + basecmd.NewFinalCurveCli(&throttleCmd.FinalCurveCmd, throttleCmd) + return throttleCmd +} + +func NewThrottleCommand() *cobra.Command { + return NewUpdateThrottleCommand().Cmd +} + +func (tCmd *ThrottleCommand) AddFlags() { + config.AddRpcRetryTimesFlag(tCmd.Cmd) + config.AddRpcTimeoutFlag(tCmd.Cmd) + config.AddBsMdsFlagOption(tCmd.Cmd) + config.AddBsPathRequiredFlag(tCmd.Cmd) + config.AddBsThrottleTypeRequiredFlag(tCmd.Cmd) + config.AddBsUserOptionFlag(tCmd.Cmd) + config.AddBsPasswordOptionFlag(tCmd.Cmd) + config.AddBsLimitRequiredFlag(tCmd.Cmd) + config.AddBsBurstOptionFlag(tCmd.Cmd) + config.AddBsBurstLengthOptionFlag(tCmd.Cmd) +} + +func (tCmd *ThrottleCommand) Init(cmd *cobra.Command, args []string) error { + path := config.GetBsFlagString(cmd, config.CURVEBS_PATH) + throttleTypeStr := config.GetBsFlagString(cmd, config.CURVEBS_TYPE) + throttleType, err := cobrautil.ParseThrottleType(throttleTypeStr) + if err.TypeCode() != cmderror.CODE_SUCCESS { + return err.ToError() + } + limit := config.GetBsFlagUint64(cmd, config.CURVEBS_LIMIT) + params := &nameserver2.ThrottleParams{ + Type: &throttleType, + Limit: &limit, + } + if config.GetFlagChanged(cmd, config.CURVEBS_BURST) { + burst := config.GetBsFlagUint64(cmd, config.CURVEBS_BURST) + burstLength := config.GetBsFlagUint64(cmd, config.CURVEBS_BURST_LENGTH) + if burstLength == 0 { + burstLength = 1 + } + params.Burst = &burst + params.BurstLength = &burstLength + } + date, errDat := cobrautil.GetTimeofDayUs() + owner := config.GetBsFlagString(tCmd.Cmd, config.CURVEBS_USER) + if errDat.TypeCode() != cmderror.CODE_SUCCESS { + return errDat.ToError() + } + request := &nameserver2.UpdateFileThrottleParamsRequest{ + FileName: &path, + Owner: &owner, + Date: &date, + ThrottleParams: params, + } + password := config.GetBsFlagString(tCmd.Cmd, config.CURVEBS_PASSWORD) + if owner == viper.GetString(config.VIPER_CURVEBS_USER) && len(password) != 0 { + strSig := cobrautil.GetString2Signature(date, owner) + sig := cobrautil.CalcString2Signature(strSig, password) + request.Signature = &sig + } + mdsAddrs, errMds := config.GetBsMdsAddrSlice(tCmd.Cmd) + if errMds.TypeCode() != cmderror.CODE_SUCCESS { + return errMds.ToError() + } + timeout := config.GetFlagDuration(tCmd.Cmd, config.RPCTIMEOUT) + retrytimes := config.GetFlagInt32(tCmd.Cmd, config.RPCRETRYTIMES) + tCmd.Rpc = &UpdateFileThrottleRpc{ + Info: basecmd.NewRpc(mdsAddrs, timeout, retrytimes, "UpdateFileThrottle"), + Request: request, + } + tCmd.SetHeader([]string{cobrautil.ROW_RESULT}) + return nil +} + +func (tCmd *ThrottleCommand) Print(cmd *cobra.Command, args []string) error { + return output.FinalCmdOutput(&tCmd.FinalCurveCmd, tCmd) +} + +func (tCmd *ThrottleCommand) RunCommand(cmd *cobra.Command, args []string) error { + result, err := basecmd.GetRpcResponse(tCmd.Rpc.Info, tCmd.Rpc) + if err.TypeCode() != cmderror.CODE_SUCCESS { + return err.ToError() + } + tCmd.Response = result.(*nameserver2.UpdateFileThrottleParamsResponse) + tCmd.Result = tCmd.Response + tCmd.Error = cmderror.ErrUpdateFileThrottle(tCmd.Response.GetStatusCode(), tCmd.Rpc.Request.GetFileName()) + tCmd.TableNew.Append([]string{tCmd.Error.Message}) + if tCmd.Error.TypeCode() != cmderror.CODE_SUCCESS { + return tCmd.Error.ToError() + } + return nil +} + +func (tCmd *ThrottleCommand) ResultPlainOutput() error { + return output.FinalCmdOutputPlain(&tCmd.FinalCurveCmd) +} diff --git a/tools-v2/pkg/cli/command/curvebs/update/update.go b/tools-v2/pkg/cli/command/curvebs/update/update.go index 05933c216b..e7984ea8ff 100644 --- a/tools-v2/pkg/cli/command/curvebs/update/update.go +++ b/tools-v2/pkg/cli/command/curvebs/update/update.go @@ -28,6 +28,7 @@ import ( basecmd "github.com/opencurve/curve/tools-v2/pkg/cli/command" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/update/file" "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/update/peer" + "github.com/opencurve/curve/tools-v2/pkg/cli/command/curvebs/update/throttle" ) type UpdateCommand struct { @@ -40,6 +41,7 @@ func (updateCmd *UpdateCommand) AddSubCommands() { updateCmd.Cmd.AddCommand( peer.NewPeerCommand(), file.NewFileCommand(), + throttle.NewThrottleCommand(), ) } diff --git a/tools-v2/pkg/config/bs.go b/tools-v2/pkg/config/bs.go index faeb76830b..f2ce148ec3 100644 --- a/tools-v2/pkg/config/bs.go +++ b/tools-v2/pkg/config/bs.go @@ -44,6 +44,7 @@ const ( VIPER_CURVEBS_ETCDADDR = "curvebs.etcdAddr" CURVEBS_PATH = "path" VIPER_CURVEBS_PATH = "curvebs.path" + CURVEBS_DEFAULT_PATH = "/" CURVEBS_USER = "user" VIPER_CURVEBS_USER = "curvebs.root.user" CURVEBS_DEFAULT_USER = "root" @@ -56,8 +57,6 @@ const ( VIPER_CURVEBS_FILENAME = "curvebs.filename" CURVEBS_FORCEDELETE = "forcedelete" CURVEBS_DEFAULT_FORCEDELETE = false - CURVEBS_DIR = "dir" - VIPER_CURVEBS_DIR = "curvebs.dir" CURVEBS_LOGIC_POOL_ID = "logicalpoolid" VIPER_CURVEBS_LOGIC_POOL_ID = "curvebs.logicalpoolid" CURVEBS_COPYSET_ID = "copysetid" @@ -77,6 +76,14 @@ const ( CURVEBS_STRIPE_COUNT = "stripecount" VIPER_CURVEBS_STRIPE_COUNT = "curvebs.stripecount" CURVEBS_DEFAULT_STRIPE_COUNT = uint64(32) + CURVEBS_LIMIT = "limit" + VIPER_CURVEBS_LIMIT = "curvebs.limit" + CURVEBS_BURST = "burst" + VIPER_CURVEBS_BURST = "curvebs.burst" + CURVEBS_DEFAULT_BURST = uint64(30000) + CURVEBS_BURST_LENGTH = "burstlength" + VIPER_CURVEBS_BURST_LENGTH = "curvebs.burstlength" + CURVEBS_DEFAULT_BURST_LENGTH = uint64(10) ) var ( @@ -92,7 +99,6 @@ var ( CURVEBS_USER: VIPER_CURVEBS_USER, CURVEBS_PASSWORD: VIPER_CURVEBS_PASSWORD, CURVEBS_ETCDADDR: VIPER_CURVEBS_ETCDADDR, - CURVEBS_DIR: VIPER_CURVEBS_DIR, CURVEBS_LOGIC_POOL_ID: VIPER_CURVEBS_LOGIC_POOL_ID, CURVEBS_COPYSET_ID: VIPER_CURVEBS_COPYSET_ID, CURVEBS_PEERS_ADDRESS: VIPER_CURVEBS_PEERS_ADDRESS, @@ -101,6 +107,9 @@ var ( 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, } BSFLAG2DEFAULT = map[string]interface{}{ @@ -111,6 +120,9 @@ var ( 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, } ) @@ -161,6 +173,18 @@ func AddBsUint64OptionFlag(cmd *cobra.Command, name string, usage string) { } } +func AddBsInt64OptionFlag(cmd *cobra.Command, name string, usage string) { + defaultValue := BSFLAG2DEFAULT[name] + if defaultValue == nil { + defaultValue = 0 + } + cmd.Flags().Int64(name, defaultValue.(int64), usage) + err := viper.BindPFlag(BSFLAG2VIPER[name], cmd.Flags().Lookup(name)) + if err != nil { + cobra.CheckErr(err) + } +} + // add bs required flag func AddBsStringRequiredFlag(cmd *cobra.Command, name string, usage string) { cmd.Flags().String(name, "", usage+color.Red.Sprint("[required]")) @@ -220,10 +244,6 @@ func AddBsPasswordOptionFlag(cmd *cobra.Command) { AddBsStringOptionFlag(cmd, CURVEBS_PASSWORD, "user password") } -// dir -func AddBsDirOptionFlag(cmd *cobra.Command) { - AddBsStringOptionFlag(cmd, CURVEBS_DIR, "directory path") -} // etcd func AddBsEtcdAddrFlag(cmd *cobra.Command) { @@ -242,6 +262,18 @@ func AddBsStripeCountOptionFlag(cmd *cobra.Command) { AddBsUint64OptionFlag(cmd, CURVEBS_STRIPE_COUNT, "stripe volume count") } +func AddBsBurstOptionFlag(cmd *cobra.Command) { + AddBsUint64OptionFlag(cmd, CURVEBS_BURST, "burst") +} + +func AddBsBurstLengthOptionFlag(cmd *cobra.Command) { + AddBsUint64OptionFlag(cmd, CURVEBS_BURST_LENGTH, "burst length") +} + +func AddBsPathOptionFlag(cmd *cobra.Command) { + AddBsStringOptionFlag(cmd, CURVEBS_PATH, "file or directory path") +} + // add flag required // add path[required] func AddBsPathRequiredFlag(cmd *cobra.Command) { @@ -288,6 +320,14 @@ func AddBsFileTypeRequiredFlag(cmd *cobra.Command) { AddBsStringRequiredFlag(cmd, CURVEBS_TYPE, "file type, file or dir") } +func AddBsThrottleTypeRequiredFlag(cmd *cobra.Command) { + AddBsStringRequiredFlag(cmd, CURVEBS_TYPE, "throttle type, iops_total or iops_read or iops_write or bps_total or bps_read or bps_write") +} + +func AddBsLimitRequiredFlag(cmd *cobra.Command) { + AddBsUint64RequiredFlag(cmd, CURVEBS_LIMIT, "limit") +} + // get stingslice flag func GetBsFlagStringSlice(cmd *cobra.Command, flagName string) []string { var value []string @@ -337,6 +377,16 @@ func GetBsFlagUint64(cmd *cobra.Command, flagName string) uint64 { return value } +func GetBsFlagInt64(cmd *cobra.Command, flagName string) int64 { + var value int64 + if cmd.Flag(flagName).Changed { + value, _ = cmd.Flags().GetInt64(flagName) + } else { + value = viper.GetInt64(BSFLAG2VIPER[flagName]) + } + return value +} + // get mdsaddr func GetBsAddrSlice(cmd *cobra.Command, addrType string) ([]string, *cmderror.CmdError) { var addrsStr string diff --git a/tools-v2/pkg/config/config.go b/tools-v2/pkg/config/config.go index 60a30a77f3..c4d2d1b892 100644 --- a/tools-v2/pkg/config/config.go +++ b/tools-v2/pkg/config/config.go @@ -165,3 +165,11 @@ func AlignFlagsValue(caller *cobra.Command, callee *cobra.Command, flagNames []s } } } + +func GetFlagChanged(cmd *cobra.Command, flagName string) bool { + flag := cmd.Flag(flagName) + if flag != nil { + return flag.Changed + } + return false +}