From 0ed55319157a5f8bb130cb64c8754763efc41182 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Sun, 30 Jun 2019 00:13:13 +0800 Subject: [PATCH 1/2] feature: 1. esxi vm add resource pool metadata 2. esxicli support network-list 3. add cloud-provider-clirc command to generate rc for each cloud-cli --- cmd/azurecli/main.go | 8 +- cmd/climc/shell/cloudproviders.go | 21 ++++ cmd/huaweicli/main.go | 11 +- cmd/qcloudcli/main.go | 11 +- cmd/ucloudcli/main.go | 13 +-- pkg/cloudprovider/cloudprovider.go | 18 ++- pkg/compute/models/cloudproviders.go | 21 ++++ pkg/util/aliyun/aliyun.go | 8 +- pkg/util/aliyun/provider/provider.go | 8 ++ pkg/util/aws/aws.go | 15 ++- pkg/util/aws/provider/provider.go | 9 ++ pkg/util/azure/azure.go | 63 +++++------ pkg/util/azure/provider/provider.go | 31 ++++- pkg/util/esxi/datacenter.go | 50 ++++++-- pkg/util/esxi/manager.go | 4 +- pkg/util/esxi/network.go | 144 ++++++++++++++++++++++++ pkg/util/esxi/provider/provider.go | 18 +++ pkg/util/esxi/resourcepool.go | 27 +++++ pkg/util/esxi/shell/network.go | 38 +++++++ pkg/util/esxi/virtualmachine.go | 33 +++++- pkg/util/huawei/huawei.go | 16 +-- pkg/util/huawei/provider/provider.go | 28 ++++- pkg/util/openstack/provider/provider.go | 22 ++++ pkg/util/pinyinutils/doc.go | 15 +++ pkg/util/qcloud/provider/provider.go | 23 +++- pkg/util/qcloud/qcloud.go | 13 ++- pkg/util/ucloud/provider/provider.go | 27 ++++- pkg/util/ucloud/ucloud.go | 16 +-- pkg/util/zstack/provider/provider.go | 9 ++ 29 files changed, 598 insertions(+), 122 deletions(-) create mode 100644 pkg/util/esxi/network.go create mode 100644 pkg/util/esxi/resourcepool.go create mode 100644 pkg/util/esxi/shell/network.go create mode 100644 pkg/util/pinyinutils/doc.go diff --git a/cmd/azurecli/main.go b/cmd/azurecli/main.go index 3455612071..494d9275d3 100644 --- a/cmd/azurecli/main.go +++ b/cmd/azurecli/main.go @@ -100,9 +100,11 @@ func newClient(options *BaseOptions) (*azure.SRegion, error) { return nil, fmt.Errorf("Missing Cloud Environment") } - account := fmt.Sprintf("%s/%s", options.DirectoryID, options.SubscriptionID) - secret := fmt.Sprintf("%s/%s", options.ApplicationID, options.ApplicationKey) - cli, err := azure.NewAzureClient("", "", account, secret, options.CloudEnv, options.Debug) + cli, err := azure.NewAzureClient("", "", options.CloudEnv, + options.DirectoryID, + options.ApplicationID, options.ApplicationKey, + options.SubscriptionID, + options.Debug) if err != nil { return nil, err } diff --git a/cmd/climc/shell/cloudproviders.go b/cmd/climc/shell/cloudproviders.go index 8247be1ff5..3f9136f6a9 100644 --- a/cmd/climc/shell/cloudproviders.go +++ b/cmd/climc/shell/cloudproviders.go @@ -15,6 +15,8 @@ package shell import ( + "fmt" + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" @@ -187,4 +189,23 @@ func init() { printObject(result) return nil }) + + type CloudproviderClientRCOptions struct { + ID string `help:"ID or name of cloud provider"` + } + R(&CloudproviderClientRCOptions{}, "cloud-provider-clirc", "Get client RC file of the cloud provider", func(s *mcclient.ClientSession, args *CloudproviderClientRCOptions) error { + result, err := modules.Cloudproviders.GetSpecific(s, args.ID, "clirc", nil) + if err != nil { + return err + } + rc := make(map[string]string) + err = result.Unmarshal(&rc) + if err != nil { + return err + } + for k, v := range rc { + fmt.Printf("export %s='%s'\n", k, v) + } + return nil + }) } diff --git a/cmd/huaweicli/main.go b/cmd/huaweicli/main.go index 0b35f73474..32b0b5cb47 100644 --- a/cmd/huaweicli/main.go +++ b/cmd/huaweicli/main.go @@ -86,14 +86,9 @@ func newClient(options *BaseOptions) (*huawei.SRegion, error) { return nil, fmt.Errorf("Missing secret") } - account := "" - if len(options.ProjectId) > 0 { - account = options.AccessKey + "/" + options.ProjectId - } else { - account = options.AccessKey - } - - cli, err := huawei.NewHuaweiClient("", "", options.CloudEnv, account, options.Secret, options.Debug) + cli, err := huawei.NewHuaweiClient("", "", options.CloudEnv, + options.AccessKey, options.Secret, options.ProjectId, + options.Debug) if err != nil { return nil, err } diff --git a/cmd/qcloudcli/main.go b/cmd/qcloudcli/main.go index ceca014f48..662dbef23d 100644 --- a/cmd/qcloudcli/main.go +++ b/cmd/qcloudcli/main.go @@ -85,12 +85,11 @@ func newClient(options *BaseOptions) (*qcloud.SRegion, error) { return nil, fmt.Errorf("Missing SecretID") } - account := options.SecretID - if len(options.AppID) > 0 { - account = fmt.Sprintf("%s/%s", account, options.AppID) - } - - if cli, err := qcloud.NewQcloudClient("", "", account, options.SecretKey, options.Debug); err != nil { + if cli, err := qcloud.NewQcloudClient("", "", + options.SecretID, + options.SecretKey, + options.AppID, + options.Debug); err != nil { return nil, err } else if region := cli.GetRegion(options.RegionId); region == nil { return nil, fmt.Errorf("No such region %s", options.RegionId) diff --git a/cmd/ucloudcli/main.go b/cmd/ucloudcli/main.go index 51afbc9fec..c612d94f57 100644 --- a/cmd/ucloudcli/main.go +++ b/cmd/ucloudcli/main.go @@ -86,14 +86,11 @@ func newClient(options *BaseOptions) (*ucloud.SRegion, error) { return nil, fmt.Errorf("Missing secret") } - account := "" - if len(options.ProjectId) > 0 { - account = options.AccessKey + "::" + options.ProjectId - } else { - account = options.AccessKey - } - - cli, err := ucloud.NewUcloudClient("", "", account, options.Secret, options.Debug) + cli, err := ucloud.NewUcloudClient("", "", + options.AccessKey, + options.Secret, + options.ProjectId, + options.Debug) if err != nil { return nil, err } diff --git a/pkg/cloudprovider/cloudprovider.go b/pkg/cloudprovider/cloudprovider.go index ef5d4b57c9..2fbc96802f 100644 --- a/pkg/cloudprovider/cloudprovider.go +++ b/pkg/cloudprovider/cloudprovider.go @@ -16,18 +16,18 @@ package cloudprovider import ( "context" - "errors" "fmt" "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) -var ( - ErrNoSuchProvder = errors.New("no such provider") +const ( + ErrNoSuchProvder = errors.Error("no such provider") ) type SCloudaccount struct { @@ -38,6 +38,8 @@ type SCloudaccount struct { type ICloudProviderFactory interface { GetProvider(providerId, providerName, url, account, secret string) (ICloudProvider, error) + GetClientRC(url, account, secret string) (map[string]string, error) + GetId() string GetName() string @@ -103,11 +105,19 @@ func GetRegistedProviderIds() []string { func GetProvider(providerId, providerName, accessUrl, account, secret, provider string) (ICloudProvider, error) { driver, err := GetProviderFactory(provider) if err != nil { - return nil, err + return nil, errors.Wrap(err, "GetProviderFactory") } return driver.GetProvider(providerId, providerName, accessUrl, account, secret) } +func GetClientRC(accessUrl, account, secret, provider string) (map[string]string, error) { + driver, err := GetProviderFactory(provider) + if err != nil { + return nil, errors.Wrap(err, "GetProviderFactory") + } + return driver.GetClientRC(accessUrl, account, secret) +} + func IsSupported(provider string) bool { _, ok := providerTable[provider] return ok diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index e97c2a2454..95d871cbab 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -1222,3 +1222,24 @@ func (manager *SCloudproviderManager) initAllRecords() { }) } } + +func (provider *SCloudprovider) AllowGetDetailsClirc(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return db.IsAdminAllowGetSpec(userCred, provider, "client-rc") +} + +func (provider *SCloudprovider) GetDetailsClirc(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { + accessUrl := provider.getAccessUrl() + passwd, err := provider.getPassword() + if err != nil { + return nil, err + } + rc, err := cloudprovider.GetClientRC(accessUrl, provider.Account, passwd, provider.Provider) + if err != nil { + return nil, err + } + return jsonutils.Marshal(rc), nil +} + +func (manager *SCloudproviderManager) ResourceScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} diff --git a/pkg/util/aliyun/aliyun.go b/pkg/util/aliyun/aliyun.go index ec8ee50cd3..edb84a7a20 100644 --- a/pkg/util/aliyun/aliyun.go +++ b/pkg/util/aliyun/aliyun.go @@ -56,7 +56,13 @@ type SAliyunClient struct { } func NewAliyunClient(providerId string, providerName string, accessKey string, secret string, isDebug bool) (*SAliyunClient, error) { - client := SAliyunClient{providerId: providerId, providerName: providerName, accessKey: accessKey, secret: secret, Debug: isDebug} + client := SAliyunClient{ + providerId: providerId, + providerName: providerName, + accessKey: accessKey, + secret: secret, + Debug: isDebug, + } err := client.fetchRegions() if err != nil { return nil, err diff --git a/pkg/util/aliyun/provider/provider.go b/pkg/util/aliyun/provider/provider.go index 1e27e0354b..0d25cee57b 100644 --- a/pkg/util/aliyun/provider/provider.go +++ b/pkg/util/aliyun/provider/provider.go @@ -80,6 +80,14 @@ func (self *SAliyunProviderFactory) GetProvider(providerId, providerName, url, a }, nil } +func (self *SAliyunProviderFactory) GetClientRC(url, account, secret string) (map[string]string, error) { + return map[string]string{ + "ALIYUN_ACCESS_KEY": account, + "ALIYUN_SECRET": secret, + "ALIYUN_REGION": aliyun.ALIYUN_DEFAULT_REGION, + }, nil +} + func init() { factory := SAliyunProviderFactory{} cloudprovider.RegisterFactory(&factory) diff --git a/pkg/util/aws/aws.go b/pkg/util/aws/aws.go index bc0a07bc44..2579114066 100644 --- a/pkg/util/aws/aws.go +++ b/pkg/util/aws/aws.go @@ -30,6 +30,9 @@ const ( CLOUD_PROVIDER_AWS = api.CLOUD_PROVIDER_AWS CLOUD_PROVIDER_AWS_CN = "AWS" + AWS_INTERNATIONAL_CLOUDENV = "InternationalCloud" + AWS_CHINA_CLOUDENV = "ChinaCloud" + AWS_INTERNATIONAL_DEFAULT_REGION = "us-west-1" AWS_CHINA_DEFAULT_REGION = "cn-north-1" AWS_API_VERSION = "2018-10-10" @@ -54,18 +57,22 @@ func NewAwsClient(providerId string, providerName string, accessUrl string, acce return &client, nil } -func (self *SAwsClient) getDefaultRegionId() string { +func GetDefaultRegionId(accessUrl string) string { defaultRegion := AWS_INTERNATIONAL_DEFAULT_REGION - switch self.accessUrl { - case "InternationalCloud": + switch accessUrl { + case AWS_INTERNATIONAL_CLOUDENV: defaultRegion = AWS_INTERNATIONAL_DEFAULT_REGION - case "ChinaCloud": + case AWS_CHINA_CLOUDENV: defaultRegion = AWS_CHINA_DEFAULT_REGION } return defaultRegion } +func (self *SAwsClient) getDefaultRegionId() string { + return GetDefaultRegionId(self.accessUrl) +} + func (self *SAwsClient) getDefaultSession() (*session.Session, error) { defaultRegion := self.getDefaultRegionId() return session.NewSession(&sdk.Config{ diff --git a/pkg/util/aws/provider/provider.go b/pkg/util/aws/provider/provider.go index 51c3163b34..f4a262c9ca 100644 --- a/pkg/util/aws/provider/provider.go +++ b/pkg/util/aws/provider/provider.go @@ -88,6 +88,15 @@ func (self *SAwsProviderFactory) GetProvider(providerId, providerName, url, acco }, nil } +func (self *SAwsProviderFactory) GetClientRC(url, account, secret string) (map[string]string, error) { + return map[string]string{ + "AWS_ACCESS_URL": url, + "AWS_ACCESS_KEY": account, + "AWS_SECRET": secret, + "AWS_REGION": aws.GetDefaultRegionId(url), + }, nil +} + func init() { factory := SAwsProviderFactory{} cloudprovider.RegisterFactory(&factory) diff --git a/pkg/util/azure/azure.go b/pkg/util/azure/azure.go index 819e406040..f7561adfe5 100644 --- a/pkg/util/azure/azure.go +++ b/pkg/util/azure/azure.go @@ -31,7 +31,7 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" + // "yunion.io/x/onecloud/pkg/httperrors" ) const ( @@ -42,16 +42,16 @@ const ( ) type SAzureClient struct { - client autorest.Client - providerId string - providerName string - subscriptionId string - tenantId string - clientId string - clientScret string - domain string - baseUrl string - secret string + client autorest.Client + providerId string + providerName string + subscriptionId string + tenantId string + clientId string + clientScret string + domain string + baseUrl string + // secret string envName string ressourceGroups []SResourceGroup fetchResourceGroups bool @@ -87,29 +87,22 @@ var DEFAULT_API_VERSION = map[string]string{ "Microsoft.Compute/locations": "2018-06-01", } -func NewAzureClient(providerId string, providerName string, accessKey string, secret string, envName string, debug bool) (*SAzureClient, error) { - clientInfo := strings.Split(secret, "/") - accountInfo := strings.Split(accessKey, "/") - if len(clientInfo) >= 2 && len(accountInfo) >= 1 { - client := SAzureClient{ - providerId: providerId, - providerName: providerName, - secret: secret, - envName: envName, - debug: debug, - } - client.clientId, client.clientScret = clientInfo[0], strings.Join(clientInfo[1:], "/") - client.tenantId = accountInfo[0] - if len(accountInfo) == 2 { - client.subscriptionId = accountInfo[1] - } - err := client.fetchRegions() - if err != nil { - return nil, err - } - return &client, nil +func NewAzureClient(providerId string, providerName string, envName, tenantId, clientId, clientSecret, subscriptionId string, debug bool) (*SAzureClient, error) { + client := SAzureClient{ + providerId: providerId, + providerName: providerName, + envName: envName, + tenantId: tenantId, + clientId: clientId, + clientScret: clientSecret, + subscriptionId: subscriptionId, + debug: debug, } - return nil, httperrors.NewUnauthorizedError("clientId、clientScret or subscriptId input error") + err := client.fetchRegions() + if err != nil { + return nil, err + } + return &client, nil } func (self *SAzureClient) getDefaultClient() (*autorest.Client, error) { @@ -678,7 +671,7 @@ func _jsonRequest(client *autorest.Client, method, domain, baseURL, body string) return jsonutils.Parse([]byte(_data)) } -func (self *SAzureClient) UpdateAccount(tenantId, secret, envName string) error { +/*func (self *SAzureClient) UpdateAccount(envName, tenantId, appId, appKey, subscriptionId string) error { if self.tenantId != tenantId || self.secret != secret || self.envName != envName { if clientInfo, accountInfo := strings.Split(secret, "/"), strings.Split(tenantId, "/"); len(clientInfo) >= 2 && len(accountInfo) >= 1 { self.clientId, self.clientScret = clientInfo[0], strings.Join(clientInfo[1:], "/") @@ -696,7 +689,7 @@ func (self *SAzureClient) UpdateAccount(tenantId, secret, envName string) error } } return nil -} +}*/ func (self *SAzureClient) fetchRegions() error { if len(self.subscriptionId) > 0 { diff --git a/pkg/util/azure/provider/provider.go b/pkg/util/azure/provider/provider.go index 5e263bacc7..76dfc02555 100644 --- a/pkg/util/azure/provider/provider.go +++ b/pkg/util/azure/provider/provider.go @@ -17,6 +17,7 @@ package provider import ( "context" "fmt" + "strings" "yunion.io/x/jsonutils" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/azure" - // "yunion.io/x/log" ) type SAzureProviderFactory struct { @@ -87,8 +87,23 @@ func (self *SAzureProviderFactory) ValidateUpdateCloudaccountCredential(ctx cont return account, nil } +func parseAccount(account, secret string) (tenantId string, appId string, appKey string, subId string) { + clientInfo := strings.Split(secret, "/") + accountInfo := strings.Split(account, "/") + tenantId = accountInfo[0] + if len(accountInfo) > 1 { + subId = strings.Join(accountInfo[1:], "/") + } + appId = clientInfo[0] + if len(clientInfo) > 1 { + appKey = strings.Join(clientInfo[1:], "/") + } + return +} + func (self *SAzureProviderFactory) GetProvider(providerId, providerName, url, account, secret string) (cloudprovider.ICloudProvider, error) { - if client, err := azure.NewAzureClient(providerId, providerName, account, secret, url, false); err != nil { + tenantId, appId, appKey, subId := parseAccount(account, secret) + if client, err := azure.NewAzureClient(providerId, providerName, url, tenantId, appId, appKey, subId, false); err != nil { return nil, err } else { return &SAzureProvider{ @@ -98,6 +113,18 @@ func (self *SAzureProviderFactory) GetProvider(providerId, providerName, url, ac } } +func (self *SAzureProviderFactory) GetClientRC(url, account, secret string) (map[string]string, error) { + tenantId, appId, appKey, subId := parseAccount(account, secret) + return map[string]string{ + "AZURE_DIRECTORY_ID": tenantId, + "AZURE_SUBSCRIPTION_ID": subId, + "AZURE_APPLICATION_ID": appId, + "AZURE_APPLICATION_KEY": appKey, + "AZURE_REGION_ID": "", + "AZURE_CLOUD_ENV": url, + }, nil +} + func init() { factory := SAzureProviderFactory{} cloudprovider.RegisterFactory(&factory) diff --git a/pkg/util/esxi/datacenter.go b/pkg/util/esxi/datacenter.go index 09f44c2abf..fb8ce5e795 100644 --- a/pkg/util/esxi/datacenter.go +++ b/pkg/util/esxi/datacenter.go @@ -21,7 +21,6 @@ import ( "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" - "yunion.io/x/log" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" @@ -35,6 +34,7 @@ type SDatacenter struct { ihosts []cloudprovider.ICloudHost istorages []cloudprovider.ICloudStorage + inetworks []IVMNetwork Name string } @@ -58,7 +58,7 @@ func (dc *SDatacenter) scanHosts() error { var hosts []mo.HostSystem err := dc.manager.scanMObjects(dc.object.Entity().Self, HOST_SYSTEM_PROPS, &hosts) if err != nil { - return err + return errors.Wrap(err, "dc.manager.scanMObjects") } dc.ihosts = make([]cloudprovider.ICloudHost, len(hosts)) for i := 0; i < len(hosts); i += 1 { @@ -71,7 +71,7 @@ func (dc *SDatacenter) scanHosts() error { func (dc *SDatacenter) GetIHosts() ([]cloudprovider.ICloudHost, error) { err := dc.scanHosts() if err != nil { - return nil, err + return nil, errors.Wrap(err, "dc.scanHosts") } return dc.ihosts, nil } @@ -83,8 +83,7 @@ func (dc *SDatacenter) scanDatastores() error { if dsList != nil { err := dc.manager.references2Objects(dsList, DATASTORE_PROPS, &stores) if err != nil { - log.Errorf("references2Objects dsList fail %s", err) - return err + return errors.Wrap(err, "dc.manager.references2Objects") } } dc.istorages = make([]cloudprovider.ICloudStorage, 0) @@ -110,7 +109,7 @@ func (dc *SDatacenter) GetIStorages() ([]cloudprovider.ICloudStorage, error) { func (dc *SDatacenter) GetIHostByMoId(idstr string) (cloudprovider.ICloudHost, error) { ihosts, err := dc.GetIHosts() if err != nil { - return nil, err + return nil, errors.Wrap(err, "dc.GetIHosts") } for i := 0; i < len(ihosts); i += 1 { if ihosts[i].GetId() == idstr { @@ -123,7 +122,7 @@ func (dc *SDatacenter) GetIHostByMoId(idstr string) (cloudprovider.ICloudHost, e func (dc *SDatacenter) GetIStorageByMoId(idstr string) (cloudprovider.ICloudStorage, error) { istorages, err := dc.GetIStorages() if err != nil { - return nil, err + return nil, errors.Wrap(err, "dc.GetIStorages") } for i := 0; i < len(istorages); i += 1 { if istorages[i].GetId() == idstr { @@ -142,8 +141,7 @@ func (dc *SDatacenter) fetchVms(vmRefs []types.ManagedObjectReference, all bool) if vmRefs != nil { err := dc.manager.references2Objects(vmRefs, VIRTUAL_MACHINE_PROPS, &vms) if err != nil { - log.Errorf("references2Objects fail %s", err) - return nil, err + return nil, errors.Wrap(err, "dc.manager.references2Objects") } } @@ -155,3 +153,37 @@ func (dc *SDatacenter) fetchVms(vmRefs []types.ManagedObjectReference, all bool) } return retVms, nil } + +func (dc *SDatacenter) scanNetworks() error { + if dc.inetworks == nil { + dc.inetworks = make([]IVMNetwork, 0) + + netMOBs := dc.getDatacenter().Network + for i := range netMOBs { + dvport := mo.DistributedVirtualPortgroup{} + err := dc.manager.reference2Object(netMOBs[i], DVPORTGROUP_PROPS, &dvport) + if err == nil { + net := NewDistributedVirtualPortgroup(dc.manager, &dvport, dc) + dc.inetworks = append(dc.inetworks, net) + } else { + net := mo.Network{} + err = dc.manager.reference2Object(netMOBs[i], NETWORK_PROPS, &net) + if err == nil { + vnet := NewNetwork(dc.manager, &net, dc) + dc.inetworks = append(dc.inetworks, vnet) + } else { + return errors.Wrap(err, "dc.manager.reference2Object") + } + } + } + } + return nil +} + +func (dc *SDatacenter) GetNetworks() ([]IVMNetwork, error) { + err := dc.scanNetworks() + if err != nil { + return nil, errors.Wrap(err, "dc.scanNetworks") + } + return dc.inetworks, nil +} diff --git a/pkg/util/esxi/manager.go b/pkg/util/esxi/manager.go index fdbe27c611..d47137edfd 100644 --- a/pkg/util/esxi/manager.go +++ b/pkg/util/esxi/manager.go @@ -31,6 +31,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudprovider" @@ -229,8 +230,7 @@ func (cli *SESXiClient) reference2Object(ref types.ManagedObjectReference, props pc := property.DefaultCollector(cli.client.Client) err := pc.RetrieveOne(cli.context, ref, props, dst) if err != nil { - log.Errorf("pc.RetrieveOne fail %s", err) - return err + return errors.Wrap(err, "pc.RetrieveOne") } return nil } diff --git a/pkg/util/esxi/network.go b/pkg/util/esxi/network.go new file mode 100644 index 0000000000..9b05cf0119 --- /dev/null +++ b/pkg/util/esxi/network.go @@ -0,0 +1,144 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import ( + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type IVMNetwork interface { + GetId() string + GetName() string + GetVlanId() int32 + GetNumPorts() int32 + GetActivePorts() []string + GetType() string +} + +const ( + NET_TYPE_NETWORK = "network" + NET_TYPE_DVPORTGROUP = "dvportgroup" + + VLAN_MODE_NONE = "none" + VLAN_MODE_VLAN = "vlan" + VLAN_MODE_PVLAN = "pvlan" + VLAN_MODE_TRUNK = "trunk" +) + +var NETWORK_PROPS = []string{"name", "parent", "summary", "host", "vm"} +var DVPORTGROUP_PROPS = []string{"name", "parent", "summary", "host", "vm", "config"} + +type SNetwork struct { + SManagedObject +} + +type SDistributedVirtualPortgroup struct { + SManagedObject +} + +func NewNetwork(manager *SESXiClient, net *mo.Network, dc *SDatacenter) *SNetwork { + return &SNetwork{SManagedObject: newManagedObject(manager, net, dc)} +} + +func NewDistributedVirtualPortgroup(manager *SESXiClient, net *mo.DistributedVirtualPortgroup, dc *SDatacenter) *SDistributedVirtualPortgroup { + return &SDistributedVirtualPortgroup{SManagedObject: newManagedObject(manager, net, dc)} +} + +func (net *SNetwork) getMONetwork() *mo.Network { + return net.object.(*mo.Network) +} + +func (net *SNetwork) GetName() string { + return net.getMONetwork().Name +} + +func (net *SNetwork) GetType() string { + return NET_TYPE_NETWORK +} + +func (net *SNetwork) GetVlanId() int32 { + return -1 +} + +func (net *SNetwork) GetVlanMode() string { + return VLAN_MODE_NONE +} + +func (net *SNetwork) GetNumPorts() int32 { + return -1 +} + +func (net *SNetwork) GetActivePorts() []string { + return nil +} + +func (net *SDistributedVirtualPortgroup) getMODVPortgroup() *mo.DistributedVirtualPortgroup { + return net.object.(*mo.DistributedVirtualPortgroup) +} + +func (net *SDistributedVirtualPortgroup) GetName() string { + return net.getMODVPortgroup().Name +} + +func (net *SDistributedVirtualPortgroup) GetType() string { + return NET_TYPE_DVPORTGROUP +} + +func (net *SDistributedVirtualPortgroup) GetVlanId() int32 { + dvpg := net.getMODVPortgroup() + switch conf := dvpg.Config.DefaultPortConfig.(type) { + case *types.VMwareDVSPortSetting: + switch vlanConf := conf.Vlan.(type) { + case *types.VmwareDistributedVirtualSwitchTrunkVlanSpec: + return -1 + case *types.VmwareDistributedVirtualSwitchPvlanSpec: + return vlanConf.PvlanId + case *types.VmwareDistributedVirtualSwitchVlanIdSpec: + return vlanConf.VlanId + } + } + return -1 +} + +func (net *SDistributedVirtualPortgroup) GetVlanMode() string { + dvpg := net.getMODVPortgroup() + switch conf := dvpg.Config.DefaultPortConfig.(type) { + case *types.VMwareDVSPortSetting: + switch conf.Vlan.(type) { + case *types.VmwareDistributedVirtualSwitchTrunkVlanSpec: + return VLAN_MODE_TRUNK + case *types.VmwareDistributedVirtualSwitchPvlanSpec: + return VLAN_MODE_PVLAN + case *types.VmwareDistributedVirtualSwitchVlanIdSpec: + return VLAN_MODE_VLAN + } + } + return VLAN_MODE_NONE +} + +func (net *SDistributedVirtualPortgroup) GetNumPorts() int32 { + dvpg := net.getMODVPortgroup() + return dvpg.Config.NumPorts +} + +func (net *SDistributedVirtualPortgroup) GetActivePorts() []string { + dvpg := net.getMODVPortgroup() + switch conf := dvpg.Config.DefaultPortConfig.(type) { + case *types.VMwareDVSPortSetting: + return conf.UplinkTeamingPolicy.UplinkPortOrder.ActiveUplinkPort + } + return nil +} diff --git a/pkg/util/esxi/provider/provider.go b/pkg/util/esxi/provider/provider.go index 9d103eb617..3289349bcb 100644 --- a/pkg/util/esxi/provider/provider.go +++ b/pkg/util/esxi/provider/provider.go @@ -125,6 +125,24 @@ func (self *SESXiProviderFactory) GetProvider(providerId, providerName, urlStr, }, nil } +func (self *SESXiProviderFactory) GetClientRC(urlStr, account, secret string) (map[string]string, error) { + parts, err := url.Parse(urlStr) + if err != nil { + return nil, err + } + host, port, err := parseHostPort(parts.Host, 443) + if err != nil { + return nil, err + } + + return map[string]string{ + "VMWARE_HOST": host, + "VMWARE_PORT": fmt.Sprintf("%d", port), + "VMWARE_ACCOUNT": account, + "VMWARE_PASSWORD": secret, + }, nil +} + func init() { factory := SESXiProviderFactory{} cloudprovider.RegisterFactory(&factory) diff --git a/pkg/util/esxi/resourcepool.go b/pkg/util/esxi/resourcepool.go new file mode 100644 index 0000000000..5717c7e08e --- /dev/null +++ b/pkg/util/esxi/resourcepool.go @@ -0,0 +1,27 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import "github.com/vmware/govmomi/vim25/mo" + +var RESOURCEPOOL_PROPS = []string{"name", "parent"} + +type SResourcePool struct { + SManagedObject +} + +func NewResourcePool(manager *SESXiClient, rp *mo.ResourcePool, dc *SDatacenter) *SResourcePool { + return &SResourcePool{SManagedObject: newManagedObject(manager, rp, dc)} +} diff --git a/pkg/util/esxi/shell/network.go b/pkg/util/esxi/shell/network.go new file mode 100644 index 0000000000..376d20bf81 --- /dev/null +++ b/pkg/util/esxi/shell/network.go @@ -0,0 +1,38 @@ +// Copyright 2019 Yunion +// +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/util/esxi" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type NetworkListOptions struct { + DATACENTER string `help:"List datastores in datacenter"` + } + shellutils.R(&NetworkListOptions{}, "network-list", "List networks in datacenter", func(cli *esxi.SESXiClient, args *NetworkListOptions) error { + dc, err := cli.FindDatacenterByMoId(args.DATACENTER) + if err != nil { + return err + } + nets, err := dc.GetNetworks() + if err != nil { + return err + } + printList(nets, nil) + return nil + }) +} diff --git a/pkg/util/esxi/virtualmachine.go b/pkg/util/esxi/virtualmachine.go index b25d90d7da..8c465c0627 100644 --- a/pkg/util/esxi/virtualmachine.go +++ b/pkg/util/esxi/virtualmachine.go @@ -31,6 +31,7 @@ import ( "yunion.io/x/pkg/util/reflectutils" "yunion.io/x/pkg/util/regutils" + "github.com/pkg/errors" billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -38,7 +39,7 @@ import ( "yunion.io/x/onecloud/pkg/util/billing" ) -var VIRTUAL_MACHINE_PROPS = []string{"name", "parent", "runtime", "summary", "config", "guest"} +var VIRTUAL_MACHINE_PROPS = []string{"name", "parent", "runtime", "summary", "config", "guest", "resourcePool"} type SVirtualMachine struct { SManagedObject @@ -64,7 +65,24 @@ func (self *SVirtualMachine) GetSecurityGroupIds() ([]string, error) { } func (self *SVirtualMachine) GetMetadata() *jsonutils.JSONDict { - return nil + meta := jsonutils.NewDict() + meta.Set("datacenter", jsonutils.NewString(self.GetDatacenterPathString())) + rp, _ := self.getResourcePool() + if rp != nil { + rpPath := rp.GetPath() + rpOffset := -1 + for i := range rpPath { + if rpPath[i] == "Resources" { + if i > 0 { + meta.Set("cluster", jsonutils.NewString(rpPath[i-1])) + rpOffset = i + } + } else if rpOffset >= 0 && i > rpOffset { + meta.Set(fmt.Sprintf("pool%d", i-rpOffset-1), jsonutils.NewString(rpPath[i])) + } + } + } + return meta } func (self *SVirtualMachine) getVirtualMachine() *mo.VirtualMachine { @@ -797,3 +815,14 @@ func (self *SVirtualMachine) GetProjectId() string { func (self *SVirtualMachine) GetError() error { return nil } + +func (self *SVirtualMachine) getResourcePool() (*SResourcePool, error) { + vm := self.getVirtualMachine() + morp := mo.ResourcePool{} + err := self.manager.reference2Object(*vm.ResourcePool, RESOURCEPOOL_PROPS, &morp) + if err != nil { + return nil, errors.Wrap(err, "self.manager.reference2Object") + } + rp := NewResourcePool(self.manager, &morp, self.datacenter) + return rp, nil +} diff --git a/pkg/util/huawei/huawei.go b/pkg/util/huawei/huawei.go index 9e1cffca8f..634d73e295 100644 --- a/pkg/util/huawei/huawei.go +++ b/pkg/util/huawei/huawei.go @@ -55,25 +55,11 @@ type SHuaweiClient struct { iregions []cloudprovider.ICloudRegion } -func parseAccount(account string) (accessKey string, projectId string) { - segs := strings.Split(account, "/") - if len(segs) == 2 { - accessKey = segs[0] - projectId = segs[1] - } else { - accessKey = account - projectId = "" - } - - return -} - // 进行资源操作时参数account 对应数据库cloudprovider表中的account字段,由accessKey和projectID两部分组成,通过"/"分割。 // 初次导入Subaccount时,参数account对应cloudaccounts表中的account字段,即accesskey。此时projectID为空, // 只能进行同步子账号、查询region列表等projectId无关的操作。 // todo: 通过accessurl支持国际站。目前暂时未支持国际站 -func NewHuaweiClient(providerId, providerName, accessurl, account, secret string, debug bool) (*SHuaweiClient, error) { - accessKey, projectId := parseAccount(account) +func NewHuaweiClient(providerId, providerName, accessurl, accessKey, secret, projectId string, debug bool) (*SHuaweiClient, error) { client := SHuaweiClient{ providerId: providerId, providerName: providerName, diff --git a/pkg/util/huawei/provider/provider.go b/pkg/util/huawei/provider/provider.go index f0a5d3cd53..1a9745797d 100644 --- a/pkg/util/huawei/provider/provider.go +++ b/pkg/util/huawei/provider/provider.go @@ -16,6 +16,7 @@ package provider import ( "context" + "strings" "yunion.io/x/jsonutils" @@ -73,8 +74,22 @@ func (self *SHuaweiProviderFactory) ValidateUpdateCloudaccountCredential(ctx con return account, nil } +func parseAccount(account string) (accessKey string, projectId string) { + segs := strings.Split(account, "/") + if len(segs) == 2 { + accessKey = segs[0] + projectId = segs[1] + } else { + accessKey = account + projectId = "" + } + + return +} + func (self *SHuaweiProviderFactory) GetProvider(providerId, providerName, url, account, secret string) (cloudprovider.ICloudProvider, error) { - client, err := huawei.NewHuaweiClient(providerId, providerName, url, account, secret, false) + accessKey, projectId := parseAccount(account) + client, err := huawei.NewHuaweiClient(providerId, providerName, url, accessKey, secret, projectId, false) if err != nil { return nil, err } @@ -84,6 +99,17 @@ func (self *SHuaweiProviderFactory) GetProvider(providerId, providerName, url, a }, nil } +func (self *SHuaweiProviderFactory) GetClientRC(url, account, secret string) (map[string]string, error) { + accessKey, projectId := parseAccount(account) + return map[string]string{ + "HUAWEI_CLOUD_ENV": url, + "HUAWEI_ACCESS_KEY": accessKey, + "HUAWEI_SECRET": secret, + "HUAWEI_REGION": huawei.HUAWEI_DEFAULT_REGION, + "HUAWEI_PROJECT": projectId, + }, nil +} + func init() { factory := SHuaweiProviderFactory{} cloudprovider.RegisterFactory(&factory) diff --git a/pkg/util/openstack/provider/provider.go b/pkg/util/openstack/provider/provider.go index d017c198db..7cf82010cb 100644 --- a/pkg/util/openstack/provider/provider.go +++ b/pkg/util/openstack/provider/provider.go @@ -126,6 +126,28 @@ func (self *SOpenStackProviderFactory) GetProvider(providerId, providerName, url }, nil } +func (self *SOpenStackProviderFactory) GetClientRC(url, account, secret string) (map[string]string, error) { + accountInfo := strings.Split(account, "/") + if len(accountInfo) < 2 { + return nil, fmt.Errorf("Missing username or project name %s", account) + } + project, username, endpointType, domainName, projectDomainName := accountInfo[0], accountInfo[1], "internal", "Default", "Default" + if len(accountInfo) == 3 { + domainName, projectDomainName = accountInfo[2], accountInfo[2] + } + + return map[string]string{ + "OPENSTACK_AUTH_URL": url, + "OPENSTACK_USERNAME": username, + "OPENSTACK_PASSWORD": secret, + "OPENSTACK_PROJECT": project, + "OPENSTACK_ENDPOINT_TYPE": endpointType, + "OPENSTACK_DOMAIN_NAME": domainName, + "OPENSTACK_PROJECT_DOMAIN": projectDomainName, + "OPENSTACK_REGION_ID": openstack.OPENSTACK_DEFAULT_REGION, + }, nil +} + func init() { factory := SOpenStackProviderFactory{} cloudprovider.RegisterFactory(&factory) diff --git a/pkg/util/pinyinutils/doc.go b/pkg/util/pinyinutils/doc.go new file mode 100644 index 0000000000..56f8247b31 --- /dev/null +++ b/pkg/util/pinyinutils/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 pinyinutils // import "yunion.io/x/onecloud/pkg/util/pinyinutils" diff --git a/pkg/util/qcloud/provider/provider.go b/pkg/util/qcloud/provider/provider.go index 0dd048aef7..ce069400d6 100644 --- a/pkg/util/qcloud/provider/provider.go +++ b/pkg/util/qcloud/provider/provider.go @@ -90,7 +90,13 @@ func (self *SQcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx con } func (self *SQcloudProviderFactory) GetProvider(providerId, providerName, url, account, secret string) (cloudprovider.ICloudProvider, error) { - client, err := qcloud.NewQcloudClient(providerId, providerName, account, secret, false) + secretId := account + appId := "" + if tmp := strings.Split(account, "/"); len(tmp) == 2 { + secretId = tmp[0] + appId = tmp[1] + } + client, err := qcloud.NewQcloudClient(providerId, providerName, secretId, secret, appId, false) if err != nil { return nil, err } @@ -100,6 +106,21 @@ func (self *SQcloudProviderFactory) GetProvider(providerId, providerName, url, a }, nil } +func (self *SQcloudProviderFactory) GetClientRC(url, account, secret string) (map[string]string, error) { + secretId := account + appId := "" + if tmp := strings.Split(account, "/"); len(tmp) == 2 { + secretId = tmp[0] + appId = tmp[1] + } + return map[string]string{ + "QCLOUD_APPID": appId, + "QCLOUD_SECRET_ID": secretId, + "QCLOUD_SECRET_KEY": secret, + "QCLOUD_REGION": qcloud.QCLOUD_DEFAULT_REGION, + }, nil +} + func init() { factory := SQcloudProviderFactory{} cloudprovider.RegisterFactory(&factory) diff --git a/pkg/util/qcloud/qcloud.go b/pkg/util/qcloud/qcloud.go index b9b38a89d0..3cace2a64a 100644 --- a/pkg/util/qcloud/qcloud.go +++ b/pkg/util/qcloud/qcloud.go @@ -54,11 +54,14 @@ type SQcloudClient struct { Debug bool } -func NewQcloudClient(providerId string, providerName string, secretID string, secretKey string, isDebug bool) (*SQcloudClient, error) { - client := SQcloudClient{providerId: providerId, providerName: providerName, SecretID: secretID, SecretKey: secretKey, Debug: isDebug} - if account := strings.Split(secretID, "/"); len(account) == 2 { - client.SecretID = account[0] - client.AppID = account[1] +func NewQcloudClient(providerId string, providerName string, secretID string, secretKey string, appID string, isDebug bool) (*SQcloudClient, error) { + client := SQcloudClient{ + providerId: providerId, + providerName: providerName, + SecretID: secretID, + SecretKey: secretKey, + AppID: appID, + Debug: isDebug, } err := client.fetchRegions() if err != nil { diff --git a/pkg/util/ucloud/provider/provider.go b/pkg/util/ucloud/provider/provider.go index 27af551237..71716a2d35 100644 --- a/pkg/util/ucloud/provider/provider.go +++ b/pkg/util/ucloud/provider/provider.go @@ -16,6 +16,7 @@ package provider import ( "context" + "strings" "yunion.io/x/jsonutils" @@ -70,8 +71,22 @@ func (self *SUcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx con return account, nil } +func parseAccount(account string) (accessKey string, projectId string) { + segs := strings.Split(account, "::") + if len(segs) == 2 { + accessKey = segs[0] + projectId = segs[1] + } else { + accessKey = account + projectId = "" + } + + return +} + func (self *SUcloudProviderFactory) GetProvider(providerId, providerName, url, account, secret string) (cloudprovider.ICloudProvider, error) { - client, err := ucloud.NewUcloudClient(providerId, providerName, account, secret, false) + accessKey, projectId := parseAccount(account) + client, err := ucloud.NewUcloudClient(providerId, providerName, accessKey, secret, projectId, false) if err != nil { return nil, err } @@ -81,6 +96,16 @@ func (self *SUcloudProviderFactory) GetProvider(providerId, providerName, url, a }, nil } +func (self *SUcloudProviderFactory) GetClientRC(url, account, secret string) (map[string]string, error) { + accessKey, projectId := parseAccount(account) + return map[string]string{ + "UCLOUD_ACCESS_KEY": accessKey, + "UCLOUD_SECRET": secret, + "UCLOUD_REGION": ucloud.UCLOUD_DEFAULT_REGION, + "UCLOUD_PROJECT": projectId, + }, nil +} + func init() { factory := SUcloudProviderFactory{} cloudprovider.RegisterFactory(&factory) diff --git a/pkg/util/ucloud/ucloud.go b/pkg/util/ucloud/ucloud.go index 6ccabfed4f..c5d29bbd2b 100644 --- a/pkg/util/ucloud/ucloud.go +++ b/pkg/util/ucloud/ucloud.go @@ -65,23 +65,9 @@ type SUcloudClient struct { Debug bool } -func parseAccount(account string) (accessKey string, projectId string) { - segs := strings.Split(account, "::") - if len(segs) == 2 { - accessKey = segs[0] - projectId = segs[1] - } else { - accessKey = account - projectId = "" - } - - return -} - // 进行资源操作时参数account 对应数据库cloudprovider表中的account字段,由accessKey和projectID两部分组成,通过"/"分割。 // 初次导入Subaccount时,参数account对应cloudaccounts表中的account字段,即accesskey。此时projectID为空,只能进行同步子账号(项目)、查询region列表等projectId无关的操作。 -func NewUcloudClient(providerId string, providerName string, account string, secret string, isDebug bool) (*SUcloudClient, error) { - accessKey, projectId := parseAccount(account) +func NewUcloudClient(providerId string, providerName string, accessKey string, secret string, projectId string, isDebug bool) (*SUcloudClient, error) { client := SUcloudClient{ providerId: providerId, providerName: providerName, diff --git a/pkg/util/zstack/provider/provider.go b/pkg/util/zstack/provider/provider.go index 8f32163b5a..8060f9ff98 100644 --- a/pkg/util/zstack/provider/provider.go +++ b/pkg/util/zstack/provider/provider.go @@ -88,6 +88,15 @@ func (self *SZStackProviderFactory) GetProvider(providerId, providerName, url, u }, nil } +func (self *SZStackProviderFactory) GetClientRC(url, account, secret string) (map[string]string, error) { + return map[string]string{ + "ZSTACK_AUTH_URL": url, + "ZSTACK_USERNAME": account, + "ZSTACK_PASSWORD": secret, + "ZSTACK_REGION_ID": zstack.ZSTACK_DEFAULT_REGION, + }, nil +} + func init() { factory := SZStackProviderFactory{} cloudprovider.RegisterFactory(&factory) From bcb5fc06ea592026aa9fc0092d571a7c835df4a9 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Sun, 30 Jun 2019 01:05:50 +0800 Subject: [PATCH 2/2] fix: replace all ext metadata --- pkg/cloudcommon/db/metadata.go | 9 +++++---- pkg/cloudcommon/db/standalone.go | 8 ++++++-- pkg/compute/models/syncutils.go | 12 +++++++++--- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/pkg/cloudcommon/db/metadata.go b/pkg/cloudcommon/db/metadata.go index a04305ce80..03fa9ee736 100644 --- a/pkg/cloudcommon/db/metadata.go +++ b/pkg/cloudcommon/db/metadata.go @@ -38,8 +38,9 @@ const ( CLOUD_TAG_PREFIX = "ext:" USER_TAG_PREFIX = "user:" - TAG_DELETE_RANGE_USER = "user" - TAG_DELETE_RANGE_CLOUD = "cloud" + // TAG_DELETE_RANGE_USER = "user" + // TAG_DELETE_RANGE_CLOUD = CLOUD_TAG_PREFIX // "cloud" + TAG_DELETE_RANGE_ALL = "all" ) @@ -332,9 +333,9 @@ func (manager *SMetadataManager) SetAll(ctx context.Context, obj IModel, store m records := []SMetadata{} q := manager.Query().Equals("id", idStr).NotLike("key", `\_\_%`) //避免删除系统内置的metadata, _ 在mysql里面有特殊含义,需要转义 switch delRange { - case TAG_DELETE_RANGE_USER: + case USER_TAG_PREFIX: q = q.Like("key", USER_TAG_PREFIX+"%") - case TAG_DELETE_RANGE_CLOUD: + case CLOUD_TAG_PREFIX: q = q.Like("key", CLOUD_TAG_PREFIX+"%") } q = q.Filter(sqlchemy.NOT(sqlchemy.In(q.Field("key"), keys))) diff --git a/pkg/cloudcommon/db/standalone.go b/pkg/cloudcommon/db/standalone.go index d572c0be4e..45ef9d606f 100644 --- a/pkg/cloudcommon/db/standalone.go +++ b/pkg/cloudcommon/db/standalone.go @@ -258,7 +258,11 @@ func (model *SStandaloneResourceBase) SetUserMetadataValues(ctx context.Context, } func (model *SStandaloneResourceBase) SetUserMetadataAll(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error { - return Metadata.SetAll(ctx, model, dictstore, userCred, "user") + return Metadata.SetAll(ctx, model, dictstore, userCred, USER_TAG_PREFIX) +} + +func (model *SStandaloneResourceBase) SetCloudMetadataAll(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error { + return Metadata.SetAll(ctx, model, dictstore, userCred, CLOUD_TAG_PREFIX) } func (model *SStandaloneResourceBase) RemoveMetadata(ctx context.Context, key string, userCred mcclient.TokenCredential) error { @@ -343,7 +347,7 @@ func (model *SStandaloneResourceBase) PerformSetUserMetadata(ctx context.Context } dictStore := make(map[string]interface{}) for k, v := range dictMap { - dictStore["user:"+k], _ = v.GetString() + dictStore[USER_TAG_PREFIX+k], _ = v.GetString() } err = model.SetUserMetadataAll(ctx, dictStore, userCred) return nil, err diff --git a/pkg/compute/models/syncutils.go b/pkg/compute/models/syncutils.go index c64833fd77..2f69554461 100644 --- a/pkg/compute/models/syncutils.go +++ b/pkg/compute/models/syncutils.go @@ -21,11 +21,13 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/cloudcommon/db" ) type IMetadataSetter interface { - SetAllMetadata(ctx context.Context, meta map[string]interface{}, userCred mcclient.TokenCredential) error - SetMetadata(ctx context.Context, key string, value interface{}, userCred mcclient.TokenCredential) error + // SetAllMetadata(ctx context.Context, meta map[string]interface{}, userCred mcclient.TokenCredential) error + // SetMetadata(ctx context.Context, key string, value interface{}, userCred mcclient.TokenCredential) error + SetCloudMetadataAll(ctx context.Context, meta map[string]interface{}, userCred mcclient.TokenCredential) error } func syncMetadata(ctx context.Context, userCred mcclient.TokenCredential, model IMetadataSetter, remote cloudprovider.ICloudResource) error { @@ -37,9 +39,13 @@ func syncMetadata(ctx context.Context, userCred mcclient.TokenCredential, model log.Errorf("Get VM Metadata error: %v", err) return err } + store := make(map[string]interface{}, 0) for key, value := range meta { - model.SetMetadata(ctx, "ext:"+key, value, userCred) + store[db.CLOUD_TAG_PREFIX + key] = value } + // model.SetMetadata(ctx, "ext:"+key, value, userCred) + // replace all ext keys + model.SetCloudMetadataAll(ctx, store, userCred) } return nil }