fix(region): huawei subaccount (#19071)

This commit is contained in:
屈轩
2023-12-27 14:20:37 +08:00
committed by GitHub
parent 2294a47506
commit 6002deec6f
37 changed files with 481 additions and 523 deletions

2
go.mod
View File

@@ -88,7 +88,7 @@ require (
k8s.io/client-go v0.19.3
k8s.io/cluster-bootstrap v0.19.3
moul.io/http2curl/v2 v2.3.0
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231227025516-4b8aef06c15e
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231227060638-40a1db02d028
yunion.io/x/executor v0.0.0-20230705125604-c5ac3141db32
yunion.io/x/jsonutils v1.0.1-0.20230613121553-0f3b41e2ef19
yunion.io/x/log v1.0.1-0.20230411060016-feb3f46ab361

4
go.sum
View File

@@ -1201,8 +1201,8 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231227025516-4b8aef06c15e h1:MMvjpuPn5uTynnWZfX5nE2+DYpyri8SVPgVQLKMVk8c=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231227025516-4b8aef06c15e/go.mod h1:aj1gR9PPb6eqqKOwvANe26CoZFY8ydmXy0fuvgKYXH0=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231227060638-40a1db02d028 h1:Q04t1Xfw9uqR7ba1AJm4tERJ2qwPLysaz9Iekrb0f8U=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231227060638-40a1db02d028/go.mod h1:aj1gR9PPb6eqqKOwvANe26CoZFY8ydmXy0fuvgKYXH0=
yunion.io/x/executor v0.0.0-20230705125604-c5ac3141db32 h1:v7POYkQwo1XzOxBoIoRVr/k0V9Y5JyjpshlIFa9raug=
yunion.io/x/executor v0.0.0-20230705125604-c5ac3141db32/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=

View File

@@ -104,8 +104,6 @@ const (
CLOUD_ACCESS_ENV_AZURE_GERMAN = compute.CLOUD_ACCESS_ENV_AZURE_GERMAN
CLOUD_ACCESS_ENV_AZURE_US_GOVERNMENT = compute.CLOUD_ACCESS_ENV_AZURE_US_GOVERNMENT
CLOUD_ACCESS_ENV_AZURE_CHINA = compute.CLOUD_ACCESS_ENV_AZURE_CHINA
CLOUD_ACCESS_ENV_HUAWEI_GLOBAL = compute.CLOUD_ACCESS_ENV_HUAWEI_GLOBAL
CLOUD_ACCESS_ENV_HUAWEI_CHINA = compute.CLOUD_ACCESS_ENV_HUAWEI_CHINA
CLOUD_ACCESS_ENV_ALIYUN_GLOBAL = compute.CLOUD_ACCESS_ENV_ALIYUN_GLOBAL
CLOUD_ACCESS_ENV_ALIYUN_FINANCE = compute.CLOUD_ACCESS_ENV_ALIYUN_FINANCE
CLOUD_ACCESS_ENV_CTYUN_CHINA = compute.CLOUD_ACCESS_ENV_CTYUN_CHINA
@@ -287,10 +285,6 @@ var (
"InternationalCloud": CLOUD_ACCESS_ENV_AWS_GLOBAL,
"ChinaCloud": CLOUD_ACCESS_ENV_AWS_CHINA,
},
CLOUD_PROVIDER_HUAWEI: {
"InternationalCloud": CLOUD_ACCESS_ENV_HUAWEI_GLOBAL,
"ChinaCloud": CLOUD_ACCESS_ENV_HUAWEI_CHINA,
},
CLOUD_PROVIDER_ALIYUN: {
"InternationalCloud": CLOUD_PROVIDER_ALIYUN,
"FinanceCloud": CLOUD_ACCESS_ENV_ALIYUN_FINANCE,

View File

@@ -17,7 +17,6 @@ package models
import (
"context"
"database/sql"
"fmt"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
@@ -150,7 +149,7 @@ func (self *SCloudimage) syncWithImage(ctx context.Context, userCred mcclient.To
return err
}
skuUrl := fmt.Sprintf("%s/%s/%s.json", meta.ImageBase, region.ExternalId, image.GetGlobalId())
skuUrl := region.getMetaUrl(meta.ImageBase, image.GetGlobalId())
obj, err := db.FetchByExternalId(CachedimageManager, image.GetGlobalId())
if err != nil {

View File

@@ -17,7 +17,6 @@ package models
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
@@ -1275,7 +1274,7 @@ func (self *SCloudregion) newCloudimage(ctx context.Context, userCred mcclient.T
return err
}
skuUrl := fmt.Sprintf("%s/%s/%s.json", meta.ImageBase, self.ExternalId, iImage.GetGlobalId())
skuUrl := self.getMetaUrl(meta.ImageBase, iImage.GetGlobalId())
err = meta.Get(skuUrl, image)
if err != nil {
return errors.Wrapf(err, "Get")

View File

@@ -587,7 +587,7 @@ func (self *SCloudregion) newDBInstanceSkuFromCloudSku(ctx context.Context, user
sku := &SDBInstanceSku{}
sku.SetModelManager(DBInstanceSkuManager, sku)
skuUrl := fmt.Sprintf("%s/%s/%s.json", meta.DBInstanceBase, self.ExternalId, externalId)
skuUrl := self.getMetaUrl(meta.DBInstanceBase, externalId)
err = meta.Get(skuUrl, sku)
if err != nil {
return errors.Wrapf(err, "Get")

View File

@@ -474,7 +474,7 @@ func (self *SCloudregion) newFromPublicCloudSku(ctx context.Context, userCred mc
zoneMaps[zone.ExternalId] = zone.Id
}
skuUrl := fmt.Sprintf("%s/%s/%s.json", meta.ElasticCacheBase, self.ExternalId, externalId)
skuUrl := self.getMetaUrl(meta.ElasticCacheBase, externalId)
sku := &SElasticcacheSku{}
sku.SetModelManager(ElasticcacheSkuManager, sku)
err = meta.Get(skuUrl, sku)

View File

@@ -289,7 +289,7 @@ func (self *SCloudregion) newFromCloudNasSku(ctx context.Context, userCred mccli
sku := &SNasSku{}
sku.SetModelManager(NasSkuManager, sku)
skuUrl := fmt.Sprintf("%s/%s/%s.json", meta.NasBase, self.ExternalId, isku.GetGlobalId())
skuUrl := self.getMetaUrl(meta.NasBase, isku.GetGlobalId())
err = meta.Get(skuUrl, sku)
if err != nil {
return errors.Wrapf(err, "Get")

View File

@@ -293,7 +293,7 @@ func (self *SCloudregion) newFromCloudNatSku(ctx context.Context, userCred mccli
sku := &SNatSku{}
sku.SetModelManager(NatSkuManager, sku)
skuUrl := fmt.Sprintf("%s/%s/%s.json", meta.NatBase, self.ExternalId, isku.GetGlobalId())
skuUrl := self.getMetaUrl(meta.NatBase, isku.GetGlobalId())
err = meta.Get(skuUrl, sku)
if err != nil {
return errors.Wrapf(err, "Get")

View File

@@ -1162,6 +1162,14 @@ func (self *SServerSku) setPrepaidPostpaidStatus(userCred mcclient.TokenCredenti
return nil
}
func (region *SCloudregion) getMetaUrl(base string, externalId string) string {
if region.Provider == api.CLOUD_PROVIDER_HUAWEI && strings.Contains(region.ExternalId, "_") {
idx := strings.Index(region.ExternalId, "_")
return fmt.Sprintf("%s/%s/%s.json", base, region.ExternalId[:idx], externalId)
}
return fmt.Sprintf("%s/%s/%s.json", base, region.ExternalId, externalId)
}
func (region *SCloudregion) newPublicCloudSku(ctx context.Context, userCred mcclient.TokenCredential, extSku SServerSku) error {
meta, err := yunionmeta.FetchYunionmeta(ctx)
if err != nil {
@@ -1179,7 +1187,7 @@ func (region *SCloudregion) newPublicCloudSku(ctx context.Context, userCred mccl
sku := &SServerSku{}
sku.SetModelManager(ServerSkuManager, sku)
skuUrl := fmt.Sprintf("%s/%s/%s.json", meta.ServerBase, region.ExternalId, extSku.ExternalId)
skuUrl := region.getMetaUrl(meta.ServerBase, extSku.ExternalId)
err = meta.Get(skuUrl, sku)
if err != nil {
return errors.Wrapf(err, "Get")
@@ -1227,7 +1235,7 @@ func (self *SServerSku) syncWithCloudSku(ctx context.Context, userCred mcclient.
}
sku := &SServerSku{}
skuUrl := fmt.Sprintf("%s/%s/%s.json", meta.ServerBase, region.ExternalId, extSku.ExternalId)
skuUrl := region.getMetaUrl(meta.ServerBase, extSku.ExternalId)
err = meta.Get(skuUrl, sku)
if err != nil {
return errors.Wrapf(err, "Get")

View File

@@ -300,7 +300,7 @@ func (opts *SOpenStackCloudAccountCreateOptions) Params() (jsonutils.JSONObject,
type SHuaweiCloudAccountCreateOptions struct {
SCloudAccountCreateBaseOptions
SAccessKeyCredentialWithEnvironment
SAccessKeyCredential
}
func (opts *SHuaweiCloudAccountCreateOptions) Params() (jsonutils.JSONObject, error) {

View File

@@ -28,7 +28,8 @@ import (
"yunion.io/x/pkg/util/httputils"
"yunion.io/x/pkg/util/version"
"yunion.io/x/onecloud/pkg/esxi/options"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/modules/compute"
)
@@ -152,6 +153,10 @@ func (self *SSkuResourcesMeta) Index(resType string) (map[string]string, error)
}
func (self *SSkuResourcesMeta) List(resType string, regionId string, retVal interface{}) error {
if strings.HasPrefix(regionId, api.CLOUD_PROVIDER_HUAWEI) && strings.Contains(regionId, "_") {
idx := strings.Index(regionId, "_")
regionId = regionId[:idx]
}
var url string
switch resType {
case "dbinstance_sku":

168
scripts/upgrade_3_11.sh Executable file
View File

@@ -0,0 +1,168 @@
#!/usr/bin/env bash
# 登录cloudpods控制节点获取mysql账号密码信息,填写到下面变量
# kubectl get oc -n onecloud default -o yaml | grep -A 4 mysql
#
# 升级到3.11版本之后,等待所有华为云账号同步完成后,执行此升级脚本
# 脚本原理如下:
# 脚本会检索1天内deleted=1的华为云资源通过external_id反查当前数据库中对应external_id相同且deleted=0的资源
# 先会将deleted=1的资源id设为id=id-old, 再将deleted=0的资源id变更到deleted=1的资源id
#
HOST='127.0.0.1'
USERNAME='root'
PASSWORD=''
DATETIME=''
if ["$(uname)"=="Darwin"]; then
DATETIME=$(date -v-1d -u "+%Y-%m-%dT%H:%M%SZ")
else
DATETIME=$(date -d "1 day ago" -u "+%Y-%m-%dT%H:%M%SZ")
if
function exec_sql_with_db() {
export MYSQL_PWD=$PASSWORD
local db=$1
local sql=$2
echo $(mysql -u"$USERNAME" -h "$HOST" -D"$db" -s -e "$sql")
}
function get_relation_tables() {
local field=$1
exec_sql_with_db "information_schema" "select table_name from columns where column_name='$field' and table_schema='yunioncloud'"
}
function exec_sql() {
exec_sql_with_db "yunioncloud" "$1"
}
function uuid() {
echo $1 | awk -F '-' '{print $1"-"$2"-"$3"-"$4"-"$5}'
}
function change_uuid() {
local table=$1
local target_id=$2
uid=$(uuid $target_id)
if [ "$uid" != "$target_id" ]; then
target_id=$uid
else
exec_sql "update $table set id='$target_id-old' where id='$target_id'"
fi
echo $target_id
}
echo "upgrade guests_tbl"
exec_sql "select name, id, external_id from guests_tbl where deleted=1 and length(external_id) > 0 and host_id in (select id from hosts_tbl where deleted=1 and manager_id in (select id from cloudproviders_tbl where deleted=1 and provider='Huawei' and deleted_at > '$DATETIME'))" | while read -r line; do
info=($(echo $line | tr " ", "\n"))
name=${info[0]}
target_id=${info[1]}
external_id=${info[2]}
id=$(exec_sql "select id from guests_tbl where deleted=0 and external_id='$external_id' and host_id in (select id from hosts_tbl where deleted=0 and manager_id in (select id from cloudproviders_tbl where deleted=0 and provider='Huawei'))")
if [ -n "$id" ]; then
target_id=$(change_uuid "guests_tbl" $target_id)
echo "change server $name id from $id => $target_id"
exec_sql "update guests_tbl set id='$target_id' where id='$id' and deleted=0"
tables=$(get_relation_tables "guest_id")
for table in $tables; do
exec_sql "update $table set guest_id='$target_id' where guest_id='$id' and deleted=0"
done
fi
done
echo "upgrade disks_tbl"
exec_sql "select name, id, external_id from disks_tbl where deleted=1 and length(external_id) > 0 and storage_id in (select id from storages_tbl where deleted=1 and manager_id in (select id from cloudproviders_tbl where deleted=1 and provider='Huawei' and deleted_at > '$DATETIME'))" | while read -r line; do
info=($(echo $line | tr " ", "\n"))
name=${info[0]}
target_id=${info[1]}
external_id=${info[2]}
id=$(exec_sql "select id from disks_tbl where deleted=0 and external_id='$external_id' and storage_id in (select id from storages_tbl where deleted=0 and manager_id in (select id from cloudproviders_tbl where deleted=0 and provider='Huawei'))")
if [ -n "$id" ]; then
target_id=$(change_uuid "disks_tbl" $target_id)
echo "change disk $name id from $id => $target_id"
exec_sql "update disks_tbl set id='$target_id' where id='$id' and deleted=0"
tables=$(get_relation_tables "disk_id")
for table in $tables; do
exec_sql "update $table set disk_id='$target_id' where disk_id='$id' and deleted=0"
done
fi
done
echo "upgrade networks_tbl"
exec_sql "select name, id, external_id from networks_tbl where deleted=1 and length(external_id) > 0 and wire_id in (select id from wires_tbl where deleted=1 and vpc_id in (select id from vpcs_tbl where deleted=1 and manager_id in (select id from cloudproviders_tbl where deleted=1 and provider='Huawei' and deleted_at > '$DATETIME')))" | while read -r line; do
info=($(echo $line | tr " ", "\n"))
name=${info[0]}
target_id=${info[1]}
external_id=${info[2]}
id=$(exec_sql "select id from networks_tbl where deleted=0 and external_id='$external_id' and wire_id in (select id from wires_tbl where deleted=0 and vpc_id in (select id from vpcs_tbl where deleted=0 and manager_id in (select id from cloudproviders_tbl where deleted=0 and provider='Huawei')))")
if [ -n "$id" ]; then
target_id=$(change_uuid "networks_tbl" $target_id)
echo "change network $name id from $id => $target_id"
exec_sql "update networks_tbl set id='$target_id' where id='$id' and deleted=0"
tables=$(get_relation_tables "network_id")
for table in $tables; do
if [ "$table" == "network_additional_wire_tbl" ]; then
exec_sql "update $table set network_id='$target_id' where network_id='$id'"
else
exec_sql "update $table set network_id='$target_id' where network_id='$id' and deleted=0"
fi
done
fi
done
function upgrade_managed_resources_table() {
local res_type=$1
local table_name=$2
local field=$3
echo "upgrade $table_name"
exec_sql "select name, id, external_id from $table_name where deleted=1 and length(external_id) > 0 and manager_id in (select id from cloudproviders_tbl where deleted=1 and provider='Huawei' and deleted_at > '$DATETIME')" | while read -r line; do
info=($(echo $line | tr " ", "\n"))
name=${info[0]}
target_id=${info[1]}
external_id=${info[2]}
id=$(exec_sql "select id from $table_name where deleted=0 and external_id='$external_id' and manager_id in (select id from cloudproviders_tbl where deleted=0 and provider='Huawei')")
if [ -n "$id" ]; then
target_id=$(change_uuid $table_name $target_id)
echo "change $res_type $name id from $id => $target_id"
exec_sql "update $table_name set id='$target_id' where id='$id' and deleted=0"
tables=$(get_relation_tables $field)
for table in $tables; do
exec_sql "update $table set $field='$target_id' where $field='$id' and deleted=0"
done
fi
done
}
upgrade_managed_resources_table "elasticcacheinstance" "elasticcacheinstances_tbl" "elasticcache_id"
upgrade_managed_resources_table "dbinstance" "dbinstances_tbl" "dbinstance_id"
upgrade_managed_resources_table "bucket" "buckets_tbl" "bucket_id"
upgrade_managed_resources_table "vpc" "vpcs_tbl" "vpc_id"
upgrade_managed_resources_table "cdn" "cdn_domains_tbl" "cdn_domain_id"
upgrade_managed_resources_table "dns" "dnszones_tbl" "dns_zone_id"
upgrade_managed_resources_table "elastic_search" "elastic_searchs_tbl" "elastic_search_id"
upgrade_managed_resources_table "eip" "elasticips_tbl" "eip_id"
upgrade_managed_resources_table "inter_vpc_network" "inter_vpc_networks_tbl" "inter_vpc_network_id"
upgrade_managed_resources_table "kafka" "kafkas_tbl" "kafka_id"
upgrade_managed_resources_table "loadbalancer" "loadbalancers_tbl" "loadbalancer_id"
upgrade_managed_resources_table "snapshot" "snapshots_tbl" "snapshot_id"
upgrade_managed_resources_table "sslcertificate" "sslcertificates_tbl" "sslcertificate_id"

2
vendor/modules.txt vendored
View File

@@ -1465,7 +1465,7 @@ sigs.k8s.io/structured-merge-diff/v4/value
# sigs.k8s.io/yaml v1.2.0
## explicit; go 1.12
sigs.k8s.io/yaml
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231227025516-4b8aef06c15e
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231227060638-40a1db02d028
## explicit; go 1.18
yunion.io/x/cloudmux/pkg/apis
yunion.io/x/cloudmux/pkg/apis/billing

View File

@@ -68,8 +68,6 @@ const (
CLOUD_ACCESS_ENV_AZURE_GERMAN = CLOUD_PROVIDER_AZURE + "-de"
CLOUD_ACCESS_ENV_AZURE_US_GOVERNMENT = CLOUD_PROVIDER_AZURE + "-us-gov"
CLOUD_ACCESS_ENV_AZURE_CHINA = CLOUD_PROVIDER_AZURE
CLOUD_ACCESS_ENV_HUAWEI_GLOBAL = CLOUD_PROVIDER_HUAWEI + "-int"
CLOUD_ACCESS_ENV_HUAWEI_CHINA = CLOUD_PROVIDER_HUAWEI
CLOUD_ACCESS_ENV_ALIYUN_GLOBAL = CLOUD_PROVIDER_ALIYUN
CLOUD_ACCESS_ENV_ALIYUN_FINANCE = CLOUD_PROVIDER_ALIYUN + "-fin"
CLOUD_ACCESS_ENV_CTYUN_CHINA = CLOUD_PROVIDER_CTYUN

View File

@@ -60,11 +60,12 @@ const (
STORAGE_CLOUD_HSSD = "cloud_hssd" //增强型SSD云硬盘
// huawei storage type
STORAGE_HUAWEI_SSD = "SSD" // 超高IO云硬盘
STORAGE_HUAWEI_SAS = "SAS" // 高IO云硬盘
STORAGE_HUAWEI_SATA = "SATA" // 普通IO云硬盘
STORAGE_HUAWEI_GPSSD = "GPSSD" // 通用型SSD
STORAGE_HUAWEI_ESSD = "ESSD" // 急速型SSD
STORAGE_HUAWEI_SSD = "SSD" // 超高IO云硬盘
STORAGE_HUAWEI_SAS = "SAS" // 高IO云硬盘
STORAGE_HUAWEI_SATA = "SATA" // 普通IO云硬盘
STORAGE_HUAWEI_GPSSD = "GPSSD" // 通用型SSD
STORAGE_HUAWEI_GPSSD2 = "GPSSD2" // 通用型SSD V2
STORAGE_HUAWEI_ESSD = "ESSD" // 急速型SSD
// openstack
STORAGE_OPENSTACK_ISCSI = "iscsi"

View File

@@ -292,10 +292,6 @@ type ModelartsStatistics struct {
Value float64
}
func (self *SHuaweiClient) GetPoolNetworks(poolName string) (jsonutils.JSONObject, error) {
return self.modelartsPoolNetworkList(nil)
}
func (self *SHuaweiClient) CreatePoolNetworks(cidr string) (jsonutils.JSONObject, error) {
params := map[string]interface{}{
"apiVersion": "v1",

View File

@@ -340,7 +340,7 @@ func (self *SHuaweiClient) DetachGroupRole(groupId, roleId string) error {
return errors.Wrapf(err, "GetProjects")
}
for _, project := range projects {
err := self.KeystoneRemoveProjectPermissionFromGroup(project.ID, groupId, role.Id)
err := self.KeystoneRemoveProjectPermissionFromGroup(project.Id, groupId, role.Id)
if err != nil {
return errors.Wrapf(err, "remove project role ")
}
@@ -400,7 +400,7 @@ func (self *SHuaweiClient) AttachGroupRole(groupId, roleId string) error {
return errors.Wrapf(err, "GetProjects")
}
for _, project := range projects {
err := self.KeystoneAssociateGroupWithProjectPermission(project.ID, groupId, role.Id)
err := self.KeystoneAssociateGroupWithProjectPermission(project.Id, groupId, role.Id)
if err != nil {
return errors.Wrapf(err, "add project role ")
}
@@ -432,7 +432,7 @@ func (self *SHuaweiClient) AttachGroupCustomRole(groupId, roleId string) error {
return errors.Wrapf(err, "GetProjects")
}
for _, project := range projects {
err := self.KeystoneAssociateGroupWithProjectPermission(project.ID, groupId, role.Id)
err := self.KeystoneAssociateGroupWithProjectPermission(project.Id, groupId, role.Id)
if err != nil {
return errors.Wrapf(err, "add project role ")
}
@@ -464,7 +464,7 @@ func (self *SHuaweiClient) DetachGroupCustomRole(groupId, roleId string) error {
return errors.Wrapf(err, "GetProjects")
}
for _, project := range projects {
err := self.KeystoneRemoveProjectPermissionFromGroup(project.ID, groupId, role.Id)
err := self.KeystoneRemoveProjectPermissionFromGroup(project.Id, groupId, role.Id)
if err != nil {
return errors.Wrapf(err, "remove project role ")
}

View File

@@ -474,8 +474,7 @@ func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceC
}
params := map[string]interface{}{
"region": region.ID,
"name": desc.Name,
"name": desc.Name,
"datastore": map[string]string{
"type": desc.Engine,
"version": desc.EngineVersion,

View File

@@ -131,11 +131,11 @@ func (region *SRegion) RevokeDBInstancePrivilege(instanceId string, account, dat
},
}
resource := fmt.Sprintf("instances/%s/db_privilege", instanceId)
url, err := region.client.getUrl(SERVICE_RDS, region.ID, resource, httputils.DELETE, nil)
url, err := region.client.getUrl(SERVICE_RDS, region.Id, resource, httputils.DELETE, nil)
if err != nil {
return err
}
_, err = region.client.request(httputils.DELETE, url, nil, params)
_, err = region.client.request(httputils.DELETE, region.Id, url, nil, params)
return err
}

View File

@@ -406,12 +406,15 @@ func (self *SRegion) GetDisk(diskId string) (*SDisk, error) {
}
// https://console.huaweicloud.com/apiexplorer/#/openapi/EVS/doc?api=ListVolumes
func (self *SRegion) GetDisks(zoneId string) ([]SDisk, error) {
func (self *SRegion) GetDisks(zoneId, storageTypeId string) ([]SDisk, error) {
ret := []SDisk{}
query := url.Values{}
if len(zoneId) > 0 {
query.Set("availability_zone", zoneId)
}
if len(storageTypeId) > 0 {
query.Set("volume_type_id", storageTypeId)
}
for {
resp, err := self.list(SERVICE_EVS, "cloudvolumes/detail", query)
if err != nil {

View File

@@ -14,13 +14,11 @@
package huawei
import "strings"
type SDiskType struct {
ExtraSpecs ExtraSpecs `json:"extra_specs"`
Name string `json:"name"`
QosSpecsID string `json:"qos_specs_id"`
ID string `json:"id"`
Id string `json:"id"`
IsPublic bool `json:"is_public"`
}
@@ -30,11 +28,3 @@ type ExtraSpecs struct {
RESKEYAvailabilityZones string `json:"RESKEY:availability_zones"`
OSVendorExtendedSoldOutAvailabilityZones string `json:"os-vendor-extended:sold_out_availability_zones"`
}
func (self *SDiskType) IsAvaliableInZone(zoneId string) bool {
if len(self.QosSpecsID) > 0 && strings.Contains(self.ExtraSpecs.RESKEYAvailabilityZones, zoneId) && !strings.Contains(self.ExtraSpecs.OSVendorExtendedSoldOutAvailabilityZones, zoneId) {
return true
}
return false
}

View File

@@ -391,14 +391,14 @@ func (self *SRegion) setEipTags(id string, existedTags, tags map[string]string,
}
if len(deleteTagsKey) > 0 {
for _, k := range deleteTagsKey {
err := self.DeletePublicipTag(self.ID, k)
err := self.DeletePublicipTag(id, k)
if err != nil {
return errors.Wrapf(err, "remove tags")
}
}
}
if len(tags) > 0 {
err := self.CreatePublicipTag(self.ID, tags)
err := self.CreatePublicipTag(id, tags)
if err != nil {
return errors.Wrapf(err, "add tags")
}

View File

@@ -30,8 +30,6 @@ import (
type SHost struct {
multicloud.SHostBase
zone *SZone
projectId string
}
func (self *SHost) GetId() string {

View File

@@ -20,7 +20,6 @@ import (
"net/http"
"net/url"
"strings"
"sync"
"time"
"github.com/huaweicloud/huaweicloud-sdk-go/auth/aksk"
@@ -28,6 +27,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/gotypes"
"yunion.io/x/pkg/util/httputils"
"yunion.io/x/pkg/util/timeutils"
@@ -41,12 +41,8 @@ const (
CLOUD_PROVIDER_HUAWEI_CN = "华为云"
CLOUD_PROVIDER_HUAWEI_EN = "Huawei"
HUAWEI_INTERNATIONAL_CLOUDENV = "InternationalCloud"
HUAWEI_CHINA_CLOUDENV = "ChinaCloud"
HUAWEI_DEFAULT_REGION = "cn-north-1"
HUAWEI_CERT_DEFAULT_REGION = "cn-north-4"
HUAWEI_API_VERSION = "2018-12-25"
HUAWEI_DEFAULT_REGION = "cn-north-4"
HUAWEI_API_VERSION = "2018-12-25"
SERVICE_IAM = "iam"
SERVICE_IAM_V3 = "iam_v3"
@@ -85,27 +81,17 @@ const (
SERVICE_FUNCTIONGRAPH = "functiongraph"
)
var HUAWEI_REGION_CACHES sync.Map
type userRegionsCache struct {
UserId string
ExpireAt time.Time
Regions []SRegion
}
type HuaweiClientConfig struct {
cpcfg cloudprovider.ProviderConfig
projectId string // 华为云项目ID.
accessKey string
accessSecret string
debug bool
}
func NewHuaweiClientConfig(accessKey, accessSecret, projectId string) *HuaweiClientConfig {
func NewHuaweiClientConfig(accessKey, accessSecret string) *HuaweiClientConfig {
cfg := &HuaweiClientConfig{
projectId: projectId,
accessKey: accessKey,
accessSecret: accessSecret,
}
@@ -125,33 +111,26 @@ func (cfg *HuaweiClientConfig) Debug(debug bool) *HuaweiClientConfig {
type SHuaweiClient struct {
*HuaweiClientConfig
isMainProject bool // whether the project is the main project in the region
isDefaultProject bool // whether the project is the default region project
clientRegion string
userId string
ownerId string
ownerName string
ownerCreateTime time.Time
iregions []cloudprovider.ICloudRegion
iBuckets []cloudprovider.ICloudBucket
projects []SProject
regions []SRegion
projects map[string]SProject
regions map[string]SRegion
httpClient *http.Client
orders map[string]SOrderResource
}
// 进行资源操作时参数account 对应数据库cloudprovider表中的account字段,由accessKey和projectID两部分组成通过"/"分割。
// 初次导入Subaccount时参数account对应cloudaccounts表中的account字段即accesskey。此时projectID为空
// 只能进行同步子账号、查询region列表等projectId无关的操作。
// todo: 通过accessurl支持国际站。目前暂时未支持国际站
func NewHuaweiClient(cfg *HuaweiClientConfig) (*SHuaweiClient, error) {
client := SHuaweiClient{
HuaweiClientConfig: cfg,
regions: map[string]SRegion{},
projects: map[string]SProject{},
}
err := client.init()
if err != nil {
@@ -161,16 +140,13 @@ func NewHuaweiClient(cfg *HuaweiClientConfig) (*SHuaweiClient, error) {
}
func (self *SHuaweiClient) init() error {
err := self.fetchRegions()
_, err := self.getRegions()
if err != nil {
return err
return errors.Wrapf(err, "GetRegions")
}
err = self.initOwner()
_, err = self.GetProjects()
if err != nil {
return errors.Wrap(err, "fetchOwner")
}
if self.debug {
log.Debugf("OwnerId: %s name: %s", self.ownerId, self.ownerName)
return errors.Wrapf(err, "GetProjects")
}
return nil
}
@@ -234,7 +210,7 @@ func (self *SHuaweiClient) getAkClient() *akClient {
}
}
func (self *SHuaweiClient) request(method httputils.THttpMethod, url string, query url.Values, params map[string]interface{}) (jsonutils.JSONObject, error) {
func (self *SHuaweiClient) request(method httputils.THttpMethod, regionId, url string, query url.Values, params map[string]interface{}) (jsonutils.JSONObject, error) {
client := self.getAkClient()
if len(query) > 0 {
url = fmt.Sprintf("%s?%s", url, query.Encode())
@@ -244,8 +220,11 @@ func (self *SHuaweiClient) request(method httputils.THttpMethod, url string, que
body = jsonutils.Marshal(params)
}
header := http.Header{}
if len(self.projectId) > 0 && !strings.Contains(url, "eps") {
header.Set("X-Project-Id", self.projectId)
if project, ok := self.projects[regionId]; ok {
if len(project.Id) > 0 && !strings.Contains(url, "eps") {
header.Set("X-Project-Id", project.Id)
}
}
if (strings.Contains(url, "/OS-CREDENTIAL/") ||
strings.Contains(url, "/users") ||
@@ -264,64 +243,30 @@ func (self *SHuaweiClient) request(method httputils.THttpMethod, url string, que
}
// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListRegions
func (self *SHuaweiClient) fetchRegions() error {
if self.regions == nil {
userId, err := self.GetUserId()
if err != nil {
return errors.Wrap(err, "GetUserId")
}
if regionsCache, ok := HUAWEI_REGION_CACHES.Load(userId); !ok || regionsCache.(*userRegionsCache).ExpireAt.Sub(time.Now()).Seconds() > 0 {
resp, err := self.list(SERVICE_IAM_V3, "", "regions", nil)
if err != nil {
return errors.Wrapf(err, "list regions")
}
regions := make([]SRegion, 0)
err = resp.Unmarshal(&regions, "regions")
if err != nil {
return errors.Wrapf(err, "Unmarshal")
}
HUAWEI_REGION_CACHES.Store(userId, &userRegionsCache{ExpireAt: time.Now().Add(24 * time.Hour), UserId: userId, Regions: regions})
}
if regionsCache, ok := HUAWEI_REGION_CACHES.Load(userId); ok {
self.regions = regionsCache.(*userRegionsCache).Regions
}
}
filtedRegions := make([]SRegion, 0)
if len(self.projectId) > 0 {
project, err := self.GetProjectById(self.projectId)
if err != nil {
return err
}
func (self *SHuaweiClient) getRegions() ([]SRegion, error) {
if len(self.regions) > 0 {
ret := []SRegion{}
for _, region := range self.regions {
if strings.Count(project.Name, region.ID) >= 1 {
self.clientRegion = region.ID
filtedRegions = append(filtedRegions, region)
}
if project.Name == region.ID {
self.isMainProject = true
}
ret = append(ret, region)
}
if project.Name == HUAWEI_CERT_DEFAULT_REGION {
self.isDefaultProject = true
}
} else {
filtedRegions = self.regions
return ret, nil
}
resp, err := self.list(SERVICE_IAM_V3, "", "regions", nil)
if err != nil {
return nil, errors.Wrapf(err, "list regions")
}
if len(filtedRegions) == 0 {
return errors.Wrapf(cloudprovider.ErrNotFound, "empty regions")
self.regions = map[string]SRegion{}
regions := make([]SRegion, 0)
err = resp.Unmarshal(&regions, "regions")
if err != nil {
return nil, errors.Wrapf(err, "Unmarshal")
}
self.iregions = make([]cloudprovider.ICloudRegion, len(filtedRegions))
for i := 0; i < len(filtedRegions); i += 1 {
filtedRegions[i].client = self
self.iregions[i] = &filtedRegions[i]
for _, region := range regions {
region.client = self
self.regions[region.Id] = region
}
return nil
return regions, nil
}
func (self *SHuaweiClient) invalidateIBuckets() {
@@ -387,13 +332,13 @@ func (self *SHuaweiClient) fetchBuckets() error {
ret := make([]cloudprovider.ICloudBucket, 0)
for i := range output.Buckets {
bInfo := output.Buckets[i]
region, err := self.getIRegionByRegionId(bInfo.Location)
if err != nil {
region := self.GetRegion(bInfo.Location)
if gotypes.IsNil(region) {
log.Errorf("fail to find region %s", bInfo.Location)
continue
}
b := SBucket{
region: region.(*SRegion),
region: region,
Name: bInfo.Name,
Location: bInfo.Location,
@@ -405,153 +350,81 @@ func (self *SHuaweiClient) fetchBuckets() error {
return nil
}
func (self *SHuaweiClient) GetCloudRegionExternalIdPrefix() string {
if len(self.projectId) > 0 {
return self.iregions[0].GetGlobalId()
} else {
return CLOUD_PROVIDER_HUAWEI
}
}
func (self *SHuaweiClient) GetRegions() []SRegion {
regions := make([]SRegion, len(self.iregions))
for i := 0; i < len(regions); i += 1 {
region := self.iregions[i].(*SRegion)
regions[i] = *region
}
return regions
}
func (self *SHuaweiClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
projects, err := self.fetchProjects()
if err != nil {
return nil, err
}
// https://support.huaweicloud.com/api-iam/zh-cn_topic_0074171149.html
subAccounts := make([]cloudprovider.SSubAccount, 0)
for i := range projects {
project := projects[i]
find := false
for j := range self.iregions {
region := self.iregions[j].(*SRegion)
if strings.Contains(project.Name, region.ID) {
find = true
break
}
}
if !find {
// name 为MOS的project是华为云内部的一个特殊project。不需要同步到本地
// skip invalid project
continue
}
// https://www.huaweicloud.com/notice/2018/20190618171312411.html
// expiredAt, _ := timeutils.ParseTimeStr("2020-09-16 00:00:00")
// if !self.ownerCreateTime.IsZero() && self.ownerCreateTime.After(expiredAt) && strings.ToLower(project.Name) == "cn-north-1" {
// continue
// }
s := cloudprovider.SSubAccount{
Id: project.ID,
Name: fmt.Sprintf("%s-%s", self.cpcfg.Name, project.Name),
Account: fmt.Sprintf("%s/%s", self.accessKey, project.ID),
HealthStatus: project.GetHealthStatus(),
DefaultProjectId: "0",
Desc: project.GetDescription(),
}
for j := range self.iregions {
region := self.iregions[j].(*SRegion)
if strings.Contains(project.Name, region.ID) {
s.Desc = region.Locales.ZhCN
break
}
}
subAccounts = append(subAccounts, s)
}
return subAccounts, nil
subAccount := cloudprovider.SSubAccount{}
subAccount.Id = self.GetAccountId()
subAccount.Name = self.cpcfg.Name
subAccount.Account = self.accessKey
subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NORMAL
subAccount.DefaultProjectId = "0"
return []cloudprovider.SSubAccount{subAccount}, nil
}
func (client *SHuaweiClient) GetAccountId() string {
return client.ownerId
ownerId, _ := client.GetOwnerId()
return ownerId
}
func (client *SHuaweiClient) GetIamLoginUrl() string {
return fmt.Sprintf("https://auth.huaweicloud.com/authui/login.html?account=%s#/login", client.ownerName)
}
func (self *SHuaweiClient) GetIRegions() []cloudprovider.ICloudRegion {
return self.iregions
}
func (self *SHuaweiClient) getIRegionByRegionId(id string) (cloudprovider.ICloudRegion, error) {
for i := 0; i < len(self.iregions); i += 1 {
log.Debugf("%d ID: %s", i, self.iregions[i].GetId())
if self.iregions[i].GetId() == id {
return self.iregions[i], nil
func (self *SHuaweiClient) GetRegions() []SRegion {
ret := []SRegion{}
for id := range self.regions {
if _, ok := self.projects[id]; !ok {
continue
}
region := self.regions[id]
region.client = self
ret = append(ret, region)
}
for id := range self.projects {
project := self.projects[id]
if strings.Contains(project.Name, "_") {
regionId := project.GetRegionId()
if region, ok := self.regions[regionId]; ok {
region.Id = project.Name
region.client = self
ret = append(ret, region)
}
}
}
return nil, cloudprovider.ErrNotFound
return ret
}
func (self *SHuaweiClient) GetIRegions() []cloudprovider.ICloudRegion {
regions := self.GetRegions()
ret := []cloudprovider.ICloudRegion{}
for i := range regions {
ret = append(ret, &regions[i])
}
return ret
}
func (self *SHuaweiClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
for i := 0; i < len(self.iregions); i += 1 {
if self.iregions[i].GetGlobalId() == id {
return self.iregions[i], nil
regions := self.GetIRegions()
for i := range regions {
if regions[i].GetId() == id || regions[i].GetGlobalId() == id {
return regions[i], nil
}
}
return nil, cloudprovider.ErrNotFound
return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
}
func (self *SHuaweiClient) GetRegion(regionId string) *SRegion {
if len(regionId) == 0 {
regionId = HUAWEI_DEFAULT_REGION
}
for i := 0; i < len(self.iregions); i += 1 {
if self.iregions[i].GetId() == regionId {
return self.iregions[i].(*SRegion)
regions := self.GetRegions()
for i := range regions {
if regions[i].Id == regionId {
return &regions[i]
}
}
return nil
}
func (self *SHuaweiClient) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
for i := 0; i < len(self.iregions); i += 1 {
ihost, err := self.iregions[i].GetIHostById(id)
if err == nil {
return ihost, nil
} else if errors.Cause(err) != cloudprovider.ErrNotFound {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SHuaweiClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
for i := 0; i < len(self.iregions); i += 1 {
ivpc, err := self.iregions[i].GetIVpcById(id)
if err == nil {
return ivpc, nil
} else if errors.Cause(err) != cloudprovider.ErrNotFound {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SHuaweiClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
for i := 0; i < len(self.iregions); i += 1 {
istorage, err := self.iregions[i].GetIStorageById(id)
if err == nil {
return istorage, nil
} else if errors.Cause(err) != cloudprovider.ErrNotFound {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
}
type SBalance struct {
Amount float64 `json:"amount"`
Currency string `json:"currency"`
@@ -616,7 +489,7 @@ func (self *SHuaweiClient) GetCapabilities() []string {
cloudprovider.CLOUD_CAPABILITY_SECURITY_GROUP,
cloudprovider.CLOUD_CAPABILITY_EIP,
cloudprovider.CLOUD_CAPABILITY_LOADBALANCER,
// cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE,
cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE,
cloudprovider.CLOUD_CAPABILITY_RDS,
cloudprovider.CLOUD_CAPABILITY_CACHE,
cloudprovider.CLOUD_CAPABILITY_EVENT,
@@ -627,16 +500,8 @@ func (self *SHuaweiClient) GetCapabilities() []string {
cloudprovider.CLOUD_CAPABILITY_QUOTA + cloudprovider.READ_ONLY_SUFFIX,
cloudprovider.CLOUD_CAPABILITY_MODELARTES,
cloudprovider.CLOUD_CAPABILITY_VPC_PEER,
}
// huawei objectstore is shared across projects(subscriptions)
// to avoid multiple project access the same bucket
// only main project is allow to access objectstore bucket
if self.isMainProject {
caps = append(caps, cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE)
}
if self.isDefaultProject {
caps = append(caps, cloudprovider.CLOUD_CAPABILITY_CERT)
caps = append(caps, cloudprovider.CLOUD_CAPABILITY_CDN+cloudprovider.READ_ONLY_SUFFIX)
cloudprovider.CLOUD_CAPABILITY_CERT,
cloudprovider.CLOUD_CAPABILITY_CDN + cloudprovider.READ_ONLY_SUFFIX,
}
return caps
}
@@ -698,20 +563,12 @@ func (self *SHuaweiClient) GetOwnerId() (string, error) {
return self.ownerId, nil
}
func (self *SHuaweiClient) initOwner() error {
_, err := self.GetOwnerId()
if err != nil {
return errors.Wrap(err, "SHuaweiClient.initOwner")
}
return nil
}
func (self *SHuaweiClient) list(service, regionId, resource string, query url.Values) (jsonutils.JSONObject, error) {
url, err := self.getUrl(service, regionId, resource, httputils.GET, nil)
if err != nil {
return nil, err
}
return self.request(httputils.GET, url, query, nil)
return self.request(httputils.GET, regionId, url, query, nil)
}
func (self *SHuaweiClient) delete(service, regionId, resource string) (jsonutils.JSONObject, error) {
@@ -719,12 +576,21 @@ func (self *SHuaweiClient) delete(service, regionId, resource string) (jsonutils
if err != nil {
return nil, err
}
return self.request(httputils.DELETE, url, nil, nil)
return self.request(httputils.DELETE, regionId, url, nil, nil)
}
func (self *SHuaweiClient) getUrl(service, regionId, resource string, method httputils.THttpMethod, params map[string]interface{}) (string, error) {
url := ""
resource = strings.TrimPrefix(resource, "/")
if len(regionId) == 0 {
regionId = HUAWEI_DEFAULT_REGION
}
projectId := ""
project, ok := self.projects[regionId]
if ok {
regionId = project.GetRegionId()
projectId = project.Id
}
switch service {
case SERVICE_IAM:
url = fmt.Sprintf("https://iam.myhuaweicloud.com/v3.0/%s", resource)
@@ -733,60 +599,60 @@ func (self *SHuaweiClient) getUrl(service, regionId, resource string, method htt
case SERVICE_IAM_V3_EXT:
url = fmt.Sprintf("https://iam.myhuaweicloud.com/v3-ext/%s", resource)
case SERVICE_ELB:
url = fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v3/%s/%s", regionId, projectId, resource)
case SERVICE_VPC:
url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, projectId, resource)
case SERVICE_VPC_V2_0:
url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v2.0/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v2.0/%s/%s", regionId, projectId, resource)
if strings.Contains(resource, "/peerings") {
url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v2.0/%s", regionId, resource)
}
case SERVICE_VPC_V3:
url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v3/%s/%s", regionId, projectId, resource)
case SERVICE_CES:
url = fmt.Sprintf("https://ces.%s.myhuaweicloud.com/v1.0/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://ces.%s.myhuaweicloud.com/v1.0/%s/%s", regionId, projectId, resource)
case SERVICE_MODELARTS:
url = fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/%s", regionId, projectId, resource)
case SERVICE_MODELARTS_V1:
url = fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v1/%s/%s", regionId, projectId, resource)
case SERVICE_RDS:
url = fmt.Sprintf("https://rds.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://rds.%s.myhuaweicloud.com/v3/%s/%s", regionId, projectId, resource)
case SERVICE_ECS:
url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/v1/%s/%s", regionId, projectId, resource)
case SERVICE_ECS_V1_1:
url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/v1.1/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/v1.1/%s/%s", regionId, projectId, resource)
case SERVICE_ECS_V2_1:
url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/v2.1/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/v2.1/%s/%s", regionId, projectId, resource)
case SERVICE_EPS:
url = fmt.Sprintf("https://eps.myhuaweicloud.com/v1.0/%s", resource)
case SERVICE_EVS_V1:
url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/v1/%s/%s", regionId, projectId, resource)
case SERVICE_EVS:
url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/v2/%s/%s", regionId, projectId, resource)
case SERVICE_EVS_V2_1:
url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/v2.1/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/v2.1/%s/%s", regionId, projectId, resource)
case SERVICE_BSS:
url = fmt.Sprintf("https://bss.myhuaweicloud.com/v2/%s", resource)
case SERVICE_SFS:
url = fmt.Sprintf("https://sfs-turbo.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://sfs-turbo.%s.myhuaweicloud.com/v1/%s/%s", regionId, projectId, resource)
case SERVICE_IMS:
url = fmt.Sprintf("https://ims.%s.myhuaweicloud.com/v2/%s", regionId, resource)
case SERVICE_IMS_V1:
url = fmt.Sprintf("https://ims.%s.myhuaweicloud.com/v1/%s", regionId, resource)
case SERVICE_DCS:
url = fmt.Sprintf("https://dcs.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://dcs.%s.myhuaweicloud.com/v2/%s/%s", regionId, projectId, resource)
case SERVICE_CTS:
url = fmt.Sprintf("https://cts.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://cts.%s.myhuaweicloud.com/v3/%s/%s", regionId, projectId, resource)
case SERVICE_NAT:
url = fmt.Sprintf("https://nat.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource)
url = fmt.Sprintf("https://nat.%s.myhuaweicloud.com/v3/%s/%s", regionId, projectId, resource)
case SERVICE_SCM:
url = fmt.Sprintf("https://scm.cn-north-4.myhuaweicloud.com/v3/%s", resource)
case SERVICE_CDN:
url = fmt.Sprintf("https://cdn.myhuaweicloud.com/v1.0/%s", resource)
case SERVICE_GAUSSDB, SERVICE_GAUSSDB_NOSQL:
url = fmt.Sprintf("https://%s.%s.myhuaweicloud.com/v3/%s/%s", service, regionId, self.projectId, resource)
url = fmt.Sprintf("https://%s.%s.myhuaweicloud.com/v3/%s/%s", service, regionId, projectId, resource)
case SERVICE_FUNCTIONGRAPH:
url = fmt.Sprintf("https://%s.%s.myhuaweicloud.com/v2/%s/%s", service, regionId, self.projectId, resource)
url = fmt.Sprintf("https://%s.%s.myhuaweicloud.com/v2/%s/%s", service, regionId, projectId, resource)
default:
return "", fmt.Errorf("invalid service %s", service)
}
@@ -798,7 +664,7 @@ func (self *SHuaweiClient) post(service, regionId, resource string, params map[s
if err != nil {
return nil, err
}
return self.request(httputils.POST, url, nil, params)
return self.request(httputils.POST, regionId, url, nil, params)
}
func (self *SHuaweiClient) patch(service, regionId, resource string, query url.Values, params map[string]interface{}) (jsonutils.JSONObject, error) {
@@ -806,7 +672,7 @@ func (self *SHuaweiClient) patch(service, regionId, resource string, query url.V
if err != nil {
return nil, err
}
return self.request(httputils.PATCH, url, query, params)
return self.request(httputils.PATCH, regionId, url, query, params)
}
func (self *SHuaweiClient) put(service, regionId, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) {
@@ -814,5 +680,5 @@ func (self *SHuaweiClient) put(service, regionId, resource string, params map[st
if err != nil {
return nil, err
}
return self.request(httputils.PUT, url, nil, params)
return self.request(httputils.PUT, regionId, url, nil, params)
}

View File

@@ -761,7 +761,7 @@ func (self *SRegion) CreateInstance(keypair, zoneId string, opts *cloudprovider.
})
}
extendparam := map[string]interface{}{
"regionID": self.GetId(),
"regionID": self.getId(),
"chargingMode": POST_PAID,
}
if len(opts.ProjectId) > 0 {

View File

@@ -559,6 +559,11 @@ func (self *SRegion) CreateLoadBalancer(opts *cloudprovider.SLoadbalancerCreateO
return nil, errors.Wrap(err, "getNetwork")
}
projectId := ""
project, ok := self.client.projects[self.Id]
if ok {
projectId = project.Id
}
params := map[string]interface{}{
"name": opts.Name,
"description": opts.Desc,
@@ -566,7 +571,7 @@ func (self *SRegion) CreateLoadBalancer(opts *cloudprovider.SLoadbalancerCreateO
"provider": "vlb",
"admin_state_up": true,
"guaranteed": true,
"project_id": self.client.projectId,
"project_id": projectId,
"charge_mode": "lcu",
}
if len(opts.ProjectId) > 0 {

View File

@@ -150,9 +150,9 @@ func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreat
}
if len(netId) == 0 {
createNetObj, err := self.client.CreatePoolNetworks(args.Cidr)
createNetObj, err := self.CreatePoolNetworks(args.Cidr)
if err != nil {
return nil, errors.Wrap(err, "SHuaweiClient.CreatePoolNetworks")
return nil, errors.Wrap(err, "CreatePoolNetworks")
}
netId, _ = createNetObj.GetString("metadata", "name")
for i := 0; i < 10; i++ {
@@ -290,11 +290,7 @@ type ModelartsStatistics struct {
Value float64
}
func (self *SHuaweiClient) GetPoolNetworks(poolName string) (jsonutils.JSONObject, error) {
return self.list(SERVICE_MODELARTS_V1, self.clientRegion, "networks", nil)
}
func (self *SHuaweiClient) CreatePoolNetworks(cidr string) (jsonutils.JSONObject, error) {
func (self *SRegion) CreatePoolNetworks(cidr string) (jsonutils.JSONObject, error) {
params := map[string]interface{}{
"apiVersion": "v1",
"kind": "Network",
@@ -308,7 +304,7 @@ func (self *SHuaweiClient) CreatePoolNetworks(cidr string) (jsonutils.JSONObject
"cidr": cidr,
},
}
return self.post(SERVICE_MODELARTS_V1, self.clientRegion, "networks", params)
return self.post(SERVICE_MODELARTS_V1, "networks", params)
}
func (self *SModelartsPool) GetCreatedAt() time.Time {

View File

@@ -73,7 +73,7 @@ func (self *SHuaweiClient) getServerMetrics(opts *cloudprovider.MetricListOption
})
}
params["metrics"] = metrics
resp, err := self.post(SERVICE_CES, self.clientRegion, "batch-query-metric-data", params)
resp, err := self.post(SERVICE_CES, opts.RegionExtId, "batch-query-metric-data", params)
if err != nil {
return nil, err
}
@@ -155,7 +155,7 @@ func (self *SHuaweiClient) getServerAgentMetrics(opts *cloudprovider.MetricListO
})
}
params["metrics"] = metrics
resp, err := self.post(SERVICE_CES, self.clientRegion, "batch-query-metric-data", params)
resp, err := self.post(SERVICE_CES, opts.RegionExtId, "batch-query-metric-data", params)
if err != nil {
return nil, err
}
@@ -226,7 +226,7 @@ func (self *SHuaweiClient) getRedisMetrics(opts *cloudprovider.MetricListOptions
})
}
params["metrics"] = metrics
resp, err := self.post(SERVICE_CES, self.clientRegion, "batch-query-metric-data", params)
resp, err := self.post(SERVICE_CES, opts.RegionExtId, "batch-query-metric-data", params)
if err != nil {
return nil, err
}
@@ -322,7 +322,7 @@ func (self *SHuaweiClient) getRdsMetrics(opts *cloudprovider.MetricListOptions)
})
}
params["metrics"] = metrics
resp, err := self.post(SERVICE_CES, self.clientRegion, "batch-query-metric-data", params)
resp, err := self.post(SERVICE_CES, opts.RegionExtId, "batch-query-metric-data", params)
if err != nil {
return nil, err
}
@@ -411,7 +411,7 @@ func (self *SHuaweiClient) getBucketMetrics(opts *cloudprovider.MetricListOption
})
}
params["metrics"] = metrics
resp, err := self.post(SERVICE_CES, self.clientRegion, "batch-query-metric-data", params)
resp, err := self.post(SERVICE_CES, opts.RegionExtId, "batch-query-metric-data", params)
if err != nil {
return nil, err
}
@@ -492,7 +492,7 @@ func (self *SHuaweiClient) getLoadbalancerMetrics(opts *cloudprovider.MetricList
})
}
params["metrics"] = metrics
resp, err := self.post(SERVICE_CES, self.clientRegion, "batch-query-metric-data", params)
resp, err := self.post(SERVICE_CES, opts.RegionExtId, "batch-query-metric-data", params)
if err != nil {
return nil, err
}
@@ -545,7 +545,7 @@ func (self *SHuaweiClient) getLoadbalancerMetrics(opts *cloudprovider.MetricList
func (self *SHuaweiClient) getModelartsPoolMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
resource := fmt.Sprintf("pools/%s/monitor", opts.ResourceId)
resp, err := self.list(SERVICE_MODELARTS, self.clientRegion, resource, nil)
resp, err := self.list(SERVICE_MODELARTS, opts.RegionExtId, resource, nil)
if err != nil {
return nil, err
}

View File

@@ -18,43 +18,34 @@ import (
"fmt"
"strings"
api "yunion.io/x/cloudmux/pkg/apis/compute"
"yunion.io/x/pkg/errors"
)
// https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845625.html
type SProject struct {
client *SHuaweiClient
IsDomain bool `json:"is_domain"`
Description string `json:"description"`
Enabled bool `json:"enabled"`
ID string `json:"id"`
ParentID string `json:"parent_id"`
DomainID string `json:"domain_id"`
Name string `json:"name"`
IsDomain bool
Description string
Enabled bool
Id string
ParentId string
DomainId string
Name string
}
func (self *SProject) GetRegionID() string {
func (self *SProject) GetRegionId() string {
return strings.Split(self.Name, "_")[0]
}
func (self *SProject) GetDescription() string {
return self.Description
}
func (self *SProject) GetHealthStatus() string {
if self.Enabled {
return api.CLOUD_PROVIDER_HEALTH_NORMAL
}
return api.CLOUD_PROVIDER_HEALTH_SUSPENDED
}
func (self *SHuaweiClient) fetchProjects() ([]SProject, error) {
func (self *SHuaweiClient) GetProjects() ([]SProject, error) {
if len(self.projects) > 0 {
return self.projects, nil
ret := []SProject{}
for _, project := range self.projects {
ret = append(ret, project)
}
return ret, nil
}
self.projects = map[string]SProject{}
projects := []SProject{}
resp, err := self.list(SERVICE_IAM_V3, "", "auth/projects", nil)
if err != nil {
@@ -64,8 +55,10 @@ func (self *SHuaweiClient) fetchProjects() ([]SProject, error) {
if err != nil {
return nil, errors.Wrapf(err, "Unmarshal")
}
self.projects = projects
return self.projects, nil
for _, project := range projects {
self.projects[project.Name] = project
}
return projects, nil
}
// obs 权限必须赋予到mos project之上
@@ -76,26 +69,22 @@ func (self *SHuaweiClient) GetMosProjectId() string {
}
for i := range projects {
if strings.ToLower(projects[i].Name) == "mos" {
return projects[i].ID
return projects[i].Id
}
}
return ""
}
func (self *SHuaweiClient) GetProjectById(projectId string) (SProject, error) {
projects, err := self.fetchProjects()
projects, err := self.GetProjects()
if err != nil {
return SProject{}, err
}
for _, project := range projects {
if project.ID == projectId {
if project.Id == projectId {
return project, nil
}
}
return SProject{}, fmt.Errorf("project %s not found", projectId)
}
func (self *SHuaweiClient) GetProjects() ([]SProject, error) {
return self.fetchProjects()
}

View File

@@ -16,7 +16,6 @@ package provider
import (
"context"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
@@ -111,24 +110,10 @@ func (self *SHuaweiProviderFactory) ValidateUpdateCloudaccountCredential(ctx con
return output, 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(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) {
accessKey, projectId := parseAccount(cfg.Account)
client, err := huawei.NewHuaweiClient(
huawei.NewHuaweiClientConfig(
accessKey, cfg.Secret, projectId,
cfg.Account, cfg.Secret,
).CloudproviderConfig(cfg),
)
if err != nil {
@@ -141,16 +126,10 @@ func (self *SHuaweiProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig
}
func (self *SHuaweiProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) {
accessKey, projectId := parseAccount(info.Account)
data := strings.Split(info.Name, "-")
if len(info.Region) == 0 && len(data) >= 3 {
info.Region = strings.Join(data[len(data)-3:], "-")
}
return map[string]string{
"HUAWEI_ACCESS_KEY": accessKey,
"HUAWEI_ACCESS_KEY": info.Account,
"HUAWEI_SECRET": info.Secret,
"HUAWEI_REGION": info.Region,
"HUAWEI_PROJECT": projectId,
"HUAWEI_REGION": huawei.HUAWEI_DEFAULT_REGION,
}, nil
}
@@ -211,7 +190,7 @@ func (self *SHuaweiProvider) GetIamLoginUrl() string {
}
func (self *SHuaweiProvider) GetCloudRegionExternalIdPrefix() string {
return self.client.GetCloudRegionExternalIdPrefix()
return api.CLOUD_PROVIDER_HUAWEI + "/"
}
func (self *SHuaweiProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) {

View File

@@ -35,18 +35,17 @@ type Locales struct {
ZhCN string `json:"zh-cn"`
}
// https://support.huaweicloud.com/api-iam/zh-cn_topic_0067148043.html
type SRegion struct {
multicloud.SRegion
client *SHuaweiClient
obsClient *obs.ObsClient // 对象存储client.请勿直接引用。
Description string `json:"description"`
ID string `json:"id"`
Locales Locales `json:"locales"`
ParentRegionID string `json:"parent_region_id"`
Type string `json:"type"`
Description string
Id string
Locales Locales
ParentRegionId string
Type string
storageCache *SStoragecache
}
@@ -56,32 +55,32 @@ func (self *SRegion) GetClient() *SHuaweiClient {
}
func (self *SRegion) list(service, resource string, query url.Values) (jsonutils.JSONObject, error) {
return self.client.list(service, self.ID, resource, query)
return self.client.list(service, self.Id, resource, query)
}
func (self *SRegion) delete(service, resource string) (jsonutils.JSONObject, error) {
return self.client.delete(service, self.ID, resource)
return self.client.delete(service, self.Id, resource)
}
func (self *SRegion) put(service, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) {
return self.client.put(service, self.ID, resource, params)
return self.client.put(service, self.Id, resource, params)
}
func (self *SRegion) post(service, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) {
return self.client.post(service, self.ID, resource, params)
return self.client.post(service, self.Id, resource, params)
}
func (self *SRegion) patch(service, resource string, query url.Values, params map[string]interface{}) (jsonutils.JSONObject, error) {
return self.client.patch(service, self.ID, resource, query, params)
return self.client.patch(service, self.Id, resource, query, params)
}
func (self *SRegion) getOBSEndpoint() string {
return getOBSEndpoint(self.GetId())
return getOBSEndpoint(self.getId())
}
func (self *SRegion) getOBSClient(signType obs.SignatureType) (*obs.ObsClient, error) {
if self.obsClient == nil {
obsClient, err := self.client.getOBSClient(self.GetId(), signType)
obsClient, err := self.client.getOBSClient(self.getId(), signType)
if err != nil {
return nil, err
}
@@ -119,7 +118,7 @@ func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
}
func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo {
if info, ok := LatitudeAndLongitude[self.ID]; ok {
if info, ok := LatitudeAndLongitude[self.getId()]; ok {
return info
}
return cloudprovider.SGeographicInfo{}
@@ -206,24 +205,49 @@ func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadb
return iret, nil
}
// https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845622.html
func (self *SRegion) GetId() string {
return self.ID
return self.Id
}
func (self *SRegion) GetName() string {
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.Locales.ZhCN)
name := self.Locales.ZhCN
suffix := self.getSuffix()
if len(suffix) > 0 {
name = fmt.Sprintf("%s-%s", name, suffix)
}
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, name)
}
func (self *SRegion) getId() string {
idx := strings.Index(self.Id, "_")
if idx > 0 {
return self.Id[:idx]
}
return self.Id
}
func (self *SRegion) getSuffix() string {
idx := strings.Index(self.Id, "_")
if idx > 0 {
return self.Id[idx+1:]
}
return ""
}
func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable {
en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.Locales.EnUs)
en := self.Locales.EnUs
suffix := self.getSuffix()
if len(suffix) > 0 {
en = fmt.Sprintf("%s-%s", en, suffix)
}
en = fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, en)
table := cloudprovider.SModelI18nTable{}
table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en)
return table
}
func (self *SRegion) GetGlobalId() string {
return fmt.Sprintf("%s/%s", api.CLOUD_PROVIDER_HUAWEI, self.ID)
return fmt.Sprintf("%s/%s", api.CLOUD_PROVIDER_HUAWEI, self.Id)
}
func (self *SRegion) GetStatus() string {
@@ -234,24 +258,6 @@ func (self *SRegion) Refresh() error {
return nil
}
func (self *SRegion) IsEmulated() bool {
return false
}
func (self *SRegion) GetLatitude() float32 {
if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok {
return locationInfo.Latitude
}
return 0.0
}
func (self *SRegion) GetLongitude() float32 {
if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok {
return locationInfo.Longitude
}
return 0.0
}
func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
zones, err := self.GetZones()
if err != nil {
@@ -494,7 +500,10 @@ func (self *SRegion) CreateSecurityGroup(opts *cloudprovider.SecurityGroupCreate
params := map[string]interface{}{
"name": opts.Name,
"description": opts.Desc,
"enterprise_project_id": opts.ProjectId,
"enterprise_project_id": "0",
}
if len(opts.ProjectId) > 0 {
params["enterprise_project_id"] = opts.ProjectId
}
resp, err := self.post(SERVICE_VPC_V3, "vpc/security-groups", map[string]interface{}{"security_group": params})
if err != nil {
@@ -556,7 +565,7 @@ func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr
}
input := &obs.CreateBucketInput{}
input.Bucket = name
input.Location = region.GetId()
input.Location = region.getId()
if len(aclStr) > 0 {
if strings.EqualFold(aclStr, string(obs.AclPrivate)) {
input.ACL = obs.AclPrivate
@@ -673,22 +682,6 @@ func (self *SRegion) GetDiskTypes() ([]SDiskType, error) {
return ret, nil
}
func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error) {
dts, err := self.GetDiskTypes()
if err != nil {
return nil, errors.Wrap(err, "GetDiskTypes")
}
ret := []string{}
for i := range dts {
if dts[i].IsAvaliableInZone(zoneId) {
ret = append(ret, dts[i].Name)
}
}
return ret, nil
}
func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
vms, err := region.GetInstances("")
if err != nil {

View File

@@ -30,19 +30,20 @@ type SStorage struct {
zone *SZone
multicloud.SStorageBase
HuaweiTags
storageType string // volume_type 目前支持“SSD”“SAS”和“SATA”三种
storageType string
volumeTypeId string
}
func (self *SStorage) GetId() string {
return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType)
return fmt.Sprintf("%s-%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.region.Id, self.zone.GetId(), self.storageType)
}
func (self *SStorage) GetName() string {
return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType)
return fmt.Sprintf("%s-%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.region.Id, self.zone.GetId(), self.storageType)
}
func (self *SStorage) GetGlobalId() string {
return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType)
return fmt.Sprintf("%s-%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.region.Id, self.zone.GetGlobalId(), self.storageType)
}
func (self *SStorage) GetStatus() string {
@@ -66,26 +67,16 @@ func (self *SStorage) GetIZone() cloudprovider.ICloudZone {
}
func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
disks, err := self.zone.region.GetDisks(self.zone.GetId())
disks, err := self.zone.region.GetDisks(self.zone.ZoneName, self.volumeTypeId)
if err != nil {
return nil, err
}
// 按storage type 过滤出disk
filtedDisks := make([]SDisk, 0)
for i := range disks {
disk := disks[i]
if disk.VolumeType == self.storageType {
filtedDisks = append(filtedDisks, disk)
}
ret := []cloudprovider.ICloudDisk{}
for i := 0; i < len(disks); i += 1 {
disks[i].storage = self
ret = append(ret, &disks[i])
}
idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks))
for i := 0; i < len(filtedDisks); i += 1 {
filtedDisks[i].storage = self
idisks[i] = &filtedDisks[i]
}
return idisks, nil
return ret, nil
}
func (self *SStorage) GetStorageType() string {

View File

@@ -98,7 +98,7 @@ func (event *SEvent) GetCreatedAt() time.Time {
}
func (self *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) {
if !self.client.isMainProject {
if self.Id != HUAWEI_DEFAULT_REGION {
return nil, cloudprovider.ErrNotSupported
}
events, err := self.GetEvents(start, end)

View File

@@ -197,7 +197,11 @@ func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error {
}
func (self *SVpc) GetAuthorityOwnerId() string {
return self.region.client.projectId
project, ok := self.region.client.projects[self.region.Id]
if ok {
return project.Id
}
return ""
}
func (self *SVpc) getVpcPeeringConnections() ([]SVpcPeering, error) {

View File

@@ -88,13 +88,17 @@ func (self *SRegion) GetVpcPeering(id string) (*SVpcPeering, error) {
// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=CreateVpcPeering
func (self *SRegion) CreateVpcPeering(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPeering, error) {
projectId := ""
if project, ok := self.client.projects[self.Id]; ok {
projectId = project.Id
}
params := map[string]interface{}{
"peering": map[string]interface{}{
"name": opts.Name,
"description": opts.Desc,
"request_vpc_info": map[string]interface{}{
"vpc_id": vpcId,
"tenant_id": self.client.projectId,
"tenant_id": projectId,
},
"accept_vpc_info": map[string]interface{}{
"vpc_id": opts.PeerVpcId,

View File

@@ -16,8 +16,8 @@ package huawei
import (
"fmt"
"strings"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
api "yunion.io/x/cloudmux/pkg/apis/compute"
@@ -25,57 +25,23 @@ import (
"yunion.io/x/cloudmux/pkg/multicloud"
)
var StorageTypes = []string{
api.STORAGE_HUAWEI_SAS,
api.STORAGE_HUAWEI_SATA,
api.STORAGE_HUAWEI_SSD,
}
type ZoneState struct {
Available bool `json:"available"`
}
// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0065817728.html
type SZone struct {
multicloud.SResourceBase
HuaweiTags
region *SRegion
host *SHost
istorages []cloudprovider.ICloudStorage
ZoneState ZoneState `json:"zoneState"`
ZoneName string `json:"zoneName"`
/* 支持的磁盘种类集合 */
storageTypes []string
}
func (self *SZone) getStorageType() {
if len(self.storageTypes) == 0 {
if sts, err := self.region.GetZoneSupportedDiskTypes(self.GetId()); err == nil {
self.storageTypes = sts
} else {
log.Errorf("GetZoneSupportedDiskTypes %s %s", self.GetId(), err)
self.storageTypes = StorageTypes
}
}
}
func (self *SZone) fetchStorages() error {
self.getStorageType()
self.istorages = make([]cloudprovider.ICloudStorage, len(self.storageTypes))
for i, sc := range self.storageTypes {
storage := SStorage{zone: self, storageType: sc}
self.istorages[i] = &storage
}
return nil
}
func (self *SZone) getHost() *SHost {
if self.host == nil {
self.host = &SHost{zone: self, projectId: self.region.client.projectId}
self.host = &SHost{zone: self}
}
return self.host
}
@@ -96,7 +62,7 @@ func (self *SZone) GetI18n() cloudprovider.SModelI18nTable {
}
func (self *SZone) GetGlobalId() string {
return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneName)
return fmt.Sprintf("%s/%s/%s", api.CLOUD_PROVIDER_HUAWEI, self.region.getId(), self.ZoneName)
}
func (self *SZone) GetStatus() string {
@@ -128,28 +94,34 @@ func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
}
func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
if self.istorages == nil {
err := self.fetchStorages()
if err != nil {
return nil, errors.Wrapf(err, "fetchStorages")
storageTypes, err := self.region.GetDiskTypes()
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudStorage{}
for _, storageType := range storageTypes {
if strings.Contains(storageType.ExtraSpecs.RESKEYAvailabilityZones, self.ZoneName) {
ret = append(ret, &SStorage{
zone: self,
storageType: storageType.Name,
volumeTypeId: storageType.Id,
})
}
}
return self.istorages, nil
return ret, nil
}
func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
if self.istorages == nil {
err := self.fetchStorages()
if err != nil {
return nil, errors.Wrapf(err, "fetchStorages")
storages, err := self.GetIStorages()
if err != nil {
return nil, err
}
for i := range storages {
if storages[i].GetGlobalId() == id {
return storages[i], nil
}
}
for i := 0; i < len(self.istorages); i += 1 {
if self.istorages[i].GetGlobalId() == id {
return self.istorages[i], nil
}
}
return nil, cloudprovider.ErrNotFound
return nil, errors.Wrapf(cloudprovider.ErrNotFound, id)
}
func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) {
@@ -180,14 +152,15 @@ func (self *SZone) getStorageByCategory(category string) (*SStorage, error) {
}
func (self *SRegion) getZoneById(id string) (*SZone, error) {
izones, err := self.GetIZones()
zones, err := self.GetZones()
if err != nil {
return nil, err
}
for i := 0; i < len(izones); i += 1 {
zone := izones[i].(*SZone)
for i := 0; i < len(zones); i += 1 {
zones[i].region = self
zone := zones[i]
if zone.GetId() == id {
return zone, nil
return &zone, nil
}
}
return nil, fmt.Errorf("no such zone %s", id)