diff --git a/base/client.go b/base/client.go index bb5a713d8b..09d22e76f1 100644 --- a/base/client.go +++ b/base/client.go @@ -1,10 +1,11 @@ package base import ( - pudisk "github.com/ucloud/ucloud-sdk-go/private/services/udisk" + pudb "github.com/ucloud/ucloud-sdk-go/private/services/udb" puhost "github.com/ucloud/ucloud-sdk-go/private/services/uhost" "github.com/ucloud/ucloud-sdk-go/services/pathx" "github.com/ucloud/ucloud-sdk-go/services/uaccount" + "github.com/ucloud/ucloud-sdk-go/services/udb" "github.com/ucloud/ucloud-sdk-go/services/udisk" "github.com/ucloud/ucloud-sdk-go/services/udpn" "github.com/ucloud/ucloud-sdk-go/services/uhost" @@ -15,12 +16,12 @@ import ( "github.com/ucloud/ucloud-sdk-go/ucloud/auth" ) -//PrivateUDiskClient 私有模块的udisk client 即未在官网开放的接口 -type PrivateUDiskClient = pudisk.UDiskClient - -//PrivateUHostClient 私有模块的udisk client 即未在官网开放的接口 +//PrivateUHostClient 私有模块的uhost client 即未在官网开放的接口 type PrivateUHostClient = puhost.UHostClient +//PrivateUDBClient 私有模块的udb client 即未在官网开放的接口 +type PrivateUDBClient = pudb.UDBClient + //Client aggregate client for business type Client struct { uaccount.UAccountClient @@ -31,7 +32,9 @@ type Client struct { pathx.PathXClient udisk.UDiskClient ulb.ULBClient + udb.UDBClient PrivateUHostClient + PrivateUDBClient } // NewClient will return a aggregate client @@ -45,6 +48,8 @@ func NewClient(config *ucloud.Config, credential *auth.Credential) *Client { *pathx.NewClient(config, credential), *udisk.NewClient(config, credential), *ulb.NewClient(config, credential), + *udb.NewClient(config, credential), *puhost.NewClient(config, credential), + *pudb.NewClient(config, credential), } } diff --git a/base/config.go b/base/config.go index f1566c814f..89405f244e 100644 --- a/base/config.go +++ b/base/config.go @@ -11,6 +11,7 @@ import ( "github.com/ucloud/ucloud-sdk-go/services/uaccount" sdk "github.com/ucloud/ucloud-sdk-go/ucloud" "github.com/ucloud/ucloud-sdk-go/ucloud/auth" + "github.com/ucloud/ucloud-sdk-go/ucloud/log" ) //ConfigFile filename @@ -40,6 +41,19 @@ var ClientConfig *sdk.Config //AuthCredential 创建sdk client参数 var AuthCredential *auth.Credential +//Global 全局flag +var Global GlobalFlag + +//GlobalFlag 几乎所有接口都需要的参数,例如 region zone projectID +type GlobalFlag struct { + Debug bool + JSON bool + Version bool + Completion bool + Config bool + Signup bool +} + //CLIConfig cli_config element type CLIConfig struct { ProjectID string `json:"project_id"` @@ -75,26 +89,26 @@ type AggConfig struct { func (p *AggConfig) ConfigPublicKey() error { Cxt.Print("Your public-key:") _, err := fmt.Scanf("%s\n", &p.PublicKey) - p.PublicKey = strings.TrimSpace(p.PublicKey) - AuthCredential.PublicKey = p.PublicKey - p.Save() if err != nil { Cxt.Println(err) + return err } - return err + p.PublicKey = strings.TrimSpace(p.PublicKey) + AuthCredential.PublicKey = p.PublicKey + return nil } //ConfigPrivateKey 输入私钥 func (p *AggConfig) ConfigPrivateKey() error { Cxt.Print("Your private-key:") _, err := fmt.Scanf("%s\n", &p.PrivateKey) - p.PrivateKey = strings.TrimSpace(p.PrivateKey) - AuthCredential.PrivateKey = p.PrivateKey - p.Save() if err != nil { Cxt.Println(err) + return err } - return err + p.PrivateKey = strings.TrimSpace(p.PrivateKey) + AuthCredential.PrivateKey = p.PrivateKey + return nil } //GetClientConfig 用来生成sdkClient @@ -491,8 +505,8 @@ func init() { ClientConfig = &sdk.Config{ BaseUrl: ConfigIns.BaseURL, Timeout: timeout, - UserAgent: fmt.Sprintf("UCloud CLI v%s", Version), - LogLevel: 1, + UserAgent: fmt.Sprintf("UCloud-CLI/%s", Version), + LogLevel: log.FatalLevel, } AuthCredential = &auth.Credential{ diff --git a/base/util.go b/base/util.go index 1fd2d1cdf6..44e236e09b 100644 --- a/base/util.go +++ b/base/util.go @@ -157,8 +157,8 @@ func PrintTableS(dataSet interface{}) { } //PrintList 打印表格或者JSON -func PrintList(dataSet interface{}, json bool) { - if json { +func PrintList(dataSet interface{}) { + if Global.JSON { PrintJSON(dataSet) } else { PrintTableS(dataSet) @@ -280,6 +280,9 @@ func FormatDate(seconds int) string { return time.Unix(int64(seconds), 0).Format("2006-01-02") } +//DateTimeLayout 时间格式 +const DateTimeLayout = "2006-01-02/15:04:05" + //FormatDateTime 格式化时间,把以秒为单位的时间戳格式化未年月日/时分秒 func FormatDateTime(seconds int) string { return time.Unix(int64(seconds), 0).Format("2006-01-02/15:04:05") @@ -362,14 +365,12 @@ func (p *Poller) Spoll(resourceID, pollText string, targetStates []string) { done := make(chan bool) go func() { - if resp, err := w.Wait(); err != nil { + if _, err := w.Wait(); err != nil { log.Error(err) if _, ok := err.(*waiter.TimeoutError); ok { done <- false return } - } else { - log.Infof("%#v", resp) } done <- true }() @@ -427,14 +428,12 @@ func (p *Poller) Poll(resourceID, projectID, region, zone, pollText string, targ done := make(chan bool) go func() { - if resp, err := w.Wait(); err != nil { + if _, err := w.Wait(); err != nil { log.Error(err) if _, ok := err.(*waiter.TimeoutError); ok { done <- false return } - } else { - log.Infof("%#v", resp) } done <- true }() @@ -509,7 +508,6 @@ func GetFileList(suffix string) []string { } files, err := ioutil.ReadDir(pathPrefix) if err != nil { - log.Fatal(err) return nil } names := []string{} @@ -529,3 +527,16 @@ func GetFileList(suffix string) []string { } return names } + +//Confirm 二次确认 +func Confirm(yes bool, text string) bool { + if yes { + return true + } + sure, err := ux.Prompt(text) + if err != nil { + Cxt.Println(err) + return false + } + return sure +} diff --git a/cmd/backup.go b/cmd/backup.go new file mode 100644 index 0000000000..898a9f5095 --- /dev/null +++ b/cmd/backup.go @@ -0,0 +1,528 @@ +// Copyright © 2018 NAME HERE tony.li@ucloud.cn +// +// 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. + +package cmd + +import ( + "fmt" + "io" + "strconv" + "time" + + "github.com/spf13/cobra" + + sdk "github.com/ucloud/ucloud-sdk-go/ucloud" + + "github.com/ucloud/ucloud-cli/base" +) + +//NewCmdUDBBackup ucloud udb backup +func NewCmdUDBBackup() *cobra.Command { + cmd := &cobra.Command{ + Use: "backup", + Short: "List and manipulate backups of MySQL instance", + Long: "List and manipulate backups of MySQL instance", + } + out := base.Cxt.GetWriter() + cmd.AddCommand(NewCmdUDBBackupCreate(out)) + cmd.AddCommand(NewCmdUDBBackupList()) + cmd.AddCommand(NewCmdUDBBackupDelete(out)) + cmd.AddCommand(NewCmdUDBBackupGetDownloadURL(out)) + return cmd +} + +//NewCmdUDBBackupCreate ucloud udb backup create +func NewCmdUDBBackupCreate(out io.Writer) *cobra.Command { + req := base.BizClient.NewBackupUDBInstanceRequest() + cmd := &cobra.Command{ + Use: "create", + Short: "Create backups for MySQL instance manually", + Long: "Create backups for MySQL instance manually", + Run: func(c *cobra.Command, args []string) { + *req.DBId = base.PickResourceID(*req.DBId) + _, err := base.BizClient.BackupUDBInstance(req) + if err != nil { + base.HandleError(err) + return + } + fmt.Fprintf(out, "udb[%s] backuped\n", *req.DBId) + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + req.DBId = flags.String("udb-id", "", "Required. Resource ID of UDB instnace to backup") + req.BackupName = flags.String("name", "", "Required. Name of backup") + bindProjectID(req, flags) + bindRegion(req, flags) + bindZone(req, flags) + + cmd.MarkFlagRequired("udb-id") + cmd.MarkFlagRequired("name") + + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "sql", *req.ProjectId, *req.Region, *req.Zone) + }) + + return cmd +} + +type udbBackupRow struct { + BackupID int + BackupName string + DB string + BackupSize string + BackupType string + Status string + AvailabilityZone string + BackupBeginTime string + BackupEndTime string +} + +//NewCmdUDBBackupList ucloud udb backup list +func NewCmdUDBBackupList() *cobra.Command { + var bpType, dbType, beginTime, endTime, backupID string + bpTypeMap := map[string]int{ + "manual": 1, + "auto": 0, + } + reverseBpTypeMap := map[int]string{ + 1: "manual", + 0: "auto", + } + req := base.BizClient.NewDescribeUDBBackupRequest() + cmd := &cobra.Command{ + Use: "list", + Short: "List backups of MySQL instance", + Long: "List backups of MySQL instance", + Run: func(c *cobra.Command, args []string) { + if v, ok := bpTypeMap[bpType]; ok { + req.BackupType = &v + } + if v, ok := dbTypeMap[dbType]; ok { + req.ClassType = &v + } + if *req.DBId != "" { + *req.DBId = base.PickResourceID(*req.DBId) + } + if backupID != "" { + id, err := strconv.Atoi(base.PickResourceID(backupID)) + if err != nil { + base.HandleError(err) + return + } + req.BackupId = &id + } + if beginTime != "" { + bt, err := time.Parse("2006-01-02/15:04:05", beginTime) + if err != nil { + base.HandleError(err) + return + } + req.BeginTime = sdk.Int(int(bt.Unix())) + } + if endTime != "" { + bt, err := time.Parse("2006-01-02/15:04:05", endTime) + if err != nil { + base.HandleError(err) + return + } + req.EndTime = sdk.Int(int(bt.Unix())) + } + resp, err := base.BizClient.DescribeUDBBackup(req) + if err != nil { + base.HandleError(err) + return + } + list := []udbBackupRow{} + for _, ins := range resp.DataSet { + row := udbBackupRow{ + BackupID: ins.BackupId, + BackupName: ins.BackupName, + AvailabilityZone: ins.Zone, + DB: fmt.Sprintf("%s|%s", ins.DBName, ins.DBId), + BackupSize: fmt.Sprintf("%dB", ins.BackupSize), + BackupType: reverseBpTypeMap[ins.BackupType], + Status: ins.State, + BackupBeginTime: base.FormatDateTime(ins.BackupTime), + BackupEndTime: base.FormatDateTime(ins.BackupEndTime), + } + list = append(list, row) + } + base.PrintList(list) + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + req.DBId = flags.String("udb-id", "", "Optional. Resource ID of UDB for list the backups of the specifid UDB") + flags.StringVar(&backupID, "backup-id", "", "Optional. Resource ID of backup. List the specified backup only") + flags.StringVar(&bpType, "backup-type", "", "Optional. Backup type. Accept values:auto or manual") + flags.StringVar(&dbType, "db-type", "", "Optional. Only list backups of the UDB of the specified DB type") + flags.StringVar(&beginTime, "begin-time", "", "Optional. Begin time of backup. For example, 2019-02-26/11:21:39") + flags.StringVar(&endTime, "end-time", "", "Optional. End time of backup. For example, 2019-02-26/11:31:39") + + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + bindOffset(req, flags) + bindLimit(req, flags) + + flags.SetFlagValues("backup-type", "auto", "manual") + flags.SetFlagValues("db-type", dbTypeList...) + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "sql", *req.ProjectId, *req.Region, *req.Zone) + }) + + return cmd +} + +//NewCmdUDBBackupDelete ucloud udb backup delete +func NewCmdUDBBackupDelete(out io.Writer) *cobra.Command { + ids := []int{} + req := base.BizClient.NewDeleteUDBBackupRequest() + cmd := &cobra.Command{ + Use: "delete", + Short: "Delete backups of MySQL instance", + Long: "Delete backups of MySQL instance", + Example: "ucloud udb backup delete --backup-id 65534,65535", + Run: func(c *cobra.Command, args []string) { + for _, id := range ids { + req.BackupId = sdk.Int(id) + _, err := base.BizClient.DeleteUDBBackup(req) + if err != nil { + base.HandleError(err) + continue + } + fmt.Fprintf(out, "backup[%d] deleted\n", id) + } + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + flags.IntSliceVar(&ids, "backup-id", nil, "Required. BackupID of backups to delete") + bindProjectID(req, flags) + bindRegion(req, flags) + bindZone(req, flags) + + cmd.MarkFlagRequired("backup-id") + return cmd +} + +//NewCmdUDBBackupGetDownloadURL ucloud udb backup get-download-url +func NewCmdUDBBackupGetDownloadURL(out io.Writer) *cobra.Command { + req := base.BizClient.NewDescribeUDBInstanceBackupURLRequest() + cmd := &cobra.Command{ + Use: "download", + Short: "Display download url of backup", + Long: "Display download url of backup", + Run: func(c *cobra.Command, args []string) { + resp, err := base.BizClient.DescribeUDBInstanceBackupURL(req) + if err != nil { + base.HandleError(err) + return + } + fmt.Fprintln(out, resp.BackupPath) + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + req.BackupId = flags.Int("backup-id", -1, "Required. BackupID of backup to delete") + req.DBId = flags.String("udb-id", "", "Required. Resource ID of udb which the backup belongs to") + bindProjectID(req, flags) + bindRegion(req, flags) + bindZone(req, flags) + + cmd.MarkFlagRequired("udb-id") + cmd.MarkFlagRequired("backup-id") + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "sql", *req.ProjectId, *req.Region, *req.Zone) + }) + return cmd +} + +//NewCmdUDBLog ucloud udb log +func NewCmdUDBLog() *cobra.Command { + cmd := &cobra.Command{ + Use: "logs", + Short: "List and manipulate logs of MySQL instance", + Long: "List and manipulate logs of MySQL instance", + } + + out := base.Cxt.GetWriter() + cmd.AddCommand(NewCmdUDBLogArchiveCreate(out)) + cmd.AddCommand(NewCmdUDBLogArchiveList(out)) + cmd.AddCommand(NewCmdUDBLogArchiveGetDownloadURL(out)) + cmd.AddCommand(NewCmdUDBLogArchiveDelete(out)) + + return cmd +} + +//NewCmdUDBLogArchiveCreate ucloud udb log archive create +func NewCmdUDBLogArchiveCreate(out io.Writer) *cobra.Command { + var region, zone, project, udbID string + var name, logType, beginTime, endTime string + cmd := &cobra.Command{ + Use: "archive", + Short: "Archive the log of mysql as a compressed file", + Long: "Archive the log of mysql as a compressed file", + Example: "ucloud mysql logs archive --name test.cli2 --udb-id udb-xxx/test.cli1 --log-type slow_query --begin-time 2019-02-23/15:30:00 --end-time 2019-02-24/15:31:00", + Run: func(c *cobra.Command, args []string) { + udbID = base.PickResourceID(udbID) + if logType == "slow_query" { + if beginTime == "" || endTime == "" { + fmt.Fprintln(out, "Error. Both begin-time and end-time can not be empty") + return + } + bt, err := time.Parse(base.DateTimeLayout, beginTime) + if err != nil { + base.HandleError(err) + return + } + et, err := time.Parse(base.DateTimeLayout, endTime) + if err != nil { + base.HandleError(err) + return + } + + req := base.BizClient.NewBackupUDBInstanceSlowLogRequest() + req.BeginTime = sdk.Int(int(bt.Unix())) + req.EndTime = sdk.Int(int(et.Unix())) + req.DBId = &udbID + req.BackupName = &name + req.Region = ®ion + req.ProjectId = &project + + _, err = base.BizClient.BackupUDBInstanceSlowLog(req) + if err != nil { + base.HandleError(err) + return + } + fmt.Fprintf(out, "mysql log archive[%s] created\n", name) + } else if logType == "error" { + req := base.BizClient.NewBackupUDBInstanceErrorLogRequest() + req.DBId = &udbID + req.BackupName = &name + req.Region = ®ion + req.Zone = &zone + req.ProjectId = &project + + _, err := base.BizClient.BackupUDBInstanceErrorLog(req) + if err != nil { + base.HandleError(err) + return + } + fmt.Fprintf(out, "mysql log archive[%s] created\n", name) + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringVar(&udbID, "udb-id", "", "Required. Resource ID of UDB instance which we fetch logs from") + flags.StringVar(&name, "name", "", "Required. Name of compressed file") + flags.StringVar(&logType, "log-type", "", "Required. Type of log to package. Accept values: slow_query, error") + flags.StringVar(&beginTime, "begin-time", "", "Optional. Required when log-type is slow. For example 2019-01-02/15:04:05") + flags.StringVar(&endTime, "end-time", "", "Optional. Required when log-type is slow. For example 2019-01-02/15:04:05") + bindRegionS(®ion, flags) + bindZoneS(&zone, ®ion, flags) + bindProjectIDS(&project, flags) + + cmd.MarkFlagRequired("udb-id") + cmd.MarkFlagRequired("name") + cmd.MarkFlagRequired("log-type") + + flags.SetFlagValues("log-type", "slow_query", "error") + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "sql", project, region, base.ConfigIns.Zone) + }) + return cmd +} + +type udbArchiveRow struct { + ArchiveID int + Name string + LogType string + DB string + Size string + Status string + CreateTime string +} + +//NewCmdUDBLogArchiveList ucloud udb log archive list +func NewCmdUDBLogArchiveList(out io.Writer) *cobra.Command { + var beginTime, endTime string + logTypes := []string{} + logTypeMap := map[string]int{ + "binlog": 2, + "slow_query": 3, + "error": 4, + } + rLogTypeMap := map[int]string{ + 2: "binlog", + 3: "slow_query", + 4: "error", + } + req := base.BizClient.NewDescribeUDBLogPackageRequest() + cmd := &cobra.Command{ + Use: "list", + Short: "List mysql log archives(log files)", + Long: "List mysql log archives(log files)", + Run: func(c *cobra.Command, args []string) { + if beginTime != "" { + bt, err := time.Parse(base.DateTimeLayout, beginTime) + if err != nil { + base.HandleError(err) + return + } + req.BeginTime = sdk.Int(int(bt.Unix())) + } + if endTime != "" { + et, err := time.Parse(base.DateTimeLayout, endTime) + if err != nil { + base.HandleError(err) + return + } + req.EndTime = sdk.Int(int(et.Unix())) + } + + if *req.DBId != "" { + *req.DBId = base.PickResourceID(*req.DBId) + } + + for _, s := range logTypes { + if v, ok := logTypeMap[s]; ok { + req.Types = append(req.Types, v) + } else { + fmt.Fprintln(out, "Error, log-type should be one of 'binlog', 'slow_query' or 'error'") + } + } + + resp, err := base.BizClient.DescribeUDBLogPackage(req) + if err != nil { + base.HandleError(err) + return + } + list := []udbArchiveRow{} + for _, ins := range resp.DataSet { + row := udbArchiveRow{ + ArchiveID: ins.BackupId, + Name: ins.BackupName, + LogType: rLogTypeMap[ins.BackupType], + DB: fmt.Sprintf("%s|%s", ins.DBId, ins.DBName), + Size: fmt.Sprintf("%dB", ins.BackupSize), + Status: ins.State, + CreateTime: base.FormatDateTime(ins.BackupTime), + } + list = append(list, row) + } + base.PrintList(list) + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringSliceVar(&logTypes, "log-type", nil, "Optional. Type of log. Accept Values: binlog, slow_query and error") + req.DBId = flags.String("udb-id", "", "Optional. Resource ID of UDB instance which the listed logs belong to") + flags.StringVar(&beginTime, "begin-time", "", "Optional. For example 2019-01-02/15:04:05") + flags.StringVar(&endTime, "end-time", "", "Optional. For example 2019-01-02/15:04:05") + bindProjectID(req, flags) + bindRegion(req, flags) + bindZone(req, flags) + bindLimit(req, flags) + bindOffset(req, flags) + + flags.SetFlagValues("log-type", "binlog", "slow_query", "error") + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "sql", *req.ProjectId, *req.Region, *req.Zone) + }) + + return cmd +} + +//NewCmdUDBLogArchiveGetDownloadURL ucloud udb log archive get-download-url +func NewCmdUDBLogArchiveGetDownloadURL(out io.Writer) *cobra.Command { + req := base.BizClient.NewDescribeUDBBinlogBackupURLRequest() + cmd := &cobra.Command{ + Use: "download", + Short: "Display url of an archive(log file)", + Long: "Display url of an archive(log file)", + Example: "ucloud mysql logs download --udb-id udb-urixxx/test.cli1 --archive-id 35044", + Run: func(c *cobra.Command, args []string) { + *req.DBId = base.PickResourceID(*req.DBId) + resp, err := base.BizClient.DescribeUDBBinlogBackupURL(req) + if err != nil { + base.HandleError(err) + return + } + fmt.Fprintln(out, resp.BackupPath) + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + req.BackupId = flags.Int("archive-id", 0, "Required. ArchiveID of archive to download") + req.DBId = flags.String("udb-id", "", "Required. Resource ID of UDB which the archive belongs to") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + + cmd.MarkFlagRequired("archive-id") + cmd.MarkFlagRequired("udb-id") + + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "sql", *req.ProjectId, *req.Region, *req.Zone) + }) + + return cmd +} + +//NewCmdUDBLogArchiveDelete ucloud udb log archive delete +func NewCmdUDBLogArchiveDelete(out io.Writer) *cobra.Command { + var ids []int + req := base.BizClient.NewDeleteUDBLogPackageRequest() + cmd := &cobra.Command{ + Use: "delete", + Short: "Delete log archives(log files)", + Long: "Delete log archives(log files)", + Example: "ucloud mysql logs delete --archive-id 35025", + Run: func(c *cobra.Command, args []string) { + for _, id := range ids { + req.BackupId = sdk.Int(id) + _, err := base.BizClient.DeleteUDBLogPackage(req) + if err != nil { + base.HandleError(err) + continue + } + fmt.Fprintf(out, "archive[%d] deleted\n", id) + } + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + flags.IntSliceVar(&ids, "archive-id", nil, "Optional. ArchiveID of log archives to delete") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + + cmd.MarkFlagRequired("archive-id") + + return cmd +} diff --git a/cmd/bandwidth.go b/cmd/bandwidth.go index e011527a5c..d24304a6ce 100644 --- a/cmd/bandwidth.go +++ b/cmd/bandwidth.go @@ -132,11 +132,7 @@ func NewCmdSharedBWList() *cobra.Command { row.EIP = strings.Join(eipList, "\n") list = append(list, row) } - if global.json { - base.PrintJSON(list) - } else { - base.PrintTableS(list) - } + base.PrintList(list) }, } flags := cmd.Flags() @@ -361,11 +357,7 @@ func NewCmdBandwidthPkgList() *cobra.Command { row.EIP = eip list = append(list, row) } - if global.json { - base.PrintJSON(list) - } else { - base.PrintTableS(list) - } + base.PrintList(list) }, } flags := cmd.Flags() diff --git a/cmd/configure.go b/cmd/configure.go index d518e5b68a..64970fa392 100644 --- a/cmd/configure.go +++ b/cmd/configure.go @@ -20,6 +20,8 @@ import ( "github.com/spf13/cobra" + uerr "github.com/ucloud/ucloud-sdk-go/ucloud/error" + "github.com/ucloud/ucloud-cli/base" ) @@ -52,6 +54,12 @@ func NewCmdInit() *cobra.Command { region, zone, err := getDefaultRegion() if err != nil { + if uErr, ok := err.(uerr.Error); ok { + if uErr.Code() == 172 { + fmt.Println("public key or private key is invalid.") + return + } + } base.Cxt.Println(err) return } @@ -82,11 +90,13 @@ func NewCmdInit() *cobra.Command { func printHello() { userInfo, err := getUserInfo() - base.Cxt.Printf("You are logged in as: [%s]\n", userInfo.UserEmail) - certified := isUserCertified(userInfo) if err != nil { base.Cxt.PrintErr(err) - } else if certified == false { + return + } + base.Cxt.Printf("You are logged in as: [%s]\n", userInfo.UserEmail) + certified := isUserCertified(userInfo) + if !certified { base.Cxt.Println("\nWarning: Please authenticate the account with your valid documentation at 'https://accountv2.ucloud.cn/authentication'.") } base.Cxt.Println(helloUcloud) @@ -202,7 +212,7 @@ func NewCmdConfigList() *cobra.Command { Short: "list all settings", Long: `list all settings`, Run: func(c *cobra.Command, args []string) { - base.ListAggConfig(global.json) + base.ListAggConfig(global.JSON) }, } return cmd diff --git a/cmd/disk.go b/cmd/disk.go index 3f60f3bd61..4178f13cb8 100644 --- a/cmd/disk.go +++ b/cmd/disk.go @@ -222,11 +222,7 @@ func NewCmdDiskList() *cobra.Command { } list = append(list, row) } - if global.json { - base.PrintJSON(list) - } else { - base.PrintTableS(list) - } + base.PrintList(list) }, } flags := cmd.Flags() @@ -516,7 +512,6 @@ func NewCmdDiskExpand() *cobra.Command { req.ProjectId = flags.String("project-id", base.ConfigIns.ProjectID, "Optional. Assign project-id") req.Region = flags.String("region", base.ConfigIns.Region, "Optional. Assign region") req.Zone = flags.String("zone", base.ConfigIns.Zone, "Optional. Assign availability zone") - req.CouponId = flags.String("coupon-id", "", "Optional. Coupon ID, The Coupon can deduct part of the payment,see https://accountv2.ucloud.cn") flags.SetFlagValuesFunc("udisk-id", func() []string { return getDiskList([]string{status.DISK_AVAILABLE}, *req.ProjectId, *req.Region, *req.Zone) @@ -675,11 +670,7 @@ func NewCmdSnapshotList(out io.Writer) *cobra.Command { } list = append(list, row) } - if global.json { - base.PrintJSON(list) - } else { - base.PrintTableS(list) - } + base.PrintList(list) }, } diff --git a/cmd/eip.go b/cmd/eip.go index 07c73f84b7..51ea2db4c1 100644 --- a/cmd/eip.go +++ b/cmd/eip.go @@ -108,11 +108,7 @@ func NewCmdEIPList() *cobra.Command { row.ExpirationTime = time.Unix(int64(eip.ExpireTime), 0).Format("2006-01-02") list = append(list, row) } - if global.json { - base.PrintJSON(list) - } else { - base.PrintTableS(list) - } + base.PrintList(list) }, } diff --git a/cmd/firewall.go b/cmd/firewall.go index 3a5359c0cf..1b7aade303 100644 --- a/cmd/firewall.go +++ b/cmd/firewall.go @@ -94,11 +94,7 @@ func NewCmdFirewallList() *cobra.Command { } list = append(list, row) } - if global.json { - base.PrintJSON(list) - } else { - base.PrintTableS(list) - } + base.PrintList(list) }, } flags := cmd.Flags() @@ -493,11 +489,7 @@ func NewCmdFirewallResource() *cobra.Command { row.Remark = rs.Remark list = append(list, row) } - if global.json { - base.PrintJSON(list) - } else { - base.PrintTableS(list) - } + base.PrintList(list) }, } flags := cmd.Flags() diff --git a/cmd/globalssh.go b/cmd/globalssh.go index 755acf9c38..b5c04bc027 100644 --- a/cmd/globalssh.go +++ b/cmd/globalssh.go @@ -90,7 +90,7 @@ func NewCmdGsshList() *cobra.Command { } list = append(list, row) } - base.PrintList(list, global.json) + base.PrintList(list) } }, } diff --git a/cmd/image.go b/cmd/image.go index 07bdebc18c..d48d3fb03e 100644 --- a/cmd/image.go +++ b/cmd/image.go @@ -84,7 +84,7 @@ func NewCmdUImageList() *cobra.Command { list = append(list, row) } } - base.PrintList(list, global.json) + base.PrintList(list) }, } req.ProjectId = cmd.Flags().String("project-id", base.ConfigIns.ProjectID, "Optional. Assign project-id") diff --git a/cmd/mysql.go b/cmd/mysql.go new file mode 100644 index 0000000000..46745edb9b --- /dev/null +++ b/cmd/mysql.go @@ -0,0 +1,896 @@ +// Copyright © 2018 NAME HERE tony.li@ucloud.cn +// +// 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. + +package cmd + +import ( + "fmt" + "io" + "strconv" + "strings" + "time" + + "github.com/spf13/cobra" + + "github.com/ucloud/ucloud-sdk-go/services/udb" + sdk "github.com/ucloud/ucloud-sdk-go/ucloud" + + "github.com/ucloud/ucloud-cli/base" + "github.com/ucloud/ucloud-cli/model/status" +) + +var dbVersionList = []string{"mysql-5.1", "mysql-5.5", "mysql-5.6", "mysql-5.7", "percona-5.5", "percona-5.6", "percona-5.7", "mariadb-10.0"} +var dbDiskTypeList = []string{"normal", "sata_ssd", "pcie_ssd"} + +var poller = base.NewSpoller(describeUdbByID, base.Cxt.GetWriter()) + +//NewCmdMysql ucloud mysql +func NewCmdMysql() *cobra.Command { + cmd := &cobra.Command{ + Use: "mysql", + Short: "Manipulate MySQL on UCloud platform", + Long: "Manipulate MySQL on UCloud platform", + } + out := base.Cxt.GetWriter() + cmd.AddCommand(NewCmdMysqlDB(out)) + cmd.AddCommand(NewCmdUDBConf()) + cmd.AddCommand(NewCmdUDBBackup()) + cmd.AddCommand(NewCmdUDBLog()) + return cmd +} + +//NewCmdMysqlDB ucloud mysql db +func NewCmdMysqlDB(out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "db", + Short: "Manange MySQL instances", + Long: "Manange MySQL instances", + } + + cmd.AddCommand(NewCmdUDBList()) + cmd.AddCommand(NewCmdMysqlCreate(out)) + cmd.AddCommand(NewCmdUDBDelete(out)) + cmd.AddCommand(NewCmdUDBStart(out)) + cmd.AddCommand(NewCmdUDBStop(out)) + cmd.AddCommand(NewCmdUDBRestart(out)) + cmd.AddCommand(NewCmdUDBResize(out)) + cmd.AddCommand(NewCmdUDBRestore(out)) + cmd.AddCommand(NewCmdUDBResetPassword(out)) + cmd.AddCommand(NewCmdUDBCreateSlave(out)) + cmd.AddCommand(NewCmdUDBPromoteSlave(out)) + // cmd.AddCommand(NewCmdUDBPromoteToHA(out)) + + return cmd +} + +//NewCmdMysqlCreate ucloud mysql create +func NewCmdMysqlCreate(out io.Writer) *cobra.Command { + var confID, diskType string + var backupID int + var async bool + req := base.BizClient.NewCreateUDBInstanceRequest() + cmd := &cobra.Command{ + Use: "create", + Short: "Create MySQL instance on UCloud platform", + Long: "Create MySQL instance on UCloud platform", + Run: func(c *cobra.Command, args []string) { + confID = base.PickResourceID(confID) + id, err := strconv.Atoi(confID) + if err != nil { + base.HandleError(err) + return + } + req.ParamGroupId = &id + if len(*req.Name) < 6 { + fmt.Fprintln(out, "Error, length of name shoud be larger than 5") + return + } + if *req.DiskSpace > 3000 || *req.DiskSpace < 20 { + fmt.Fprintln(out, "Error, disk-size-gb should be between 20 and 3000") + return + } + if *req.MemoryLimit < 1 || *req.MemoryLimit > 128 { + fmt.Fprintln(out, "Error, memory-size-gb should be between 1 and 128") + return + } + if backupID != -1 { + req.BackupId = &backupID + } + *req.MemoryLimit = *req.MemoryLimit * 1000 + switch diskType { + case "normal": + req.UseSSD = sdk.Bool(false) + case "sata_ssd": + req.UseSSD = sdk.Bool(true) + req.SSDType = sdk.String("SATA") + case "pcie_ssd": + req.UseSSD = sdk.Bool(true) + req.SSDType = sdk.String("PCI-E") + default: + if diskType != "" { + req.UseSSD = sdk.Bool(true) + req.SSDType = sdk.String(diskType) + } + } + resp, err := base.BizClient.CreateUDBInstance(req) + if err != nil { + base.HandleError(err) + return + } + text := fmt.Sprintf("udb[%s] is initializing", resp.DBId) + if async { + fmt.Fprintf(out, "udb[%s] is initializing\n", resp.DBId) + } else { + poller.Spoll(resp.DBId, text, []string{status.UDB_RUNNING, status.UDB_FAIL}) + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + bindProjectID(req, flags) + bindRegion(req, flags) + bindZone(req, flags) + req.DBTypeId = flags.String("version", "", "Required. Version of udb instance") + req.Name = flags.String("name", "", "Required. Name of udb instance to create, at least 6 letters") + flags.StringVar(&confID, "conf-id", "", "Required. ConfID of configuration. see 'ucloud mysql conf list'") + req.AdminUser = flags.String("admin-user-name", "root", "Optional. Name of udb instance's administrator") + req.AdminPassword = flags.String("password", "", "Required. Password of udb instance's administrator") + flags.IntVar(&backupID, "backup-id", -1, "Optional. BackupID of the backup which the newly created UDB instance will recover from if specified. See 'ucloud mysql backup list'") + req.Port = flags.Int("port", 3306, "Optional. Port of udb instance") + flags.StringVar(&diskType, "disk-type", "", "Optional. Setting this flag means using SSD disk. Accept values: 'normal','sata_ssd','pcie_ssd'") + req.DiskSpace = flags.Int("disk-size-gb", 20, "Optional. Disk size of udb instance. From 20 to 3000 according to memory size. Unit GB") + req.MemoryLimit = flags.Int("memory-size-gb", 1, "Optional. Memory size of udb instance. From 1 to 128. Unit GB") + req.InstanceMode = flags.String("mode", "Normal", "Optional. Mode of udb instance. Normal or HA, HA means high-availability. Both the normal and high-availability versions can create master-slave synchronization for data redundancy and read/write separation. The high-availability version provides a dual-master hot standby architecture to avoid database unavailability due to downtime or hardware failure. One more thing. It does better job for master-slave synchronization and disaster recovery using the InnoDB engine") + req.VPCId = flags.String("vpc-id", "", "Optional. Resource ID of VPC which the UDB to create belong to. See 'ucloud vpc list'") + req.SubnetId = flags.String("subnet-id", "", "Optional. Resource ID of subnet that the UDB to create belong to. See 'ucloud subnet list'") + flags.BoolVar(&async, "async", false, "Optional. Do not wait for the long-running operation to finish.") + bindChargeType(req, flags) + bindQuantity(req, flags) + + flags.SetFlagValues("version", dbVersionList...) + flags.SetFlagValues("disk-type", dbDiskTypeList...) + flags.SetFlagValuesFunc("vpc-id", func() []string { + return getAllVPCIdNames(*req.ProjectId, *req.Region) + }) + flags.SetFlagValuesFunc("subnet-id", func() []string { + return getAllSubnetIDNames(*req.VPCId, *req.ProjectId, *req.Region) + }) + flags.SetFlagValuesFunc("conf-id", func() []string { + return getConfIDList(*req.DBTypeId, *req.ProjectId, *req.Region, *req.Zone) + }) + + cmd.MarkFlagRequired("version") + cmd.MarkFlagRequired("name") + cmd.MarkFlagRequired("password") + cmd.MarkFlagRequired("conf-id") + return cmd +} + +//UDBMysqlRow 表格行 +type UDBMysqlRow struct { + Name string + ResourceID string + Role string + Status string + Config string + Mode string + DiskType string + IP string + Group string + Zone string + VPC string + Subnet string + // CreateTime string +} + +//NewCmdUDBList ucloud udb list +func NewCmdUDBList() *cobra.Command { + req := base.BizClient.NewDescribeUDBInstanceRequest() + cmd := &cobra.Command{ + Use: "list", + Short: "List MySQL instances", + Long: "List MySQL instances", + Run: func(c *cobra.Command, args []string) { + if *req.DBId != "" { + *req.DBId = base.PickResourceID(*req.DBId) + } + resp, err := base.BizClient.DescribeUDBInstance(req) + if err != nil { + base.HandleError(err) + return + } + list := []UDBMysqlRow{} + for _, ins := range resp.DataSet { + row := UDBMysqlRow{} + row.Name = ins.Name + row.Zone = ins.Zone + row.Role = ins.Role + row.ResourceID = ins.DBId + row.Group = ins.Tag + row.VPC = ins.VPCId + row.Subnet = ins.SubnetId + row.IP = ins.VirtualIP + row.Mode = ins.InstanceMode + row.DiskType = ins.InstanceType + row.Status = ins.State + row.Config = fmt.Sprintf("%s|%dG|%dG", ins.DBTypeId, ins.MemoryLimit/1000, ins.DiskSpace) + list = append(list, row) + for _, slave := range ins.DataSet { + row := UDBMysqlRow{} + row.Name = slave.Name + row.Zone = slave.Zone + row.Role = fmt.Sprintf("\u2b91 %s", slave.Role) + row.ResourceID = slave.DBId + row.Group = slave.Tag + row.VPC = slave.VPCId + row.Subnet = slave.SubnetId + row.IP = slave.VirtualIP + row.Mode = slave.InstanceMode + row.DiskType = slave.InstanceType + row.Config = fmt.Sprintf("%s|%dG|%dG", slave.DBTypeId, slave.MemoryLimit/1000, slave.DiskSpace) + row.Status = slave.State + list = append(list, row) + } + } + base.PrintList(list) + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + req.DBId = flags.String("udb-id", "", "Optional. List the specified mysql") + bindProjectID(req, flags) + bindRegion(req, flags) + bindZone(req, flags) + bindLimit(req, flags) + bindOffset(req, flags) + req.IncludeSlaves = flags.Bool("include-slaves", false, "Optional. When specifying the udb-id, whether to display its slaves together. Accept values:true, false") + req.ClassType = sdk.String("sql") + + flags.SetFlagValues("include-slaves", "true", "false") + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "sql", *req.ProjectId, *req.Region, *req.Zone) + }) + + return cmd +} + +//NewCmdUDBDelete ucloud udb delete +func NewCmdUDBDelete(out io.Writer) *cobra.Command { + var idNames []string + var yes bool + req := base.BizClient.NewDeleteUDBInstanceRequest() + cmd := &cobra.Command{ + Use: "delete", + Short: "Delete MySQL instances by udb-id", + Long: "Delete MySQL instances by udb-id", + Run: func(c *cobra.Command, args []string) { + ok := base.Confirm(yes, "Are you sure you want to delete the udb(s)?") + if !ok { + return + } + for _, idname := range idNames { + id := base.PickResourceID(idname) + any, err := describeUdbByID(id) + if err != nil { + base.HandleError(err) + continue + } + req.DBId = &id + ins, ok := any.(*udb.UDBInstanceSet) + if ok && ins.State == status.UDB_RUNNING { + stopReq := base.BizClient.NewStopUDBInstanceRequest() + stopReq.ProjectId = req.ProjectId + stopReq.Region = req.Region + stopReq.Zone = req.Zone + stopReq.DBId = req.DBId + stopUdbIns(stopReq, false, out) + } + _, err = base.BizClient.DeleteUDBInstance(req) + if err != nil { + base.HandleError(err) + continue + } + fmt.Fprintf(out, "udb[%s] deleted\n", idname) + } + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringSliceVar(&idNames, "udb-id", nil, "Required. Resource ID of UDB instances to delete") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + flags.BoolVarP(&yes, "yes", "y", false, "Optional. Do not prompt for confirmation.") + + cmd.MarkFlagRequired("udb-id") + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "", *req.ProjectId, *req.Region, *req.Zone) + }) + return cmd +} + +//NewCmdUDBStop ucloud udb stop +func NewCmdUDBStop(out io.Writer) *cobra.Command { + var idNames []string + var async bool + req := base.BizClient.NewStopUDBInstanceRequest() + cmd := &cobra.Command{ + Use: "stop", + Short: "Stop MySQL instances by udb-id", + Long: "Stop MySQL instances by udb-id", + Run: func(c *cobra.Command, args []string) { + for _, idname := range idNames { + req.DBId = sdk.String(base.PickResourceID(idname)) + stopUdbIns(req, async, out) + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringSliceVar(&idNames, "udb-id", nil, "Required. Resource ID of UDB instances to stop") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + req.ForceToKill = flags.Bool("force", false, "Optional. Stop UDB instances by force or not") + flags.BoolVarP(&async, "async", "a", false, "Optional. Do not wait for the long-running operation to finish.") + + cmd.MarkFlagRequired("udb-id") + + flags.SetFlagValues("force", "true", "false") + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList([]string{status.UDB_RUNNING}, "", *req.ProjectId, *req.Region, *req.Zone) + }) + + return cmd +} + +//NewCmdUDBStart ucloud udb start +func NewCmdUDBStart(out io.Writer) *cobra.Command { + var async bool + var idNames []string + req := base.BizClient.NewStartUDBInstanceRequest() + cmd := &cobra.Command{ + Use: "start", + Short: "Start MySQL instances by udb-id", + Long: "Start MySQL instances by udb-id", + Run: func(c *cobra.Command, args []string) { + for _, idname := range idNames { + id := base.PickResourceID(idname) + req.DBId = &id + _, err := base.BizClient.StartUDBInstance(req) + if err != nil { + base.HandleError(err) + continue + } + if async { + fmt.Fprintf(out, "udb[%s] is starting\n", idname) + } else { + text := fmt.Sprintf("udb[%s] is starting", idname) + poller.Spoll(*req.DBId, text, []string{status.UDB_RUNNING, status.UDB_FAIL}) + } + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringSliceVar(&idNames, "udb-id", nil, "Required. Resource ID of UDB instances to start") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + flags.BoolVarP(&async, "async", "a", false, "Optional. Do not wait for the long-running operation to finish.") + + cmd.MarkFlagRequired("udb-id") + + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList([]string{status.UDB_SHUTOFF}, "", *req.ProjectId, *req.Region, *req.Zone) + }) + return cmd +} + +//NewCmdUDBRestart ucloud udb restart +func NewCmdUDBRestart(out io.Writer) *cobra.Command { + var async bool + var idNames []string + req := base.BizClient.NewRestartUDBInstanceRequest() + cmd := &cobra.Command{ + Use: "restart", + Short: "Restart MySQL instances by udb-id", + Long: "Restart MySQL instances by udb-id", + Run: func(c *cobra.Command, args []string) { + for _, idname := range idNames { + id := base.PickResourceID(idname) + req.DBId = &id + _, err := base.BizClient.RestartUDBInstance(req) + if err != nil { + base.HandleError(err) + continue + } + if async { + fmt.Fprintf(out, "udb[%s] is restarting\n", idname) + } else { + text := fmt.Sprintf("udb[%s] is restarting", idname) + poller.Spoll(*req.DBId, text, []string{status.UDB_RUNNING, status.UDB_FAIL}) + } + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringSliceVar(&idNames, "udb-id", nil, "Required. Resource ID of UDB instances to restart") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + flags.BoolVarP(&async, "async", "a", false, "Optional. Do not wait for the long-running operation to finish.") + + cmd.MarkFlagRequired("udb-id") + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "", *req.ProjectId, *req.Region, *req.Zone) + }) + return cmd +} + +//NewCmdUDBResize ucloud udb resize +func NewCmdUDBResize(out io.Writer) *cobra.Command { + var diskTypes = []string{"normal", "sata_ssd", "pcie_ssd", "normal_volume", "sata_ssd_volume", "pcie_ssd_volume"} + var async, yes bool + var idNames []string + var memory, disk int + var diskType string + req := base.BizClient.NewResizeUDBInstanceRequest() + cmd := &cobra.Command{ + Use: "resize", + Short: "Reszie MySQL instances, such as memory size, disk size and disk type", + Long: "Reszie MySQL instances, such as memory size, disk size and disk type", + Run: func(c *cobra.Command, args []string) { + if diskType != "" { + switch diskType { + case "normal": + req.InstanceType = sdk.String("Normal") + case "sata_ssd": + req.InstanceType = sdk.String("SATA_SSD") + case "pcie_ssd": + req.InstanceType = sdk.String("PCIE_SSD") + case "normal_volume": + req.InstanceType = sdk.String("Normal_Volume") + case "sata_ssd_volume": + req.InstanceType = sdk.String("SATA_SSD_Volume") + case "pcie_ssd_volume": + req.InstanceType = sdk.String("PCIE_SSD_Volume") + default: + req.InstanceType = &diskType + } + } + + for _, idname := range idNames { + id := base.PickResourceID(idname) + req.DBId = &id + any, err := describeUdbByID(id) + if err != nil { + base.HandleError(err) + continue + } + + ins, ok := any.(*udb.UDBInstanceSet) + if !ok { + continue + } + + if memory != 0 { + req.MemoryLimit = sdk.Int(memory * 1000) + } else { + req.MemoryLimit = &ins.MemoryLimit + } + if disk != 0 { + req.DiskSpace = &disk + } else { + req.DiskSpace = &ins.DiskSpace + } + + if ins.State == status.UDB_RUNNING { + ok := base.Confirm(yes, fmt.Sprintf("Need to shut down udb[%s] before upgrading, whether to continue?", idname)) + if !ok { + continue + } + stopReq := base.BizClient.NewStopUDBInstanceRequest() + stopReq.ProjectId = req.ProjectId + stopReq.Region = req.Region + stopReq.Zone = req.Zone + stopReq.DBId = req.DBId + stopUdbIns(stopReq, false, out) + } + _, err = base.BizClient.ResizeUDBInstance(req) + if err != nil { + base.HandleError(err) + continue + } + if async { + fmt.Fprintf(out, "udb[%s] is resizing\n", idname) + } else { + text := fmt.Sprintf("udb[%s] is resizing", idname) + poller.Spoll(*req.DBId, text, []string{status.UDB_RUNNING, status.UDB_SHUTOFF, status.UDB_FAIL, status.UDB_UPGRADE_FAIL}) + } + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringSliceVar(&idNames, "udb-id", nil, "Required. Resource ID of UDB instances to restart") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + flags.IntVar(&memory, "memory-size-gb", 0, "Optional. Memory size of udb instance. From 1 to 128. Unit GB") + flags.IntVar(&disk, "disk-size-gb", 0, "Optional. Disk size of udb instance. From 20 to 3000 according to memory size. Unit GB. Step 10GB") + flags.StringVar(&diskType, "disk-type", "", fmt.Sprintf("Optional. Disk type of udb instance. Accept values:%s", strings.Join(diskTypes, ", "))) + req.StartAfterUpgrade = flags.Bool("start-after-upgrade", true, "Optional. Automatic start the UDB instances after upgrade") + flags.BoolVarP(&async, "async", "a", false, "Optional. Do not wait for the long-running operation to finish") + flags.BoolVarP(&yes, "yes", "y", false, "Optional. Do not prompt for confirmation") + + flags.SetFlagValues("disk-type", diskTypes...) + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "", *req.ProjectId, *req.Region, *req.Zone) + }) + + cmd.MarkFlagRequired("udb-id") + + return cmd +} + +//NewCmdUDBResetPassword ucloud udb reset-password +func NewCmdUDBResetPassword(out io.Writer) *cobra.Command { + var idNames []string + req := base.BizClient.NewModifyUDBInstancePasswordRequest() + cmd := &cobra.Command{ + Use: "reset-password", + Short: "Reset password of MySQL instances", + Long: "Reset password of MySQL instances", + Run: func(c *cobra.Command, args []string) { + for _, idname := range idNames { + id := base.PickResourceID(idname) + req.DBId = &id + _, err := base.BizClient.ModifyUDBInstancePassword(req) + if err != nil { + base.HandleError(err) + continue + } + fmt.Fprintf(out, "udb[%s]'s password modified\n", idname) + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringSliceVar(&idNames, "udb-id", nil, "Required. Resource ID of UDB instances to reset password") + req.Password = flags.String("password", "", "Required. New password") + bindProjectID(req, flags) + bindRegion(req, flags) + bindZone(req, flags) + + cmd.MarkFlagRequired("udb-id") + cmd.MarkFlagRequired("password") + + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "", *req.ProjectId, *req.Region, *req.Zone) + }) + + return cmd +} + +//NewCmdUDBRestore ucloud udb restore +func NewCmdUDBRestore(out io.Writer) *cobra.Command { + var datetime, diskType string + var async bool + req := base.BizClient.NewCreateUDBInstanceByRecoveryRequest() + cmd := &cobra.Command{ + Use: "restore", + Short: "Create MySQL instance and restore the newly created db to the specified DB at a specified point in time", + Long: "Create MySQL instance and restore the newly created db to the specified DB at a specified point in time", + Run: func(c *cobra.Command, args []string) { + t, err := time.Parse(time.RFC3339, datetime) + if err != nil { + base.HandleError(err) + return + } + req.RecoveryTime = sdk.Int(int(t.Unix())) + req.SrcDBId = sdk.String(base.PickResourceID(*req.SrcDBId)) + if diskType == "" { + any, err := describeUdbByID(*req.SrcDBId) + if err != nil { + base.HandleError(err) + return + } + ins, ok := any.(*udb.UDBInstanceSet) + if !ok { + fmt.Fprintln(out, fmt.Sprintf("fetch udb[%s] instance", *req.SrcDBId)) + } + req.UseSSD = &ins.UseSSD + } else if diskType == "normal" { + req.UseSSD = sdk.Bool(false) + } else if diskType == "ssd" { + req.UseSSD = sdk.Bool(true) + } + resp, err := base.BizClient.CreateUDBInstanceByRecovery(req) + if async { + fmt.Fprintf(out, "udb[%s] is restorting from udb[%s] at time point %s", resp.DBId, *req.SrcDBId, datetime) + } else { + text := fmt.Sprintf("udb[%s] is restorting from udb[%s] at time point %s", resp.DBId, *req.SrcDBId, datetime) + poller.Spoll(resp.DBId, text, []string{status.UDB_RUNNING, status.UDB_RECOVER_FAIL, status.UDB_FAIL}) + } + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + req.Name = flags.String("name", "", "Required. Name of UDB instance to create") + req.SrcDBId = flags.String("src-udb-id", "", "Required. Resource ID of source UDB") + flags.StringVar(&datetime, "restore-to-time", "", "Required. The date and time to restore the DB to. Value must be a time in Universal Coordinated Time (UTC) format.Example: 2019-02-23T23:45:00Z") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + flags.StringVar(&diskType, "disk-type", "", "Optional. Disk type. The default is to be consistent with the source database. Accept values: normal, ssd") + bindChargeType(req, flags) + bindQuantity(req, flags) + flags.BoolVarP(&async, "async", "a", false, "Optional. Do not wait for the long-running operation to finish") + + cmd.MarkFlagRequired("name") + cmd.MarkFlagRequired("src-udb-id") + cmd.MarkFlagRequired("restore-to-time") + + flags.SetFlagValues("disk-type", "noraml", "ssd") + flags.SetFlagValuesFunc("src-udb-id", func() []string { + return getUDBIDList(nil, "sql", *req.ProjectId, *req.Region, *req.Zone) + }) + + return cmd +} + +//NewCmdUDBCreateSlave ucloud udb create-slave +func NewCmdUDBCreateSlave(out io.Writer) *cobra.Command { + var diskType string + var async bool + req := base.BizClient.NewCreateUDBSlaveRequest() + cmd := &cobra.Command{ + Use: "create-slave", + Short: "Create slave database", + Long: "Create slave database", + Run: func(c *cobra.Command, args []string) { + *req.SrcId = base.PickResourceID(*req.SrcId) + switch diskType { + case "normal": + req.UseSSD = sdk.Bool(false) + case "sata_ssd": + req.UseSSD = sdk.Bool(true) + req.SSDType = sdk.String("SATA") + case "pcie_ssd": + req.UseSSD = sdk.Bool(true) + req.SSDType = sdk.String("PCI-E") + } + *req.MemoryLimit *= 1000 + resp, err := base.BizClient.CreateUDBSlave(req) + if err != nil { + base.HandleError(err) + return + } + if async { + fmt.Fprintf(out, "udb[%s] is initializing\n", resp.DBId) + } else { + poller.Spoll(resp.DBId, fmt.Sprintf("udb[%s] is initializing", resp.DBId), []string{status.UDB_RUNNING, status.UDB_FAIL}) + } + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + req.SrcId = flags.String("master-udb-id", "", "Required. Resource ID of master UDB instance") + req.Name = flags.String("name", "", "Required. Name of the slave DB to create") + req.Port = flags.Int("port", 3306, "Optional. Port of the slave db service") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + flags.StringVar(&diskType, "disk-type", "Normal", fmt.Sprintf("Optional. Setting this flag means using SSD disk. Accept values: %s", strings.Join(dbDiskTypeList, ", "))) + req.MemoryLimit = flags.Int("memory-size-gb", 1, "Optional. Memory size of udb instance. From 1 to 128. Unit GB") + flags.BoolVar(&async, "async", false, "Optional. Do not wait for the long-running operation to finish") + req.IsLock = flags.Bool("is-lock", false, "Optional. Lock master DB or not") + + cmd.MarkFlagRequired("master-udb-id") + cmd.MarkFlagRequired("name") + + flags.SetFlagValues("disk-type", dbDiskTypeList...) + flags.SetFlagValuesFunc("master-udb-id", func() []string { + return getUDBIDList(nil, "", *req.ProjectId, *req.Region, *req.Zone) + }) + return cmd +} + +//NewCmdUDBPromoteSlave ucloud udb promote-slave +func NewCmdUDBPromoteSlave(out io.Writer) *cobra.Command { + var ids []string + req := base.BizClient.NewPromoteUDBSlaveRequest() + cmd := &cobra.Command{ + Use: "promote-slave", + Short: "Promote slave db to master", + Long: "Promote slave db to master", + Run: func(c *cobra.Command, args []string) { + for _, id := range ids { + req.DBId = sdk.String(id) + _, err := base.BizClient.PromoteUDBSlave(req) + if err != nil { + base.HandleError(err) + return + } + fmt.Fprintf(out, "udb[%s] was promoted\n", *req.DBId) + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringSliceVar(&ids, "udb-id", nil, "Required. Resource ID of slave db to promote") + req.IsForce = flags.Bool("is-force", false, "Optional. Force to promote slave db or not. If the slave db falls behind, the force promote may lose some data") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + + cmd.MarkFlagRequired("udb-id") + + return cmd +} + +//NewCmdUDBPromoteToHA ucloud udb promote-to-ha 低频操作 暂不开放 +func NewCmdUDBPromoteToHA(out io.Writer) *cobra.Command { + var idNames []string + req := base.BizClient.NewPromoteUDBInstanceToHARequest() + cmd := &cobra.Command{ + Use: "promote-to-ha", + Short: "Promote db of normal mode to high availability db. ", + Long: "Promote db of normal mode to high availability db", + Run: func(c *cobra.Command, args []string) { + for _, idname := range idNames { + id := base.PickResourceID(idname) + req.DBId = &id + _, err := base.BizClient.PromoteUDBInstanceToHA(req) + if err != nil { + base.HandleError(err) + continue + } + poller.Spoll(id, fmt.Sprintf("udb[%s] is synchronizing data", id), []string{status.UDB_TOBE_SWITCH, status.UDB_FAIL}) + any, err := describeUdbByID(id) + if err != nil { + fmt.Fprintf(out, "udb[%s] promoted failed, please contact technical support; %v\n", idname, err) + continue + } + ins, ok := any.(*udb.UDBInstanceSet) + if !ok { + fmt.Fprintf(out, "udb[%s] promoted failed, please contact technical support. \n", idname) + continue + } + if ins.State != status.UDB_TOBE_SWITCH { + fmt.Fprintf(out, "udb[%s] promoted failed, please contact technical support. udb[%s]'s status:%s\n", idname, idname, ins.State) + continue + } + switchReq := base.BizClient.NewSwitchUDBInstanceToHARequest() + switchReq.DBId = &id + switchReq.Region = req.Region + switchReq.ProjectId = req.ProjectId + switchReq.ChargeType = &ins.ChargeType + switchReq.Quantity = sdk.String("0") + switchReq.Zone = &base.ConfigIns.Zone + switchResp, err := base.BizClient.SwitchUDBInstanceToHA(switchReq) + if err != nil { + fmt.Fprintf(out, "udb[%s] promoted failed, please contact technical support; %v\n", idname, err) + continue + } + poller.Spoll(switchResp.DBId, fmt.Sprintf("udb[%s] is switching to high availability mode", switchResp.DBId), []string{status.UDB_RUNNING, status.UDB_FAIL}) + } + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + bindRegion(req, flags) + bindProjectID(req, flags) + flags.StringSliceVar(&idNames, "udb-id", nil, "Required. Resource ID of UDB instances to be promoted as high availability mode") + + cmd.MarkFlagRequired("udb-id") + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "", *req.ProjectId, *req.Region, "") + }) + return cmd +} + +func stopUdbIns(req *udb.StopUDBInstanceRequest, async bool, out io.Writer) { + _, err := base.BizClient.StopUDBInstance(req) + if err != nil { + base.HandleError(err) + return + } + text := fmt.Sprintf("udb[%s] is stopping", *req.DBId) + if async { + fmt.Fprintln(out, text) + } else { + poller.Spoll(*req.DBId, text, []string{status.UDB_SHUTOFF, status.UDB_FAIL}) + } +} + +func getUDBIDList(states []string, dbType, project, region, zone string) []string { + udbs, err := getUDBList(states, dbType, project, region, zone) + if err != nil { + return nil + } + list := []string{} + for _, db := range udbs { + list = append(list, fmt.Sprintf("%s/%s", db.DBId, db.Name)) + } + return list +} + +func getUDBList(states []string, dbType, project, region, zone string) ([]udb.UDBInstanceSet, error) { + req := base.BizClient.NewDescribeUDBInstanceRequest() + if dbType == "" { + dbType = "sql" + } + req.ClassType = &dbType + req.ProjectId = &project + req.Region = ®ion + req.Zone = &zone + list := []udb.UDBInstanceSet{} + for offset, limit := 0, 50; ; offset += limit { + req.Offset = sdk.Int(offset) + req.Limit = sdk.Int(limit) + resp, err := base.BizClient.DescribeUDBInstance(req) + if err != nil { + return nil, err + } + for _, ins := range resp.DataSet { + if states != nil { + for _, s := range states { + if s == ins.State { + list = append(list, ins) + } + } + } else { + list = append(list, resp.DataSet...) + } + } + if offset+limit >= resp.TotalCount { + break + } + } + return list, nil +} + +func describeUdbByID(udbID string) (interface{}, error) { + req := base.BizClient.NewDescribeUDBInstanceRequest() + req.DBId = sdk.String(udbID) + resp, err := base.BizClient.DescribeUDBInstance(req) + if err != nil { + return nil, err + } + if len(resp.DataSet) < 1 { + return nil, fmt.Errorf("udb[%s] may not exist", udbID) + } + return &resp.DataSet[0], nil +} diff --git a/cmd/project.go b/cmd/project.go index 93f837bc3e..3eea71dbbf 100644 --- a/cmd/project.go +++ b/cmd/project.go @@ -141,7 +141,7 @@ func listProject() error { if resp.RetCode != 0 { return base.HandleBizError(resp) } - if global.json { + if global.JSON { base.PrintJSON(resp.ProjectSet) } else { base.PrintTable(resp.ProjectSet, []string{"ProjectId", "ProjectName"}) diff --git a/cmd/region.go b/cmd/region.go index ef6124dcc0..e27dbb4cd4 100644 --- a/cmd/region.go +++ b/cmd/region.go @@ -44,11 +44,7 @@ func NewCmdRegion() *cobra.Command { for region, zones := range regionMap { regionList = append(regionList, RegionTable{region, strings.Join(zones, ", ")}) } - if global.json { - base.PrintJSON(regionList) - } else { - base.PrintTableS(regionList) - } + base.PrintList(regionList) }, } return cmd diff --git a/cmd/root.go b/cmd/root.go index 88bcd6a548..0c7d479ae2 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -18,23 +18,14 @@ import ( "fmt" "os" - "github.com/Sirupsen/logrus" "github.com/spf13/cobra" + "github.com/ucloud/ucloud-sdk-go/ucloud/log" + "github.com/ucloud/ucloud-cli/base" ) -//GlobalFlag 几乎所有接口都需要的参数,例如 region zone projectID -type GlobalFlag struct { - debug bool - json bool - version bool - completion bool - config bool - signup bool -} - -var global GlobalFlag +var global = base.Global //NewCmdRoot 创建rootCmd rootCmd represents the base command when called without any subcommands func NewCmdRoot() *cobra.Command { @@ -45,13 +36,13 @@ func NewCmdRoot() *cobra.Command { Long: `UCloud CLI - manage UCloud resources and developer workflow`, BashCompletionFunction: "__ucloud_init_completion", Run: func(cmd *cobra.Command, args []string) { - if global.version { + if global.Version { base.Cxt.Printf("ucloud cli %s\n", base.Version) - } else if global.completion { + } else if global.Completion { NewCmdCompletion().Run(cmd, args) - } else if global.config { - base.ListAggConfig(global.json) - } else if global.signup { + } else if global.Config { + base.ListAggConfig(global.JSON) + } else if global.Signup { NewCmdSignup().Run(cmd, args) } else { cmd.HelpFunc()(cmd, args) @@ -59,12 +50,12 @@ func NewCmdRoot() *cobra.Command { }, } - cmd.PersistentFlags().BoolVarP(&global.debug, "debug", "d", false, "Running in debug mode") - cmd.PersistentFlags().BoolVarP(&global.json, "json", "j", false, "Print result in JSON format whenever possible") - cmd.Flags().BoolVarP(&global.version, "version", "v", false, "Display version") - cmd.Flags().BoolVar(&global.completion, "completion", false, "Turn on auto completion according to the prompt") - cmd.Flags().BoolVar(&global.config, "config", false, "Display configuration") - cmd.Flags().BoolVar(&global.signup, "signup", false, "Launch UCloud sign up page in browser") + cmd.PersistentFlags().BoolVarP(&global.Debug, "debug", "d", false, "Running in debug mode") + cmd.PersistentFlags().BoolVarP(&global.JSON, "json", "j", false, "Print result in JSON format whenever possible") + cmd.Flags().BoolVarP(&global.Version, "version", "v", false, "Display version") + cmd.Flags().BoolVar(&global.Completion, "completion", false, "Turn on auto completion according to the prompt") + cmd.Flags().BoolVar(&global.Config, "config", false, "Display configuration") + cmd.Flags().BoolVar(&global.Signup, "signup", false, "Launch UCloud sign up page in browser") cmd.AddCommand(NewCmdInit()) cmd.AddCommand(NewCmdConfig()) @@ -81,6 +72,7 @@ func NewCmdRoot() *cobra.Command { cmd.AddCommand(NewCmdBandwidth()) cmd.AddCommand(NewCmdUDPN(out)) cmd.AddCommand(NewCmdULB()) + cmd.AddCommand(NewCmdMysql()) return cmd } @@ -132,8 +124,6 @@ func Execute() { rootCmd.SetUsageTemplate(usageTmpl) resetHelpFunc(rootCmd) - // err := doc.GenReSTTree(rootCmd, "./doc") - // fmt.Println(err) if err := rootCmd.Execute(); err != nil { os.Exit(1) } @@ -170,8 +160,8 @@ func initialize(cmd *cobra.Command) { base.ClientConfig.Zone = zone } - if global.debug { - logrus.SetLevel(logrus.DebugLevel) + if global.Debug { + log.SetLevel(log.DebugLevel) } userInfo, err := base.LoadUserInfo() diff --git a/cmd/udb.go b/cmd/udb.go new file mode 100644 index 0000000000..9e91adafd4 --- /dev/null +++ b/cmd/udb.go @@ -0,0 +1,640 @@ +// Copyright © 2018 NAME HERE tony.li@ucloud.cn +// +// 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. + +package cmd + +import ( + "bufio" + "encoding/base64" + "fmt" + "io" + "os" + "strconv" + "strings" + + "github.com/spf13/cobra" + + "github.com/ucloud/ucloud-sdk-go/services/udb" + sdk "github.com/ucloud/ucloud-sdk-go/ucloud" + + "github.com/ucloud/ucloud-cli/base" + "github.com/ucloud/ucloud-cli/model/status" +) + +//NewCmdUDBConf ucloud udb conf +func NewCmdUDBConf() *cobra.Command { + cmd := &cobra.Command{ + Use: "conf", + Short: "List and manipulate configuration files of MySQL instances", + Long: "List and manipulate configuration files of MySQL instances", + } + out := base.Cxt.GetWriter() + cmd.AddCommand(NewCmdUDBConfList()) + cmd.AddCommand(NewCmdUDBConfDescribe(out)) + cmd.AddCommand(NewCmdUDBConfClone(out)) + cmd.AddCommand(NewCmdUDBConfUpload(out)) + cmd.AddCommand(NewCmdUDBConfUpdate(out)) + cmd.AddCommand(NewCmdUDBConfDelete(out)) + cmd.AddCommand(NewCmdUDBConfApply(out)) + cmd.AddCommand(NewCmdUDBConfDownload(out)) + return cmd +} + +//UDBConfRow 表格行 +type UDBConfRow struct { + ConfID int + DBVersion string + Name string + Description string + Modifiable bool + Zone string +} + +var dbTypeMap = map[string]string{ + "mysql": "sql", + "mongodb": "nosql", + "postgresql": "postgresql", + "sqlserver": "sqlserver", +} + +var dbTypeList = []string{"mysql", "mongodb", "postgresql", "sqlserver"} + +//NewCmdUDBConfList ucloud mysql conf list +func NewCmdUDBConfList() *cobra.Command { + req := base.BizClient.NewDescribeUDBParamGroupRequest() + cmd := &cobra.Command{ + Use: "list", + Short: "List configuartion files of MySQL instances", + Long: "List configuartion files of MySQL instances", + Run: func(c *cobra.Command, args []string) { + if *req.GroupId == 0 { + req.GroupId = nil + } + resp, err := base.BizClient.DescribeUDBParamGroup(req) + if err != nil { + base.HandleError(err) + return + } + list := []UDBConfRow{} + for _, ins := range resp.DataSet { + row := UDBConfRow{ + ConfID: ins.GroupId, + Name: ins.GroupName, + Zone: ins.Zone, + DBVersion: ins.DBTypeId, + Description: ins.Description, + Modifiable: ins.Modifiable, + } + list = append(list, row) + } + base.PrintList(list) + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + bindOffset(req, flags) + bindLimit(req, flags) + req.GroupId = flags.Int("conf-id", 0, "Optional. Configuration identifier for the configuration to be described") + req.ClassType = sdk.String("sql") + + flags.SetFlagValuesFunc("conf-id", func() []string { + return getConfIDList(*req.ClassType, *req.ProjectId, *req.Region, *req.Zone) + }) + + return cmd +} + +//UDBConfParamRow 参数配置展示表格行 +type UDBConfParamRow struct { + Key string + Value string +} + +//NewCmdUDBConfDescribe ucloud udb conf describe +func NewCmdUDBConfDescribe(out io.Writer) *cobra.Command { + var confID string + req := base.BizClient.NewDescribeUDBParamGroupRequest() + req.RegionFlag = sdk.Bool(false) + cmd := &cobra.Command{ + Use: "describe", + Short: "Display details about a configuration file of MySQL instance", + Long: "Display details about a configuration file of MySQL instance", + Run: func(c *cobra.Command, args []string) { + id, err := strconv.Atoi(base.PickResourceID(confID)) + if err != nil { + base.HandleError(err) + return + } + req.GroupId = &id + resp, err := base.BizClient.DescribeUDBParamGroup(req) + if err != nil { + base.HandleError(err) + return + } + if len(resp.DataSet) != 1 { + fmt.Fprintf(out, "Error, conf-id[%d] may not be exist\n", req.GroupId) + return + } + conf := resp.DataSet[0] + attrs := []base.DescribeTableRow{ + base.DescribeTableRow{Attribute: "ConfID", Content: strconv.Itoa(conf.GroupId)}, + base.DescribeTableRow{Attribute: "DBVersion", Content: conf.DBTypeId}, + base.DescribeTableRow{Attribute: "Name", Content: conf.GroupName}, + base.DescribeTableRow{Attribute: "Description", Content: conf.Description}, + base.DescribeTableRow{Attribute: "Modifiable", Content: strconv.FormatBool(conf.Modifiable)}, + base.DescribeTableRow{Attribute: "Zone", Content: conf.Zone}, + } + fmt.Fprintln(out, "Attributes:") + base.PrintList(attrs) + + params := []UDBConfParamRow{} + for _, p := range conf.ParamMember { + if p.Value == "" { + continue + } + row := UDBConfParamRow{ + Key: p.Key, + Value: p.Value, + } + params = append(params, row) + } + fmt.Fprintln(out, "\nParameters:") + base.PrintList(params) + + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringVar(&confID, "conf-id", "", "Requried. Configuration identifier for the configuration to be described") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + + cmd.MarkFlagRequired("conf-id") + flags.SetFlagValuesFunc("conf-id", func() []string { + return getConfIDList("sql", *req.ProjectId, *req.Region, *req.Zone) + }) + + return cmd +} + +//NewCmdUDBConfClone ucloud udb conf clone +func NewCmdUDBConfClone(out io.Writer) *cobra.Command { + var srcConfID string + req := base.BizClient.NewCreateUDBParamGroupRequest() + cmd := &cobra.Command{ + Use: "clone", + Short: "Create configuration file by cloning existed configuration", + Long: "Create configuration file by cloning existed configuration", + Run: func(c *cobra.Command, args []string) { + id, err := strconv.Atoi(base.PickResourceID(srcConfID)) + if err != nil { + base.HandleError(err) + return + } + if *req.DBTypeId == "" { + confIns, err := getConfByID(id, *req.ProjectId, *req.Region, *req.Zone) + if err != nil { + base.HandleError(err) + return + } + req.DBTypeId = sdk.String(confIns.DBTypeId) + } + req.SrcGroupId = &id + resp, err := base.BizClient.CreateUDBParamGroup(req) + if err != nil { + base.HandleError(err) + return + } + fmt.Fprintf(out, "conf[%d] created\n", resp.GroupId) + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + req.DBTypeId = flags.String("db-version", "", fmt.Sprintf("Required. Version of DB. Accept values:%s", strings.Join(dbVersionList, ", "))) + req.GroupName = flags.String("name", "", "Required. Name of configuration. It's length should be between 6 and 63") + req.Description = flags.String("description", " ", "Optional. Description of the configuration to clone") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + flags.StringVar(&srcConfID, "src-conf-id", "", "Optional. The ConfID of source configuration which to be cloned from") + + flags.SetFlagValues("db-version", dbVersionList...) + flags.SetFlagValuesFunc("src-conf-id", func() []string { + return getConfIDList("sql", *req.ProjectId, *req.Region, *req.Zone) + }) + + cmd.MarkFlagRequired("name") + cmd.MarkFlagRequired("src-conf-id") + return cmd +} + +var udbSubtypeMap = map[string]int{ + "unknow": 0, + "Shardsvr-MMAPv1": 1, + "Shardsvr-WiredTiger": 2, + "Configsvr-MMAPv1": 3, + "Configsvr-WiredTiger": 4, + "Mongos": 5, + "Mysql": 10, + "Postgresql": 20, +} + +var subtypeList = []string{"Shardsvr-MMAPv1", "Shardsvr-WiredTiger", "Configsvr-MMAPv1", "Configsvr-WiredTiger", "Mongos", "Mysql", "Postgresql"} + +//NewCmdUDBConfUpload ucloud udb conf upload +func NewCmdUDBConfUpload(out io.Writer) *cobra.Command { + var file string + req := base.BizClient.NewUploadUDBParamGroupRequest() + cmd := &cobra.Command{ + Use: "upload", + Short: "Create configuration file by uploading local DB configuration file", + Long: "Create configuration file by uploading local DB configuration file", + Run: func(c *cobra.Command, args []string) { + content, err := readFile(file) + if err != nil { + base.HandleError(err) + return + } + if l := len(*req.GroupName); l < 6 || l > 63 { + fmt.Fprintln(out, "Error, length of name shoud be between 6 and 63") + return + } + req.Content = sdk.String(base64.StdEncoding.EncodeToString([]byte(content))) + req.ParamGroupTypeId = sdk.Int(10) + resp, err := base.BizClient.UploadUDBParamGroup(req) + if err != nil { + base.HandleError(err) + return + } + fmt.Fprintf(out, "conf[%d] uploaded\n", resp.GroupId) + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringVar(&file, "conf-file", "", "Required. Path of local configuration file") + req.DBTypeId = flags.String("db-version", "", fmt.Sprintf("Required. Version of DB. Accept values:%s", strings.Join(dbVersionList, ", "))) + req.GroupName = flags.String("name", "", "Required. Name of configuration. It's length should be between 6 and 63") + req.Description = flags.String("description", " ", "Optional. Description of the configuration to clone") + // flags.StringVar(&subtype, "db-type", "", fmt.Sprintf("Optional. DB type. Accept values: %s", strings.Join(subtypeList, ", "))) + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + + cmd.MarkFlagRequired("conf-file") + cmd.MarkFlagRequired("name") + cmd.MarkFlagRequired("db-version") + // cmd.MarkFlagRequired("db-type") + + flags.SetFlagValues("db-version", dbVersionList...) + // flags.SetFlagValues("db-type", subtypeList...) + flags.SetFlagValuesFunc("conf-file", func() []string { + return base.GetFileList("") + }) + return cmd +} + +//NewCmdUDBConfUpdate ucloud udb conf update +func NewCmdUDBConfUpdate(out io.Writer) *cobra.Command { + var confID, key, value, file string + req := base.BizClient.NewUpdateUDBParamGroupRequest() + cmd := &cobra.Command{ + Use: "update", + Short: "Update parameters of DB's configuration", + Long: "Update parameters of DB's configuration", + Run: func(c *cobra.Command, args []string) { + id, err := strconv.Atoi(base.PickResourceID(confID)) + if err != nil { + base.HandleError(err) + return + } + req.GroupId = &id + + if key != "" && value != "" { + req.Key = &key + req.Value = &value + _, err := base.BizClient.UpdateUDBParamGroup(req) + if err != nil { + base.HandleError(err) + } else { + fmt.Printf("conf[%s]'sparameter[%s = %s] updated\n", confID, key, value) + } + } + if file != "" { + params, err := parseParam(file) + if err != nil { + base.HandleError(err) + return + } + for _, p := range params { + req.Key = sdk.String(p.Key) + req.Value = sdk.String(p.Value) + _, err := base.BizClient.UpdateUDBParamGroup(req) + if err != nil { + fmt.Printf("conf[%s]'sparameter[%s = %s] failed\n", confID, p.Key, p.Value) + base.HandleError(err) + } else { + fmt.Printf("conf[%s]'sparameter[%s = %s] updated\n", confID, p.Key, p.Value) + } + fmt.Println("") + } + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + + flags.StringVar(&confID, "conf-id", "", "Required. ConfID of configuration to update") + flags.StringVar(&key, "key", "", "Optional. Key of parameter") + flags.StringVar(&value, "value", "", "Optional. Value of parameter") + flags.StringVar(&file, "file", "", "Optional. Path of file in which each parameter occupies one line with format 'key = value'") + + flags.SetFlagValuesFunc("conf-id", func() []string { + return getModifiableConfIDList("", *req.ProjectId, *req.Region, *req.Zone) + }) + flags.SetFlagValuesFunc("file", func() []string { + return base.GetFileList("") + }) + + cmd.MarkFlagRequired("conf-id") + return cmd +} + +//NewCmdUDBConfDelete ucloud udb conf delete +func NewCmdUDBConfDelete(out io.Writer) *cobra.Command { + var confID string + req := base.BizClient.NewDeleteUDBParamGroupRequest() + cmd := &cobra.Command{ + Use: "delete", + Short: "Delete configuration of udb by conf-id", + Long: "Delete configuration of udb by conf-id", + Run: func(c *cobra.Command, args []string) { + id, err := strconv.Atoi(base.PickResourceID(confID)) + if err != nil { + base.HandleError(err) + return + } + req.GroupId = &id + _, err = base.BizClient.DeleteUDBParamGroup(req) + if err != nil { + base.HandleError(err) + return + } + fmt.Fprintf(out, "conf[%s] deleted\n", confID) + }, + } + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringVar(&confID, "conf-id", "", "Required. ConfID of the configuration to delete") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + + cmd.MarkFlagRequired("conf-id") + flags.SetFlagValuesFunc("conf-id", func() []string { + return getModifiableConfIDList("", *req.ProjectId, *req.Region, *req.Zone) + }) + return cmd +} + +// NewCmdUDBConfApply ucloud udb conf apply +func NewCmdUDBConfApply(out io.Writer) *cobra.Command { + var confID string + var udbIDs []string + var restart, yes, async bool + + req := base.BizClient.NewChangeUDBParamGroupRequest() + cmd := &cobra.Command{ + Use: "apply", + Short: "Apply configuration for UDB instances", + Long: "Apply configuration for UDB instances", + Run: func(c *cobra.Command, args []string) { + req.GroupId = sdk.String(base.PickResourceID(confID)) + for _, idname := range udbIDs { + req.DBId = sdk.String(base.PickResourceID(idname)) + _, err := base.BizClient.ChangeUDBParamGroup(req) + if err != nil { + base.HandleError(err) + continue + } + fmt.Fprintf(out, "conf[%s] has applied for udb[%s]\n", confID, idname) + if !restart { + continue + } + ok := base.Confirm(yes, fmt.Sprintf("udb[%s] is about to restart, do you want to continue?", idname)) + if !ok { + continue + } + restartReq := base.BizClient.NewRestartUDBInstanceRequest() + restartReq.Region = req.Region + restartReq.Zone = req.Zone + restartReq.ProjectId = req.ProjectId + restartReq.DBId = req.DBId + _, err = base.BizClient.RestartUDBInstance(restartReq) + if err != nil { + base.HandleError(err) + continue + } + if async { + fmt.Fprintf(out, "udb[%s] is restarting\n", idname) + } else { + text := fmt.Sprintf("udb[%s] is restarting", idname) + poller.Spoll(*req.DBId, text, []string{status.UDB_FAIL, status.UDB_RUNNING}) + } + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringVar(&confID, "conf-id", "", "Required. ConfID of the configuration to be applied") + flags.StringSliceVar(&udbIDs, "udb-id", nil, "Required. Resource ID of UDB instances to change configuration") + flags.BoolVar(&restart, "restart-after-apply", true, "Optional. The new configuration will take effect after DB restarts") + flags.BoolVarP(&yes, "yes", "y", false, "Optional. Do not prompt for confirmation") + flags.BoolVarP(&async, "async", "a", false, "Optional. Do not wait for the long-running operation to finish.") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + + cmd.MarkFlagRequired("conf-id") + cmd.MarkFlagRequired("udb-id") + + flags.SetFlagValuesFunc("conf-id", func() []string { + return getModifiableConfIDList("", *req.ProjectId, *req.Region, *req.Zone) + }) + flags.SetFlagValuesFunc("udb-id", func() []string { + return getUDBIDList(nil, "", *req.ProjectId, *req.Region, *req.Zone) + }) + + return cmd +} + +//NewCmdUDBConfDownload ucloud udb conf download +func NewCmdUDBConfDownload(out io.Writer) *cobra.Command { + var confID string + req := base.BizClient.NewExtractUDBParamGroupRequest() + cmd := &cobra.Command{ + Use: "download", + Short: "Download UDB configuration", + Long: "Download UDB configuration", + Run: func(c *cobra.Command, args []string) { + id, err := strconv.Atoi(base.PickResourceID(confID)) + if err != nil { + base.HandleError(err) + return + } + + req.GroupId = &id + resp, err := base.BizClient.ExtractUDBParamGroup(req) + if err != nil { + base.HandleError(err) + return + } + fmt.Fprint(out, resp.Content) + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringVar(&confID, "conf-id", "", "Required. ConfID of configuration to download") + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + + cmd.MarkFlagRequired("conf-id") + + flags.SetFlagValuesFunc("conf-id", func() []string { + return getConfIDList("sql", *req.ProjectId, *req.Region, *req.Zone) + }) + + return cmd +} + +type confParam struct { + Key string + Value string +} + +func parseParam(filePath string) ([]confParam, error) { + file, err := os.Open(filePath) + if err != nil { + return nil, err + } + defer file.Close() + params := []confParam{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + line = strings.TrimSpace(line) + if len(line) == 0 { + continue + } + strs := strings.SplitN(line, "=", 2) + if len(strs) < 2 { + continue + } + param := confParam{ + Key: strings.TrimSpace(strs[0]), + Value: strings.TrimSpace(strs[1]), + } + params = append(params, param) + } + if err := scanner.Err(); err != nil { + return nil, err + } + return params, nil +} + +func getConfByID(confID int, project, region, zone string) (*udb.UDBParamGroupSet, error) { + req := base.BizClient.NewDescribeUDBParamGroupRequest() + req.ProjectId = &project + req.Region = ®ion + req.Zone = &zone + req.GroupId = &confID + resp, err := base.BizClient.DescribeUDBParamGroup(req) + if err != nil { + return nil, err + } + if len(resp.DataSet) != 1 { + return nil, fmt.Errorf("conf-id[%d] may not exist", *req.GroupId) + } + return &resp.DataSet[0], nil +} + +func getConfList(dbType, project, region, zone string) ([]udb.UDBParamGroupSet, error) { + req := base.BizClient.NewDescribeUDBParamGroupRequest() + req.ClassType = &dbType + req.ProjectId = &project + req.Region = ®ion + req.Zone = &zone + list := []udb.UDBParamGroupSet{} + for offset, limit := 0, 50; ; offset += limit { + req.Offset = sdk.Int(offset) + req.Limit = sdk.Int(limit) + resp, err := base.BizClient.DescribeUDBParamGroup(req) + if err != nil { + return nil, err + } + for _, conf := range resp.DataSet { + list = append(list, conf) + } + if resp.TotalCount <= offset+limit { + break + } + } + return list, nil +} + +func getModifiableConfIDList(dbType, project, region, zone string) []string { + confs, err := getConfList(dbType, project, region, zone) + if err != nil { + return nil + } + list := []string{} + for _, conf := range confs { + if conf.Modifiable == true { + list = append(list, fmt.Sprintf("%d/%s", conf.GroupId, conf.GroupName)) + } + } + return list +} + +func getConfIDList(dbType, project, region, zone string) []string { + confs, err := getConfList(dbType, project, region, zone) + if err != nil { + return nil + } + list := []string{} + for _, conf := range confs { + list = append(list, fmt.Sprintf("%d/%s", conf.GroupId, conf.GroupName)) + } + return list +} diff --git a/cmd/uhost.go b/cmd/uhost.go index fbc1d54a8b..749577886d 100644 --- a/cmd/uhost.go +++ b/cmd/uhost.go @@ -113,7 +113,7 @@ func NewCmdUHostList() *cobra.Command { row.Type = host.UHostType + "/" + host.HostType list = append(list, row) } - base.PrintList(list, global.json) + base.PrintList(list) }, } cmd.Flags().SortFlags = false @@ -230,8 +230,7 @@ func NewCmdUHostCreate(out io.Writer) *cobra.Command { req.Quantity = flags.Int("quantity", 1, "Optional. The duration of the instance. N years/months.") bindProjectID(req, flags) bindRegion(req, flags) - // bindZone(req, flags) - req.Zone = flags.String("zone", base.ConfigIns.Zone, "Optional. Override default available zone, see 'ucloud region'") + bindZone(req, flags) req.UHostType = flags.String("type", defaultUhostType, "Optional. Default is 'N2' of which cpu is V4 and sata disk. also support 'N1' means V3 cpu and sata disk;'I2' means V4 cpu and ssd disk;'D1' means big data model;'G1' means GPU type, model for K80;'G2' model for P40; 'G3' model for V100") req.NetCapability = flags.String("net-capability", "Normal", "Optional. Default is 'Normal', also support 'Super' which will enhance multiple times network capability as before") @@ -272,7 +271,7 @@ func NewCmdUHostCreate(out io.Writer) *cobra.Command { }) cmd.MarkFlagRequired("cpu") - cmd.MarkFlagRequired("memory") + cmd.MarkFlagRequired("memory-gb") cmd.MarkFlagRequired("password") cmd.MarkFlagRequired("image-id") @@ -347,7 +346,7 @@ func NewCmdUHostDelete(out io.Writer) *cobra.Command { cmd.Flags().SetFlagValues("release-eip", "true", "false") cmd.Flags().SetFlagValues("delete-cloud-disk", "true", "false") cmd.Flags().SetFlagValuesFunc("uhost-id", func() []string { - return getUhostList([]string{status.HOST_RUNNING, status.HOST_FAIL, status.HOST_FAIL}, *req.ProjectId, *req.Region, *req.Zone) + return getUhostList([]string{status.HOST_RUNNING, status.HOST_STOPPED, status.HOST_FAIL}, *req.ProjectId, *req.Region, *req.Zone) }) cmd.MarkFlagRequired("uhost-id") @@ -391,7 +390,7 @@ func stopUhostIns(req *uhost.StopUHostInstanceRequest, async bool, out io.Writer if err != nil { base.HandleError(err) } else { - text := fmt.Sprintf("uhost:[%v] is shutting down", resp.UhostId) + text := fmt.Sprintf("uhost[%v] is shutting down", resp.UhostId) if async { fmt.Fprintln(out, text) } else { diff --git a/cmd/ulb.go b/cmd/ulb.go index 684ad18ece..fb677d486c 100644 --- a/cmd/ulb.go +++ b/cmd/ulb.go @@ -95,7 +95,7 @@ func NewCmdULBList() *cobra.Command { list = append(list, row) } - base.PrintList(list, global.json) + base.PrintList(list) }, } @@ -417,7 +417,7 @@ func NewCmdULBVServerList(out io.Writer) *cobra.Command { row.HealthCheckPath = vs.Path list = append(list, row) } - base.PrintList(list, global.json) + base.PrintList(list) }, } @@ -721,7 +721,7 @@ func NewCmdULBVServerListNode(out io.Writer) *cobra.Command { } list = append(list, row) } - base.PrintList(list, global.json) + base.PrintList(list) }, } flags := cmd.Flags() @@ -1036,7 +1036,7 @@ func NewCmdULBVServerListPolicy(out io.Writer) *cobra.Command { row.Backends = strings.Join(nodes, ",") list = append(list, row) } - base.PrintList(list, global.json) + base.PrintList(list) } }, } @@ -1264,7 +1264,7 @@ func NewCmdSSLList() *cobra.Command { row.BindResource = strings.Join(targets, ",") rows = append(rows, row) } - base.PrintList(rows, global.json) + base.PrintList(rows) }, } flags := cmd.Flags() @@ -1335,7 +1335,7 @@ func NewCmdSSLDescribe(out io.Writer) *cobra.Command { Content: sslcf.SSLContent, }, } - base.PrintDescribe(rows, global.json) + base.PrintDescribe(rows, global.JSON) }, } flags := cmd.Flags() diff --git a/cmd/unet.go b/cmd/unet.go index a132fa40c1..92eb281006 100644 --- a/cmd/unet.go +++ b/cmd/unet.go @@ -133,11 +133,7 @@ func NewCmdUDPNList(out io.Writer) *cobra.Command { row.CreationTime = base.FormatDate(udpn.CreateTime) list = append(list, row) } - if global.json { - base.PrintJSON(list) - } else { - base.PrintTableS(list) - } + base.PrintList(list) }, } diff --git a/cmd/util.go b/cmd/util.go index d0dc06d577..ab9dde9c81 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -25,13 +25,21 @@ func bindRegionS(region *string, flags *pflag.FlagSet) { func bindZone(req request.Common, flags *pflag.FlagSet) { var zone string - flags.StringVar(&zone, "zone", base.ConfigIns.Zone, "Optional. Override default available zone, see 'ucloud region'") + flags.StringVar(&zone, "zone", base.ConfigIns.Zone, "Optional. Override default availability zone, see 'ucloud region'") flags.SetFlagValuesFunc("zone", func() []string { return getZoneList(req.GetRegion()) }) req.SetZoneRef(&zone) } +func bindZoneS(zone, region *string, flags *pflag.FlagSet) { + *zone = base.ConfigIns.Zone + flags.StringVar(zone, "zone", base.ConfigIns.Zone, "Optional. Override default availability zone, see 'ucloud region'") + flags.SetFlagValuesFunc("zone", func() []string { + return getZoneList(*region) + }) +} + func bindProjectID(req request.Common, flags *pflag.FlagSet) { var project string flags.StringVar(&project, "project-id", base.ConfigIns.ProjectID, "Optional. Override default project-id, see 'ucloud project list'") @@ -60,8 +68,23 @@ func bindLimit(req interface{}, flags *pflag.FlagSet) { } func bindOffset(req interface{}, flags *pflag.FlagSet) { - limit := flags.Int("offset", 0, "Optional. The index(a number) of resource which start to list") + offset := flags.Int("offset", 0, "Optional. The index(a number) of resource which start to list") v := reflect.ValueOf(req).Elem() - f := v.FieldByName("Limit") - f.Set(reflect.ValueOf(limit)) + f := v.FieldByName("Offset") + f.Set(reflect.ValueOf(offset)) +} + +func bindChargeType(req interface{}, flags *pflag.FlagSet) { + chargeType := flags.String("charge-type", "Month", "Optional. Enumeration value.'Year',pay yearly;'Month',pay monthly;'Dynamic', pay hourly(requires permission),'Trial', free trial(need permission)") + v := reflect.ValueOf(req).Elem() + f := v.FieldByName("ChargeType") + f.Set(reflect.ValueOf(chargeType)) + flags.SetFlagValues("charge-type", "Month", "Dynamic", "Year") +} + +func bindQuantity(req interface{}, flags *pflag.FlagSet) { + quanitiy := flags.Int("quantity", 1, "Optional. The duration of the instance. N years/months.") + v := reflect.ValueOf(req).Elem() + f := v.FieldByName("Quantity") + f.Set(reflect.ValueOf(quanitiy)) } diff --git a/cmd/vpc.go b/cmd/vpc.go index d2f4a6187b..9042f1bd8f 100644 --- a/cmd/vpc.go +++ b/cmd/vpc.go @@ -19,8 +19,8 @@ import ( func NewCmdVpc() *cobra.Command { cmd := &cobra.Command{ Use: "vpc", - Short: "List and manipulate vpc instances", - Long: "List and manipulate vpc instances", + Short: "List and manipulate VPC instances", + Long: "List and manipulate VPC instances", Args: cobra.NoArgs, } @@ -72,11 +72,7 @@ func NewCmdVPCList() *cobra.Command { row.CreationTime = base.FormatDate(vpc.CreateTime) list = append(list, row) } - if global.json { - base.PrintJSON(list) - } else { - base.PrintTableS(list) - } + base.PrintList(list) }, } flags := cmd.Flags() @@ -254,11 +250,7 @@ func NewCmdVpcListPeer() *cobra.Command { row.Group = VPCIntercom.Tag list = append(list, row) } - if global.json { - base.PrintJSON(list) - } else { - base.PrintTableS(list) - } + base.PrintList(list) }, } req.VPCId = cmd.Flags().String("vpc-id", "", "Required. The vpc id which you wnat to describe the information") @@ -391,11 +383,7 @@ func NewCmdSubnetList() *cobra.Command { row.CreationTime = base.FormatDate(sn.CreateTime) list = append(list, row) } - if global.json { - base.PrintJSON(list) - } else { - base.PrintTableS(list) - } + base.PrintList(list) }, } @@ -528,7 +516,7 @@ func NewCmdSubnetListResource(out io.Writer) *cobra.Command { } list = append(list, row) } - base.PrintList(list, global.json) + base.PrintList(list) }, } flags := cmd.Flags() diff --git a/model/status/status.go b/model/status/status.go index 8f48b862b5..f4516032a3 100644 --- a/model/status/status.go +++ b/model/status/status.go @@ -14,6 +14,15 @@ const DISK_AVAILABLE = "Available" const DISK_FAILED = "Failed" const DISK_RESTORING = "Restoring" +const UDB_INIT = "Init" +const UDB_FAIL = "Fail" +const UDB_RUNNING = "Running" +const UDB_SHUTOFF = "Shutoff" +const UDB_DELETE = "Delete" +const UDB_RECOVER_FAIL = "Recover fail" +const UDB_UPGRADE_FAIL = "UpgradeFail" +const UDB_TOBE_SWITCH = "WaitForSwitch" + const SNAPSHOT_NORMAL = "Normal" const EIP_FREE = "free"