From 8641e9232b1ad020440bf7647cd7b95b17ebadd3 Mon Sep 17 00:00:00 2001 From: lvyangyang Date: Mon, 28 Dec 2020 16:11:04 +0800 Subject: [PATCH] feat(region): add tags implement --- pkg/multicloud/google/instance.go | 47 ++++++++++++++ pkg/multicloud/google/shell/instance.go | 24 +++++++ pkg/multicloud/huawei/host.go | 8 +-- pkg/multicloud/huawei/instance.go | 83 ++++++++++++++++++++++++- pkg/multicloud/huawei/shell/instance.go | 32 ++++++++++ 5 files changed, 189 insertions(+), 5 deletions(-) diff --git a/pkg/multicloud/google/instance.go b/pkg/multicloud/google/instance.go index 16f5a539c4..73ae3932c7 100644 --- a/pkg/multicloud/google/instance.go +++ b/pkg/multicloud/google/instance.go @@ -104,6 +104,7 @@ type SInstance struct { ServiceAccounts []ServiceAccount Scheduling map[string]interface{} CpuPlatform string + Labels map[string]string LabelFingerprint string StartRestricted bool DeletionProtection bool @@ -665,6 +666,11 @@ func (region *SRegion) _createVM(zone string, desc *cloudprovider.SManagedVMCrea }, "disks": disks, } + + if len(desc.Tags) > 0 { + params["labels"] = desc.Tags + } + if tags, ok := secgroups[SECGROUP_TYPE_TAG]; ok && len(tags) > 0 { for i := range tags { tags[i] = strings.ToLower(tags[i]) @@ -906,3 +912,44 @@ func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudpro } return nil, errors.Wrapf(cloudprovider.ErrNotFound, "no valid system disk found") } + +func (self *SInstance) GetTags() (map[string]string, error) { + return self.Labels, nil +} + +func (self *SInstance) GetSysTags() map[string]string { + data := map[string]string{} + data["SecurityGroup"] = strings.Join(self.Tags.Items, ",") + return data +} + +func (region *SRegion) SetLabels(id string, labels map[string]string, labelFingerprint string) error { + params := map[string]interface{}{ + "labels": labels, + "labelFingerprint": labelFingerprint, + } + err := region.Do(id, "setLabels", nil, jsonutils.Marshal(params)) + if err != nil { + return errors.Wrapf(err, `region.Do(%s, "setLabels", nil, %s)`, id, jsonutils.Marshal(params).String()) + } + return nil +} + +func (self *SInstance) SetTags(tags map[string]string, replace bool) error { + if !replace { + for k, v := range self.Labels { + if _, ok := tags[k]; !ok { + tags[k] = v + } + } + } + err := self.Refresh() + if err != nil { + return errors.Wrap(err, "self.Refresh()") + } + err = self.host.zone.region.SetLabels(self.GetId(), tags, self.LabelFingerprint) + if err != nil { + return errors.Wrapf(err, ` self.host.zone.region.SsetLabels()`) + } + return nil +} diff --git a/pkg/multicloud/google/shell/instance.go b/pkg/multicloud/google/shell/instance.go index d44fc80b54..a1a0e4cbf6 100644 --- a/pkg/multicloud/google/shell/instance.go +++ b/pkg/multicloud/google/shell/instance.go @@ -16,6 +16,7 @@ package shell import ( "fmt" + "strings" "yunion.io/x/pkg/errors" @@ -203,4 +204,27 @@ func init() { return nil }) + type InstanceSetTagsOptions struct { + ID string `help:"Instance ID"` + Tags []string + } + shellutils.R(&InstanceSetTagsOptions{}, "instance-set-tags", "get intance metadata", func(cli *google.SRegion, args *InstanceSetTagsOptions) error { + tags := map[string]string{} + for i := range args.Tags { + splited := strings.Split(args.Tags[i], "=") + if len(splited) == 2 { + tags[splited[0]] = splited[1] + } + } + instance, err := cli.GetInstance(args.ID) + if err != nil { + return errors.Wrap(err, "cli.GetInstance") + } + err = cli.SetLabels(args.ID, tags, instance.LabelFingerprint) + if err != nil { + return err + } + return nil + }) + } diff --git a/pkg/multicloud/huawei/host.go b/pkg/multicloud/huawei/host.go index 065ea9479b..6cf4e8cde7 100644 --- a/pkg/multicloud/huawei/host.go +++ b/pkg/multicloud/huawei/host.go @@ -183,7 +183,7 @@ func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudpr desc.Description, desc.Account, desc.Password, desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, - desc.UserData, desc.BillingCycle, desc.ProjectId) + desc.UserData, desc.BillingCycle, desc.ProjectId, desc.Tags) if err != nil { return nil, err } @@ -203,7 +203,7 @@ func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, networkId string, ipAddr string, desc string, account string, passwd string, diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupId string, - userData string, bc *billing.SBillingCycle, projectId string) (string, error) { + userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (string, error) { net := self.zone.getNetworkById(networkId) if net == nil { return "", fmt.Errorf("invalid network ID %s", networkId) @@ -272,7 +272,7 @@ func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SD // 创建实例 if len(instanceType) > 0 { log.Debugf("Try instancetype : %s", instanceType) - vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId) + vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) if err != nil { log.Errorf("Failed for %s: %s", instanceType, err) return "", fmt.Errorf("create %s failed:%s", instanceType, ErrMessage(err)) @@ -294,7 +294,7 @@ func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SD for _, instType := range instanceTypes { instanceTypeId := instType.Name log.Debugf("Try instancetype : %s", instanceTypeId) - vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId) + vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) if err != nil { log.Errorf("Failed for %s: %s", instanceTypeId, err) } else { diff --git a/pkg/multicloud/huawei/instance.go b/pkg/multicloud/huawei/instance.go index 88cd8f0b05..836b46856e 100644 --- a/pkg/multicloud/huawei/instance.go +++ b/pkg/multicloud/huawei/instance.go @@ -291,6 +291,79 @@ func (self *SInstance) GetSysTags() map[string]string { return data } +func (self *SInstance) GetTags() (map[string]string, error) { + tags := map[string]string{} + for _, kv := range self.Tags { + splited := strings.Split(kv, "=") + if len(splited) == 2 { + tags[splited[0]] = splited[1] + } + } + return tags, nil +} + +// https://support.huaweicloud.com/api-ecs/ecs_02_1002.html +// key 相同时value不会替换 +func (self *SRegion) CreateServerTags(instanceId string, tags map[string]string) error { + params := map[string]interface{}{ + "action": "create", + } + + tagsObj := []map[string]string{} + for k, v := range tags { + tagsObj = append(tagsObj, map[string]string{"key": k, "value": v}) + } + params["tags"] = tagsObj + + _, err := self.ecsClient.Servers.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") + return err +} + +// https://support.huaweicloud.com/api-ecs/ecs_02_1003.html +func (self *SRegion) DeleteServerTags(instanceId string, tagsKey []string) error { + params := map[string]interface{}{ + "action": "delete", + } + tagsObj := []map[string]string{} + for _, k := range tagsKey { + tagsObj = append(tagsObj, map[string]string{"key": k}) + } + params["tags"] = tagsObj + + _, err := self.ecsClient.Servers.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") + return err +} + +func (self *SInstance) SetTags(tags map[string]string, replace bool) error { + existedTags, err := self.GetTags() + if err != nil { + return errors.Wrap(err, "self.GetTags()") + } + deleteTagsKey := []string{} + for k := range existedTags { + if replace { + deleteTagsKey = append(deleteTagsKey, k) + } else { + if _, ok := tags[k]; ok { + deleteTagsKey = append(deleteTagsKey, k) + } + } + } + if len(deleteTagsKey) > 0 { + err := self.host.zone.region.DeleteServerTags(self.GetId(), deleteTagsKey) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.DeleteServerTags(%s,%s)", self.GetId(), deleteTagsKey) + } + } + if len(tags) > 0 { + err := self.host.zone.region.CreateServerTags(self.GetId(), tags) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.CreateServerTags(%s,%s)", self.GetId(), jsonutils.Marshal(tags).String()) + } + } + return nil +} + func (self *SInstance) GetBillingType() string { // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html // charging_mode “0”:按需计费 “1”:按包年包月计费 @@ -824,7 +897,7 @@ type ServerTag struct { */ func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, SubnetId string, securityGroupId string, vpcId string, zoneId string, desc string, disks []SDisk, ipAddr string, - keypair string, publicKey string, passwd string, userData string, bc *billing.SBillingCycle, projectId string) (string, error) { + keypair string, publicKey string, passwd string, userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (string, error) { params := SServerCreate{} params.AvailabilityZone = zoneId params.Name = name @@ -885,6 +958,14 @@ func (self *SRegion) CreateInstance(name string, imageId string, instanceType st params.UserData = userData } + if len(tags) > 0 { + serverTags := []ServerTag{} + for k, v := range tags { + serverTags = append(serverTags, ServerTag{Key: k, Value: v}) + } + params.ServerTags = serverTags + } + serverObj := jsonutils.Marshal(params) createParams := jsonutils.NewDict() createParams.Add(serverObj, "server") diff --git a/pkg/multicloud/huawei/shell/instance.go b/pkg/multicloud/huawei/shell/instance.go index d6700e74a4..19cb24b199 100644 --- a/pkg/multicloud/huawei/shell/instance.go +++ b/pkg/multicloud/huawei/shell/instance.go @@ -17,6 +17,7 @@ package shell import ( "context" "fmt" + "strings" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/multicloud/huawei" @@ -190,4 +191,35 @@ func init() { return nil }) + type InstanceSetTagsOptions struct { + ID string `help:"Instance ID"` + Tags []string + } + shellutils.R(&InstanceSetTagsOptions{}, "instance-set-tags", "get intance metadata", func(cli *huawei.SRegion, args *InstanceSetTagsOptions) error { + tags := map[string]string{} + for i := range args.Tags { + splited := strings.Split(args.Tags[i], "=") + if len(splited) == 2 { + tags[splited[0]] = splited[1] + } + } + err := cli.CreateServerTags(args.ID, tags) + if err != nil { + return err + } + return nil + }) + + type InstanceDelTagsOptions struct { + ID string `help:"Instance ID"` + Tags []string + } + shellutils.R(&InstanceDelTagsOptions{}, "instance-del-tags", "del intance metadata", func(cli *huawei.SRegion, args *InstanceDelTagsOptions) error { + + err := cli.DeleteServerTags(args.ID, args.Tags) + if err != nil { + return err + } + return nil + }) }