From fe7121d08946ff57e774f08ac6e75de326dc1954 Mon Sep 17 00:00:00 2001 From: ysicing Date: Fri, 4 Nov 2022 17:36:31 +0800 Subject: [PATCH] feat(arm): update arm update arm Signed-off-by: ysicing --- README.md | 4 +- cloud/qcloud/qcloud.go | 146 +++++++++++++++++++++++++++++++--------- cmd/arm.go | 27 ++++++++ cmd/root.go | 4 +- cmd/scan.go | 20 ------ config.example.arm.yaml | 13 ++++ go.mod | 1 - go.sum | 3 - version.txt | 2 +- 9 files changed, 159 insertions(+), 61 deletions(-) create mode 100644 cmd/arm.go delete mode 100644 cmd/scan.go create mode 100644 config.example.arm.yaml diff --git a/README.md b/README.md index 1390a5f..0fabaeb 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,12 @@ ## 功能 -- [x] 开通Linux/Windows机器 +- [x] 开通Linux/Windows竞价机器 - [x] 重启机器 - [x] 销毁机器 - [x] 列出镜像列表 - [x] 选择镜像启动虚拟机 -- [ ] 专业版漏洞扫描 +- [x] 开通LinuxArm架构按量机器(限定广州地域) ## 安装 diff --git a/cloud/qcloud/qcloud.go b/cloud/qcloud/qcloud.go index fe90740..ceb7231 100644 --- a/cloud/qcloud/qcloud.go +++ b/cloud/qcloud/qcloud.go @@ -15,12 +15,10 @@ import ( "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312" - cwp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cwp/v20180228" ) type Client struct { - cvmCliet *cvm.Client - cwpClient *cwp.Client + cvmCliet *cvm.Client } type Instance struct { @@ -44,7 +42,7 @@ type Image struct { OsName string } -func NewClient() *Client { +func NewClient(regions ...string) *Client { // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密 // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取 credential := common.NewCredential( @@ -52,15 +50,15 @@ func NewClient() *Client { viper.GetString("qcloud.account.secret"), ) logrus.Debugf("credential: %s, %s", credential.SecretId, credential.SecretKey) + region := viper.GetString("qcloud.region") + if len(regions) > 0 { + region = regions[0] + } // 实例化一个client选项,可选的,没有特殊需求可以跳过 cvmcpf := profile.NewClientProfile() cvmcpf.HttpProfile.Endpoint = "cvm.tencentcloudapi.com" - // 实例化要请求产品的client对象,clientProfile是可选的 - cvmClient, _ := cvm.NewClient(credential, viper.GetString("qcloud.region"), cvmcpf) - cwpcpf := profile.NewClientProfile() - cwpcpf.HttpProfile.Endpoint = "cwp.tencentcloudapi.com" - cwpClient, _ := cwp.NewClient(credential, viper.GetString("qcloud.region"), cwpcpf) - return &Client{cvmCliet: cvmClient, cwpClient: cwpClient} + cvmClient, _ := cvm.NewClient(credential, region, cvmcpf) + return &Client{cvmCliet: cvmClient} } func (c *Client) Create(count int64, netaccess, windows bool, image string) error { @@ -154,6 +152,112 @@ func (c *Client) Create(count int64, netaccess, windows bool, image string) erro return nil } +func (c *Client) CreateArm(count, exp int64, netaccess bool, image string) error { + + // 实例化一个请求对象,每个接口都会对应一个request对象 + request := cvm.NewRunInstancesRequest() + // arm 只支持按量 + request.InstanceChargeType = common.StringPtr("POSTPAID_BY_HOUR") + qzone := viper.GetString("qcloud.zone") + if !strings.HasPrefix(qzone, "ap-guangzhou-") { + qzone = "ap-guangzhou-6" + } + request.Placement = &cvm.Placement{ + Zone: common.StringPtr(qzone), + } + if viper.GetInt64("qcloud.project.id") > 0 { + request.Placement.ProjectId = common.Int64Ptr(viper.GetInt64("qcloud.project.id")) + } + intype := viper.GetString("qcloud.instance.type") + if !strings.HasPrefix(intype, "SR") { + intype = "SR1.MEDIUM2" + } + request.InstanceType = common.StringPtr(intype) + disk := viper.GetInt64("qcloud.instance.disk") + if disk == 0 { + disk = 50 + } + request.SystemDisk = &cvm.SystemDisk{ + DiskType: common.StringPtr("CLOUD_PREMIUM"), + DiskSize: common.Int64Ptr(disk), + } + vpcid := viper.GetString("qcloud.instance.network.vpc.id") + vpcsub := viper.GetString("qcloud.instance.network.subnet.id") + if len(vpcid) > 4 && len(vpcsub) > 7 { + request.VirtualPrivateCloud = &cvm.VirtualPrivateCloud{ + VpcId: common.StringPtr(vpcid), + SubnetId: common.StringPtr(vpcsub), + AsVpcGateway: common.BoolPtr(false), + Ipv6AddressCount: common.Uint64Ptr(0), + } + } + if count == 1 && netaccess { + request.InternetAccessible = &cvm.InternetAccessible{ + InternetChargeType: common.StringPtr("TRAFFIC_POSTPAID_BY_HOUR"), + InternetMaxBandwidthOut: common.Int64Ptr(100), + PublicIpAssigned: common.BoolPtr(true), + } + } else { + request.InternetAccessible = &cvm.InternetAccessible{ + InternetMaxBandwidthOut: common.Int64Ptr(0), + PublicIpAssigned: common.BoolPtr(false), + } + } + request.InstanceCount = common.Int64Ptr(int64(count)) + defaultImage := viper.GetString("qcloud.instance.image") + if len(image) == 0 { + image = defaultImage + } + namePrefix := "spot-arm" + request.LoginSettings = &cvm.LoginSettings{ + KeyIds: common.StringPtrs(viper.GetStringSlice("qcloud.instance.auth.sshkey.ids")), + } + request.ImageId = common.StringPtr(image) + request.InstanceName = common.StringPtr(fmt.Sprintf("%s-%s", namePrefix, time.Now().Format("20060102150405"))) + request.SecurityGroupIds = common.StringPtrs(viper.GetStringSlice("qcloud.instance.securitygroup.ids")) + request.EnhancedService = &cvm.EnhancedService{ + SecurityService: &cvm.RunSecurityServiceEnabled{ + Enabled: common.BoolPtr(true), + }, + MonitorService: &cvm.RunMonitorServiceEnabled{ + Enabled: common.BoolPtr(true), + }, + AutomationService: &cvm.RunAutomationServiceEnabled{ + Enabled: common.BoolPtr(true), + }, + } + request.InstanceMarketOptions = &cvm.InstanceMarketOptionsRequest{ + SpotOptions: &cvm.SpotMarketOptions{ + MaxPrice: common.StringPtr("1000"), + }, + } + request.DisableApiTermination = common.BoolPtr(false) + if exp >= 12 { + exp = 12 + } + if exp <= 1 { + exp = 1 + } + request.ActionTimer = &cvm.ActionTimer{ + TimerAction: common.StringPtr("TerminateInstances"), + ActionTime: common.StringPtr(time.Now().Add(time.Hour * time.Duration(exp)).Format("2006-01-02 15:04:05")), + Externals: &cvm.Externals{ + ReleaseAddress: common.BoolPtr(true), + }, + } + + // 返回的resp是一个RunInstancesResponse的实例,与请求对象对应 + response, err := c.cvmCliet.RunInstances(request) + if _, ok := err.(*errors.TencentCloudSDKError); ok { + return fmt.Errorf("tencent api error has returned: %v", err) + } + if err != nil { + return err + } + logrus.Debugf("%s", response.ToJsonString()) + return nil +} + func (c *Client) List() ([]Instance, error) { // 实例化一个请求对象,每个接口都会对应一个request对象 request := cvm.NewDescribeInstancesRequest() @@ -251,28 +355,6 @@ func (c *Client) Restart(id string) error { return nil } -func (c *Client) Scan(id string) error { - request := cwp.NewScanVulRequest() - request.VulLevels = common.StringPtr("1;2;3;4") - request.HostType = common.Uint64Ptr(2) - request.VulCategories = common.StringPtr("1;2;4") - request.QuuidList = common.StringPtrs([]string{id}) - request.TimeoutPeriod = common.Uint64Ptr(3600) - response, err := c.cwpClient.ScanVul(request) - if terr, ok := err.(*errors.TencentCloudSDKError); ok { - if terr.Code == "OperationDenied" { - logrus.Warnf("%s %s", id, terr.Message) - return nil - } - return fmt.Errorf("tencent api error has returned: %v", err) - } - if err != nil { - return err - } - logrus.Infof("Scan %s task create %d", id, response.Response.TaskId) - return nil -} - func (c *Client) ImageList(notPublic bool) ([]Image, error) { request := cvm.NewDescribeImagesRequest() request.Offset = common.Uint64Ptr(0) diff --git a/cmd/arm.go b/cmd/arm.go new file mode 100644 index 0000000..b2de27f --- /dev/null +++ b/cmd/arm.go @@ -0,0 +1,27 @@ +package cmd + +import ( + "github.com/ysicing/spot/cloud/qcloud" + + "github.com/spf13/cobra" +) + +func cmdNewArm() *cobra.Command { + var count, exp int64 + var netaccess bool + var image string + c := &cobra.Command{ + Use: "arm", + Short: "新建腾讯云ARM虚拟机", + Version: "0.1.0", + RunE: func(c *cobra.Command, args []string) error { + client := qcloud.NewClient("ap-guangzhou") + return client.CreateArm(count, exp, netaccess, image) + }, + } + c.Flags().Int64VarP(&count, "count", "c", 1, "虚拟机数量") + c.Flags().BoolVar(&netaccess, "net", true, "是否开启公网访问, 单节点生效") + c.Flags().StringVarP(&image, "image", "i", "", "指定linux arm镜像") + c.Flags().Int64VarP(&exp, "exp", "e", 2, "销毁时间(区间1-12小时)") + return c +} diff --git a/cmd/root.go b/cmd/root.go index 776e983..e1080ed 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -35,7 +35,7 @@ func BuildRoot() *cobra.Command { rootCmd.AddCommand(cmdList()) rootCmd.AddCommand(cmdDestroy()) rootCmd.AddCommand(cmdRestart()) - rootCmd.AddCommand(cmdScan()) + rootCmd.AddCommand(cmdNewArm()) rootCmd.AddCommand(cmdImage()) return rootCmd } @@ -47,7 +47,7 @@ func NewRootCmd() *cobra.Command { SilenceUsage: true, SilenceErrors: true, Short: "腾讯云虚拟机管理工具", - Version: "0.0.5", + Version: "0.1.0", PersistentPreRunE: func(cobraCmd *cobra.Command, args []string) error { if globalFlags.Debug { logrus.SetLevel(logrus.DebugLevel) diff --git a/cmd/scan.go b/cmd/scan.go deleted file mode 100644 index 3062be6..0000000 --- a/cmd/scan.go +++ /dev/null @@ -1,20 +0,0 @@ -package cmd - -import ( - "github.com/spf13/cobra" - "github.com/ysicing/spot/cloud/qcloud" -) - -func cmdScan() *cobra.Command { - var uuid string - scan := &cobra.Command{ - Use: "scan", - Short: "扫描虚拟机镜像漏洞", - RunE: func(c *cobra.Command, args []string) error { - client := qcloud.NewClient() - return client.Scan(uuid) - }, - } - scan.Flags().StringVarP(&uuid, "uuid", "i", "", "主机安全UUID") - return scan -} diff --git a/config.example.arm.yaml b/config.example.arm.yaml new file mode 100644 index 0000000..ee63a3c --- /dev/null +++ b/config.example.arm.yaml @@ -0,0 +1,13 @@ +qcloud: + account: + id: + secret: + instance: + image: img-kh0snalc + type: SR1.MEDIUM2 + auth: + sshkey: + ids: + - sshkey-id + securitygroup: + id: sg-id diff --git a/go.mod b/go.mod index 36272ac..b7d9801 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/spf13/viper v1.13.0 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.527 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.0.527 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cwp v1.0.515 ) require ( diff --git a/go.sum b/go.sum index 399abc4..f0d222f 100644 --- a/go.sum +++ b/go.sum @@ -376,13 +376,10 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.515/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.527 h1:hpZMjoYnR+ma5HMWWNaNc5fshpFXXaUPrZMo4OXPxYQ= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.527/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.0.527 h1:I+jCU9S0o6EMRZ4121/Rj7llkX2Fsy1ksmSCf3y6r1M= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm v1.0.527/go.mod h1:mqG8ES2o28GJam1eGuudqzj2cduhDFXeTEB4jO0H64I= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cwp v1.0.515 h1:42n+Eh5o2Rwf4VNqAyUvU89D6RHLVmMu/DdLGV6Rvro= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cwp v1.0.515/go.mod h1:sYPKkNBw8FpgP8+AnEbqh9K3bSDxZJhKqK8BxxXz4AM= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= diff --git a/version.txt b/version.txt index bbdeab6..6e8bf73 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.0.5 +0.1.0