diff --git a/Makefile b/Makefile index bfbaa58ce5..ef80c4ceff 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -export VERSION=0.1.11 +export VERSION=0.1.12 .PHONY : build build: diff --git a/base/client.go b/base/client.go index 09d22e76f1..17d4b5c522 100644 --- a/base/client.go +++ b/base/client.go @@ -3,6 +3,7 @@ package base import ( pudb "github.com/ucloud/ucloud-sdk-go/private/services/udb" puhost "github.com/ucloud/ucloud-sdk-go/private/services/uhost" + pumem "github.com/ucloud/ucloud-sdk-go/private/services/umem" "github.com/ucloud/ucloud-sdk-go/services/pathx" "github.com/ucloud/ucloud-sdk-go/services/uaccount" "github.com/ucloud/ucloud-sdk-go/services/udb" @@ -10,6 +11,7 @@ import ( "github.com/ucloud/ucloud-sdk-go/services/udpn" "github.com/ucloud/ucloud-sdk-go/services/uhost" "github.com/ucloud/ucloud-sdk-go/services/ulb" + "github.com/ucloud/ucloud-sdk-go/services/umem" "github.com/ucloud/ucloud-sdk-go/services/unet" "github.com/ucloud/ucloud-sdk-go/services/vpc" "github.com/ucloud/ucloud-sdk-go/ucloud" @@ -22,6 +24,9 @@ type PrivateUHostClient = puhost.UHostClient //PrivateUDBClient 私有模块的udb client 即未在官网开放的接口 type PrivateUDBClient = pudb.UDBClient +//PrivateUMemClient 私有模块的udb client 即未在官网开放的接口 +type PrivateUMemClient = pumem.UMemClient + //Client aggregate client for business type Client struct { uaccount.UAccountClient @@ -33,8 +38,10 @@ type Client struct { udisk.UDiskClient ulb.ULBClient udb.UDBClient + umem.UMemClient PrivateUHostClient PrivateUDBClient + PrivateUMemClient } // NewClient will return a aggregate client @@ -49,7 +56,9 @@ func NewClient(config *ucloud.Config, credential *auth.Credential) *Client { *udisk.NewClient(config, credential), *ulb.NewClient(config, credential), *udb.NewClient(config, credential), + *umem.NewClient(config, credential), *puhost.NewClient(config, credential), *pudb.NewClient(config, credential), + *pumem.NewClient(config, credential), } } diff --git a/base/config.go b/base/config.go index 6342879c43..5b85a59a1a 100644 --- a/base/config.go +++ b/base/config.go @@ -30,7 +30,7 @@ const DefaultBaseURL = "https://api.ucloud.cn/" const DefaultProfile = "default" //Version 版本号 -const Version = "0.1.11" +const Version = "0.1.12" //ConfigIns 配置实例, 程序加载时生成 var ConfigIns = &AggConfig{} diff --git a/cmd/root.go b/cmd/root.go index 223c45855c..c5e5fa178d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -73,6 +73,8 @@ func NewCmdRoot() *cobra.Command { cmd.AddCommand(NewCmdUDPN(out)) cmd.AddCommand(NewCmdULB()) cmd.AddCommand(NewCmdMysql()) + cmd.AddCommand(NewCmdRedis()) + cmd.AddCommand(NewCmdMemcache()) return cmd } diff --git a/cmd/umem.go b/cmd/umem.go new file mode 100644 index 0000000000..c0a6a62311 --- /dev/null +++ b/cmd/umem.go @@ -0,0 +1,454 @@ +// 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" + "strings" + + "github.com/spf13/cobra" + + sdk "github.com/ucloud/ucloud-sdk-go/ucloud" + + "github.com/ucloud/ucloud-cli/base" +) + +//NewCmdRedis ucloud redis +func NewCmdRedis() *cobra.Command { + cmd := &cobra.Command{ + Use: "redis", + Short: "List and manipulate redis instances", + Long: "List and manipulate redis instances", + } + out := base.Cxt.GetWriter() + cmd.AddCommand(NewCmdRedisList()) + cmd.AddCommand(NewCmdRedisCreate()) + cmd.AddCommand(NewCmdRedisDelete(out)) + return cmd +} + +//NewCmdMemcache ucloud memcache +func NewCmdMemcache() *cobra.Command { + cmd := &cobra.Command{ + Use: "memcache", + Short: "List and manipulate memcache instances", + Long: "List and manipulate memcache instances", + } + out := base.Cxt.GetWriter() + cmd.AddCommand(NewCmdMemcacheList()) + cmd.AddCommand(NewCmdMemcacheCreate(out)) + cmd.AddCommand(NewCmdMemcacheDelete(out)) + return cmd +} + +//UMemRedisRow 表格行 +type UMemRedisRow struct { + ResourceID string + Name string + Role string + Type string + Address string + Size string + UsedSize string + State string + Group string + Zone string + CreateTime string +} + +var redisTypeMap = map[string]string{ + "single": "master-replica", + "distributed": "distributed", +} + +//NewCmdRedisList ucloud redis list +func NewCmdRedisList() *cobra.Command { + req := base.BizClient.NewDescribeUMemRequest() + cmd := &cobra.Command{ + Use: "list", + Short: "List redis instances", + Long: "List redis instances", + Run: func(c *cobra.Command, args []string) { + resp, err := base.BizClient.DescribeUMem(req) + if err != nil { + base.HandleError(err) + return + } + list := []UMemRedisRow{} + for _, ins := range resp.DataSet { + row := UMemRedisRow{ + ResourceID: ins.ResourceId, + Name: ins.Name, + Role: ins.Role, + Type: redisTypeMap[ins.ResourceType], + Group: ins.Tag, + Size: fmt.Sprintf("%dGB", ins.Size), + UsedSize: fmt.Sprintf("%dMB", ins.UsedSize), + State: ins.State, + Zone: ins.Zone, + CreateTime: base.FormatDate(ins.CreateTime), + } + addrs := []string{} + for _, addr := range ins.Address { + addrs = append(addrs, fmt.Sprintf("%s:%d", addr.IP, addr.Port)) + } + row.Address = strings.Join(addrs, "|") + list = append(list, row) + for _, slave := range ins.DataSet { + srow := UMemRedisRow{ + ResourceID: slave.GroupId, + Name: slave.Name, + Role: fmt.Sprintf("\u2b91 %s", slave.Role), + Type: redisTypeMap[slave.ResourceType], + Group: slave.Tag, + Size: fmt.Sprintf("%dGB", slave.Size), + UsedSize: fmt.Sprintf("%dMB", slave.UsedSize), + State: slave.State, + Zone: slave.Zone, + Address: fmt.Sprintf("%s:%d", slave.VirtualIP, slave.Port), + CreateTime: base.FormatDate(slave.CreateTime), + } + list = append(list, srow) + } + } + base.PrintList(list) + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + req.ResourceId = flags.String("umem-id", "", "Optional. Resource ID of the redis to list") + bindRegion(req, flags) + bindZoneEmpty(req, flags) + bindProjectID(req, flags) + bindOffset(req, flags) + bindLimit(req, flags) + req.Protocol = sdk.String("redis") + + flags.SetFlagValuesFunc("umem-id", func() []string { + return getRedisIDList(*req.ProjectId, *req.Region) + }) + + return cmd +} + +//NewCmdRedisCreate ucloud redis create +func NewCmdRedisCreate() *cobra.Command { + req := base.BizClient.NewCreateURedisGroupRequest() + req.HighAvailability = sdk.String("enable") + var redisType, password string + cmd := &cobra.Command{ + Use: "create", + Short: "Create redis instance", + Long: "Create redis instance", + Run: func(c *cobra.Command, args []string) { + if redisType == "master-replica" { + resp, err := base.BizClient.CreateURedisGroup(req) + if err != nil { + base.HandleError(err) + return + } + fmt.Printf("redis[%s] created\n", resp.GroupId) + } else if redisType == "distributed" { + dreq := base.BizClient.NewCreateUMemSpaceRequest() + dreq.Region = req.Region + dreq.Zone = req.Zone + dreq.ProjectId = req.ProjectId + dreq.Name = req.Name + dreq.Size = req.Size + if *req.Size == 1 { + dreq.Size = sdk.Int(16) + } + dreq.ChargeType = req.ChargeType + dreq.Quantity = req.Quantity + dreq.Tag = req.Tag + dreq.Password = req.Password + resp, err := base.BizClient.CreateUMemSpace(dreq) + if err != nil { + base.HandleError(err) + return + } + fmt.Printf("redis[%s] created\n", resp.SpaceId) + } else { + fmt.Printf("unknow redis type[%s], it's should be 'master-replica' or 'distributed'\n", redisType) + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + req.Name = flags.String("name", "", "Required. Name of the redis to create") + flags.StringVar(&redisType, "type", "", "Required. Type of the redis. Accept values:'master-replica','distributed'") + req.Size = flags.Int("size-gb", 1, "Optional. Memory size. Default value 1GB(for master-replica redis type) or 16GB(for distributed redis type). Unit GB") + req.Version = flags.String("version", "3.2", "Optional. Version of redis") + req.VPCId = flags.String("vpc-id", "", "Optional. VPC ID. This field is required under VPC2.0. See 'ucloud vpc list'") + req.SubnetId = flags.String("subnet-id", "", "Optional. Subnet ID. This field is required under VPC2.0. See 'ucloud subnet list'") + flags.StringVar(&password, "password", "", "Optional. Password of redis to create") + + bindRegion(req, flags) + bindZone(req, flags) + bindProjectID(req, flags) + bindGroup(req, flags) + bindChargeType(req, flags) + bindQuantity(req, flags) + + flags.SetFlagValues("version", "3.0", "3.2", "4.0") + flags.SetFlagValues("type", "master-replica", "distributed") + 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) + }) + + cmd.MarkFlagRequired("name") + cmd.MarkFlagRequired("type") + + return cmd +} + +//NewCmdRedisDelete ucloud redis delete +func NewCmdRedisDelete(out io.Writer) *cobra.Command { + var idNames []string + req := base.BizClient.NewDeleteURedisGroupRequest() + cmd := &cobra.Command{ + Use: "delete", + Short: "Delete redis instances", + Long: "Delete redis instances", + Example: "ucloud redis delete --umem-id uredis-rl5xuxx/testcli1,uredis-xsdfa/testcli2", + Run: func(c *cobra.Command, args []string) { + for _, idname := range idNames { + id := base.PickResourceID(idname) + req.GroupId = &id + _, err := base.BizClient.DeleteURedisGroup(req) + if err != nil { + base.HandleError(err) + continue + } + fmt.Fprintf(out, "redis[%s] deleted\n", idname) + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringSliceVar(&idNames, "umem-id", nil, "Required. Resource ID of redis intances to delete") + bindProjectID(req, flags) + bindRegion(req, flags) + bindZone(req, flags) + + cmd.MarkFlagRequired("umem-id") + + flags.SetFlagValuesFunc("umem-id", func() []string { + return getRedisIDList(*req.ProjectId, *req.Region) + }) + + return cmd +} + +func getRedisIDList(project, region string) []string { + req := base.BizClient.NewDescribeURedisGroupRequest() + req.ProjectId = &project + req.Region = ®ion + list := []string{} + + for limit, offset := 50, 0; ; offset += limit { + req.Limit = sdk.Int(limit) + req.Offset = sdk.Int(offset) + resp, err := base.BizClient.DescribeURedisGroup(req) + if err != nil { + return nil + } + for _, ins := range resp.DataSet { + list = append(list, fmt.Sprintf("%s/%s", ins.GroupId, ins.Name)) + } + if offset+limit >= resp.TotalCount { + break + } + } + return list +} + +//UMemMemcacheRow 表格行 +type UMemMemcacheRow struct { + ResourceID string + Name string + Address string + Size string + UsedSize string + State string + Group string + CreateTime string +} + +//NewCmdMemcacheList ucloud memcache list +func NewCmdMemcacheList() *cobra.Command { + req := base.BizClient.NewDescribeUMemcacheGroupRequest() + cmd := &cobra.Command{ + Use: "list", + Short: "List memcache instances", + Long: "List memcache instances", + Run: func(c *cobra.Command, args []string) { + resp, err := base.BizClient.DescribeUMemcacheGroup(req) + if err != nil { + base.HandleError(err) + return + } + list := []UMemMemcacheRow{} + for _, ins := range resp.DataSet { + row := UMemMemcacheRow{ + ResourceID: ins.GroupId, + Name: ins.Name, + Group: ins.Tag, + Size: fmt.Sprintf("%dGB", ins.Size), + UsedSize: fmt.Sprintf("%dMB", ins.UsedSize), + State: ins.State, + CreateTime: base.FormatDate(ins.CreateTime), + Address: fmt.Sprintf("%s:%d", ins.VirtualIP, ins.Port), + } + list = append(list, row) + } + base.PrintList(list) + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + req.GroupId = flags.String("umem-id", "", "Optional. Resource ID of the redis to list") + bindRegion(req, flags) + bindZoneEmpty(req, flags) + bindProjectID(req, flags) + bindOffset(req, flags) + bindLimit(req, flags) + + return cmd +} + +//NewCmdMemcacheCreate ucloud memcache create +func NewCmdMemcacheCreate(out io.Writer) *cobra.Command { + req := base.BizClient.NewCreateUMemcacheGroupRequest() + cmd := &cobra.Command{ + Use: "create", + Short: "Create memcache instance", + Long: "Create memcache instance", + Run: func(c *cobra.Command, args []string) { + if *req.Size > 32 || *req.Size < 1 { + fmt.Fprintln(out, "size-gb should be between 1 and 32") + return + } + resp, err := base.BizClient.CreateUMemcacheGroup(req) + if err != nil { + base.HandleError(err) + return + } + fmt.Fprintf(out, "memcache[%s] created\n", resp.GroupId) + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + req.Name = flags.String("name", "", "Required. Name of memcache instance to create") + req.Size = flags.Int("size-gb", 1, "Optional. Memory size of memcache instance. Unit GB. Accpet values:1,2,4,8,16,32") + req.VPCId = flags.String("vpc-id", "", "Optional. VPC ID. See 'ucloud vpc list'") + req.SubnetId = flags.String("subnet-id", "", "Optional. Subnet ID. See 'ucloud subnet list'") + bindProjectID(req, flags) + bindRegion(req, flags) + bindZone(req, flags) + bindChargeType(req, flags) + bindQuantity(req, flags) + bindGroup(req, flags) + + flags.SetFlagValues("size-gb", "1", "2", "4", "8", "16", "32") + 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) + }) + + cmd.MarkFlagRequired("name") + + return cmd +} + +//NewCmdMemcacheDelete ucloud memcache delete +func NewCmdMemcacheDelete(out io.Writer) *cobra.Command { + var idNames []string + req := base.BizClient.NewDeleteUMemcacheGroupRequest() + cmd := &cobra.Command{ + Use: "delete", + Short: "Delete memcache instances", + Long: "Delete memcache instances", + Example: "ucloud memcache delete --umem-id umemcache-rl5xuxx/testcli1,umemcache-xsdfa/testcli2", + Run: func(c *cobra.Command, args []string) { + for _, idname := range idNames { + id := base.PickResourceID(idname) + req.GroupId = &id + _, err := base.BizClient.DeleteUMemcacheGroup(req) + if err != nil { + base.HandleError(err) + continue + } + fmt.Fprintf(out, "memcache[%s] deleted\n", idname) + } + }, + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringSliceVar(&idNames, "umem-id", nil, "Required. Resource ID of memcache intances to delete") + bindProjectID(req, flags) + bindRegion(req, flags) + bindZoneEmpty(req, flags) + + cmd.MarkFlagRequired("umem-id") + + flags.SetFlagValuesFunc("umem-id", func() []string { + return getMemcacheIDList(*req.ProjectId, *req.Region) + }) + + return cmd +} + +func getMemcacheIDList(project, region string) []string { + req := base.BizClient.NewDescribeUMemcacheGroupRequest() + req.ProjectId = &project + req.Region = ®ion + list := []string{} + + for limit, offset := 50, 0; ; offset += limit { + req.Limit = sdk.Int(limit) + req.Offset = sdk.Int(offset) + resp, err := base.BizClient.DescribeUMemcacheGroup(req) + if err != nil { + fmt.Println(err) + return nil + } + for _, ins := range resp.DataSet { + list = append(list, fmt.Sprintf("%s/%s", ins.GroupId, ins.Name)) + } + if offset+limit >= resp.TotalCount { + break + } + } + return list +} diff --git a/go.mod b/go.mod index 19afb22118..9f5ea2aa9b 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.12 require ( github.com/spf13/cobra v0.0.3 github.com/spf13/pflag v1.0.3 - github.com/ucloud/ucloud-sdk-go v0.7.3 + github.com/ucloud/ucloud-sdk-go v0.8.1-alpha ) replace ( diff --git a/go.sum b/go.sum index 4372bfcbda..290863d2ac 100644 --- a/go.sum +++ b/go.sum @@ -45,8 +45,8 @@ github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/ucloud/ucloud-sdk-go v0.7.3 h1:gGygQn+wcSJIiB6xRAmfwLP/MI3p5yt2mxD4ruPU+Lk= -github.com/ucloud/ucloud-sdk-go v0.7.3/go.mod h1:lM6fpI8y6iwACtlbHUav823/uKPdXsNBlnBpRF2fj3c= +github.com/ucloud/ucloud-sdk-go v0.8.1-alpha h1:nnrkUqp1BWBd2wS8zP+HgMbj52KJtuEcWeEcHLDXIps= +github.com/ucloud/ucloud-sdk-go v0.8.1-alpha/go.mod h1:lM6fpI8y6iwACtlbHUav823/uKPdXsNBlnBpRF2fj3c= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=