From 7a922aeedebae5eea0593d2fd5e86f0219e2dd82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Wed, 20 Dec 2023 19:31:18 +0800 Subject: [PATCH] fix(region): refactor huawei api for support organization (#19068) --- go.mod | 2 +- go.sum | 4 +- pkg/compute/guestdrivers/managedvirtual.go | 3 + pkg/compute/models/elasticcache_instances.go | 25 +- pkg/compute/models/vpc_peering_connections.go | 6 +- pkg/compute/models/vpcs.go | 2 +- .../vpc_peering_connection_create_task.go | 2 +- .../vpc_peering_connection_syncstatus_task.go | 2 +- vendor/modules.txt | 10 +- .../x/cloudmux/pkg/cloudprovider/errors.go | 1 + .../multicloud/hcso/client/modules/mod_ces.go | 50 +- .../x/cloudmux/pkg/multicloud/hcso/monitor.go | 2 +- .../huawei/client/auth/credential.go | 18 - .../auth/credentials/access_key_credential.go | 27 - .../huawei/client/auth/credentials/doc.go | 15 - .../pkg/multicloud/huawei/client/auth/doc.go | 15 - .../multicloud/huawei/client/auth/signer.go | 215 ---- .../huawei/client/auth/signers/doc.go | 15 - .../client/auth/signers/signer_access_key.go | 55 - .../pkg/multicloud/huawei/client/client.go | 232 ---- .../pkg/multicloud/huawei/client/doc.go | 15 - .../multicloud/huawei/client/manager/doc.go | 15 - .../huawei/client/manager/manager.go | 81 -- .../multicloud/huawei/client/modules/doc.go | 15 - .../huawei/client/modules/manager_base.go | 271 ----- .../huawei/client/modules/manager_resource.go | 298 ----- .../huawei/client/modules/mod_ces.go | 152 --- .../huawei/client/modules/mod_credential.go | 37 - .../huawei/client/modules/mod_dbinstance.go | 103 -- .../client/modules/mod_dbinstance_backup.go | 37 - .../client/modules/mod_dbinstance_flavor.go | 37 - .../client/modules/mod_dbinstance_job.go | 43 - .../huawei/client/modules/mod_disks.go | 76 -- .../huawei/client/modules/mod_dnat_rules.go | 41 - .../huawei/client/modules/mod_domains.go | 95 -- .../huawei/client/modules/mod_elasticcache.go | 118 -- .../client/modules/mod_enterpriceprojects.go | 39 - .../huawei/client/modules/mod_flavors.go | 37 - .../huawei/client/modules/mod_groups.go | 39 - .../huawei/client/modules/mod_images.go | 102 -- .../huawei/client/modules/mod_interface.go | 38 - .../huawei/client/modules/mod_jobs.go | 71 -- .../huawei/client/modules/mod_mapping.go | 39 - .../huawei/client/modules/mod_natgateway.go | 50 - .../huawei/client/modules/mod_orders.go | 104 -- .../huawei/client/modules/mod_port.go | 53 - .../huawei/client/modules/mod_projects.go | 89 -- .../huawei/client/modules/mod_regions.go | 37 - .../huawei/client/modules/mod_roles.go | 39 - .../huawei/client/modules/mod_routetables.go | 37 - .../client/modules/mod_saml_provider.go | 39 - .../huawei/client/modules/mod_servers.go | 124 -- .../huawei/client/modules/mod_sfs.go | 48 - .../huawei/client/modules/mod_snapshots.go | 59 - .../huawei/client/modules/mod_snat_rules.go | 41 - .../huawei/client/modules/mod_subnets.go | 37 - .../huawei/client/modules/mod_traces.go | 37 - .../huawei/client/modules/mod_users.go | 69 -- .../huawei/client/modules/mod_vpc_peerings.go | 37 - .../huawei/client/modules/mod_vpc_routes.go | 38 - .../huawei/client/modules/mod_vpcs.go | 37 - .../huawei/client/modules/mod_zones.go | 37 - .../multicloud/huawei/client/requests/doc.go | 15 - .../huawei/client/requests/requests.go | 276 ----- .../multicloud/huawei/client/responses/doc.go | 15 - .../huawei/client/responses/responses.go | 77 -- .../pkg/multicloud/huawei/cloudgroup.go | 213 ++-- .../pkg/multicloud/huawei/clouduser.go | 83 +- .../pkg/multicloud/huawei/dbinstance.go | 163 ++- .../multicloud/huawei/dbinstance_account.go | 90 +- .../multicloud/huawei/dbinstance_backup.go | 53 +- .../multicloud/huawei/dbinstance_database.go | 37 +- .../multicloud/huawei/dbinstance_parameter.go | 19 +- .../x/cloudmux/pkg/multicloud/huawei/disk.go | 259 ++-- .../cloudmux/pkg/multicloud/huawei/domain.go | 15 +- .../x/cloudmux/pkg/multicloud/huawei/eip.go | 52 +- .../multicloud/huawei/elasticcache_account.go | 32 +- .../multicloud/huawei/elasticcache_backup.go | 11 +- .../huawei/elasticcache_instance.go | 483 ++++---- .../multicloud/huawei/enterpriseprojects.go | 48 +- .../x/cloudmux/pkg/multicloud/huawei/host.go | 151 +-- .../cloudmux/pkg/multicloud/huawei/huawei.go | 197 ++-- .../x/cloudmux/pkg/multicloud/huawei/image.go | 235 ++-- .../pkg/multicloud/huawei/instance.go | 1048 +++++------------ .../pkg/multicloud/huawei/instancenic.go | 74 +- .../pkg/multicloud/huawei/instancetype.go | 30 +- .../cloudmux/pkg/multicloud/huawei/keypair.go | 5 +- .../pkg/multicloud/huawei/loadbalancer.go | 31 +- .../multicloud/huawei/loadbalancer_backend.go | 38 +- .../huawei/loadbalancer_backendgroup.go | 4 +- .../pkg/multicloud/huawei/modelarts_pool.go | 6 +- .../multicloud/huawei/modelarts_pool_sku.go | 2 +- .../cloudmux/pkg/multicloud/huawei/monitor.go | 9 - .../pkg/multicloud/huawei/natdtable.go | 57 +- .../pkg/multicloud/huawei/natgateway.go | 138 ++- .../pkg/multicloud/huawei/natstable.go | 57 +- .../cloudmux/pkg/multicloud/huawei/network.go | 75 +- .../x/cloudmux/pkg/multicloud/huawei/order.go | 204 +--- .../x/cloudmux/pkg/multicloud/huawei/port.go | 52 +- .../cloudmux/pkg/multicloud/huawei/project.go | 21 +- .../multicloud/huawei/provider/provider.go | 8 +- .../cloudmux/pkg/multicloud/huawei/region.go | 194 +-- .../x/cloudmux/pkg/multicloud/huawei/roles.go | 45 +- .../pkg/multicloud/huawei/routetables.go | 68 +- .../pkg/multicloud/huawei/saml_provider.go | 119 +- .../pkg/multicloud/huawei/secgrouprule.go | 9 +- .../pkg/multicloud/huawei/securitygroup.go | 12 +- .../pkg/multicloud/huawei/sfs-turbo.go | 47 +- .../pkg/multicloud/huawei/snapshot.go | 101 +- .../cloudmux/pkg/multicloud/huawei/storage.go | 21 +- .../pkg/multicloud/huawei/storagecache.go | 72 +- .../x/cloudmux/pkg/multicloud/huawei/task.go | 83 +- .../cloudmux/pkg/multicloud/huawei/traces.go | 34 +- .../x/cloudmux/pkg/multicloud/huawei/utils.go | 270 ----- .../x/cloudmux/pkg/multicloud/huawei/vpc.go | 160 +-- .../pkg/multicloud/huawei/vpc_peering.go | 112 +- .../x/cloudmux/pkg/multicloud/huawei/wire.go | 136 +-- .../x/cloudmux/pkg/multicloud/huawei/zone.go | 30 +- 118 files changed, 2256 insertions(+), 7152 deletions(-) delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credential.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/access_key_credential.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/doc.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/doc.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signer.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/doc.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/signer_access_key.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/client.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/doc.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/doc.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/manager.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/doc.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_base.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_resource.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_ces.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_credential.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_backup.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_flavor.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_job.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_disks.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dnat_rules.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_domains.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_elasticcache.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_enterpriceprojects.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_flavors.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_groups.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_images.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_interface.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_jobs.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_mapping.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_natgateway.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_orders.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_port.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_projects.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_regions.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_roles.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_routetables.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_saml_provider.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_servers.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_sfs.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snapshots.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snat_rules.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_subnets.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_traces.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_users.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_peerings.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_routes.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpcs.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_zones.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/doc.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/requests.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/doc.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/responses.go delete mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/utils.go diff --git a/go.mod b/go.mod index 42f4ad67d8..9c4044cdfc 100644 --- a/go.mod +++ b/go.mod @@ -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.20231220031827-28bfe13ab842 + yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231220111524-ab10dde9c9b0 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 diff --git a/go.sum b/go.sum index 77032be8da..50f6631b79 100644 --- a/go.sum +++ b/go.sum @@ -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.20231220031827-28bfe13ab842 h1:4AjLgwOnaAexsd+nrUodqg4m6cm4sB+HaA9deBkd9Tc= -yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231220031827-28bfe13ab842/go.mod h1:aj1gR9PPb6eqqKOwvANe26CoZFY8ydmXy0fuvgKYXH0= +yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231220111524-ab10dde9c9b0 h1:2Sj/zBlEgWaQGNxQXh1ZYLlNzZh0DAsTe3J/+eYBXZE= +yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231220111524-ab10dde9c9b0/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= diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index a4fc71e65d..1761636093 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -590,6 +590,9 @@ func (drv *SManagedVirtualizedGuestDriver) RemoteDeployGuestForCreate(ctx contex if err == nil || !options.Options.EnableAutoSwitchServerSku { return iVM, err } + if errors.Cause(err) != cloudprovider.ErrInvalidSku { + return iVM, err + } skus, e := models.ServerSkuManager.GetSkus(host.GetProviderName(), guest.VcpuCount, guest.VmemSize) if e != nil { return iVM, errors.Wrapf(e, "GetSkus") diff --git a/pkg/compute/models/elasticcache_instances.go b/pkg/compute/models/elasticcache_instances.go index 3a55b73a1f..2aef9492ac 100644 --- a/pkg/compute/models/elasticcache_instances.go +++ b/pkg/compute/models/elasticcache_instances.go @@ -102,7 +102,7 @@ type SElasticcache struct { CapacityMB int `nullable:"false" list:"user" create:"optional" json:"capacity_mb"` // 对应Sku - LocalCategory string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"local_category"` + LocalCategory string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"local_category"` // 类型 // single(单副本) | double(双副本) | readone (单可读) | readthree (3可读) | readfive(5只读) @@ -212,22 +212,23 @@ func (manager *SElasticcacheManager) FetchCustomizeColumns( virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) - vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) netIds := make([]string, len(objs)) cacheIds := make([]string, len(objs)) + vpcIds := make([]string, len(objs)) zoneIds := []string{} for i := range rows { rows[i] = api.ElasticcacheDetails{ VirtualResourceDetails: virtRows[i], - VpcResourceInfo: vpcRows[i], ZoneResourceInfoBase: zoneRows[i].ZoneResourceInfoBase, } rows[i].ManagedResourceInfo = manRows[i] rows[i].CloudregionResourceInfo = regRows[i] - netIds[i] = objs[i].(*SElasticcache).NetworkId - cacheIds[i] = objs[i].(*SElasticcache).Id + cache := objs[i].(*SElasticcache) + netIds[i] = cache.NetworkId + cacheIds[i] = cache.Id + vpcIds[i] = cache.VpcId sz := strings.Split(objs[i].(*SElasticcache).SlaveZones, ",") for j := range sz { @@ -237,8 +238,15 @@ func (manager *SElasticcacheManager) FetchCustomizeColumns( } } + vpcs := make(map[string]SVpc) + err := db.FetchStandaloneObjectsByIds(VpcManager, vpcIds, vpcs) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return nil + } + networks := make(map[string]SNetwork) - err := db.FetchStandaloneObjectsByIds(NetworkManager, netIds, &networks) + err = db.FetchStandaloneObjectsByIds(NetworkManager, netIds, &networks) if err != nil { log.Errorf("FetchStandaloneObjectsByIds fail %s", err) return rows @@ -248,6 +256,11 @@ func (manager *SElasticcacheManager) FetchCustomizeColumns( if net, ok := networks[netIds[i]]; ok { rows[i].Network = net.Name } + if vpc, ok := vpcs[vpcIds[i]]; ok { + rows[i].Vpc = vpc.Name + rows[i].VpcExtId = vpc.ExternalId + rows[i].IsDefaultVpc = vpc.IsDefault + } } if len(fields) == 0 || fields.Contains("secgroups") || fields.Contains("secgroup") { diff --git a/pkg/compute/models/vpc_peering_connections.go b/pkg/compute/models/vpc_peering_connections.go index 20f1ab25fb..54d7ae3d63 100644 --- a/pkg/compute/models/vpc_peering_connections.go +++ b/pkg/compute/models/vpc_peering_connections.go @@ -354,11 +354,15 @@ func (self *SVpcPeeringConnection) syncRemove(ctx context.Context, userCred mccl return self.RealDelete(ctx, userCred) } -func (self *SVpcPeeringConnection) SyncWithCloudPeerConnection(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudVpcPeeringConnection, provider *SCloudprovider) error { +func (self *SVpcPeeringConnection) SyncWithCloudPeerConnection(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudVpcPeeringConnection) error { vpc, err := self.GetVpc() if err != nil { return errors.Wrapf(err, "GetVpc") } + provider := vpc.GetCloudprovider() + if provider == nil { + return errors.Wrapf(cloudprovider.ErrNotFound, "cloudprovider for vpc %s", vpc.Name) + } _, err = db.Update(self, func() error { self.Status = ext.GetStatus() self.ExternalId = ext.GetGlobalId() diff --git a/pkg/compute/models/vpcs.go b/pkg/compute/models/vpcs.go index cfc65fdbe1..b5ef48394a 100644 --- a/pkg/compute/models/vpcs.go +++ b/pkg/compute/models/vpcs.go @@ -1742,7 +1742,7 @@ func (svpc *SVpc) SyncVpcPeeringConnections( if !xor { for i := 0; i < len(commondb); i += 1 { - err = commondb[i].SyncWithCloudPeerConnection(ctx, userCred, commonext[i], provider) + err = commondb[i].SyncWithCloudPeerConnection(ctx, userCred, commonext[i]) if err != nil { result.UpdateError(err) continue diff --git a/pkg/compute/tasks/vpc_peering_connection_create_task.go b/pkg/compute/tasks/vpc_peering_connection_create_task.go index cfaf3556cf..0f6f263ee5 100644 --- a/pkg/compute/tasks/vpc_peering_connection_create_task.go +++ b/pkg/compute/tasks/vpc_peering_connection_create_task.go @@ -90,7 +90,7 @@ func (self *VpcPeeringConnectionCreateTask) OnInit(ctx context.Context, obj db.I } iPeerConnection.Refresh() - err = peer.SyncWithCloudPeerConnection(ctx, self.GetUserCred(), iPeerConnection, nil) + err = peer.SyncWithCloudPeerConnection(ctx, self.GetUserCred(), iPeerConnection) if err != nil { self.taskFailed(ctx, peer, errors.Wrapf(err, "SyncWithCloudPeerConnection")) return diff --git a/pkg/compute/tasks/vpc_peering_connection_syncstatus_task.go b/pkg/compute/tasks/vpc_peering_connection_syncstatus_task.go index 2535205bde..d9b496b93f 100644 --- a/pkg/compute/tasks/vpc_peering_connection_syncstatus_task.go +++ b/pkg/compute/tasks/vpc_peering_connection_syncstatus_task.go @@ -69,7 +69,7 @@ func (self *VpcPeeringConnectionSyncstatusTask) OnInit(ctx context.Context, obj return } - err = peer.SyncWithCloudPeerConnection(ctx, self.UserCred, ipeer, nil) + err = peer.SyncWithCloudPeerConnection(ctx, self.UserCred, ipeer) if err != nil { self.taskFail(ctx, peer, errors.Wrapf(err, "SyncWithCloudPeerConnection(ctx, self.UserCred, %s, nil)", jsonutils.Marshal(ipeer).String())) return diff --git a/vendor/modules.txt b/vendor/modules.txt index be0cd0e8fe..423ded0760 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -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.20231220031827-28bfe13ab842 +# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20231220111524-ab10dde9c9b0 ## explicit; go 1.18 yunion.io/x/cloudmux/pkg/apis yunion.io/x/cloudmux/pkg/apis/billing @@ -1509,14 +1509,6 @@ yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses yunion.io/x/cloudmux/pkg/multicloud/hcso/provider yunion.io/x/cloudmux/pkg/multicloud/huawei -yunion.io/x/cloudmux/pkg/multicloud/huawei/client -yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth -yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials -yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers -yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager -yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules -yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests -yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses yunion.io/x/cloudmux/pkg/multicloud/huawei/obs yunion.io/x/cloudmux/pkg/multicloud/huawei/provider yunion.io/x/cloudmux/pkg/multicloud/jdcloud diff --git a/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/errors.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/errors.go index a07b50f826..40f7618f38 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/errors.go +++ b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/errors.go @@ -29,6 +29,7 @@ const ( ErrNoPermission = errors.Error("NoPermission") ErrNoSuchProvder = errors.Error("no such provider") ErrTooManyRequests = errors.Error("TooManyRequests") + ErrInvalidSku = errors.Error("InvalidSku") ErrNotFound = errors.ErrNotFound ErrDuplicateId = errors.ErrDuplicateId diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_ces.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_ces.go index e92678ddb9..44b56b935c 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_ces.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_ces.go @@ -23,13 +23,45 @@ import ( "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests" - hw_mod "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" ) type SCloudEyeManager struct { SResourceManager } +type SMetricDimension struct { + Name string `json:"name"` + Value string `json:"value"` +} + +type SDatapoint struct { + Timestamp int64 `json:"timestamp"` + Max float64 `json:"max,omitzero"` + Min float64 `json:"min,omitzero"` + Average float64 `json:"average,omitzero"` + Sum float64 `json:"sum,omitzero"` + Variance float64 `json:"variance,omitzero"` +} + +type SMetricData struct { + SMetricMeta + + Datapoints []SDatapoint +} + +type SMetricMeta struct { + SMetric + + Unit string `json:"unit"` +} + +type SMetric struct { + MetricName string `json:"metric_name"` + Namespace string `json:"namespace"` + + Dimensions []SMetricDimension `json:"dimensions"` +} + func NewCloudEyeManager(cfg manager.IManagerConfig) *SCloudEyeManager { return &SCloudEyeManager{SResourceManager: SResourceManager{ SBaseManager: NewBaseManager(cfg), @@ -43,8 +75,8 @@ func NewCloudEyeManager(cfg manager.IManagerConfig) *SCloudEyeManager { }} } -func (ces *SCloudEyeManager) ListMetrics() ([]hw_mod.SMetricMeta, error) { - metrics := make([]hw_mod.SMetricMeta, 0) +func (ces *SCloudEyeManager) ListMetrics() ([]SMetricMeta, error) { + metrics := make([]SMetricMeta, 0) next := "" for { marker, data, err := ces.listMetricsInternal(next) @@ -60,7 +92,7 @@ func (ces *SCloudEyeManager) ListMetrics() ([]hw_mod.SMetricMeta, error) { return metrics, nil } -func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []hw_mod.SMetricMeta, error) { +func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []SMetricMeta, error) { request := requests.NewResourceRequest(ces.GetEndpoint(), "GET", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, ces.ResourceKeyword) request.AddQueryParam("limit", "1000") if len(start) > 0 { @@ -71,7 +103,7 @@ func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []hw_mod return "", nil, errors.Wrap(err, "ces.jsonRequest") } marker, _ := resp.GetString("meta_data", "marker") - metrics := make([]hw_mod.SMetricMeta, 0) + metrics := make([]SMetricMeta, 0) err = resp.Unmarshal(&metrics, "metrics") if err != nil { return "", nil, errors.Wrap(err, "resp.Unmarshal metrics") @@ -80,7 +112,7 @@ func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []hw_mod } type SBatchQueryMetricDataInput struct { - Metrics []hw_mod.SMetric `json:"metrics"` + Metrics []SMetric `json:"metrics"` From int64 `json:"from"` To int64 `json:"to"` @@ -88,11 +120,11 @@ type SBatchQueryMetricDataInput struct { Filter string `json:"filter"` } -func (ces *SCloudEyeManager) GetMetricsData(metrics []hw_mod.SMetricMeta, since time.Time, until time.Time) ([]hw_mod.SMetricData, error) { +func (ces *SCloudEyeManager) GetMetricsData(metrics []SMetricMeta, since time.Time, until time.Time) ([]SMetricData, error) { if len(metrics) > 10 { return nil, errors.Wrap(cloudprovider.ErrTooLarge, "request more than 10 metrics") } - metricReq := make([]hw_mod.SMetric, len(metrics)) + metricReq := make([]SMetric, len(metrics)) for i := range metrics { metricReq[i] = metrics[i].SMetric } @@ -111,7 +143,7 @@ func (ces *SCloudEyeManager) GetMetricsData(metrics []hw_mod.SMetricMeta, since return nil, errors.Wrap(err, "ces.jsonRequest") } //log.Debugf("%s", resp) - result := make([]hw_mod.SMetricData, 0) + result := make([]SMetricData, 0) err = resp.Unmarshal(&result, "metrics") if err != nil { return nil, errors.Wrap(err, "resp.Unmarshal") diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/monitor.go index d80a1b5394..5df9bbac1d 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/monitor.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/monitor.go @@ -25,7 +25,7 @@ import ( api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/cloudmux/pkg/cloudprovider" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules" ) type MetricData struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credential.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credential.go deleted file mode 100644 index 8dc818fb15..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credential.go +++ /dev/null @@ -1,18 +0,0 @@ -// 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 auth - -type Credential interface { -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/access_key_credential.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/access_key_credential.go deleted file mode 100644 index b156c01d3e..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/access_key_credential.go +++ /dev/null @@ -1,27 +0,0 @@ -// 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 credentials - -type AccessKeyCredential struct { - AccessKeyId string - AccessKeySecret string -} - -func NewAccessKeyCredential(accessKeyId, accessKeySecret string) *AccessKeyCredential { - return &AccessKeyCredential{ - AccessKeyId: accessKeyId, - AccessKeySecret: accessKeySecret, - } -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/doc.go deleted file mode 100644 index dd5b1f282b..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// 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 credentials // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/doc.go deleted file mode 100644 index 3cb37b7add..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// 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 auth // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signer.go deleted file mode 100644 index c2bf12f0e7..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signer.go +++ /dev/null @@ -1,215 +0,0 @@ -// 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 auth - -import ( - "crypto/md5" - "crypto/sha256" - "encoding/hex" - "fmt" - "io/ioutil" - "sort" - "strings" - "sync" - "time" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" -) - -type Signer interface { - GetName() string // 签名算法名称 - GetAccessKeyId() (accessKeyId string, err error) // 签名access key - GetSecretKey() (secretKey string, err error) // access secret - Sign(stringToSign, secretSuffix string) string // 生成签名结果 -} - -func NewSignerWithCredential(credential Credential) (signer Signer, err error) { - switch instance := credential.(type) { - case *credentials.AccessKeyCredential: - return signers.NewAccessKeySigner(instance), nil - default: - return nil, fmt.Errorf("unsupported credential error") - } -} - -// 对request进行签名 -func Sign(request requests.IRequest, signer Signer) (err error) { - return signRequest(request, signer) -} - -func signRequest(request requests.IRequest, signer Signer) error { - // https://support.huaweicloud.com/api-dis/dis_02_0508.html - // requestTime - reqTime := time.Now() - // 添加 必须的Headers - fillRequiredHeaders(request, reqTime) - // 计算CanonicalRequest - canonicalRequest := canonicalRequest(request) - // stringToSign - credentialScope := strings.Join([]string{ - formattedSignTime(reqTime, "Date"), - request.GetRegionId(), - request.GetProduct(), - "sdk_request", - }, "/") - stringToSign := strings.Join([]string{"SDK-HMAC-SHA256", - formattedSignTime(reqTime, "DateTime"), - credentialScope, - hashSha256([]byte(canonicalRequest)), - }, "\n") - // 计算SigningKey - secret, _ := signer.GetSecretKey() - signKey := getSigningKey(secret, formattedSignTime(reqTime, "Date"), - request.GetRegionId(), request.GetProduct()) - // 计算Signature - signature := signer.Sign(stringToSign, signKey) - accesskey, _ := signer.GetAccessKeyId() - addAuthorizationHeader(request, accesskey, credentialScope, signature) - return nil -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0132456728.html -// X-Project-Id 如果是专属云场景采用AK/SK 认证方式的接口请求或者多project场景采用AK/SK认证的接口请求则该字段必选。 -func fillRequiredHeaders(request requests.IRequest, t time.Time) { - request.AddHeaderParam("HOST", request.GetHost()) - request.AddHeaderParam("X-Sdk-Date", formattedSignTime(t, "DateTime")) - if len(request.GetProjectId()) > 0 { - request.AddHeaderParam("X-Project-Id", request.GetProjectId()) - } - return -} - -func buildRequestStringToSign(request requests.IRequest) string { - return "" -} - -func formattedSignTime(t time.Time, format string) string { - switch format { - case "Date": - return t.UTC().Format("20060102") - case "DateTime": - return t.UTC().Format("20060102T150405Z") - default: - return t.UTC().Format("20060102T150405Z") - } -} - -func contentSha256(request requests.IRequest) string { - method := strings.ToUpper(request.GetMethod()) - content := []byte{} - body := request.GetBodyReader() - content, _ = ioutil.ReadAll(body) - if method == "POST" { - if len(content) == 0 { - // other http method use query as content - content = []byte(request.BuildQueries()) - } - } - - return hashSha256(content) -} - -func hashSha256(msg []byte) string { - sh256 := sha256.New() - sh256.Write(msg) - - return hex.EncodeToString(sh256.Sum(nil)) -} - -func canonicalRequest(request requests.IRequest) string { - sha256 := contentSha256(request) - uri := request.GetURI() - if !strings.HasSuffix(uri, "/") { - uri = uri + "/" - } - - return strings.Join([]string{ - request.GetMethod(), - uri, - canonicalQueryString(request), - canonicalHeaders(request), - canonicalHeaderNames(request), - sha256, - }, "\n") -} - -func sortedHeaderNames(request requests.IRequest) []string { - headers := request.GetHeaders() - keys := make([]string, 0) - for k := range headers { - keys = append(keys, k) - } - - sort.Slice(keys, func(i, j int) bool { - return strings.ToLower(keys[i]) < strings.ToLower(keys[j]) - }) - - return keys -} - -func canonicalQueryString(request requests.IRequest) string { - if strings.ToUpper(request.GetMethod()) != "POST" { - return request.BuildQueries() - } - - return "" -} - -func canonicalHeaders(request requests.IRequest) string { - keys := sortedHeaderNames(request) - headers := request.GetHeaders() - ret := []string{} - for _, k := range keys { - ret = append(ret, strings.ToLower(k)+":"+strings.TrimSpace(headers[k])) - } - - return strings.Join(ret, "\n") + "\n" -} - -func canonicalHeaderNames(request requests.IRequest) string { - keys := sortedHeaderNames(request) - ret := strings.Join(keys, ";") - return strings.ToLower(ret) -} - -var SigningKeyCache sync.Map // map[string][]byte{} - -func getSigningKey(secretKey, date, regionId, service string) string { - joinedKey := strings.Join([]string{secretKey, date, regionId, service}, "") - cacheKey := fmt.Sprintf("%x", md5.Sum([]byte(joinedKey))) - if v, ok := SigningKeyCache.Load(cacheKey); ok { - return v.(string) - } - - ret := []byte("SDK" + secretKey) - for _, k := range []string{date, regionId, service, "sdk_request"} { - ret = signers.HmacSha256(k, ret) - } - - SigningKeyCache.Store(cacheKey, string(ret)) - return string(ret) -} - -func addAuthorizationHeader(request requests.IRequest, accessKey, credentialScope, signature string) { - auth := "SDK-HMAC-SHA256" + " " + strings.Join([]string{ - "Credential=" + accessKey + "/" + credentialScope, - "SignedHeaders=" + canonicalHeaderNames(request), - "Signature=" + signature, - }, ", ") - - request.AddHeaderParam("Authorization", auth) -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/doc.go deleted file mode 100644 index 40021b4369..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// 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 signers // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/signer_access_key.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/signer_access_key.go deleted file mode 100644 index 8920307491..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/signer_access_key.go +++ /dev/null @@ -1,55 +0,0 @@ -// 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 signers - -import ( - "crypto/hmac" - "crypto/sha256" - "encoding/hex" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials" -) - -type AccessKeySigner struct { - credential *credentials.AccessKeyCredential -} - -func (signer *AccessKeySigner) GetName() string { - return "HmacSha256" -} - -func (signer *AccessKeySigner) GetAccessKeyId() (accessKeyId string, err error) { - return signer.credential.AccessKeyId, nil -} - -func (signer *AccessKeySigner) GetSecretKey() (secretKey string, err error) { - return signer.credential.AccessKeySecret, nil -} - -func (signer *AccessKeySigner) Sign(stringToSign, secretSuffix string) string { - return hex.EncodeToString(HmacSha256(stringToSign, []byte(secretSuffix))) -} - -func HmacSha256(data string, key []byte) []byte { - mac := hmac.New(sha256.New, key) - mac.Write([]byte(data)) - return mac.Sum(nil) -} - -func NewAccessKeySigner(credential *credentials.AccessKeyCredential) *AccessKeySigner { - return &AccessKeySigner{ - credential: credential, - } -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/client.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/client.go deleted file mode 100644 index d6dc91b9c2..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/client.go +++ /dev/null @@ -1,232 +0,0 @@ -// 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 client - -import ( - "net/http" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" -) - -type Client struct { - cfg *SClientConfig - // 标记初始化状态 - init bool - - Credentials *modules.SCredentialManager - Disks *modules.SDiskManager - Domains *modules.SDomainManager - Elasticcache *modules.SElasticcacheManager - DcsAvailableZone *modules.SDcsAvailableZoneManager - Flavors *modules.SFlavorManager - Images *modules.SImageManager - OpenStackImages *modules.SImageManager - Interface *modules.SInterfaceManager - Jobs *modules.SJobManager - Orders *modules.SOrderManager - Port *modules.SPortManager - Projects *modules.SProjectManager - Regions *modules.SRegionManager - Servers *modules.SServerManager - ServersV2 *modules.SServerManager - NovaServers *modules.SServerManager - Snapshots *modules.SSnapshotManager - OsSnapshots *modules.SSnapshotManager - Subnets *modules.SSubnetManager - Users *modules.SUserManager - Vpcs *modules.SVpcManager - Zones *modules.SZoneManager - VpcRoutes *modules.SVpcRouteManager - SNatRules *modules.SNatSRuleManager - DNatRules *modules.SNatDRuleManager - NatGateways *modules.SNatGatewayManager - VpcPeerings *modules.SVpcPeeringManager - DBInstance *modules.SDBInstanceManager - DBInstanceBackup *modules.SDBInstanceBackupManager - DBInstanceFlavor *modules.SDBInstanceFlavorManager - DBInstanceJob *modules.SDBInstanceJobManager - Traces *modules.STraceManager - CloudEye *modules.SCloudEyeManager - EnterpriseProjects *modules.SEnterpriseProjectManager - Roles *modules.SRoleManager - Groups *modules.SGroupManager - SAMLProviders *modules.SAMLProviderManager - SAMLProviderMappings *modules.SAMLProviderMappingManager - SfsTurbos *modules.SfsTurboManager - RouteTables *modules.SRouteTableManager -} - -type SClientConfig struct { - signer auth.Signer - endpoint string // myhuaweicloud.com - regionId string - domainId string - projectId string - - debug bool -} - -func (self *SClientConfig) GetSigner() auth.Signer { - return self.signer -} - -func (self *SClientConfig) GetEndpoint() string { - return self.endpoint -} - -func (self *SClientConfig) GetRegionId() string { - return self.regionId -} - -func (self *SClientConfig) GetDomainId() string { - return self.domainId -} - -func (self *SClientConfig) GetProjectId() string { - return self.projectId -} - -func (self *SClientConfig) GetDebug() bool { - return self.debug -} - -func (self *Client) SetHttpClient(httpClient *http.Client) { - self.Credentials.SetHttpClient(httpClient) - self.Servers.SetHttpClient(httpClient) - self.ServersV2.SetHttpClient(httpClient) - self.NovaServers.SetHttpClient(httpClient) - self.Snapshots.SetHttpClient(httpClient) - self.OsSnapshots.SetHttpClient(httpClient) - self.Images.SetHttpClient(httpClient) - self.OpenStackImages.SetHttpClient(httpClient) - self.Projects.SetHttpClient(httpClient) - self.Regions.SetHttpClient(httpClient) - self.Zones.SetHttpClient(httpClient) - self.Vpcs.SetHttpClient(httpClient) - self.Elasticcache.SetHttpClient(httpClient) - self.DcsAvailableZone.SetHttpClient(httpClient) - self.Disks.SetHttpClient(httpClient) - self.Domains.SetHttpClient(httpClient) - self.Orders.SetHttpClient(httpClient) - self.Subnets.SetHttpClient(httpClient) - self.Users.SetHttpClient(httpClient) - self.Interface.SetHttpClient(httpClient) - self.Jobs.SetHttpClient(httpClient) - self.Port.SetHttpClient(httpClient) - self.Flavors.SetHttpClient(httpClient) - self.VpcRoutes.SetHttpClient(httpClient) - self.SNatRules.SetHttpClient(httpClient) - self.DNatRules.SetHttpClient(httpClient) - self.NatGateways.SetHttpClient(httpClient) - self.DBInstance.SetHttpClient(httpClient) - self.DBInstanceBackup.SetHttpClient(httpClient) - self.DBInstanceFlavor.SetHttpClient(httpClient) - self.DBInstanceJob.SetHttpClient(httpClient) - self.Traces.SetHttpClient(httpClient) - self.CloudEye.SetHttpClient(httpClient) - self.EnterpriseProjects.SetHttpClient(httpClient) - self.Roles.SetHttpClient(httpClient) - self.Groups.SetHttpClient(httpClient) - self.SAMLProviders.SetHttpClient(httpClient) - self.SAMLProviderMappings.SetHttpClient(httpClient) - self.SfsTurbos.SetHttpClient(httpClient) - self.RouteTables.SetHttpClient(httpClient) -} - -func (self *Client) InitWithAccessKey(endpoint, regionId, domainId, projectId, accessKey, secretKey string, debug bool) error { - // accessKey signer - credential := &credentials.AccessKeyCredential{ - AccessKeyId: accessKey, - AccessKeySecret: secretKey, - } - - // 从signer中初始化 - signer, err := auth.NewSignerWithCredential(credential) - if err != nil { - return err - } - self.cfg = &SClientConfig{ - signer: signer, - endpoint: endpoint, - regionId: regionId, - domainId: domainId, - projectId: projectId, - debug: debug, - } - - // 初始化 resource manager - self.initManagers() - return err -} - -func (self *Client) initManagers() { - if !self.init { - self.Servers = modules.NewServerManager(self.cfg) - self.ServersV2 = modules.NewServerV2Manager(self.cfg) - self.NovaServers = modules.NewNovaServerManager(self.cfg) - self.Snapshots = modules.NewSnapshotManager(self.cfg) - self.OsSnapshots = modules.NewOsSnapshotManager(self.cfg) - self.Images = modules.NewImageManager(self.cfg) - self.OpenStackImages = modules.NewOpenstackImageManager(self.cfg) - self.Projects = modules.NewProjectManager(self.cfg) - self.Regions = modules.NewRegionManager(self.cfg) - self.Zones = modules.NewZoneManager(self.cfg) - self.Vpcs = modules.NewVpcManager(self.cfg) - self.Elasticcache = modules.NewElasticcacheManager(self.cfg) - self.DcsAvailableZone = modules.NewDcsAvailableZoneManager(self.cfg) - self.Disks = modules.NewDiskManager(self.cfg) - self.Domains = modules.NewDomainManager(self.cfg) - self.Orders = modules.NewOrderManager(self.cfg) - self.Subnets = modules.NewSubnetManager(self.cfg) - self.Users = modules.NewUserManager(self.cfg) - self.Interface = modules.NewInterfaceManager(self.cfg) - self.Jobs = modules.NewJobManager(self.cfg) - self.Credentials = modules.NewCredentialManager(self.cfg) - self.Port = modules.NewPortManager(self.cfg) - self.Flavors = modules.NewFlavorManager(self.cfg) - self.VpcRoutes = modules.NewVpcRouteManager(self.cfg) - self.SNatRules = modules.NewNatSManager(self.cfg) - self.DNatRules = modules.NewNatDManager(self.cfg) - self.NatGateways = modules.NewNatGatewayManager(self.cfg) - self.VpcPeerings = modules.NewVpcPeeringManager(self.cfg) - self.DBInstance = modules.NewDBInstanceManager(self.cfg) - self.DBInstanceBackup = modules.NewDBInstanceBackupManager(self.cfg) - self.DBInstanceFlavor = modules.NewDBInstanceFlavorManager(self.cfg) - self.DBInstanceJob = modules.NewDBInstanceJobManager(self.cfg) - self.Traces = modules.NewTraceManager(self.cfg) - self.CloudEye = modules.NewCloudEyeManager(self.cfg) - self.EnterpriseProjects = modules.NewEnterpriseProjectManager(self.cfg) - self.Roles = modules.NewRoleManager(self.cfg) - self.Groups = modules.NewGroupManager(self.cfg) - self.SAMLProviders = modules.NewSAMLProviderManager(self.cfg) - self.SAMLProviderMappings = modules.NewSAMLProviderMappingManager(self.cfg) - self.SfsTurbos = modules.NewSfsTurboManager(self.cfg) - self.RouteTables = modules.NewRouteTableManager(self.cfg) - } - - self.init = true -} - -func NewClientWithAccessKey(endpoint, regionId, domainId, projectId, accessKey, secretKey string, debug bool) (*Client, error) { - c := &Client{} - err := c.InitWithAccessKey(endpoint, regionId, domainId, projectId, accessKey, secretKey, debug) - return c, err -} - -func NewPublicCloudClientWithAccessKey(regionId, domainId, projectId, accessKey, secretKey string, debug bool) (*Client, error) { - return NewClientWithAccessKey("myhuaweicloud.com", regionId, domainId, projectId, accessKey, secretKey, debug) -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/doc.go deleted file mode 100644 index b50b2e2b90..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// 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 client // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/doc.go deleted file mode 100644 index fd4bfdd238..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// 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 manager // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/manager.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/manager.go deleted file mode 100644 index ceaa387cbf..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/manager.go +++ /dev/null @@ -1,81 +0,0 @@ -// 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 manager - -import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type IManagerContext interface { - GetPath() string -} - -type IBaseManager interface { - Version() string - KeyString() string - ServiceType() string - GetColumns() []string -} - -type IManager interface { - IBaseManager - // 获取资源列表 GET /cloudservers/? - List(queries map[string]string) (*responses.ListResult, error) - // 根据上文获取资源列表 GET /cloudservers//nics? - ListInContext(ctx IManagerContext, queries map[string]string) (*responses.ListResult, error) - ListInContextWithSpec(ctx IManagerContext, spec string, queries map[string]string, responseKey string) (*responses.ListResult, error) - - // 查询单个资源 GET /cloudservers/? - Get(id string, queries map[string]string) (jsonutils.JSONObject, error) - // 根据上文获取资源查询单个资源 GET /cloudservers//nics/? - GetInContext(ctx IManagerContext, id string, queries map[string]string) (jsonutils.JSONObject, error) - - // 创建单个资源 POST /cloudservers - Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文创建单个资源 POST /cloudservers//nics/ - CreateInContext(ctx IManagerContext, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 异步任务创建 POST /cloudservers. 返回异步任务 job_id。 todo:// 后续考虑返回一个task对象 - AsyncCreate(params jsonutils.JSONObject) (string, error) - - // 更新单个资源 PUT /cloudservers/ - Update(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文更新单个资源 PUT /cloudservers//nics/ - UpdateInContext(ctx IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文和spec更新单个资源 PUT /v2.1/{project_id}/servers/{server_id}/os-reset-password - UpdateInContextWithSpec(ctx IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) - - // 删除单个资源 DELETE /cloudservers/ - Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文删除单个资源 DELETE /cloudservers//nics/ - DeleteInContext(ctx IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文和spec删除单个资源 - DeleteInContextWithSpec(ctx IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) - // 批量执行操作 POST /cloudservers/ - // BatchPerformAction(action string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 执行操作 POST /cloudservers// - PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) -} - -type IManagerConfig interface { - GetSigner() auth.Signer - GetEndpoint() string - GetRegionId() string - GetDomainId() string - GetProjectId() string - GetDebug() bool -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/doc.go deleted file mode 100644 index 10bf5c141d..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// 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 modules // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_base.go deleted file mode 100644 index 64facb5fae..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_base.go +++ /dev/null @@ -1,271 +0,0 @@ -// 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 modules - -import ( - "context" - "fmt" - "net/http" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/httputils" - - "yunion.io/x/cloudmux/pkg/cloudprovider" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type IRequestHook interface { - Process(r requests.IRequest) -} - -type SBaseManager struct { - cfg manager.IManagerConfig - httpClient *http.Client - requestHook IRequestHook // 用于对request做特殊处理。非必要请不要使用!!!。目前只有port接口用到。 - - columns []string - debug bool -} - -type sThrottlingThreshold struct { - locked bool - lockTime time.Time -} - -func (t *sThrottlingThreshold) CheckingLock() { - if !t.locked { - return - } - - for { - if t.lockTime.Sub(time.Now()).Seconds() < 0 { - return - } - log.Debugf("throttling threshold has been reached. release at %s", t.lockTime) - time.Sleep(5 * time.Second) - } -} - -func (t *sThrottlingThreshold) Lock() { - // 锁定至少15秒 - t.locked = true - t.lockTime = time.Now().Add(15 * time.Second) -} - -var ThrottlingLock = sThrottlingThreshold{locked: false, lockTime: time.Time{}} - -func NewBaseManager2(cfg manager.IManagerConfig, requesthk IRequestHook) SBaseManager { - return SBaseManager{ - cfg: cfg, - httpClient: httputils.GetDefaultClient(), - debug: cfg.GetDebug(), - requestHook: requesthk, - } -} - -func NewBaseManager(cfg manager.IManagerConfig) SBaseManager { - return NewBaseManager2(cfg, nil) -} - -func (self *SBaseManager) GetEndpoint() string { - return self.cfg.GetEndpoint() -} - -func (self *SBaseManager) GetColumns() []string { - return self.columns -} - -func (self *SBaseManager) SetHttpClient(httpClient *http.Client) { - self.httpClient = httpClient -} - -func (self *SBaseManager) _list(request requests.IRequest, responseKey string) (*responses.ListResult, error) { - _, body, err := self.jsonRequest(request) - if err != nil { - return nil, err - } - if body == nil { - log.Warningf("empty response") - return &responses.ListResult{}, nil - } - - rets, err := body.GetArray(responseKey) - if err != nil { - return nil, errors.Wrapf(err, "body.GetArray %s", responseKey) - } - total, _ := body.Int("count") - // if err != nil { - // total = int64(len(rets)) - //} - - //if total == 0 { - // total = int64(len(rets)) - //} - - limit := 0 - if v, exists := request.GetQueryParams()["limit"]; exists { - limit, _ = strconv.Atoi(v) - } - - offset := 0 - if v, exists := request.GetQueryParams()["offset"]; exists { - offset, _ = strconv.Atoi(v) - } - - return &responses.ListResult{ - Data: rets, - Total: int(total), - Limit: limit, - Offset: offset, - }, nil -} - -func (self *SBaseManager) _do(request requests.IRequest, responseKey string) (jsonutils.JSONObject, error) { - _, resp, e := self.jsonRequest(request) - if e != nil { - return nil, e - } - - if resp == nil { // no reslt - return jsonutils.NewDict(), nil - } - - if len(responseKey) == 0 { - return resp, nil - } - - ret, e := resp.Get(responseKey) - if e != nil { - return nil, e - } - - return ret, nil -} - -func (self *SBaseManager) _get(request requests.IRequest, responseKey string) (jsonutils.JSONObject, error) { - return self._do(request, responseKey) -} - -type HuaweiClientError struct { - Code int - Errorcode []string - err error - Details string - ErrorCode string -} - -func (ce *HuaweiClientError) Error() string { - return jsonutils.Marshal(ce).String() -} - -func (ce *HuaweiClientError) ParseErrorFromJsonResponse(statusCode int, status string, body jsonutils.JSONObject) error { - if body != nil { - body.Unmarshal(ce) - } - if ce.Code == 0 { - ce.Code = statusCode - } - if len(ce.Details) == 0 && body != nil { - ce.Details = body.String() - } - return ce -} - -func (self *SBaseManager) jsonRequest(request requests.IRequest) (http.Header, jsonutils.JSONObject, error) { - ThrottlingLock.CheckingLock() - ctx := context.Background() - // hook request - if self.requestHook != nil { - self.requestHook.Process(request) - } - // 拼接、编译、签名 requests here。 - err := self.buildRequestWithSigner(request, self.cfg.GetSigner()) - if err != nil { - return nil, nil, err - } - header := http.Header{} - for k, v := range request.GetHeaders() { - header.Set(k, v) - } - - var jsonBody jsonutils.JSONObject - content := request.GetContent() - if len(content) > 0 { - jsonBody, err = jsonutils.Parse(content) - if err != nil { - return nil, nil, fmt.Errorf("not a json body") - } - } - - client := httputils.NewJsonClient(self.httpClient) - req := httputils.NewJsonRequest(httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), jsonBody) - req.SetHeader(header) - resp := &HuaweiClientError{} - const MAX_RETRY = 3 - retry := MAX_RETRY - for { - h, b, e := client.Send(ctx, req, resp, self.debug) - if e == nil { - return h, b, nil - } - - log.Errorf("[%s] %s body: %v error: %v", req.GetHttpMethod(), req.GetUrl(), jsonBody, e) - - switch err := e.(type) { - case *HuaweiClientError: - if err.ErrorCode == "APIGW.0301" { - return h, b, errors.Wrapf(cloudprovider.ErrInvalidAccessKey, e.Error()) - } else if err.Code == 499 && retry > 0 && request.GetMethod() == "GET" { - retry -= 1 - time.Sleep(3 * time.Second * time.Duration(MAX_RETRY-retry)) - } else if (err.Code == 404 || strings.Contains(err.Details, "could not be found") || - strings.Contains(err.Error(), "Not Found") || - strings.Contains(err.Details, "does not exist")) && request.GetMethod() != "POST" { - return h, b, errors.Wrap(cloudprovider.ErrNotFound, err.Error()) - } else if err.Code == 429 && retry > 0 { - // 当前请求过多。 - ThrottlingLock.Lock() - retry -= 1 - time.Sleep(15 * time.Second) - } else { - return h, b, e - } - default: - return h, b, e - } - } -} - -func (self *SBaseManager) rawRequest(request requests.IRequest) (*http.Response, error) { - ctx := context.Background() - // 拼接、编译requests here。 - header := http.Header{} - for k, v := range request.GetHeaders() { - header.Set(k, v) - } - return httputils.Request(self.httpClient, ctx, httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), header, request.GetBodyReader(), self.debug) -} - -func (self *SBaseManager) buildRequestWithSigner(request requests.IRequest, signer auth.Signer) error { - return auth.Sign(request, signer) -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_resource.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_resource.go deleted file mode 100644 index 91fa296c38..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_resource.go +++ /dev/null @@ -1,298 +0,0 @@ -// 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 modules - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type ServiceNameType string - -const HuaWeiDefaultDomain = "myhuaweicloud.com" - -const ( - ServiceNameECS ServiceNameType = "ecs" // 弹性云服务 - ServiceNameCCE ServiceNameType = "cce" // 云容器服务 - ServiceNameAS ServiceNameType = "as" // 弹性伸缩服务 - ServiceNameIAM ServiceNameType = "iam" // 统一身份认证服务 - ServiceNameIMS ServiceNameType = "ims" // 镜像服务 - ServiceNameCSBS ServiceNameType = "csbs" // 云服务器备份服务 - ServiceNameCCI ServiceNameType = "cci" // 云容器实例 CCI - ServiceNameBMS ServiceNameType = "bms" // 裸金属服务器 - ServiceNameEVS ServiceNameType = "evs" // 云硬盘 EVS - ServiceNameVBS ServiceNameType = "vbs" // 云硬盘备份 VBS - ServiceNameOBS ServiceNameType = "obs" // 对象存储服务 OBS - ServiceNameVPC ServiceNameType = "vpc" // 虚拟私有云 VPC - ServiceNameELB ServiceNameType = "elb" // 弹性负载均衡 ELB - ServiceNameBSS ServiceNameType = "bss" // 合作伙伴运营能力 - ServiceNameNAT ServiceNameType = "nat" // Nat网关 NAT - ServiceNameDCS ServiceNameType = "dcs" // 分布式缓存服务 - ServiceNameRDS ServiceNameType = "rds" // 关系型数据库 RDS - ServiceNameCTS ServiceNameType = "cts" // 云审计服务 - ServiceNameCES ServiceNameType = "ces" // 监控服务 CloudEye - ServiceNameEPS ServiceNameType = "eps" // 企业项目 - - ServiceNameModelarts ServiceNameType = "modelarts" // AI ModelArts - - ServiceNameSFSTurbo ServiceNameType = "sfs-turbo" // 文件系统 -) - -type SManagerContext struct { - InstanceManager manager.IManager - InstanceId string -} - -func (self *SManagerContext) GetPath() string { - path := self.InstanceManager.KeyString() - if len(self.InstanceId) > 0 { - path += fmt.Sprintf("/%s", url.PathEscape(self.InstanceId)) - } - - return path -} - -type SResourceManager struct { - SBaseManager - ctx manager.IManagerContext - ServiceName ServiceNameType // 服务名称: ecs - Region string // 区域: cn-north-1 - DomainId string - ProjectId string // 项目ID: uuid - version string // api 版本号 - Keyword string // 资源名称单数。构建URL时使用 - KeywordPlural string // 资源名称复数形式。构建URL时使用 - - ResourceKeyword string // 资源名称。url中使用 -} - -func getContent(params jsonutils.JSONObject) string { - if params == nil { - return "" - } - - return params.String() -} - -func (self *SResourceManager) Version() string { - return self.version -} - -func (self *SResourceManager) KeyString() string { - return self.ResourceKeyword -} - -func (self *SResourceManager) ServiceType() string { - return string(self.ServiceName) -} - -func (self *SResourceManager) GetColumns() []string { - return []string{} -} - -func (self *SResourceManager) SetDomainId(domainId string) { - self.DomainId = domainId -} - -func (self *SResourceManager) getReourcePath(ctx manager.IManagerContext, rid string, spec string) string { - segs := []string{} - if ctx != nil { - segs = append(segs, ctx.GetPath()) - } - - segs = append(segs, self.KeyString()) - - if len(rid) > 0 { - segs = append(segs, url.PathEscape(rid)) - } - - if len(spec) > 0 { - specSegs := strings.Split(spec, "/") - for _, specSeg := range specSegs { - segs = append(segs, url.PathEscape(specSeg)) - } - } - - return strings.Join(segs, "/") -} - -func (self *SResourceManager) newRequest(method, rid, spec string, ctx manager.IManagerContext) *requests.SRequest { - resourcePath := self.getReourcePath(ctx, rid, spec) - return requests.NewResourceRequest(self.GetEndpoint(), method, string(self.ServiceName), self.version, self.Region, self.ProjectId, resourcePath) -} - -func (self *SResourceManager) List(queries map[string]string) (*responses.ListResult, error) { - return self.ListInContext(self.ctx, queries) -} - -func (self *SResourceManager) ListInContext(ctx manager.IManagerContext, queries map[string]string) (*responses.ListResult, error) { - return self.ListInContextWithSpec(ctx, "", queries, self.KeywordPlural) -} - -func (self *SResourceManager) ListInContextWithSpec(ctx manager.IManagerContext, spec string, queries map[string]string, responseKey string) (*responses.ListResult, error) { - request := self.newRequest("GET", "", spec, ctx) - for k, v := range queries { - request.AddQueryParam(k, v) - } - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._list(request, responseKey) -} - -func (self *SResourceManager) Get(id string, queries map[string]string) (jsonutils.JSONObject, error) { - return self.GetInContext(self.ctx, id, queries) -} - -func (self *SResourceManager) GetInContext(ctx manager.IManagerContext, id string, queries map[string]string) (jsonutils.JSONObject, error) { - return self.GetInContextWithSpec(ctx, id, "", queries, self.Keyword) -} - -func (self *SResourceManager) GetInContextWithSpec(ctx manager.IManagerContext, id string, spec string, queries map[string]string, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("GET", id, spec, ctx) - for k, v := range queries { - request.AddQueryParam(k, v) - } - - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._get(request, responseKey) -} - -func (self *SResourceManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.CreateInContext(self.ctx, params) -} - -func (self *SResourceManager) CreateInContext(ctx manager.IManagerContext, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.CreateInContextWithSpec(ctx, "", params, self.Keyword) -} - -func (self *SResourceManager) CreateInContextWithSpec(ctx manager.IManagerContext, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("POST", "", spec, ctx) - request.SetContent([]byte(params.String())) - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { - return "", fmt.Errorf("not supported") -} - -func (self *SResourceManager) Update(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.UpdateInContext(self.ctx, id, params) -} - -func (self *SResourceManager) UpdateInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.UpdateInContextWithSpec(ctx, id, "", params, self.Keyword) -} - -func (self *SResourceManager) UpdateInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("PUT", id, spec, ctx) - content := getContent(params) - if len(content) > 0 { - request.SetContent([]byte(content)) - } - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) Patch(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.PatchInContext(self.ctx, id, params) -} - -func (self *SResourceManager) PatchInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.PatchInContextWithSpec(ctx, id, "", params, self.Keyword) -} - -func (self *SResourceManager) PatchInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("PATCH", id, spec, ctx) - content := getContent(params) - if len(content) > 0 { - request.SetContent([]byte(content)) - } - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.DeleteInContext(self.ctx, id, params) -} - -func (self *SResourceManager) DeleteInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.DeleteInContextWithSpec(ctx, id, "", nil, params, "") -} - -func (self *SResourceManager) DeleteInContextWithSpec(ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("DELETE", id, spec, ctx) - for k, v := range queries { - request.AddQueryParam(k, v) - } - - content := getContent(params) - if len(content) > 0 { - request.SetContent([]byte(content)) - } - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.PerformAction2(action, id, params, self.Keyword) -} - -func (self *SResourceManager) PerformAction2(action string, id string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("POST", id, action, nil) - request.SetContent([]byte(getContent(params))) - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) SetVersion(v string) { - self.version = v -} - -func (self *SResourceManager) versionedURL(path string) string { - return "" -} - -// todo: Init a manager with environment variables -func (self *SResourceManager) Init() error { - return nil -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_ces.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_ces.go deleted file mode 100644 index f38a32a8ef..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_ces.go +++ /dev/null @@ -1,152 +0,0 @@ -// 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 modules - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/cloudmux/pkg/cloudprovider" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" -) - -type SCloudEyeManager struct { - SResourceManager -} - -func NewCloudEyeManager(cfg manager.IManagerConfig) *SCloudEyeManager { - return &SCloudEyeManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameCES, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "V1.0", - Keyword: "", - KeywordPlural: "metrics", - ResourceKeyword: "metrics", - }} -} - -type SMetricDimension struct { - Name string `json:"name"` - Value string `json:"value"` -} - -type SDatapoint struct { - Timestamp int64 `json:"timestamp"` - Max float64 `json:"max,omitzero"` - Min float64 `json:"min,omitzero"` - Average float64 `json:"average,omitzero"` - Sum float64 `json:"sum,omitzero"` - Variance float64 `json:"variance,omitzero"` -} - -type SMetricData struct { - SMetricMeta - - Datapoints []SDatapoint -} - -type SMetricMeta struct { - SMetric - - Unit string `json:"unit"` -} - -type SMetric struct { - MetricName string `json:"metric_name"` - Namespace string `json:"namespace"` - - Dimensions []SMetricDimension `json:"dimensions"` -} - -func (ces *SCloudEyeManager) ListMetrics() ([]SMetricMeta, error) { - metrics := make([]SMetricMeta, 0) - next := "" - for { - marker, data, err := ces.listMetricsInternal(next) - if err != nil { - return nil, errors.Wrap(err, "ces.listMetricsInternal") - } - if len(data) == 0 { - break - } - metrics = append(metrics, data...) - next = marker - } - return metrics, nil -} - -func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []SMetricMeta, error) { - request := requests.NewResourceRequest(ces.GetEndpoint(), "GET", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, ces.ResourceKeyword) - request.AddQueryParam("limit", "1000") - if len(start) > 0 { - request.AddQueryParam("start", start) - } - _, resp, err := ces.jsonRequest(request) - if err != nil { - return "", nil, errors.Wrap(err, "ces.jsonRequest") - } - marker, _ := resp.GetString("meta_data", "marker") - metrics := make([]SMetricMeta, 0) - err = resp.Unmarshal(&metrics, "metrics") - if err != nil { - return "", nil, errors.Wrap(err, "resp.Unmarshal metrics") - } - return marker, metrics, nil -} - -type SBatchQueryMetricDataInput struct { - Metrics []SMetric `json:"metrics"` - - From int64 `json:"from"` - To int64 `json:"to"` - Period string `json:"period"` - Filter string `json:"filter"` -} - -func (ces *SCloudEyeManager) GetMetricsData(metrics []SMetricMeta, since time.Time, until time.Time) ([]SMetricData, error) { - if len(metrics) > 10 { - return nil, errors.Wrap(cloudprovider.ErrTooLarge, "request more than 10 metrics") - } - metricReq := make([]SMetric, len(metrics)) - for i := range metrics { - metricReq[i] = metrics[i].SMetric - } - request := requests.NewResourceRequest(ces.GetEndpoint(), "POST", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, "batch-query-metric-data") - input := SBatchQueryMetricDataInput{ - Metrics: metricReq, - From: since.Unix() * 1000, - To: until.Unix() * 1000, - Period: "1", - Filter: "average", - } - body := jsonutils.Marshal(&input).String() - request.SetContent([]byte(body)) - _, resp, err := ces.jsonRequest(request) - if err != nil { - return nil, errors.Wrap(err, "ces.jsonRequest") - } - //log.Debugf("%s", resp) - result := make([]SMetricData, 0) - err = resp.Unmarshal(&result, "metrics") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return result, nil -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_credential.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_credential.go deleted file mode 100644 index 171e1788d5..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_credential.go +++ /dev/null @@ -1,37 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SCredentialManager struct { - SResourceManager -} - -func NewCredentialManager(cfg manager.IManagerConfig) *SCredentialManager { - return &SCredentialManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3.0", - Keyword: "credential", - KeywordPlural: "credentials", - - ResourceKeyword: "OS-CREDENTIAL/credentials", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance.go deleted file mode 100644 index 663e6fd465..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance.go +++ /dev/null @@ -1,103 +0,0 @@ -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/cloudmux/pkg/cloudprovider" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type SDBInstanceManager struct { - SResourceManager -} - -func NewDBInstanceManager(cfg manager.IManagerConfig) *SDBInstanceManager { - return &SDBInstanceManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameRDS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v3", - Keyword: "", - KeywordPlural: "instances", - - ResourceKeyword: "instances", - }} -} - -func (self *SDBInstanceManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - if len(id) == 0 { - return nil, cloudprovider.ErrNotFound - } - resp, err := self.GetInContextWithSpec(nil, "", "", map[string]string{"id": id}, "") - if err != nil { - return nil, err - } - instances, err := resp.GetArray("instances") - if err != nil { - return nil, err - } - if len(instances) == 0 { - return nil, cloudprovider.ErrNotFound - } else if len(instances) == 1 { - return instances[0], nil - } - return nil, cloudprovider.ErrDuplicateId -} - -func (self *SDBInstanceManager) ListParameters(queries map[string]string) (*responses.ListResult, error) { - id, _ := queries["instance_id"] - if len(id) == 0 { - return nil, fmt.Errorf("SDBInstanceManager.ListParameters missing parameter instance_id") - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/configurations", id), queries, "configuration_parameters") -} - -func (self *SDBInstanceManager) ListDatabases(queries map[string]string) (*responses.ListResult, error) { - id, _ := queries["instance_id"] - if len(id) == 0 { - return nil, fmt.Errorf("SDBInstanceManager.ListDatabases missing parameter instance_id") - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/database/detail", id), queries, "databases") -} - -func (self *SDBInstanceManager) ListAccounts(queries map[string]string) (*responses.ListResult, error) { - id, _ := queries["instance_id"] - if len(id) == 0 { - return nil, fmt.Errorf("SDBInstanceManager.ListAccounts missing parameter instance_id") - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/db_user/detail", id), queries, "users") -} - -func (self *SDBInstanceManager) ListPrivileges(queries map[string]string) (*responses.ListResult, error) { - id, _ := queries["instance_id"] - if len(id) == 0 { - return nil, fmt.Errorf("SDBInstanceManager.ListPrivileges missing parameter instance_id") - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/db_user/database", id), queries, "databases") -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_backup.go deleted file mode 100644 index 6062aa256f..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_backup.go +++ /dev/null @@ -1,37 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SDBInstanceBackupManager struct { - SResourceManager -} - -func NewDBInstanceBackupManager(cfg manager.IManagerConfig) *SDBInstanceBackupManager { - return &SDBInstanceBackupManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameRDS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v3", - Keyword: "backup", - KeywordPlural: "backups", - - ResourceKeyword: "backups", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_flavor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_flavor.go deleted file mode 100644 index 9f937891b1..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_flavor.go +++ /dev/null @@ -1,37 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SDBInstanceFlavorManager struct { - SResourceManager -} - -func NewDBInstanceFlavorManager(cfg manager.IManagerConfig) *SDBInstanceFlavorManager { - return &SDBInstanceFlavorManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameRDS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v3", - Keyword: "flavor", - KeywordPlural: "flavor", - - ResourceKeyword: "flavors", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_job.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_job.go deleted file mode 100644 index 53777a6bc9..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_job.go +++ /dev/null @@ -1,43 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SDBInstanceJobManager struct { - SResourceManager -} - -func NewDBInstanceJobManager(cfg manager.IManagerConfig) *SDBInstanceJobManager { - return &SDBInstanceJobManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameRDS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v3", - Keyword: "", - KeywordPlural: "", - - ResourceKeyword: "jobs", - }} -} - -func (self *SDBInstanceJobManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - return self.GetInContextWithSpec(nil, "", "", map[string]string{"id": id}, "job") -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_disks.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_disks.go deleted file mode 100644 index 0aa79990cd..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_disks.go +++ /dev/null @@ -1,76 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type SDiskManager struct { - SResourceManager -} - -func NewDiskManager(cfg manager.IManagerConfig) *SDiskManager { - return &SDiskManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEVS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "volume", - KeywordPlural: "volumes", - - ResourceKeyword: "cloudvolumes", - }} -} - -func (self *SDiskManager) List(querys map[string]string) (*responses.ListResult, error) { - return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) -} - -// https://support.huaweicloud.com/api-evs/evs_04_2003.html -func (self *SDiskManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { - origin_version := self.version - self.version = "v2.1" - defer func() { self.version = origin_version }() - - ret, err := self.CreateInContextWithSpec(nil, "", params, "") - if err != nil { - log.Debugf("AsyncCreate %s", err) - return "", err - } - - log.Debugf("AsyncCreate result %s", ret.String()) - // 按需机器 - jobId, err := ret.GetString("job_id") - if err == nil { - return jobId, nil - } - - // 包年包月机器 - return ret.GetString("order_id") -} - -// https://support.huaweicloud.com/api-evs/evs_04_2003.html -func (self *SDiskManager) GetDiskTypes() (*responses.ListResult, error) { - originKeyword := self.ResourceKeyword - self.ResourceKeyword = "" - defer func() { self.ResourceKeyword = originKeyword }() - return self.ListInContextWithSpec(self.ctx, "types", nil, "volume_types") -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dnat_rules.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dnat_rules.go deleted file mode 100644 index 70ba9f3868..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dnat_rules.go +++ /dev/null @@ -1,41 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SNatDRuleManager struct { - SResourceManager -} - -func NewNatDManager(cfg manager.IManagerConfig) *SNatDRuleManager { - man := &SNatDRuleManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameNAT, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2.0", - Keyword: "dnat_rule", - KeywordPlural: "dnat_rules", - - ResourceKeyword: "dnat_rules", - }} - if len(cfg.GetProjectId()) > 0 { - man.requestHook = &sProjectHook{cfg.GetProjectId()} - } - return man -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_domains.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_domains.go deleted file mode 100644 index f2ced5b04c..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_domains.go +++ /dev/null @@ -1,95 +0,0 @@ -// 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 modules - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/cloudmux/pkg/cloudprovider" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type SDomainManager struct { - SResourceManager -} - -func NewDomainManager(cfg manager.IManagerConfig) *SDomainManager { - m := &SDomainManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3/auth", - Keyword: "domain", - KeywordPlural: "domains", - - ResourceKeyword: "domains", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} - -func (manager *SDomainManager) DeleteRole(domainId string, groupId, roleId string) error { - if len(domainId) == 0 { - return fmt.Errorf("missing domainId") - } - if len(groupId) == 0 { - return fmt.Errorf("missing groupId") - } - if len(roleId) == 0 { - return fmt.Errorf("missing roleId") - } - manager.SetVersion("v3") - defer manager.SetVersion("v3/auth") - res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) - _, err := manager.DeleteInContextWithSpec(nil, domainId, res, nil, nil, "") - if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return err -} - -func (manager *SDomainManager) ListRoles(domainId string, groupId string) (*responses.ListResult, error) { - if len(domainId) == 0 { - return nil, fmt.Errorf("missing domainId") - } - if len(groupId) == 0 { - return nil, fmt.Errorf("missing groupId") - } - manager.SetVersion("v3") - defer manager.SetVersion("v3/auth") - res := fmt.Sprintf("%s/groups/%s/roles", domainId, groupId) - return manager.ListInContextWithSpec(nil, res, nil, "roles") -} - -func (manager *SDomainManager) AddRole(domainId string, groupId, roleId string) error { - if len(domainId) == 0 { - return fmt.Errorf("missing domainId") - } - if len(groupId) == 0 { - return fmt.Errorf("missing groupId") - } - if len(roleId) == 0 { - return fmt.Errorf("missing roleId") - } - manager.SetVersion("v3") - defer manager.SetVersion("v3/auth") - res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) - _, err := manager.UpdateInContextWithSpec(nil, domainId, res, nil, "") - return err -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_elasticcache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_elasticcache.go deleted file mode 100644 index 0ec087ae94..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_elasticcache.go +++ /dev/null @@ -1,118 +0,0 @@ -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type SElasticcacheManager struct { - SResourceManager -} - -type SDcsAvailableZoneManager struct { - SResourceManager -} - -func NewElasticcacheManager(cfg manager.IManagerConfig) *SElasticcacheManager { - return &SElasticcacheManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameDCS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1.0", - Keyword: "", - KeywordPlural: "instances", - - ResourceKeyword: "instances", - }} -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html -func (self *SElasticcacheManager) ListBackups(queries map[string]string) (*responses.ListResult, error) { - var spec string - if id, _ := queries["instance_id"]; len(id) == 0 { - return nil, fmt.Errorf("SElasticcacheManager.ListBackups missing parameter instance_id") - } else { - spec = fmt.Sprintf("%s/backups", id) - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, spec, queries, "backup_record_response") -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html -func (self *SElasticcacheManager) ListParameters(queries map[string]string) (*responses.ListResult, error) { - var spec string - if id, _ := queries["instance_id"]; len(id) == 0 { - return nil, fmt.Errorf("SElasticcacheManager.ListParameters missing parameter instance_id") - } else { - spec = fmt.Sprintf("%s/configs", id) - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, spec, queries, "redis_config") -} - -func (self *SElasticcacheManager) Restart(instanceId string) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances") - params.Add(jsonutils.NewString("restart"), "action") - return self.UpdateInContextWithSpec(nil, "", "status", params, "") -} - -// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 -func (self *SElasticcacheManager) Flush(instanceId string) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances") - params.Add(jsonutils.NewString("flush"), "action") - return self.UpdateInContextWithSpec(nil, "", "status", params, "") -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html -func (self *SElasticcacheManager) RestoreInstance(instanceId string, backupId string) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewArray(jsonutils.NewString(backupId)), "backup_id") - - return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/restores", instanceId), params, "") -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html -func (self *SElasticcacheManager) ChangeInstanceSpec(instanceId string, specCode string, newCapacity int64) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Set("new_capacity", jsonutils.NewInt(newCapacity)) - params.Set("spec_code", jsonutils.NewString(specCode)) - - return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/extend", instanceId), params, "") -} - -func NewDcsAvailableZoneManager(cfg manager.IManagerConfig) *SDcsAvailableZoneManager { - return &SDcsAvailableZoneManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameDCS, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v1.0", - Keyword: "available_zone", - KeywordPlural: "available_zones", - - ResourceKeyword: "availableZones", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_enterpriceprojects.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_enterpriceprojects.go deleted file mode 100644 index 33bfd3b1bd..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_enterpriceprojects.go +++ /dev/null @@ -1,39 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SEnterpriseProjectManager struct { - SResourceManager -} - -func NewEnterpriseProjectManager(cfg manager.IManagerConfig) *SEnterpriseProjectManager { - m := &SEnterpriseProjectManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEPS, - Region: "", - ProjectId: "", - version: "v1.0", - Keyword: "enterprise_project", - KeywordPlural: "enterprise_projects", - - ResourceKeyword: "enterprise-projects", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_flavors.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_flavors.go deleted file mode 100644 index 596a20e68e..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_flavors.go +++ /dev/null @@ -1,37 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SFlavorManager struct { - SResourceManager -} - -func NewFlavorManager(cfg manager.IManagerConfig) *SFlavorManager { - return &SFlavorManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "flavor", - KeywordPlural: "flavors", - - ResourceKeyword: "cloudservers/flavors", // 这个接口有点特殊,实际只用到了list一个方法。为了简便直接把cloudservers附上。 - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_groups.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_groups.go deleted file mode 100644 index d7c13e487b..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_groups.go +++ /dev/null @@ -1,39 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SGroupManager struct { - SResourceManager -} - -func NewGroupManager(cfg manager.IManagerConfig) *SGroupManager { - m := &SGroupManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3", - Keyword: "group", - KeywordPlural: "groups", - - ResourceKeyword: "groups", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_images.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_images.go deleted file mode 100644 index feb90ead63..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_images.go +++ /dev/null @@ -1,102 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/cloudmux/pkg/cloudprovider" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" -) - -type SImageManager struct { - SResourceManager -} - -type imageProject struct { - projectId string -} - -// image创建接口若非默认project,需要在header中指定X-Project-ID。url中未携带project信息(与其他接口相比有一点特殊) -// 绕过了ResourceManager中的projectid。直接在发送json请求前注入X-Project-ID -func (self *imageProject) Process(request requests.IRequest) { - request.AddHeaderParam("X-Project-Id", self.projectId) -} - -func NewImageManager(cfg manager.IManagerConfig) *SImageManager { - var requestHook imageProject - if len(cfg.GetProjectId()) > 0 { - requestHook = imageProject{projectId: cfg.GetProjectId()} - } - - return &SImageManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager2(cfg, &requestHook), - ServiceName: ServiceNameIMS, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2", - Keyword: "image", - KeywordPlural: "images", - - ResourceKeyword: "cloudimages", - }} -} - -//https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091566.html -func (self *SImageManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - if querys == nil { - querys = make(map[string]string, 0) - } - - querys["id"] = id - // 这里默认使用private - // if t, exists := querys["__imagetype"]; !exists || len(t) == 0 { - // querys["__imagetype"] = "private" - // } - - ret, err := self.ListInContext(nil, querys) - if err != nil { - return nil, err - } - - if ret.Data == nil || len(ret.Data) == 0 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "image %s not found", id) - } - - return ret.Data[0], nil -} - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092108.html -// 删除image只能用这个manager -func NewOpenstackImageManager(cfg manager.IManagerConfig) *SImageManager { - var requestHook imageProject - if len(cfg.GetProjectId()) > 0 { - requestHook = imageProject{projectId: cfg.GetProjectId()} - } - - return &SImageManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager2(cfg, &requestHook), - ServiceName: ServiceNameIMS, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2", - Keyword: "image", - KeywordPlural: "images", - - ResourceKeyword: "images", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_interface.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_interface.go deleted file mode 100644 index a6c8cf5ae6..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_interface.go +++ /dev/null @@ -1,38 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SInterfaceManager struct { - SResourceManager -} - -// 不建议使用 -func NewInterfaceManager(cfg manager.IManagerConfig) *SInterfaceManager { - return &SInterfaceManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "interfaceAttachment", - KeywordPlural: "interfaceAttachments", - - ResourceKeyword: "os-interface", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_jobs.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_jobs.go deleted file mode 100644 index dbf18df310..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_jobs.go +++ /dev/null @@ -1,71 +0,0 @@ -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type SJobManager struct { - SResourceManager -} - -func NewJobManager(cfg manager.IManagerConfig) *SJobManager { - return &SJobManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: "", - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "", - KeywordPlural: "", - - ResourceKeyword: "jobs", - }} -} - -func (self *SJobManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - processedQuery, err := self.processQueryParam(querys) - if err != nil { - return nil, err - } - - return self.GetInContext(nil, id, processedQuery) -} - -func (self *SJobManager) List(querys map[string]string) (*responses.ListResult, error) { - processedQuery, err := self.processQueryParam(querys) - if err != nil { - return nil, err - } - return self.ListInContext(nil, processedQuery) -} - -// 兼容查询不同ServiceName服务的Job做的特殊处理。 -func (self *SJobManager) processQueryParam(querys map[string]string) (map[string]string, error) { - service_type, exists := querys["service_type"] - if !exists { - return querys, fmt.Errorf("must specific query parameter `service_type`. e.g. ecs|ims|iam") - } - - self.ServiceName = ServiceNameType(service_type) - delete(querys, "service_type") - return querys, nil -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_mapping.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_mapping.go deleted file mode 100644 index deb59aea3f..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_mapping.go +++ /dev/null @@ -1,39 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SAMLProviderMappingManager struct { - SResourceManager -} - -func NewSAMLProviderMappingManager(cfg manager.IManagerConfig) *SAMLProviderMappingManager { - m := &SAMLProviderMappingManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3/OS-FEDERATION", - Keyword: "mapping", - KeywordPlural: "mappings", - - ResourceKeyword: "mappings", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_natgateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_natgateway.go deleted file mode 100644 index 2b586cfd2b..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_natgateway.go +++ /dev/null @@ -1,50 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" -) - -type SNatGatewayManager struct { - SResourceManager -} - -type sProjectHook struct { - projectId string -} - -func (self *sProjectHook) Process(request requests.IRequest) { - request.AddHeaderParam("X-Project-Id", self.projectId) -} - -func NewNatGatewayManager(cfg manager.IManagerConfig) *SNatGatewayManager { - man := &SNatGatewayManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameNAT, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2.0", - Keyword: "nat_gateway", - KeywordPlural: "nat_gateways", - - ResourceKeyword: "nat_gateways", - }} - if len(cfg.GetProjectId()) > 0 { - man.requestHook = &sProjectHook{cfg.GetProjectId()} - } - return man -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_orders.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_orders.go deleted file mode 100644 index 405b4880d1..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_orders.go +++ /dev/null @@ -1,104 +0,0 @@ -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -// domian 客户账号ID https://support.huaweicloud.com/oce_faq/zh-cn_topic_0113714840.html -type SOrderManager struct { - orderCtx manager.IManagerContext - SResourceManager -} - -type orderCtx struct { - domainId string -} - -// {domain_id}/common/ -// 这个manager非常特殊。url hardcode -func (self *orderCtx) GetPath() string { - return fmt.Sprintf("%s/common", self.domainId) -} - -// 客户运营能力API的Endpoint为“bss.cn-north-1.myhuaweicloud.com”。该Endpoint为全局Endpoint,中国站所有区域均可使用。 -// https://support.huaweicloud.com/api-oce/zh-cn_topic_0084961226.html -func NewOrderManager(cfg manager.IManagerConfig) *SOrderManager { - return &SOrderManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameBSS, - Region: "cn-north-1", - ProjectId: "", - version: "v1.0", - Keyword: "", - KeywordPlural: "", - - ResourceKeyword: "order-mgr", - }} -} - -func (self *SOrderManager) SetDomainId(domainId string) error { - if len(domainId) == 0 { - return fmt.Errorf("SetDomainId domain id should not be emtpy") - } - - self.orderCtx = &orderCtx{domainId: domainId} - return nil -} - -// 查询客户包周期资源列表 https://support.huaweicloud.com/api-oce/zh-cn_topic_0084961226.html -func (self *SOrderManager) List(querys map[string]string) (*responses.ListResult, error) { - return nil, fmt.Errorf("Not Suppport List Order") -} - -// 查询订单的资源开通详情 https://support.huaweicloud.com/api-oce/api_order_00001.html -func (self *SOrderManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - if self.orderCtx == nil { - return nil, fmt.Errorf("domainId is emtpy.Use SetDomainId method to set.") - } - - // !!!特殊调用 - return self.GetInContextWithSpec(self.orderCtx, "orders-resource", id, querys, "") -} - -func (self *SOrderManager) PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - request := self.newRequest("POST", id, action, self.orderCtx) - request.SetContent([]byte(getContent(params))) - - return self._do(request, "") -} - -func (self *SOrderManager) GetPeriodResourceList(querys map[string]string) (*responses.ListResult, error) { - if self.orderCtx == nil { - return nil, fmt.Errorf("domainId is emtpy.Use SetDomainId method to set.") - } - - return self.ListInContextWithSpec(self.orderCtx, "resources/detail", querys, "data") -} - -// https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0082522029.html -func (self *SOrderManager) RenewPeriodResource(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if self.orderCtx == nil { - return nil, fmt.Errorf("domainId is emtpy.Use SetDomainId method to set.") - } - - return self.CreateInContextWithSpec(self.orderCtx, "resources/renew", params, "order_ids") -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_port.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_port.go deleted file mode 100644 index 37b3feecb2..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_port.go +++ /dev/null @@ -1,53 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" -) - -type SPortManager struct { - SResourceManager -} - -type portProject struct { - projectId string -} - -// port接口查询时若非默认project,需要在header中指定X-Project-ID。url中未携带project信息(与其他接口相比有一点特殊) -// 绕过了ResourceManager中的projectid。直接在发送json请求前注入X-Project-ID -func (self *portProject) Process(request requests.IRequest) { - request.AddHeaderParam("X-Project-Id", self.projectId) -} - -func NewPortManager(cfg manager.IManagerConfig) *SPortManager { - var requestHook portProject - if len(cfg.GetProjectId()) > 0 { - requestHook = portProject{projectId: cfg.GetProjectId()} - } - - return &SPortManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager2(cfg, &requestHook), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "port", - KeywordPlural: "ports", - - ResourceKeyword: "ports", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_projects.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_projects.go deleted file mode 100644 index 2544b7ef24..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_projects.go +++ /dev/null @@ -1,89 +0,0 @@ -// 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 modules - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/cloudmux/pkg/cloudprovider" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type SProjectManager struct { - SResourceManager -} - -func NewProjectManager(cfg manager.IManagerConfig) *SProjectManager { - m := &SProjectManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3", - Keyword: "project", - KeywordPlural: "projects", - - ResourceKeyword: "projects", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} - -func (manager *SProjectManager) ListRoles(projectId, groupId string) (*responses.ListResult, error) { - if len(projectId) == 0 { - return nil, fmt.Errorf("missing projectId") - } - if len(groupId) == 0 { - return nil, fmt.Errorf("missing groupId") - } - res := fmt.Sprintf("%s/groups/%s/roles", projectId, groupId) - return manager.ListInContextWithSpec(nil, res, nil, "roles") -} - -func (manager *SProjectManager) DeleteProjectRole(projectId, groupId, roleId string) error { - if len(projectId) == 0 { - return fmt.Errorf("missing projectId") - } - if len(groupId) == 0 { - return fmt.Errorf("missing groupId") - } - if len(roleId) == 0 { - return fmt.Errorf("missing roleId") - } - res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) - _, err := manager.DeleteInContextWithSpec(nil, projectId, res, nil, nil, "") - if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return err -} - -func (manager *SProjectManager) AddProjectRole(projectId string, groupId, roleId string) error { - if len(projectId) == 0 { - return fmt.Errorf("missing projectId") - } - if len(groupId) == 0 { - return fmt.Errorf("missing groupId") - } - if len(roleId) == 0 { - return fmt.Errorf("missing roleId") - } - res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) - _, err := manager.UpdateInContextWithSpec(nil, projectId, res, nil, "") - return err -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_regions.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_regions.go deleted file mode 100644 index a3a75dc369..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_regions.go +++ /dev/null @@ -1,37 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SRegionManager struct { - SResourceManager -} - -func NewRegionManager(cfg manager.IManagerConfig) *SRegionManager { - return &SRegionManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3", - Keyword: "region", - KeywordPlural: "regions", - - ResourceKeyword: "regions", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_roles.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_roles.go deleted file mode 100644 index 75b375edf9..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_roles.go +++ /dev/null @@ -1,39 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SRoleManager struct { - SResourceManager -} - -func NewRoleManager(cfg manager.IManagerConfig) *SRoleManager { - m := &SRoleManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3", - Keyword: "role", - KeywordPlural: "roles", - - ResourceKeyword: "roles", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_routetables.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_routetables.go deleted file mode 100644 index ebfd1ce5a9..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_routetables.go +++ /dev/null @@ -1,37 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SRouteTableManager struct { - SResourceManager -} - -func NewRouteTableManager(cfg manager.IManagerConfig) *SRouteTableManager { - return &SRouteTableManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "routetable", - KeywordPlural: "routetables", - - ResourceKeyword: "routetables", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_saml_provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_saml_provider.go deleted file mode 100644 index 9e24b35048..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_saml_provider.go +++ /dev/null @@ -1,39 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SAMLProviderManager struct { - SResourceManager -} - -func NewSAMLProviderManager(cfg manager.IManagerConfig) *SAMLProviderManager { - m := &SAMLProviderManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3/OS-FEDERATION", - Keyword: "identity_provider", - KeywordPlural: "identity_providers", - - ResourceKeyword: "identity_providers", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_servers.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_servers.go deleted file mode 100644 index fd33dc8805..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_servers.go +++ /dev/null @@ -1,124 +0,0 @@ -// 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 modules - -import ( - "fmt" - "strconv" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type SServerManager struct { - SResourceManager -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212668.html -// v.1.1 新增支持创建包年/包月的弹性云服务器。!!但是不支持查询等调用 https://support.huaweicloud.com/api-ecs/zh-cn_topic_0093055772.html -func NewServerManager(cfg manager.IManagerConfig) *SServerManager { - return &SServerManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "server", - KeywordPlural: "servers", - - ResourceKeyword: "cloudservers", - }} -} - -func (self *SServerManager) List(querys map[string]string) (*responses.ListResult, error) { - if offset, exists := querys["offset"]; !exists { - // 华为云分页参数各式各样。cloudserver offset从1开始。部分其他接口从0开始。 - // 另外部分接口使用pager分页 或者 maker分页 - querys["offset"] = "1" - } else { - n, err := strconv.Atoi(offset) - if err != nil { - return nil, fmt.Errorf("offset is invalid: %s", offset) - } - querys["offset"] = strconv.Itoa(n + 1) - } - return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) -} - -/* -返回job id 或者 order id - -https://support.huaweicloud.com/api-ecs/zh-cn_topic_0093055772.html -创建按需的弹性云服务 ——> job_id 任务ID (返回数据uuid举例:"70a599e0-31e7-49b7-b260-868f441e862b") -包年包月机器 --> order_id (返回数据举例: "CS1711152257C60TL") -*/ -func (self *SServerManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { - origin_version := self.version - self.version = "v1.1" - defer func() { self.version = origin_version }() - - ret, err := self.CreateInContextWithSpec(nil, "", params, "") - if err != nil { - log.Debugf("AsyncCreate %s", err) - return "", err - } - - log.Debugf("AsyncCreate result %s", ret.String()) - // 按需机器 - jobId, err := ret.GetString("job_id") - if err == nil { - return jobId, nil - } - - // 包年包月机器 - return ret.GetString("order_id") -} - -func (self *SServerManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return nil, fmt.Errorf("not supported.please use AsyncCreate") -} - -// 不推荐使用这个manager -func NewNovaServerManager(cfg manager.IManagerConfig) *SServerManager { - return &SServerManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2.1", - Keyword: "server", - KeywordPlural: "servers", - - ResourceKeyword: "servers", - }} -} - -// 重装弹性云服务器操作系统(安装Cloud-init),请用这个manager -func NewServerV2Manager(cfg manager.IManagerConfig) *SServerManager { - return &SServerManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "server", - KeywordPlural: "servers", - - ResourceKeyword: "cloudservers", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_sfs.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_sfs.go deleted file mode 100644 index e56161ebd1..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_sfs.go +++ /dev/null @@ -1,48 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type SfsTurboManager struct { - SResourceManager -} - -func NewSfsTurboManager(cfg manager.IManagerConfig) *SfsTurboManager { - return &SfsTurboManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameSFSTurbo, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "", - KeywordPlural: "shares", - - ResourceKeyword: "sfs-turbo/shares", - }} -} - -func (self *SfsTurboManager) List(querys map[string]string) (*responses.ListResult, error) { - return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) -} - -func (self *SfsTurboManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.CreateInContextWithSpec(self.ctx, "", params, "") -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snapshots.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snapshots.go deleted file mode 100644 index 24f801448c..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snapshots.go +++ /dev/null @@ -1,59 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type SSnapshotManager struct { - SResourceManager -} - -func NewSnapshotManager(cfg manager.IManagerConfig) *SSnapshotManager { - return &SSnapshotManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEVS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "snapshot", - KeywordPlural: "snapshots", - - ResourceKeyword: "snapshots", - }} -} - -func (self *SSnapshotManager) List(querys map[string]string) (*responses.ListResult, error) { - return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408629.html -// 回滚快照只能用这个manger。其他情况请不要使用 -// 另外,香港-亚太还支持另外一个接口。https://support.huaweicloud.com/api-evs/zh-cn_topic_0142374138.html -func NewOsSnapshotManager(cfg manager.IManagerConfig) *SSnapshotManager { - return &SSnapshotManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEVS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "snapshot", - KeywordPlural: "snapshots", - - ResourceKeyword: "os-vendor-snapshots", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snat_rules.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snat_rules.go deleted file mode 100644 index 82f818ea14..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snat_rules.go +++ /dev/null @@ -1,41 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SNatSRuleManager struct { - SResourceManager -} - -func NewNatSManager(cfg manager.IManagerConfig) *SNatSRuleManager { - man := &SNatSRuleManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameNAT, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2.0", - Keyword: "snat_rule", - KeywordPlural: "snat_rules", - - ResourceKeyword: "snat_rules", - }} - if len(cfg.GetProjectId()) > 0 { - man.requestHook = &sProjectHook{cfg.GetProjectId()} - } - return man -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_subnets.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_subnets.go deleted file mode 100644 index 99bef6ab13..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_subnets.go +++ /dev/null @@ -1,37 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SSubnetManager struct { - SResourceManager -} - -func NewSubnetManager(cfg manager.IManagerConfig) *SSubnetManager { - return &SSubnetManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "subnet", - KeywordPlural: "subnets", - - ResourceKeyword: "subnets", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_traces.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_traces.go deleted file mode 100644 index d46d15b47e..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_traces.go +++ /dev/null @@ -1,37 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type STraceManager struct { - SResourceManager -} - -func NewTraceManager(cfg manager.IManagerConfig) *STraceManager { - return &STraceManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameCTS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2.0", - Keyword: "trace", - KeywordPlural: "traces", - - ResourceKeyword: "system/trace", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_users.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_users.go deleted file mode 100644 index e7bb96bae0..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_users.go +++ /dev/null @@ -1,69 +0,0 @@ -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -type SUserManager struct { - SResourceManager -} - -func NewUserManager(cfg manager.IManagerConfig) *SUserManager { - user := &SUserManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3.0/OS-USER", - Keyword: "user", - KeywordPlural: "users", - - ResourceKeyword: "users", - }} - user.SetDomainId(cfg.GetDomainId()) - return user -} - -func (self *SUserManager) List(querys map[string]string) (*responses.ListResult, error) { - self.SetVersion("v3") - return self.SResourceManager.List(querys) -} - -func (self *SUserManager) Delete(id string) (jsonutils.JSONObject, error) { - self.SetVersion("v3") - return self.SResourceManager.Delete(id, nil) -} - -func (self *SUserManager) ResetPassword(id, password string) error { - params := map[string]interface{}{ - "user": map[string]string{ - "password": password, - }, - } - _, err := self.SResourceManager.Update(id, jsonutils.Marshal(params)) - return err -} - -func (self *SUserManager) ListGroups(userId string) (*responses.ListResult, error) { - self.SetVersion("v3") - return self.SResourceManager.ListInContextWithSpec(nil, fmt.Sprintf("%s/groups", userId), nil, "groups") -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_peerings.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_peerings.go deleted file mode 100644 index 35b5b78d3b..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_peerings.go +++ /dev/null @@ -1,37 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SVpcPeeringManager struct { - SResourceManager -} - -func NewVpcPeeringManager(cfg manager.IManagerConfig) *SVpcPeeringManager { - return &SVpcPeeringManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2.0", - Keyword: "peering", - KeywordPlural: "peerings", - - ResourceKeyword: "vpc/peerings", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_routes.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_routes.go deleted file mode 100644 index 493c934edd..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_routes.go +++ /dev/null @@ -1,38 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SVpcRouteManager struct { - SResourceManager -} - -func NewVpcRouteManager(cfg manager.IManagerConfig) *SVpcRouteManager { - return &SVpcRouteManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - // the url should not include the field "projectid" in huawei cloud api v2.0 - ProjectId: "", - version: "v2.0", - Keyword: "route", - KeywordPlural: "routes", - - ResourceKeyword: "vpc/routes", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpcs.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpcs.go deleted file mode 100644 index 11b218cefb..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpcs.go +++ /dev/null @@ -1,37 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SVpcManager struct { - SResourceManager -} - -func NewVpcManager(cfg manager.IManagerConfig) *SVpcManager { - return &SVpcManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "vpc", - KeywordPlural: "vpcs", - - ResourceKeyword: "vpcs", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_zones.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_zones.go deleted file mode 100644 index 25f783ae26..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_zones.go +++ /dev/null @@ -1,37 +0,0 @@ -// 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 modules - -import ( - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" -) - -type SZoneManager struct { - SResourceManager -} - -func NewZoneManager(cfg manager.IManagerConfig) *SZoneManager { - return &SZoneManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "availabilityZoneInfo", - KeywordPlural: "availabilityZoneInfo", - - ResourceKeyword: "os-availability-zone", - }} -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/doc.go deleted file mode 100644 index 1efcc36222..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// 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 requests // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/requests.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/requests.go deleted file mode 100644 index 6d8c812f57..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/requests.go +++ /dev/null @@ -1,276 +0,0 @@ -// 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 requests - -import ( - "fmt" - "io" - "net/url" - "sort" - "strings" -) - -type IRequest interface { - GetScheme() string - GetMethod() string - GetDomain() string - GetPort() string - GetRegionId() string - GetProjectId() string - GetHost() string - GetURI() string - GetHeaders() map[string]string - GetQueryParams() map[string]string - GetFormParams() map[string]string - GetContent() []byte - GetBodyReader() io.Reader - GetProduct() string - GetVersion() string - - SetStringToSign(stringToSign string) - GetStringToSign() string - - SetDomain(domain string) - SetContent(content []byte) - SetScheme(scheme string) - BuildUrl() string - BuildQueries() string - - AddHeaderParam(key, value string) - AddQueryParam(key, value string) - AddFormParam(key, value string) -} - -type SRequest struct { - Scheme string // HTTP、HTTPS - Method string // GET、PUT、DELETE、POST、PATCH - Domain string // myhuaweicloud.com - Port string // 80 - RegionId string // cn-north-1 - - product string // 弹性云服务 ECS : ecs - version string // API版本: v2 - projectId string // 项目ID: 43cbe5e77aaf4665bbb962062dc1fc9d.可以为空。 - - resourcePath string // /users/{user_id}/groups - QueryParams map[string]string - Headers map[string]string - FormParams map[string]string - Content []byte - - queries string - - stringToSign string -} - -func (self *SRequest) GetProjectId() string { - return self.projectId -} - -func (self *SRequest) GetScheme() string { - return self.Scheme -} - -func (self *SRequest) GetMethod() string { - return self.Method -} - -func (self *SRequest) GetDomain() string { - return self.Domain -} - -func (self *SRequest) GetPort() string { - return self.Port -} - -func (self *SRequest) GetRegionId() string { - return self.RegionId -} - -func (self *SRequest) GetHeaders() map[string]string { - return self.Headers -} - -func (self *SRequest) GetQueryParams() map[string]string { - return self.QueryParams -} - -func (self *SRequest) GetFormParams() map[string]string { - return self.FormParams -} - -func (self *SRequest) GetContent() []byte { - return self.Content -} - -func (self *SRequest) GetBodyReader() io.Reader { - if self.FormParams != nil && len(self.FormParams) > 0 { - formData := GetUrlFormedMap(self.FormParams) - return strings.NewReader(formData) - } else { - return strings.NewReader(string(self.Content)) - } -} - -func (self *SRequest) GetProduct() string { - return self.product -} - -func (self *SRequest) GetVersion() string { - return self.version -} - -func (self *SRequest) SetStringToSign(stringToSign string) { - self.stringToSign = stringToSign -} - -func (self *SRequest) GetStringToSign() string { - return self.stringToSign -} - -func (self *SRequest) SetDomain(domain string) { - self.Domain = domain -} - -func (self *SRequest) SetContent(content []byte) { - self.Content = content -} - -func (self *SRequest) SetScheme(scheme string) { - self.Scheme = scheme -} - -func (self *SRequest) BuildUrl() string { - scheme := strings.ToLower(self.Scheme) - baseUrl := fmt.Sprintf("%s://%s", scheme, self.GetHost()) - queries := self.BuildQueries() - if len(queries) > 0 { - return baseUrl + self.GetURI() + "?" + queries - } else { - return baseUrl + self.GetURI() - } -} - -func (self *SRequest) GetHost() string { - scheme := strings.ToLower(self.Scheme) - host := self.getEndpoint() - if len(self.Port) > 0 { - if (scheme == "http" && self.Port == "80") || (scheme == "https" && self.Port == "443") { - host = fmt.Sprintf("%s:%s", host, self.Port) - } - } - - return host -} - -func (self *SRequest) GetURI() string { - // URI - uri := "" - for _, m := range []string{self.version, self.projectId} { - if len(m) > 0 { - uri += fmt.Sprintf("/%s", m) - } - } - - if len(self.resourcePath) > 0 { - s := "" - if !strings.HasPrefix(self.resourcePath, "/") { - s = "/" - } - - if strings.HasSuffix(self.resourcePath, "/") { - strings.TrimSuffix(s, "/") - } - - uri = uri + s + self.resourcePath - } - - return uri -} - -func (self *SRequest) getEndpoint() string { - // ecs.cn-north-1.myhuaweicloud.com - items := []string{} - for _, item := range []string{self.product, self.RegionId, self.Domain} { - if len(item) > 0 { - items = append(items, item) - } - } - - return strings.Join(items, ".") -} - -func (self *SRequest) BuildQueries() string { - self.queries = GetUrlFormedMap(self.QueryParams) - return self.queries -} - -func (self *SRequest) AddHeaderParam(key, value string) { - self.Headers[key] = value -} - -func (self *SRequest) AddQueryParam(key, value string) { - self.QueryParams[key] = value -} - -func (self *SRequest) AddFormParam(key, value string) { - self.FormParams[key] = value -} - -func GetUrlFormedMap(source map[string]string) string { - // 按key排序后编译 - keys := make([]string, 0) - for k := range source { - keys = append(keys, k) - } - - sort.Slice(keys, func(i, j int) bool { - return strings.ToLower(keys[i]) < strings.ToLower(keys[j]) - }) - - urlEncoder := url.Values{} - for _, k := range keys { - urlEncoder.Add(k, source[k]) - } - - return urlEncoder.Encode() -} - -func defaultRequest() (request *SRequest) { - request = &SRequest{ - Scheme: "HTTPS", - Method: "GET", - QueryParams: make(map[string]string), - Headers: map[string]string{}, - FormParams: make(map[string]string), - } - return -} - -func NewResourceRequest(domain, method, product, version, region, project, resourcePath string) *SRequest { - return &SRequest{ - Scheme: "HTTPS", - Method: method, - Domain: domain, - product: product, - RegionId: region, - version: version, - projectId: project, - resourcePath: resourcePath, - QueryParams: make(map[string]string), - Headers: map[string]string{}, - FormParams: make(map[string]string), - } -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/doc.go deleted file mode 100644 index 64028392cf..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// 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 responses // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/responses.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/responses.go deleted file mode 100644 index 7bdae4aa35..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/responses.go +++ /dev/null @@ -1,77 +0,0 @@ -// 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 responses - -import ( - "regexp" - "strings" - - "yunion.io/x/jsonutils" -) - -type ListResult struct { - Data []jsonutils.JSONObject - Total int - Limit int - Offset int - NextLink string -} - -func ListResult2JSONWithKey(result *ListResult, key string) jsonutils.JSONObject { - obj := jsonutils.NewDict() - if result.Total > 0 { - obj.Add(jsonutils.NewInt(int64(result.Total)), "total") - } - if result.Limit > 0 { - obj.Add(jsonutils.NewInt(int64(result.Limit)), "limit") - } - if result.Offset > 0 { - obj.Add(jsonutils.NewInt(int64(result.Offset)), "offset") - } - arr := jsonutils.NewArray(result.Data...) - obj.Add(arr, key) - return obj -} - -func ListResult2JSON(result *ListResult) jsonutils.JSONObject { - return ListResult2JSONWithKey(result, "data") -} - -func JSON2ListResult(result jsonutils.JSONObject) *ListResult { - total, _ := result.Int("total") - limit, _ := result.Int("limit") - offset, _ := result.Int("offset") - data, _ := result.GetArray("data") - return &ListResult{Data: data, Total: int(total), Limit: int(limit), Offset: int(offset)} -} - -// 将key中的冒号替换成 -func TransColonToDot(obj jsonutils.JSONObject) (jsonutils.JSONObject, error) { - re, _ := regexp.Compile("[a-zA-Z0-9](:+)[^\"]+\"\\s*:\\s*") - - if obj == nil { - return obj, nil - } - - newStr := re.ReplaceAllStringFunc(obj.String(), func(s string) string { - count := strings.Count(s, ":") - if count > 1 { - return strings.Replace(s, ":", ".", count-1) - } - return s - }) - - return jsonutils.ParseString(newStr) -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/cloudgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/cloudgroup.go index ed0363eee4..e6c42119c5 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/cloudgroup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/cloudgroup.go @@ -16,9 +16,9 @@ package huawei import ( "fmt" + "net/url" "strings" - "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/cloudmux/pkg/cloudprovider" @@ -134,24 +134,24 @@ func (group *SCloudgroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { return ret, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListGroups func (self *SHuaweiClient) GetGroups(domainId, name string) ([]SCloudgroup, error) { - params := map[string]string{} + query := url.Values{} if len(domainId) > 0 { - params["domain_id"] = self.ownerId + query.Set("domain_id", self.ownerId) } if len(name) > 0 { - params["name"] = name - } - - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") + query.Set("name", name) } groups := []SCloudgroup{} - err = doListAllWithNextLink(client.Groups.List, params, &groups) + resp, err := self.list(SERVICE_IAM_V3, "", "groups", query) if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") + return nil, err + } + err = resp.Unmarshal(&groups, "groups") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") } return groups, nil } @@ -171,59 +171,53 @@ func (self *SHuaweiClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error return ret, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListUsersForGroupByAdmin func (self *SHuaweiClient) GetGroupUsers(groupId string) ([]SClouduser, error) { - client, err := self.newGeneralAPIClient() + resp, err := self.list(SERVICE_IAM_V3, "", fmt.Sprintf("groups/%s/users", groupId), nil) if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - - resp, err := client.Groups.ListInContextWithSpec(nil, fmt.Sprintf("%s/users", groupId), nil, "users") - if err != nil { - return nil, errors.Wrap(err, "") + return nil, errors.Wrapf(err, "list group users") } users := []SClouduser{} - err = jsonutils.Update(&users, resp.Data) + err = resp.Unmarshal(&users, "users") if err != nil { - return nil, errors.Wrap(err, "jsonutils.Update") + return nil, errors.Wrap(err, "Unmarshal") } return users, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneCheckDomainPermissionForGroup func (self *SHuaweiClient) GetGroupRoles(groupId string) ([]SRole, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - resp, err := client.Domains.ListRoles(self.ownerId, groupId) + res := fmt.Sprintf("domains/%s/groups/%s/roles", self.ownerId, groupId) + resp, err := self.list(SERVICE_IAM_V3, "", res, nil) if err != nil { return nil, errors.Wrap(err, "ListRoles") } roles := []SRole{} - err = jsonutils.Update(&roles, resp.Data) + err = resp.Unmarshal(&roles, "roles") if err != nil { - return nil, errors.Wrap(err, "jsonutils.Update") + return nil, errors.Wrap(err, "Unmarshal") } return roles, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneCreateGroup func (self *SHuaweiClient) CreateGroup(name, desc string) (*SCloudgroup, error) { - params := map[string]string{ + params := map[string]interface{}{ "name": name, } if len(desc) > 0 { params["description"] = desc } - client, err := self.newGeneralAPIClient() + resp, err := self.post(SERVICE_IAM_V3, "", "groups", map[string]interface{}{"group": params}) if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") + return nil, err } - - group := SCloudgroup{client: self} - err = DoCreate(client.Groups.Create, jsonutils.Marshal(map[string]interface{}{"group": params}), &group) + group := &SCloudgroup{client: self} + err = resp.Unmarshal(group, "group") if err != nil { - return nil, errors.Wrap(err, "DoCreate") + return nil, errors.Wrapf(err, "Unmarshal") } - return &group, nil + return group, nil } func (self *SHuaweiClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { @@ -234,12 +228,10 @@ func (self *SHuaweiClient) CreateICloudgroup(name, desc string) (cloudprovider.I return group, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneDeleteGroup func (self *SHuaweiClient) DeleteGroup(id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - return DoDeleteWithSpec(client.Groups.DeleteInContextWithSpec, nil, id, "", nil, nil) + _, err := self.delete(SERVICE_IAM_V3, "", "groups/"+id) + return err } func (self *SHuaweiClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { @@ -257,41 +249,46 @@ func (self *SHuaweiClient) GetICloudgroupByName(name string) (cloudprovider.IClo return &groups[0], nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneAddUserToGroup func (self *SHuaweiClient) AddUserToGroup(groupId, userId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.Groups.UpdateInContextWithSpec(nil, groupId, fmt.Sprintf("users/%s", userId), nil, "") + _, err := self.put(SERVICE_IAM_V3, "", fmt.Sprintf("groups/%s/users/%s", groupId, userId), nil) return err } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneRemoveUserFromGroup func (self *SHuaweiClient) RemoveUserFromGroup(groupId, userId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.Groups.DeleteInContextWithSpec(nil, groupId, fmt.Sprintf("users/%s", userId), nil, nil, "") + _, err := self.delete(SERVICE_IAM_V3, "", fmt.Sprintf("groups/%s/users/%s", groupId, userId)) return err } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=ListCustomPolicies func (self *SHuaweiClient) GetCustomRoles() ([]SRole, error) { - params := map[string]string{} - - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") + query := url.Values{} + query.Set("per_page", "300") + page := 1 + query.Set("page", fmt.Sprintf("%d", page)) + ret := []SRole{} + for { + resp, err := self.list(SERVICE_IAM, "", "OS-ROLE/roles", query) + if err != nil { + return nil, err + } + part := struct { + Roles []SRole + TotalNumber int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.Roles...) + if len(ret) >= part.TotalNumber || len(part.Roles) == 0 { + break + } + page++ + query.Set("page", fmt.Sprintf("%d", page)) } - - client.Roles.SetVersion("v3.0/OS-ROLE") - defer client.Roles.SetVersion("v3.0") - - roles := []SRole{} - err = doListAllWithNextLink(client.Roles.List, params, &roles) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return roles, nil + return ret, nil } func (self *SHuaweiClient) GetCustomRole(name string) (*SRole, error) { @@ -321,23 +318,19 @@ func (self *SHuaweiClient) GetRole(name string) (*SRole, error) { } func (self *SHuaweiClient) DetachGroupRole(groupId, roleId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } role, err := self.GetRole(roleId) if err != nil { return errors.Wrapf(err, "GetRole(%s)", roleId) } if role.Type == "AX" || role.Type == "AA" { - err = client.Domains.AddRole(self.ownerId, groupId, role.Id) + err := self.KeystoneRemoveDomainPermissionFromGroup(self.ownerId, groupId, roleId) if err != nil { - return errors.Wrapf(err, "AddRole") + return errors.Wrapf(err, "remove domain role") } if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { - err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) + err := self.KeystoneRemoveProjectPermissionFromGroup(self.GetMosProjectId(), groupId, role.Id) if err != nil { - return errors.Wrapf(err, "AddProjectRole") + return errors.Wrapf(err, "remove project role ") } } } @@ -347,33 +340,57 @@ func (self *SHuaweiClient) DetachGroupRole(groupId, roleId string) error { return errors.Wrapf(err, "GetProjects") } for _, project := range projects { - err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) + err := self.KeystoneRemoveProjectPermissionFromGroup(project.ID, groupId, role.Id) if err != nil { - return errors.Wrapf(err, "AddProjectRole") + return errors.Wrapf(err, "remove project role ") } } } return nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneRemoveProjectPermissionFromGroup +func (self *SHuaweiClient) KeystoneRemoveProjectPermissionFromGroup(projectId, groupId, roleId string) error { + res := fmt.Sprintf("projects/%s/groups/%s/roles/%s", projectId, groupId, roleId) + _, err := self.delete(SERVICE_IAM_V3, "", res) + return err +} + +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneAssociateGroupWithProjectPermission +func (self *SHuaweiClient) KeystoneAssociateGroupWithProjectPermission(projectId, groupId, roleId string) error { + res := fmt.Sprintf("projects/%s/groups/%s/roles/%s", self.GetMosProjectId(), groupId, roleId) + _, err := self.put(SERVICE_IAM_V3, "", res, nil) + return err +} + +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneAssociateGroupWithDomainPermission +func (self *SHuaweiClient) KeystoneAssociateGroupWithDomainPermission(domainId, groupId, roleId string) error { + res := fmt.Sprintf("domains/%s/groups/%s/roles/%s", domainId, groupId, roleId) + _, err := self.put(SERVICE_IAM_V3, "", res, nil) + return err +} + +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneRemoveDomainPermissionFromGroup +func (self *SHuaweiClient) KeystoneRemoveDomainPermissionFromGroup(domainId, groupId, roleId string) error { + res := fmt.Sprintf("domains/%s/groups/%s/roles/%s", domainId, groupId, roleId) + _, err := self.delete(SERVICE_IAM_V3, "", res) + return err +} + func (self *SHuaweiClient) AttachGroupRole(groupId, roleId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } role, err := self.GetRole(roleId) if err != nil { return errors.Wrapf(err, "GetRole(%s)", roleId) } if role.Type == "AX" || role.Type == "AA" { - err = client.Domains.AddRole(self.ownerId, groupId, role.Id) + err := self.KeystoneAssociateGroupWithDomainPermission(self.ownerId, groupId, roleId) if err != nil { return errors.Wrapf(err, "AddRole") } if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { - err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) + err := self.KeystoneAssociateGroupWithProjectPermission(self.GetMosProjectId(), groupId, role.Id) if err != nil { - return errors.Wrapf(err, "AddProjectRole") + return errors.Wrapf(err, "add project role ") } } } @@ -383,9 +400,9 @@ func (self *SHuaweiClient) AttachGroupRole(groupId, roleId string) error { return errors.Wrapf(err, "GetProjects") } for _, project := range projects { - err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) + err := self.KeystoneAssociateGroupWithProjectPermission(project.ID, groupId, role.Id) if err != nil { - return errors.Wrapf(err, "AddProjectRole") + return errors.Wrapf(err, "add project role ") } } } @@ -393,23 +410,19 @@ func (self *SHuaweiClient) AttachGroupRole(groupId, roleId string) error { } func (self *SHuaweiClient) AttachGroupCustomRole(groupId, roleId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } role, err := self.GetCustomRole(roleId) if err != nil { return errors.Wrapf(err, "GetRole(%s)", roleId) } if role.Type == "AX" || role.Type == "AA" { - err = client.Domains.AddRole(self.ownerId, groupId, role.Id) + err := self.KeystoneAssociateGroupWithDomainPermission(self.ownerId, groupId, roleId) if err != nil { return errors.Wrapf(err, "AddRole") } if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { - err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) + err = self.KeystoneAssociateGroupWithProjectPermission(self.GetMosProjectId(), groupId, role.Id) if err != nil { - return errors.Wrapf(err, "AddProjectRole") + return errors.Wrapf(err, "add project role ") } } } @@ -419,9 +432,9 @@ func (self *SHuaweiClient) AttachGroupCustomRole(groupId, roleId string) error { return errors.Wrapf(err, "GetProjects") } for _, project := range projects { - err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) + err := self.KeystoneAssociateGroupWithProjectPermission(project.ID, groupId, role.Id) if err != nil { - return errors.Wrapf(err, "AddProjectRole") + return errors.Wrapf(err, "add project role ") } } } @@ -429,23 +442,19 @@ func (self *SHuaweiClient) AttachGroupCustomRole(groupId, roleId string) error { } func (self *SHuaweiClient) DetachGroupCustomRole(groupId, roleId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } role, err := self.GetCustomRole(roleId) if err != nil { return errors.Wrapf(err, "GetCustomRole(%s)", roleId) } if role.Type == "AX" || role.Type == "AA" { - err = client.Domains.DeleteRole(self.ownerId, groupId, role.Id) + err := self.KeystoneRemoveDomainPermissionFromGroup(self.ownerId, groupId, roleId) if err != nil { return errors.Wrapf(err, "DeleteRole") } if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { - err = client.Projects.DeleteProjectRole(self.GetMosProjectId(), groupId, role.Id) + err := self.KeystoneRemoveProjectPermissionFromGroup(self.GetMosProjectId(), groupId, role.Id) if err != nil { - return errors.Wrapf(err, "DeleteProjectRole") + return errors.Wrapf(err, "remove project role ") } } } @@ -455,9 +464,9 @@ func (self *SHuaweiClient) DetachGroupCustomRole(groupId, roleId string) error { return errors.Wrapf(err, "GetProjects") } for _, project := range projects { - err = client.Projects.DeleteProjectRole(project.ID, groupId, role.Id) + err := self.KeystoneRemoveProjectPermissionFromGroup(project.ID, groupId, role.Id) if err != nil { - return errors.Wrapf(err, "DeleteProjectRole") + return errors.Wrapf(err, "remove project role ") } } } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/clouduser.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/clouduser.go index f78c9fb163..03e8cf35dc 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/clouduser.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/clouduser.go @@ -15,14 +15,14 @@ package huawei import ( + "fmt" "net/url" + "strings" "time" - "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/cloudmux/pkg/cloudprovider" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" ) type SLink struct { @@ -111,45 +111,40 @@ func (user *SClouduser) ResetPassword(password string) error { return user.client.ResetClouduserPassword(user.Id, password) } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneDeleteUser func (self *SHuaweiClient) DeleteClouduser(id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.Users.Delete(id) + _, err := self.delete(SERVICE_IAM_V3, "", "users/"+id) return err } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListGroupsForUser func (self *SHuaweiClient) ListUserGroups(userId string) ([]SCloudgroup, error) { - client, err := self.newGeneralAPIClient() + resp, err := self.list(SERVICE_IAM_V3, "", fmt.Sprintf("users/%s/groups", userId), nil) if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - result, err := client.Users.ListGroups(userId) - if err != nil { - return nil, errors.Wrap(err, "Users.ListGroups") + return nil, err } groups := []SCloudgroup{} - err = jsonutils.Update(&groups, result.Data) + err = resp.Unmarshal(&groups, "groups") if err != nil { - return nil, errors.Wrap(err, "jsonutils.Update") + return nil, err } return groups, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListUsers func (self *SHuaweiClient) GetCloudusers(name string) ([]SClouduser, error) { - params := map[string]string{} + params := url.Values{} if len(name) > 0 { - params["name"] = name + params.Set("name", name) + } + resp, err := self.list(SERVICE_IAM_V3, "", "users", params) + if err != nil { + return nil, err } users := []SClouduser{} - client, err := self.newGeneralAPIClient() + err = resp.Unmarshal(&users, "users") if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - err = doListAllWithOffset(client.Users.List, params, &users) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") + return nil, err } return users, nil } @@ -188,8 +183,9 @@ func (self *SHuaweiClient) CreateIClouduser(conf *cloudprovider.SClouduserCreate return self.CreateClouduser(conf.Name, conf.Password, conf.Desc) } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=CreateUser func (self *SHuaweiClient) CreateClouduser(name, password, desc string) (*SClouduser, error) { - params := map[string]string{ + params := map[string]interface{}{ "name": name, "domain_id": self.ownerId, } @@ -199,28 +195,29 @@ func (self *SHuaweiClient) CreateClouduser(name, password, desc string) (*SCloud if len(desc) > 0 { params["description"] = desc } - client, err := self.newGeneralAPIClient() + resp, err := self.post(SERVICE_IAM, "", "OS-USER/users", map[string]interface{}{"user": params}) if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - user := SClouduser{client: self} - err = DoCreate(client.Users.Create, jsonutils.Marshal(map[string]interface{}{"user": params}), &user) - if err != nil { - ce, ok := err.(*modules.HuaweiClientError) - if ok && len(ce.Errorcode) > 0 && ce.Errorcode[0] == "1101" { + if strings.Contains(err.Error(), "1101") { return nil, errors.Wrap(err, `IAM user name. The length is between 5 and 32. The first digit is not a number. Special characters can only contain the '_' '-' or ' '`) //https://support.huaweicloud.com/api-iam/iam_08_0015.html } - return nil, errors.Wrap(err, "DoCreate") + return nil, err } - return &user, nil + user := &SClouduser{client: self} + err = resp.Unmarshal(user, "user") + if err != nil { + return nil, err + } + return user, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=UpdateUser func (self *SHuaweiClient) ResetClouduserPassword(id, password string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - return client.Users.ResetPassword(id, password) + _, err := self.put(SERVICE_IAM, "", "OS-USER/users/"+id, map[string]interface{}{ + "user": map[string]interface{}{ + "password": password, + }, + }) + return err } type SAccessKey struct { @@ -233,6 +230,7 @@ type SAccessKey struct { CreatedAt time.Time `json:"create_time"` } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=ListPermanentAccessKeys func (self *SHuaweiClient) GetAKSK(id string) ([]cloudprovider.SAccessKey, error) { query := url.Values{} query.Set("user_id", id) @@ -253,6 +251,7 @@ func (self *SHuaweiClient) GetAKSK(id string) ([]cloudprovider.SAccessKey, error return res, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=CreatePermanentAccessKey func (self *SHuaweiClient) CreateAKSK(id, name string) (*cloudprovider.SAccessKey, error) { params := map[string]interface{}{ "credential": map[string]interface{}{ @@ -265,7 +264,10 @@ func (self *SHuaweiClient) CreateAKSK(id, name string) (*cloudprovider.SAccessKe return nil, errors.Wrap(err, "SHuaweiClient.createAKSK") } ak := SAccessKey{} - obj.Unmarshal(&ak, "credential") + err = obj.Unmarshal(&ak, "credential") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } res := cloudprovider.SAccessKey{ Name: ak.Description, AccessKey: ak.AccessKey, @@ -274,6 +276,7 @@ func (self *SHuaweiClient) CreateAKSK(id, name string) (*cloudprovider.SAccessKe return &res, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=DeletePermanentAccessKey func (self *SHuaweiClient) DeleteAKSK(accessKey string) error { _, err := self.delete(SERVICE_IAM, "", "OS-CREDENTIAL/credentials/"+accessKey) return err diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance.go index c3a6484d58..a08374e7fc 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance.go @@ -17,6 +17,7 @@ package huawei import ( "context" "fmt" + "net/url" "time" "yunion.io/x/jsonutils" @@ -97,20 +98,46 @@ type SDBInstance struct { EnterpriseProjectId string } -func (region *SRegion) GetDBInstances() ([]SDBInstance, error) { - params := map[string]string{} - dbinstances := []SDBInstance{} - err := doListAllWithOffset(region.ecsClient.DBInstance.List, params, &dbinstances) - return dbinstances, err +func (region *SRegion) GetDBInstances(id string) ([]SDBInstance, error) { + query := url.Values{} + if len(id) > 0 { + query.Set("id", id) + } + ret := []SDBInstance{} + for { + resp, err := region.list(SERVICE_RDS, "instances", query) + if err != nil { + return nil, errors.Wrapf(err, "list instances") + } + part := struct { + Instances []SDBInstance + TotalCount int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.Instances...) + if len(ret) >= part.TotalCount || len(part.Instances) == 0 { + break + } + query.Set("offset", fmt.Sprintf("%d", len(ret))) + } + return ret, nil } func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) { - if len(instanceId) == 0 { - return nil, cloudprovider.ErrNotFound + ret, err := region.GetDBInstances(instanceId) + if err != nil { + return nil, err } - instance := SDBInstance{region: region} - err := DoGet(region.ecsClient.DBInstance.Get, instanceId, nil, &instance) - return &instance, err + for i := range ret { + if ret[i].Id == instanceId { + ret[i].region = region + return &ret[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, instanceId) } func (rds *SDBInstance) GetName() string { @@ -160,8 +187,12 @@ func (rds *SDBInstance) GetStatus() string { } func (rds *SDBInstance) GetBillingType() string { - _, err := rds.region.GetOrderResourceDetail(fmt.Sprintf("%s.vm", rds.Id)) + orders, err := rds.region.client.GetOrderResources() if err != nil { + return billing_api.BILLING_TYPE_PREPAID + } + _, ok := orders[rds.Id] + if ok { return billing_api.BILLING_TYPE_POSTPAID } return billing_api.BILLING_TYPE_PREPAID @@ -184,11 +215,15 @@ func (rds *SDBInstance) fetchFlavor() error { } func (rds *SDBInstance) GetExpiredAt() time.Time { - order, err := rds.region.GetOrderResourceDetail(fmt.Sprintf("%s.vm", rds.Id)) + orders, err := rds.region.client.GetOrderResources() if err != nil { return time.Time{} } - return order.ExpireTime + order, ok := orders[rds.Id] + if ok { + return order.ExpireTime + } + return time.Time{} } func (rds *SDBInstance) GetStorageType() string { @@ -353,7 +388,7 @@ func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.IClo } func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { - instances, err := region.GetDBInstances() + instances, err := region.GetDBInstances("") if err != nil { return nil, errors.Wrapf(err, "region.GetDBInstances()") } @@ -420,7 +455,7 @@ func (rds *SDBInstance) Delete() error { } func (region *SRegion) DeleteDBInstance(instanceId string) error { - _, err := region.ecsClient.DBInstance.Delete(instanceId, nil) + _, err := region.delete(SERVICE_RDS, "instances/"+instanceId) return err } @@ -506,7 +541,7 @@ func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceC } params["flavor_ref"] = desc.InstanceType params["availability_zone"] = desc.ZoneId - resp, err := region.ecsClient.DBInstance.Create(jsonutils.Marshal(params)) + resp, err := region.post(SERVICE_RDS, "instances", params) if err != nil { return nil, errors.Wrapf(err, "Create") } @@ -518,20 +553,15 @@ func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceC } if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { err = cloudprovider.Wait(10*time.Second, 20*time.Minute, func() (bool, error) { - job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) + job, err := region.GetDBInstanceJob(jobId) if err != nil { return false, nil } - status, _ := job.GetString("status") - process, _ := job.GetString("process") - log.Debugf("create dbinstance job %s status: %s process: %s", jobId, status, process) - if status == "Completed" { - region.UpdateVM(instance.Id, cloudprovider.SInstanceUpdateOptions{ - Description: desc.Description, - }) + log.Debugf("create dbinstance job %s status: %s process: %s", jobId, job.Status, job.Process) + if job.Status == "Completed" { return true, nil } - if status == "Failed" { + if job.Status == "Failed" { return false, fmt.Errorf("create failed") } return false, nil @@ -554,25 +584,43 @@ func (rds *SDBInstance) ClosePublicConnection() error { //return rds.region.PublicConnectionAction(rds.Id, "closeRC") } +type SDBInstanceJob struct { + Status string + Process string +} + +func (self *SRegion) GetDBInstanceJob(id string) (*SDBInstanceJob, error) { + query := url.Values{} + query.Set("id", id) + resp, err := self.list(SERVICE_RDS, "jobs", query) + if err != nil { + return nil, err + } + ret := &SDBInstanceJob{} + err = resp.Unmarshal(ret, "job") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + return ret, nil +} + func (region *SRegion) PublicConnectionAction(instanceId string, action string) error { - resp, err := region.ecsClient.DBInstance.PerformAction2(action, instanceId, nil, "") + resp, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/%s", instanceId, action), nil) if err != nil { return errors.Wrapf(err, "rds.%s", action) } if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { - job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) + job, err := region.GetDBInstanceJob(jobId) if err != nil { log.Errorf("failed to get job %s info error: %v", jobId, err) return false } - status, _ := job.GetString("status") - process, _ := job.GetString("process") - if status == "Completed" { + if job.Status == "Completed" { return true } - log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, status, process) + log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, job.Status, job.Process) return false }) } @@ -582,26 +630,23 @@ func (region *SRegion) PublicConnectionAction(instanceId string, action string) } func (region *SRegion) RebootDBInstance(instanceId string) error { - params := jsonutils.Marshal(map[string]interface{}{ + params := map[string]interface{}{ "restart": map[string]string{}, - }) - resp, err := region.ecsClient.DBInstance.PerformAction2("action", instanceId, params, "") + } + resp, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/action", instanceId), params) if err != nil { return err } if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { - job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) + job, err := region.GetDBInstanceJob(jobId) if err != nil { - log.Errorf("failed to get job %s info error: %v", jobId, err) return false } - status, _ := job.GetString("status") - process, _ := job.GetString("process") - if status == "Completed" { + if job.Status == "Completed" { return true } - log.Debugf("reboot dbinstance job %s status: %s process: %s", jobId, status, process) + log.Debugf("reboot dbinstance job %s status: %s process: %s", jobId, job.Status, job.Process) return false }) } @@ -616,12 +661,20 @@ type SDBInstanceFlavor struct { } func (region *SRegion) GetDBInstanceFlavors(engine string, version string) ([]SDBInstanceFlavor, error) { - flavors := []SDBInstanceFlavor{} - resp, err := region.ecsClient.DBInstanceFlavor.ListInContextWithSpec(nil, engine, map[string]string{"version_name": version}, "flavors") + query := url.Values{} + if len(version) > 0 { + query.Set("version_name", version) + } + resp, err := region.list(SERVICE_RDS, "flavors/"+engine, query) if err != nil { return nil, err } - return flavors, jsonutils.Update(&flavors, resp.Data) + flavors := []SDBInstanceFlavor{} + err = resp.Unmarshal(&flavors, "flavors") + if err != nil { + return nil, err + } + return flavors, nil } func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { @@ -629,11 +682,11 @@ func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCrea } func (region *SRegion) CreateDBInstanceAccount(instanceId, account, password string) error { - params := map[string]string{ + params := map[string]interface{}{ "name": account, "password": password, } - _, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/db_user", instanceId), jsonutils.Marshal(params), "") + _, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/db_user", instanceId), params) return err } @@ -642,11 +695,11 @@ func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCr } func (region *SRegion) CreateDBInstanceDatabase(instanceId, database, characterSet string) error { - params := map[string]string{ + params := map[string]interface{}{ "name": database, "character_set": characterSet, } - _, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/database", instanceId), jsonutils.Marshal(params), "") + _, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/database", instanceId), params) return err } @@ -661,24 +714,24 @@ func (region *SRegion) ChangeDBInstanceConfig(instanceId string, instanceType st } if len(instanceType) > 0 { - params := map[string]map[string]string{ + params := map[string]interface{}{ "resize_flavor": map[string]string{ "spec_code": instanceType, }, } - _, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params)) + _, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/action", instanceId), params) if err != nil { return errors.Wrap(err, "resize_flavor") } cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) } if diskSizeGb > 0 { - params := map[string]map[string]int{ + params := map[string]interface{}{ "enlarge_volume": map[string]int{ "size": diskSizeGb, }, } - _, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params)) + _, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/action", instanceId), params) if err != nil { return errors.Wrap(err, "enlarge_volume") } @@ -726,8 +779,7 @@ func (self *SRegion) DeleteRdsTags(instanceId string, tagsKey []string) error { tagsObj = append(tagsObj, map[string]string{"key": k}) } params["tags"] = tagsObj - - _, err := self.ecsClient.DBInstance.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") + _, err := self.post(SERVICE_RDS, fmt.Sprintf("instances/%s/tags/action", instanceId), params) return err } @@ -741,8 +793,7 @@ func (self *SRegion) CreateRdsTags(instanceId string, tags map[string]string) er tagsObj = append(tagsObj, map[string]string{"key": k, "value": v}) } params["tags"] = tagsObj - - _, err := self.ecsClient.DBInstance.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") + _, err := self.post(SERVICE_RDS, fmt.Sprintf("instances/%s/tags/action", instanceId), params) return err } @@ -770,7 +821,7 @@ func (region *SRegion) RecoveryDBInstanceFromBackup(target, origin string, backu "instance_id": target, }, } - _, err := region.ecsClient.DBInstance.PerformAction("", "recovery", jsonutils.Marshal(params)) + _, err := region.post(SERVICE_RDS, "instances/recovery", params) if err != nil { return errors.Wrap(err, "dbinstance.recovery") } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_account.go index 83008d5e6a..df46042bcd 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_account.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_account.go @@ -16,12 +16,12 @@ package huawei import ( "fmt" - - "yunion.io/x/jsonutils" + "net/url" api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/pkg/util/httputils" ) type SDBInstanceAccount struct { @@ -40,11 +40,12 @@ func (account *SDBInstanceAccount) Delete() error { } func (region *SRegion) DeleteDBInstanceAccount(instanceId string, account string) error { - return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, fmt.Sprintf("db_user/%s", account), nil, nil) + _, err := region.delete(SERVICE_RDS, fmt.Sprintf("instances/%s/db_user/%s", instanceId, account)) + return err } func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { - privileges, err := account.instance.region.GetDBInstancePrivvileges(account.instance.Id, account.Name) + privileges, err := account.instance.region.GetDBInstancePrivileges(account.instance.Id, account.Name) if err != nil { return nil, err } @@ -57,28 +58,63 @@ func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudpro } func (region *SRegion) GetDBInstanceAccounts(instanceId string) ([]SDBInstanceAccount, error) { - params := map[string]string{ - "instance_id": instanceId, + params := url.Values{} + params.Set("limit", "100") + page := 1 + params.Set("page", fmt.Sprintf("%d", page)) + ret := []SDBInstanceAccount{} + for { + resp, err := region.list(SERVICE_RDS, fmt.Sprintf("instances/%s/db_user/detail", instanceId), params) + if err != nil { + return nil, err + } + part := struct { + Users []SDBInstanceAccount + TotalCount int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.Users...) + if len(ret) >= part.TotalCount || len(part.Users) == 0 { + break + } + page++ + params.Set("page", fmt.Sprintf("%d", page)) } - accounts := []SDBInstanceAccount{} - err := doListAllWithPage(region.ecsClient.DBInstance.ListAccounts, params, &accounts) - if err != nil { - return nil, err - } - return accounts, nil + return ret, nil } -func (region *SRegion) GetDBInstancePrivvileges(instanceId string, username string) ([]SDatabasePrivilege, error) { - params := map[string]string{ - "instance_id": instanceId, - "user-name": username, +func (region *SRegion) GetDBInstancePrivileges(instanceId string, username string) ([]SDatabasePrivilege, error) { + params := url.Values{} + params.Set("instance_id", instanceId) + params.Set("user-name", username) + params.Set("limit", "100") + page := 1 + params.Set("page", fmt.Sprintf("%d", page)) + ret := []SDatabasePrivilege{} + for { + resp, err := region.list(SERVICE_RDS, fmt.Sprintf("instances/%s/db_user/database", instanceId), params) + if err != nil { + return nil, err + } + part := struct { + Databases []SDatabasePrivilege + TotalCount int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.Databases...) + if len(ret) >= part.TotalCount || len(part.Databases) == 0 { + break + } + page++ + params.Set("page", fmt.Sprintf("%d", page)) } - privileges := []SDatabasePrivilege{} - err := doListAllWithPage(region.ecsClient.DBInstance.ListPrivileges, params, &privileges) - if err != nil { - return nil, err - } - return privileges, nil + return ret, nil } func (account *SDBInstanceAccount) RevokePrivilege(database string) error { @@ -94,7 +130,13 @@ func (region *SRegion) RevokeDBInstancePrivilege(instanceId string, account, dat }, }, } - return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, "db_privilege", nil, jsonutils.Marshal(params)) + resource := fmt.Sprintf("instances/%s/db_privilege", instanceId) + 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) + return err } func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { @@ -119,7 +161,7 @@ func (region *SRegion) GrantDBInstancePrivilege(instanceId string, account, data }, }, } - _, err := region.ecsClient.DBInstance.PerformAction("db_privilege", instanceId, jsonutils.Marshal(params)) + _, err := region.post(SERVICE_RDS, fmt.Sprintf("instances/%s/db_privilege", instanceId), params) return err } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_backup.go index 95117ac7fc..58694eb6df 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_backup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_backup.go @@ -15,6 +15,8 @@ package huawei import ( + "fmt" + "net/url" "time" "yunion.io/x/jsonutils" @@ -115,7 +117,7 @@ func (backup *SDBInstanceBackup) Delete() error { } func (region *SRegion) DeleteDBInstanceBackup(backupId string) error { - _, err := region.ecsClient.DBInstanceBackup.Delete(backupId, nil) + _, err := region.delete(SERVICE_RDS, "backups/"+backupId) return err } @@ -124,16 +126,30 @@ func (backup *SDBInstanceBackup) GetDBInstanceId() string { } func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string) ([]SDBInstanceBackup, error) { - params := map[string]string{ - "instance_id": instanceId, - } + params := url.Values{} + params.Set("instance_id", instanceId) if len(backupId) > 0 { - params["backup_id"] = backupId + params.Set("backup_id", backupId) } backups := []SDBInstanceBackup{} - err := doListAllWithOffset(region.ecsClient.DBInstanceBackup.List, params, &backups) - if err != nil { - return nil, err + for { + resp, err := region.list(SERVICE_RDS, "backups", params) + if err != nil { + return nil, err + } + part := struct { + Backups []SDBInstanceBackup + TotalCount int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + backups = append(backups, part.Backups...) + if len(backups) >= part.TotalCount || len(part.Backups) == 0 { + break + } + params.Set("offset", fmt.Sprintf("%d", len(backups))) } return backups, nil } @@ -194,19 +210,15 @@ func (backup *SDBInstanceBackup) Refresh() error { } func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { - backupId, err := rds.region.CreateDBInstanceBackup(rds.Id, conf.Name, conf.Description, conf.Databases) + backup, err := rds.region.CreateDBInstanceBackup(rds.Id, conf.Name, conf.Description, conf.Databases) if err != nil { return "", err } - backup, err := rds.region.GetIDBInstanceBackupById(backupId) - if err != nil { - return "", errors.Wrap(err, "region.GetIDBInstanceBackupById") - } cloudprovider.WaitStatus(backup, api.DBINSTANCE_BACKUP_READY, time.Second*3, time.Minute*30) - return backupId, nil + return backup.GetGlobalId(), nil } -func (region *SRegion) CreateDBInstanceBackup(instanceId string, name string, descrition string, databases []string) (string, error) { +func (region *SRegion) CreateDBInstanceBackup(instanceId string, name string, descrition string, databases []string) (*SDBInstanceBackup, error) { params := map[string]interface{}{ "instance_id": instanceId, "name": name, @@ -219,15 +231,16 @@ func (region *SRegion) CreateDBInstanceBackup(instanceId string, name string, de } params["databases"] = dbs } - resp, err := region.ecsClient.DBInstanceBackup.Create(jsonutils.Marshal(params)) + resp, err := region.post(SERVICE_RDS, "backups", params) if err != nil { - return "", errors.Wrap(err, "DBInstanceBackup.Create") + return nil, errors.Wrap(err, "DBInstanceBackup.Create") } - backupId, err := resp.GetString("id") + ret := &SDBInstanceBackup{region: region} + err = resp.Unmarshal(ret, "backup") if err != nil { - return "", errors.Wrap(err, "resp.GetBackupId") + return nil, err } - return backupId, nil + return ret, nil } func (self *SDBInstanceBackup) CreateICloudDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_database.go index d641e1739d..70bea1bd73 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_database.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_database.go @@ -16,6 +16,7 @@ package huawei import ( "fmt" + "net/url" api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/cloudmux/pkg/multicloud" @@ -55,18 +56,36 @@ func (database *SDBInstanceDatabase) Delete() error { } func (region *SRegion) DeleteDBInstanceDatabase(instanceId, database string) error { - _, err := region.ecsClient.DBInstance.DeleteInContextWithSpec(nil, instanceId, fmt.Sprintf("database/%s", database), nil, nil, "") + _, err := region.delete(SERVICE_RDS, fmt.Sprintf("instances/%s/database/%s", instanceId, database)) return err } func (region *SRegion) GetDBInstanceDatabases(instanceId string) ([]SDBInstanceDatabase, error) { - params := map[string]string{ - "instance_id": instanceId, + params := url.Values{} + params.Set("instance_id", instanceId) + params.Set("limit", "100") + page := 1 + params.Set("page", fmt.Sprintf("%d", page)) + ret := []SDBInstanceDatabase{} + for { + resp, err := region.list(SERVICE_RDS, fmt.Sprintf("instances/%s/database/detail", instanceId), params) + if err != nil { + return nil, err + } + part := struct { + Databases []SDBInstanceDatabase + TotalCount int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.Databases...) + if len(ret) >= part.TotalCount || len(part.Databases) == 0 { + break + } + page++ + params.Set("page", fmt.Sprintf("%d", page)) } - databases := []SDBInstanceDatabase{} - err := doListAllWithPage(region.ecsClient.DBInstance.ListDatabases, params, &databases) - if err != nil { - return nil, err - } - return databases, nil + return ret, nil } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_parameter.go index a426ea4a1c..ac713aaf18 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_parameter.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_parameter.go @@ -14,6 +14,12 @@ package huawei +import ( + "fmt" + + "yunion.io/x/pkg/errors" +) + type SDBInstanceParameter struct { instance *SDBInstance @@ -27,15 +33,16 @@ type SDBInstanceParameter struct { } func (region *SRegion) GetDBInstanceParameters(dbinstanceId string) ([]SDBInstanceParameter, error) { - params := map[string]string{ - "instance_id": dbinstanceId, - } - paramters := []SDBInstanceParameter{} - err := doListAll(region.ecsClient.DBInstance.ListParameters, params, ¶mters) + resp, err := region.list(SERVICE_RDS, fmt.Sprintf("instances/%s/configurations", dbinstanceId), nil) if err != nil { return nil, err } - return paramters, nil + ret := []SDBInstanceParameter{} + err = resp.Unmarshal(&ret, "configuration_parameters") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + return ret, nil } func (param *SDBInstanceParameter) GetGlobalId() string { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/disk.go index e8268e1cac..8cde29c94d 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/disk.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/disk.go @@ -16,6 +16,8 @@ package huawei import ( "context" + "fmt" + "net/url" "strings" "time" @@ -59,6 +61,7 @@ type DiskMeta struct { ResourceType string `json:"resourceType"` AttachedMode string `json:"attached_mode"` Readonly string `json:"readonly"` + OrderId string `json:"orderID"` } type VolumeImageMetadata struct { @@ -92,7 +95,6 @@ type SDisk struct { storage *SStorage multicloud.SDisk HuaweiDiskTags - details *SResourceDetail ID string `json:"id"` Name string `json:"name"` @@ -136,7 +138,6 @@ func (self *SDisk) GetGlobalId() string { } func (self *SDisk) GetStatus() string { - // https://support.huaweicloud.com/api-evs/zh-cn_topic_0051803385.html switch self.Status { case "creating", "downloading": return api.DISK_ALLOCATING @@ -174,39 +175,18 @@ func (self *SDisk) GetStatus() string { } func (self *SDisk) Refresh() error { - new, err := self.storage.zone.region.GetDisk(self.GetId()) + disk, err := self.storage.zone.region.GetDisk(self.GetId()) if err != nil { return err } - return jsonutils.Update(self, new) -} - -func (self *SDisk) IsEmulated() bool { - return false -} - -func (self *SDisk) getResourceDetails() *SResourceDetail { - if self.details != nil { - return self.details - } - - res, err := self.storage.zone.region.GetOrderResourceDetail(self.GetId()) - if err != nil { - log.Debugln(err) - return nil - } - - self.details = &res - return self.details + return jsonutils.Update(self, disk) } func (self *SDisk) GetBillingType() string { - details := self.getResourceDetails() - if details == nil { - return billing_api.BILLING_TYPE_POSTPAID - } else { + if len(self.Metadata.OrderId) > 0 { return billing_api.BILLING_TYPE_PREPAID } + return billing_api.BILLING_TYPE_POSTPAID } func (self *SDisk) GetCreatedAt() time.Time { @@ -214,13 +194,15 @@ func (self *SDisk) GetCreatedAt() time.Time { } func (self *SDisk) GetExpiredAt() time.Time { - var expiredTime time.Time - details := self.getResourceDetails() - if details != nil { - expiredTime = details.ExpireTime + orders, err := self.storage.zone.region.client.GetOrderResources() + if err != nil { + return time.Time{} } - - return expiredTime + order, ok := orders[self.ID] + if ok { + return order.ExpireTime + } + return time.Time{} } func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { @@ -228,7 +210,6 @@ func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { } func (self *SDisk) GetDiskFormat() string { - // self.volume_type ? return "vhd" } @@ -241,7 +222,7 @@ func (self *SDisk) checkAutoDelete(attachments []Attachment) bool { for _, attach := range attachments { if len(attach.ServerID) > 0 { // todo : 忽略错误?? - vm, err := self.storage.zone.region.GetInstanceByID(attach.ServerID) + vm, err := self.storage.zone.region.GetInstance(attach.ServerID) if err != nil { volumes := vm.OSExtendedVolumesVolumesAttached for _, vol := range volumes { @@ -270,14 +251,11 @@ func (self *SDisk) GetTemplateId() string { return self.VolumeImageMetadata.ImageID } -// Bootable 表示硬盘是否为启动盘。 -// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) func (self *SDisk) GetDiskType() string { if self.Bootable == "true" { return api.DISK_TYPE_SYS - } else { - return api.DISK_TYPE_DATA } + return api.DISK_TYPE_DATA } func (self *SDisk) GetFsFormat() string { @@ -289,9 +267,6 @@ func (self *SDisk) GetIsNonPersistent() bool { } func (self *SDisk) GetDriver() string { - // https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762431.html - // scsi or vbd? - // todo: implement me return "scsi" } @@ -340,28 +315,19 @@ func (self *SDisk) Delete(ctx context.Context) error { } func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { - if snapshotId, err := self.storage.zone.region.CreateSnapshot(self.GetId(), name, desc); err != nil { - log.Errorf("createSnapshot fail %s", err) - return nil, err - } else if snapshot, err := self.getSnapshot(snapshotId); err != nil { - return nil, err - } else { - snapshot.region = self.storage.zone.region - if err := cloudprovider.WaitStatus(snapshot, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil { - return nil, err - } - return snapshot, nil + snapshot, err := self.storage.zone.region.CreateSnapshot(self.GetId(), name, desc) + if err != nil { + return nil, errors.Wrapf(err, "CreateSnapshot") } -} - -func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) { - snapshot, err := self.storage.zone.region.GetSnapshotById(snapshotId) - return &snapshot, err + return snapshot, nil } func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := self.getSnapshot(snapshotId) - return snapshot, err + snapshot, err := self.storage.zone.region.GetSnapshot(snapshotId) + if err != nil { + return nil, err + } + return snapshot, nil } func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { @@ -378,17 +344,11 @@ func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { } func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { - err := cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 60*time.Second) - if err != nil { - return err - } - sizeGb := newSizeMB / 1024 - err = self.storage.zone.region.resizeDisk(self.GetId(), sizeGb) + err := self.storage.zone.region.ResizeDisk(self.GetId(), sizeGb) if err != nil { return err } - return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 15*time.Second, 5*time.Second, 60*time.Second) } @@ -417,140 +377,123 @@ func (self *SDisk) Detach() error { func (self *SDisk) Attach(device string) error { err := self.storage.zone.region.AttachDisk(self.GetMountServerId(), self.GetId(), device) if err != nil { - log.Debugf("attach server %s disk %s failed: %s", self.GetMountServerId(), self.GetId(), err) - return err + return errors.Wrapf(err, "AttachDisk") } return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 10*time.Second, 5*time.Second, 60*time.Second) } -// 在线卸载磁盘 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0036046828.html -// 对于挂载在系统盘盘位(也就是“/dev/sda”或“/dev/vda”挂载点)上的磁盘,当前仅支持离线卸载 func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - mountpoint := self.GetMountpoint() - if len(mountpoint) > 0 { - err := self.Detach() - if err != nil { - return "", err - } - } - - diskId, err := self.storage.zone.region.resetDisk(self.GetId(), snapshotId) - if err != nil { - return diskId, err - } - - err = cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 300*time.Second) - if err != nil { - return "", err - } - - if len(mountpoint) > 0 { - err := self.Attach(mountpoint) - if err != nil { - return "", err - } - } - - return diskId, nil + return "", cloudprovider.ErrNotSupported } -// 华为云不支持重置 func (self *SDisk) Rebuild(ctx context.Context) error { return cloudprovider.ErrNotSupported } +// https://console.huaweicloud.com/apiexplorer/#/openapi/EVS/doc?api=ShowVolume func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { - if len(diskId) == 0 { - return nil, cloudprovider.ErrNotFound + resp, err := self.list(SERVICE_EVS, "cloudvolumes/"+diskId, nil) + if err != nil { + return nil, errors.Wrapf(err, "show volume") } - var disk SDisk - err := DoGet(self.ecsClient.Disks.Get, diskId, nil, &disk) - return &disk, err + ret := &SDisk{} + err = resp.Unmarshal(ret, "volume") + if err != nil { + return nil, err + } + return ret, nil } -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762430.html +// https://console.huaweicloud.com/apiexplorer/#/openapi/EVS/doc?api=ListVolumes func (self *SRegion) GetDisks(zoneId string) ([]SDisk, error) { - queries := map[string]string{} + ret := []SDisk{} + query := url.Values{} if len(zoneId) > 0 { - queries["availability_zone"] = zoneId + query.Set("availability_zone", zoneId) } - - disks := make([]SDisk, 0) - err := doListAllWithOffset(self.ecsClient.Disks.List, queries, &disks) - return disks, err + for { + resp, err := self.list(SERVICE_EVS, "cloudvolumes/detail", query) + if err != nil { + return nil, errors.Wrapf(err, "list volumes") + } + part := struct { + Volumes []SDisk + Count int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + ret = append(ret, part.Volumes...) + if len(ret) >= part.Count || len(part.Volumes) == 0 { + break + } + query.Set("offset", fmt.Sprintf("%d", len(ret))) + } + return ret, nil } -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762427.html +// https://console.huaweicloud.com/apiexplorer/#/openapi/EVS/doc?api=CreateVolume func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, snapshotId string, desc string, projectId string) (string, error) { - params := jsonutils.NewDict() - volumeObj := jsonutils.NewDict() - volumeObj.Add(jsonutils.NewString(name), "name") - volumeObj.Add(jsonutils.NewString(zoneId), "availability_zone") - volumeObj.Add(jsonutils.NewString(desc), "description") - volumeObj.Add(jsonutils.NewString(category), "volume_type") - volumeObj.Add(jsonutils.NewInt(int64(sizeGb)), "size") + params := map[string]interface{}{ + "name": name, + "availability_zone": zoneId, + "description": desc, + "volume_type": category, + "size": sizeGb, + } if len(snapshotId) > 0 { - volumeObj.Add(jsonutils.NewString(snapshotId), "snapshot_id") + params["snapshot_id"] = snapshotId } if len(projectId) > 0 { - volumeObj.Add(jsonutils.NewString(projectId), "enterprise_project_id") + params["enterprise_project_id"] = projectId } - params.Add(volumeObj, "volume") - // 目前只支持创建按需资源,返回job id。 如果创建包年包月资源则返回order id - _id, err := self.ecsClient.Disks.AsyncCreate(params) + resp, err := self.post(SERVICE_EVS_V2_1, "cloudvolumes", map[string]interface{}{"volume": params}) if err != nil { - log.Debugf("AsyncCreate with params: %s", params) - return "", errors.Wrap(err, "AsyncCreate") + return "", errors.Wrapf(err, "create volume") } + ret := struct { + JobId string + OrderId string + }{} + err = resp.Unmarshal(&ret) + if err != nil { + return "", errors.Wrapf(err, "Unmarshal") + } + + id := ret.JobId + ret.OrderId + // 按需计费 - volumeId, err := self.GetTaskEntityID(self.ecsClient.Disks.ServiceType(), _id, "volume_id") + volumeId, err := self.GetTaskEntityID(SERVICE_EVS_V1, id, "volume_id") if err != nil { return "", errors.Wrap(err, "GetAllSubTaskEntityIDs") } if len(volumeId) == 0 { - return "", errors.Errorf("CreateInstance job %s result is emtpy", _id) - } else { - return volumeId, nil + return "", errors.Errorf("CreateInstance job %s result is emtpy", id) } + return volumeId, nil } -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762428.html -// 默认删除云硬盘关联的所有快照 +// https://console.huaweicloud.com/apiexplorer/#/openapi/EVS/doc?api=DeleteVolume func (self *SRegion) DeleteDisk(diskId string) error { - return DoDeleteWithSpec(self.ecsClient.Disks.DeleteInContextWithSpec, nil, diskId, "", nil, nil) -} - -/* -扩容状态为available的云硬盘时,没有约束限制。 -扩容状态为in-use的云硬盘时,有以下约束: -不支持共享云硬盘,即multiattach参数值必须为false。 -云硬盘所挂载的云服务器状态必须为ACTIVE、PAUSED、SUSPENDED、SHUTOFF才支持扩容 -*/ -func (self *SRegion) resizeDisk(diskId string, sizeGB int64) error { - params := jsonutils.NewDict() - osExtendObj := jsonutils.NewDict() - osExtendObj.Add(jsonutils.NewInt(sizeGB), "new_size") // GB - params.Add(osExtendObj, "os-extend") - _, err := self.ecsClient.Disks.PerformAction2("action", diskId, params, "") + res := fmt.Sprintf("cloudvolumes/%s", diskId) + _, err := self.delete(SERVICE_EVS, res) return err } -/* -https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408629.html -只支持快照回滚到源云硬盘,不支持快照回滚到其它指定云硬盘。 -只有云硬盘状态处于“available”或“error_rollbacking”状态才允许快照回滚到源云硬盘。 -*/ -func (self *SRegion) resetDisk(diskId, snapshotId string) (string, error) { - params := jsonutils.NewDict() - rollbackObj := jsonutils.NewDict() - rollbackObj.Add(jsonutils.NewString(diskId), "volume_id") - params.Add(rollbackObj, "rollback") - _, err := self.ecsClient.OsSnapshots.PerformAction2("rollback", snapshotId, params, "") - return diskId, err +// https://console.huaweicloud.com/apiexplorer/#/openapi/EVS/doc?api=ResizeVolume +func (self *SRegion) ResizeDisk(diskId string, sizeGB int64) error { + params := map[string]interface{}{ + "os-extend": map[string]interface{}{ + "new_size": sizeGB, + }, + } + _, err := self.post(SERVICE_EVS_V2_1, fmt.Sprintf("cloudvolumes/%s/action", diskId), params) + return err } func (self *SDisk) GetProjectId() string { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/domain.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/domain.go index 2019b875e7..65fb37fdc5 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/domain.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/domain.go @@ -26,11 +26,18 @@ type SDomain struct { Tagflag int `json:"tagflag"` } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListAuthDomains func (self *SHuaweiClient) GetDomains() ([]SDomain, error) { - huawei, _ := self.newGeneralAPIClient() - domains := make([]SDomain, 0) - err := doListAll(huawei.Domains.List, nil, &domains) - return domains, err + resp, err := self.list(SERVICE_IAM_V3, "", "auth/domains", nil) + if err != nil { + return nil, err + } + ret := []SDomain{} + err = resp.Unmarshal(&ret, "domains") + if err != nil { + return nil, err + } + return ret, nil } func (self *SHuaweiClient) getEnabledDomains() ([]SDomain, error) { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/eip.go index b93622971d..d412d6015b 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/eip.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/eip.go @@ -22,7 +22,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/httputils" billing_api "yunion.io/x/cloudmux/pkg/apis/billing" api "yunion.io/x/cloudmux/pkg/apis/compute" @@ -219,6 +218,7 @@ func (self *SRegion) GetInstancePortId(instanceId string) (string, error) { return ports[0].ID, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v2&api=CreatePublicip func (self *SRegion) AllocateEIP(opts *cloudprovider.SEip) (*SEipAddress, error) { if len(opts.BGPType) == 0 { switch self.GetId() { @@ -270,8 +270,9 @@ func (self *SRegion) AllocateEIP(opts *cloudprovider.SEip) (*SEipAddress, error) return eip, resp.Unmarshal(eip, "publicip") } +// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v3&api=ShowPublicip func (self *SRegion) GetEip(eipId string) (*SEipAddress, error) { - resp, err := self.list(SERVICE_VPC, "eip/publicips/"+eipId, nil) + resp, err := self.list(SERVICE_VPC_V3, "eip/publicips/"+eipId, nil) if err != nil { return nil, err } @@ -279,11 +280,13 @@ func (self *SRegion) GetEip(eipId string) (*SEipAddress, error) { return eip, resp.Unmarshal(eip, "publicip") } +// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v2&api=DeletePublicip func (self *SRegion) DeallocateEIP(eipId string) error { _, err := self.delete(SERVICE_VPC, "publicips/"+eipId) return err } +// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v3&api=AssociatePublicips func (self *SRegion) AssociateEip(eipId string, associateId, associateType string) error { params := map[string]interface{}{ "publicip": map[string]interface{}{ @@ -292,16 +295,18 @@ func (self *SRegion) AssociateEip(eipId string, associateId, associateType strin }, } res := fmt.Sprintf("eip/publicips/%s/associate-instance", eipId) - _, err := self.post(SERVICE_VPC, res, params) + _, err := self.post(SERVICE_VPC_V3, res, params) return err } +// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v3&api=DisassociatePublicips func (self *SRegion) DissociateEip(eipId string) error { res := fmt.Sprintf("eip/publicips/%s/disassociate-instance", eipId) - _, err := self.post(SERVICE_VPC, res, nil) + _, err := self.post(SERVICE_VPC_V3, res, nil) return err } +// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v2&api=UpdateBandwidth func (self *SRegion) UpdateEipBandwidth(bandwidthId string, bw int) error { params := map[string]interface{}{ "bandwidth": map[string]interface{}{ @@ -316,6 +321,7 @@ func (self *SEipAddress) GetProjectId() string { return self.EnterpriseProjectId } +// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v3&api=ListPublicips func (self *SRegion) GetEips(portId string, addrs []string) ([]SEipAddress, error) { query := url.Values{} for _, addr := range addrs { @@ -326,7 +332,7 @@ func (self *SRegion) GetEips(portId string, addrs []string) ([]SEipAddress, erro } eips := []SEipAddress{} for { - resp, err := self.list(SERVICE_VPC, "eip/publicips", query) + resp, err := self.list(SERVICE_VPC_V3, "eip/publicips", query) if err != nil { return nil, err } @@ -350,6 +356,28 @@ func (self *SRegion) GetEips(portId string, addrs []string) ([]SEipAddress, erro return eips, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v2&api=DeletePublicipTag +func (self *SRegion) DeletePublicipTag(eipId string, key string) error { + res := fmt.Sprintf("publicips/%s/tags/%s", eipId, key) + _, err := self.delete(SERVICE_VPC_V2_0, res) + return err +} + +// https://console.huaweicloud.com/apiexplorer/#/openapi/EIP/doc?version=v2&api=CreatePublicipTag +func (self *SRegion) CreatePublicipTag(eipId string, tags map[string]string) error { + params := map[string]interface{}{ + "action": "create", + } + add := []map[string]string{} + for k, v := range tags { + add = append(add, map[string]string{"key": k, "value": v}) + } + params["tags"] = add + res := fmt.Sprintf("publicips/%s/tags/action", eipId) + _, err := self.post(SERVICE_VPC_V2_0, res, params) + return err +} + func (self *SRegion) setEipTags(id string, existedTags, tags map[string]string, replace bool) error { deleteTagsKey := []string{} for k := range existedTags { @@ -363,24 +391,14 @@ func (self *SRegion) setEipTags(id string, existedTags, tags map[string]string, } if len(deleteTagsKey) > 0 { for _, k := range deleteTagsKey { - url := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v2.0/%s/publicips/%s/tags/%s", self.ID, self.client.projectId, id, k) - _, err := self.client.request(httputils.DELETE, url, nil, nil) + err := self.DeletePublicipTag(self.ID, k) if err != nil { return errors.Wrapf(err, "remove tags") } } } if len(tags) > 0 { - params := map[string]interface{}{ - "action": "create", - } - add := []map[string]string{} - for k, v := range tags { - add = append(add, map[string]string{"key": k, "value": v}) - } - params["tags"] = add - url := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v2.0/%s/publicips/%s/tags/action", self.ID, self.client.projectId, id) - _, err := self.client.request(httputils.POST, url, nil, params) + err := self.CreatePublicipTag(self.ID, tags) if err != nil { return errors.Wrapf(err, "add tags") } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_account.go index 0da5601978..d68b3de236 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_account.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_account.go @@ -17,9 +17,6 @@ package huawei import ( "fmt" - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/cloudmux/pkg/multicloud" @@ -60,35 +57,16 @@ func (self *SElasticcacheAccount) GetAccountPrivilege() string { return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html -// 未找到关闭密码的开放api, 不支持开启/关闭密码访问 -// https://console.huaweicloud.com/dcs/rest/v2/41f6bfe48d7f4455b7754f7c1b11ae34/instances/26db46e2-c7d8-4b5e-bd36-b5278d2fe17c/password/reset -// new_password: "26db46e2!" -// no_password_access: false func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { if input.OldPassword == nil { return fmt.Errorf("elasticcacheAccount.ResetPassword.input OldPassword should not be empty") } - - type ResetPasswordResult struct { - Result string `json:"result"` - Message string `json:"message"` + params := map[string]interface{}{ + "old_password": *input.OldPassword, + "new_password": input.NewPassword, } - - result := ResetPasswordResult{} - params := jsonutils.NewDict() - params.Set("old_password", jsonutils.NewString(*input.OldPassword)) - params.Set("new_password", jsonutils.NewString(input.NewPassword)) - err := DoUpdateWithSpec2(self.cacheDB.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.cacheDB.GetId(), "password", params, &result) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.ResetPassword") - } - - if result.Result != "success" { - return errors.Wrap(fmt.Errorf(result.Message), "elasticcacheAccount.ResetPassword") - } - - return nil + _, err := self.cacheDB.region.put(SERVICE_DCS, fmt.Sprintf("instances/%s/password", self.cacheDB.InstanceID), params) + return err } func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_backup.go index a5b8d7ae87..516b65f242 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_backup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_backup.go @@ -15,6 +15,7 @@ package huawei import ( + "fmt" "time" "yunion.io/x/jsonutils" @@ -127,12 +128,10 @@ func (self *SElasticcacheBackup) Delete() error { return cloudprovider.ErrNotSupported } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { - _, err := self.cacheDB.region.ecsClient.Elasticcache.RestoreInstance(instanceId, self.GetId()) - if err != nil { - return nil + params := map[string]interface{}{ + "backup_id": self.BackupID, } - - return nil + _, err := self.cacheDB.region.post(SERVICE_DCS, fmt.Sprintf("instances/%s/restores", self.cacheDB.InstanceID), params) + return err } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_instance.go index 0e5dce6660..8f1fdda06f 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_instance.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_instance.go @@ -16,7 +16,7 @@ package huawei import ( "fmt" - "strconv" + "net/url" "strings" "time" @@ -31,7 +31,6 @@ import ( "yunion.io/x/cloudmux/pkg/multicloud" ) -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html type SElasticcache struct { multicloud.SElasticcacheBase HuaweiTags @@ -162,21 +161,18 @@ func (self *SElasticcache) GetCreatedAt() time.Time { } func (self *SElasticcache) GetExpiredAt() time.Time { - var expiredTime time.Time - if self.ChargingMode == 1 { - res, err := self.region.GetOrderResourceDetail(self.GetId()) - if err != nil { - log.Debugln(err) - } - - expiredTime = res.ExpireTime + orders, err := self.region.client.GetOrderResources() + if err != nil { + return time.Time{} } - - return expiredTime + order, ok := orders[self.InstanceID] + if ok { + return order.ExpireTime + } + return time.Time{} } func (self *SElasticcache) GetInstanceType() string { - // todo: ?? return self.ResourceSpecCode } @@ -185,33 +181,27 @@ func (self *SElasticcache) GetCapacityMB() int { } func (self *SElasticcache) GetArchType() string { - /* - 资源规格标识。 - - dcs.single_node:表示实例类型为单机 - dcs.master_standby:表示实例类型为主备 - dcs.cluster:表示实例类型为集群 - */ if strings.Contains(self.ResourceSpecCode, "single") { return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE - } else if strings.Contains(self.ResourceSpecCode, "ha") { + } + if strings.Contains(self.ResourceSpecCode, "ha") { return api.ELASTIC_CACHE_ARCH_TYPE_MASTER - } else if strings.Contains(self.ResourceSpecCode, "cluster") { - return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER - } else if strings.Contains(self.ResourceSpecCode, "proxy") { + } + if strings.Contains(self.ResourceSpecCode, "cluster") { return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER } - - return "" + if strings.Contains(self.ResourceSpecCode, "proxy") { + return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER + } + return self.ResourceSpecCode } func (self *SElasticcache) GetNodeType() string { // single(单副本) | double(双副本) if strings.Contains(self.ResourceSpecCode, "single") { return "single" - } else { - return "double" } + return "double" } func (self *SElasticcache) GetEngine() string { @@ -324,69 +314,83 @@ func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.IC return iparameters, nil } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) { - params := make(map[string]string) - params["instance_id"] = instanceId - params["beginTime"] = startTime - params["endTime"] = endTime + params := url.Values{} + params.Set("begin_time", startTime) + params.Set("end_time", endTime) - backups := make([]SElasticcacheBackup, 0) - err := doListAll(self.ecsClient.Elasticcache.ListBackups, params, &backups) - if err != nil { - return nil, err - } - - return backups, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html -func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) { - params := make(map[string]string) - params["instance_id"] = instanceId - - parameters := make([]SElasticcacheParameter, 0) - err := doListAll(self.ecsClient.Elasticcache.ListParameters, params, ¶meters) - if err != nil { - return nil, err - } - - return parameters, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423044.html -func (self *SRegion) GetElasticCaches() ([]SElasticcache, error) { - params := make(map[string]string) - caches := make([]SElasticcache, 0) - err := doListAll(self.ecsClient.Elasticcache.List, params, &caches) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCaches") - } - - for i := range caches { - cache, err := self.GetElasticCache(caches[i].GetId()) + ret := make([]SElasticcacheBackup, 0) + for { + resp, err := self.list(SERVICE_DCS, fmt.Sprintf("instances/%s/backups", instanceId), params) if err != nil { return nil, err - } else { - caches[i] = *cache } - - caches[i].region = self + part := struct { + BackupRecordResponse []SElasticcacheBackup + TotalNum int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.BackupRecordResponse...) + if len(ret) >= part.TotalNum || len(part.BackupRecordResponse) == 0 { + break + } + params.Set("offset", fmt.Sprintf("%d", len(ret))) } - - return caches, nil + return ret, nil } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html -func (self *SRegion) GetElasticCache(instanceId string) (*SElasticcache, error) { - cache := SElasticcache{} - err := DoGet(self.ecsClient.Elasticcache.Get, instanceId, nil, &cache) +func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) { + resp, err := self.list(SERVICE_DCS, fmt.Sprintf("instances/%s/configs", instanceId), nil) if err != nil { - return nil, errors.Wrapf(err, "region.GetElasticCache %s", instanceId) + return nil, err } + ret := make([]SElasticcacheParameter, 0) + err = resp.Unmarshal(&ret, "redis_config") + if err != nil { + return nil, err + } + return ret, nil +} - cache.region = self - return &cache, nil +func (self *SRegion) GetElasticCaches() ([]SElasticcache, error) { + ret := make([]SElasticcache, 0) + query := url.Values{} + for { + resp, err := self.list(SERVICE_DCS, "instances", query) + if err != nil { + return nil, err + } + part := struct { + Instances []SElasticcache + InstanceNum int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.Instances...) + if len(ret) >= part.InstanceNum || len(part.Instances) == 0 { + break + } + query.Set("offset", fmt.Sprintf("%d", len(ret))) + } + return ret, nil +} + +func (self *SRegion) GetElasticCache(instanceId string) (*SElasticcache, error) { + resp, err := self.list(SERVICE_DCS, "instances/"+instanceId, nil) + if err != nil { + return nil, err + } + ret := &SElasticcache{region: self} + err = resp.Unmarshal(ret) + if err != nil { + return nil, err + } + return ret, nil } func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { @@ -398,188 +402,124 @@ func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasti return ec, nil } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423047.html -func (self *SRegion) zoneNameToDcsZoneIds(zoneIds []string) ([]string, error) { - type Z struct { - ID string `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - Port string `json:"port"` - ResourceAvailability string `json:"resource_availability"` - } - - rs := []Z{} - err := doListAll(self.ecsClient.DcsAvailableZone.List, nil, &rs) - if err != nil { - return nil, errors.Wrap(err, "region.zoneNameToDcsZoneIds") - } - - zoneMap := map[string]string{} - for i := range rs { - if rs[i].ResourceAvailability == "true" { - zoneMap[rs[i].Code] = rs[i].ID - } - } - - ret := []string{} - for _, zone := range zoneIds { - if id, ok := zoneMap[zone]; ok { - ret = append(ret, id) - } else { - return nil, errors.Wrap(fmt.Errorf("zone %s not found or not available", zone), "region.zoneNameToDcsZoneIds") - } - } - - return ret, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423019.html -func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { - params := jsonutils.NewDict() - params.Set("name", jsonutils.NewString(ec.InstanceName)) - params.Set("engine", jsonutils.NewString(ec.Engine)) - params.Set("engine_version", jsonutils.NewString(ec.EngineVersion)) - params.Set("capacity", jsonutils.NewInt(ec.CapacityGB)) - params.Set("vpc_id", jsonutils.NewString(ec.VpcId)) - if len(ec.SecurityGroupIds) > 0 { - params.Set("security_group_id", jsonutils.NewString(ec.SecurityGroupIds[0])) - } - params.Set("subnet_id", jsonutils.NewString(ec.NetworkId)) - params.Set("product_id", jsonutils.NewString(ec.InstanceType)) - zones, err := self.zoneNameToDcsZoneIds(ec.ZoneIds) +func (self *SRegion) CreateIElasticcaches(opts *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { + ret, err := self.CreateElasticcache(opts) if err != nil { return nil, err } - params.Set("available_zones", jsonutils.NewStringArray(zones)) - - if len(ec.ProjectId) > 0 { - params.Set("enterprise_project_id", jsonutils.NewString(ec.ProjectId)) - } - - if len(ec.Password) > 0 { - params.Set("no_password_access", jsonutils.NewString("false")) - params.Set("password", jsonutils.NewString(ec.Password)) - - // todo: 这里换成常量 - if ec.Engine == "Memcache" { - params.Set("access_user", jsonutils.NewString(ec.UserName)) - } - } else { - params.Set("no_password_access", jsonutils.NewString("true")) - } - - if len(ec.EipId) > 0 { - params.Set("enable_publicip", jsonutils.NewString("true")) - params.Set("publicip_id", jsonutils.NewString(ec.EipId)) - // enable_ssl - } else { - params.Set("enable_publicip", jsonutils.NewString("false")) - } - - if len(ec.PrivateIpAddress) > 0 { - params.Set("private_ip", jsonutils.NewString(ec.PrivateIpAddress)) - } - - if len(ec.MaintainBegin) > 0 { - params.Set("maintain_begin", jsonutils.NewString(ec.MaintainBegin)) - params.Set("maintain_end", jsonutils.NewString(ec.MaintainEnd)) - } - - if ec.BillingCycle != nil { - bssParam := jsonutils.NewDict() - bssParam.Set("charging_mode", jsonutils.NewString("prePaid")) - bssParam.Set("is_auto_pay", jsonutils.NewString("true")) - bssParam.Set("is_auto_renew", jsonutils.NewString(fmt.Sprintf("%v", ec.BillingCycle.AutoRenew))) - if ec.BillingCycle.GetMonths() >= 1 && ec.BillingCycle.GetMonths() >= 9 { - bssParam.Set("period_type", jsonutils.NewString("month")) - bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BillingCycle.GetMonths()))) - } else if ec.BillingCycle.GetYears() >= 1 && ec.BillingCycle.GetYears() <= 3 { - bssParam.Set("period_type", jsonutils.NewString("year")) - bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BillingCycle.GetYears()))) - } else { - return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)") - } - - params.Set("bss_param", bssParam) - } - - ret := &SElasticcache{} - err = DoCreate(self.ecsClient.Elasticcache.Create, params, ret) - if err != nil { - return nil, errors.Wrap(err, "region.CreateIElasticcaches") - } - - ret.region = self return ret, nil } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html -func (self *SElasticcache) Restart() error { - resp, err := self.region.ecsClient.Elasticcache.Restart(self.GetId()) - if err != nil { - return errors.Wrap(err, "elasticcache.Restart") +func (self *SRegion) CreateElasticcache(opts *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { + params := map[string]interface{}{ + "name": opts.InstanceName, + "engine": opts.Engine, + "engine_version": opts.EngineVersion, + "capacity": opts.CapacityGB, + "vpc_id": opts.VpcId, + "subnet_id": opts.NetworkId, + "product_id": opts.InstanceType, + "zone_codes": opts.ZoneIds, + "no_password_access": true, + "enable_publicip": false, + } + if len(opts.SecurityGroupIds) > 0 { + params["security_group_id"] = opts.SecurityGroupIds[0] } - rets, err := resp.GetArray("results") - if err != nil { - return errors.Wrap(err, "elasticcache.results") + if len(opts.ProjectId) > 0 { + params["enterprise_project_id"] = opts.ProjectId } - for _, r := range rets { - if ret, _ := r.GetString("result"); ret != "success" { - return fmt.Errorf("elasticcache.Restart failed") + if len(opts.Password) > 0 { + params["no_password_access"] = false + params["password"] = opts.Password + + if opts.Engine == "Memcache" { + params["access_user"] = opts.UserName } } - return nil + if len(opts.EipId) > 0 { + params["enable_publicip"] = true + params["publicip_id"] = opts.EipId + } + + if len(opts.PrivateIpAddress) > 0 { + params["private_ip"] = opts.PrivateIpAddress + } + + if len(opts.MaintainBegin) > 0 { + params["maintain_begin"] = opts.MaintainBegin + params["maintain_end"] = opts.MaintainEnd + } + + if opts.BillingCycle != nil { + bssParam := map[string]interface{}{ + "charging_mode": "prePaid", + "is_auto_pay": true, + "is_auto_renew": opts.BillingCycle.AutoRenew, + } + if opts.BillingCycle.GetMonths() >= 1 && opts.BillingCycle.GetMonths() >= 9 { + bssParam["period_type"] = "month" + bssParam["period_num"] = opts.BillingCycle.GetMonths() + } else if opts.BillingCycle.GetYears() >= 1 && opts.BillingCycle.GetYears() <= 3 { + bssParam["period_type"] = "year" + bssParam["period_num"] = opts.BillingCycle.GetYears() + } else { + return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)") + } + params["bss_param"] = bssParam + } + resp, err := self.post(SERVICE_DCS, "instances", params) + if err != nil { + return nil, err + } + ret := struct { + OrderId string + Instances []SElasticcache + }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, err + } + for i := range ret.Instances { + ret.Instances[i].region = self + return &ret.Instances[i], nil + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "after created %s", resp.String()) +} + +func (self *SElasticcache) Restart() error { + params := map[string]interface{}{ + "instances": []string{self.InstanceID}, + "action": "restart", + } + _, err := self.region.put(SERVICE_DCS, "instances/status", params) + return err } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423022.html func (self *SElasticcache) Delete() error { - err := DoDelete(self.region.ecsClient.Elasticcache.Delete, self.GetId(), nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.Delete") - } - - return nil + _, err := self.region.delete(SERVICE_DCS, "instances/"+self.GetId()) + return err } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html func (self *SElasticcache) ChangeInstanceSpec(spec string) error { - segs := strings.Split(spec, ":") - if len(segs) < 2 { - return fmt.Errorf("elasticcache.ChangeInstanceSpec invalid sku %s", spec) + params := map[string]interface{}{ + "spec_code": spec, + "new_capacity": self.CapacityGB, } - - if !strings.HasPrefix(segs[1], "m") || !strings.HasSuffix(segs[1], "g") { - return fmt.Errorf("elasticcache.ChangeInstanceSpec sku %s memeory size is invalid.", spec) - } - - newCapacity := segs[1][1 : len(segs[1])-1] - capacity, err := strconv.Atoi(newCapacity) - if err != nil { - return errors.Wrap(fmt.Errorf("invalid sku capacity %s", spec), "Elasticcache.ChangeInstanceSpec") - } - - _, err = self.region.ecsClient.Elasticcache.ChangeInstanceSpec(self.GetId(), segs[0], int64(capacity)) - if err != nil { - return errors.Wrap(err, "elasticcache.ChangeInstanceSpec") - } - - return nil + _, err := self.region.post(SERVICE_DCS, fmt.Sprintf("instances/%s/resize", self.InstanceID), params) + return err } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { - params := jsonutils.NewDict() - params.Set("maintain_begin", jsonutils.NewString(maintainStartTime)) - params.Set("maintain_end", jsonutils.NewString(maintainEndTime)) - err := DoUpdate(self.region.ecsClient.Elasticcache.Update, self.GetId(), params, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.SetMaintainTime") + params := map[string]interface{}{ + "maintain_begin": maintainStartTime, + "maintain_end": maintainEndTime, } - - return nil + _, err := self.region.put(SERVICE_DCS, "instances/"+self.InstanceID, params) + return err } // https://support.huaweicloud.com/usermanual-dcs/dcs-zh-ug-180314001.html @@ -598,22 +538,16 @@ func (self *SElasticcache) CreateAccount(account cloudprovider.SCloudElasticCach return nil, cloudprovider.ErrNotSupported } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html - func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { return nil, cloudprovider.ErrNotSupported } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423029.html func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { - params := jsonutils.NewDict() - params.Set("redis_config", config) - err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params) - if err != nil { - return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") + params := map[string]interface{}{ + "redis_config": config, } - - return nil + _, err := self.region.put(SERVICE_DCS, fmt.Sprintf("instances/%s/async-configs", self.InstanceID), params) + return err } // https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423033.html @@ -646,48 +580,27 @@ func backupPeriodTrans(config cloudprovider.SCloudElasticCacheBackupPolicyUpdate return ret } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html -func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { - params := jsonutils.NewDict() - policy := jsonutils.NewDict() - policy.Set("save_days", jsonutils.NewInt(int64(config.BackupReservedDays))) - policy.Set("backup_type", jsonutils.NewString(config.BackupType)) - plan := jsonutils.NewDict() - backTime := strings.ReplaceAll(config.PreferredBackupTime, "Z", "") - backupPeriod := backupPeriodTrans(config) - plan.Set("begin_at", jsonutils.NewString(backTime)) - plan.Set("period_type", jsonutils.NewString("weekly")) - plan.Set("backup_at", backupPeriod) - policy.Set("periodical_backup_plan", plan) - params.Set("instance_backup_policy", policy) - err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params) - if err != nil { - return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") +func (self *SElasticcache) UpdateBackupPolicy(opts cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { + params := map[string]interface{}{ + "save_days": opts.BackupReservedDays, + "backup_type": opts.BackupType, + "periodical_backup_plan": map[string]interface{}{ + "begin_at": strings.ReplaceAll(opts.PreferredBackupTime, "Z", ""), + "period_type": "weekly", + "backup_at": backupPeriodTrans(opts), + }, } - - return nil + _, err := self.region.put(SERVICE_DCS, "instances/"+self.InstanceID, map[string]interface{}{"instance_backup_policy": params}) + return err } -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html -// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { - resp, err := self.region.ecsClient.Elasticcache.Flush(self.GetId()) - if err != nil { - return errors.Wrap(err, "elasticcache.FlushInstance") + params := map[string]interface{}{ + "instances": []string{self.InstanceID}, + "action": "flush", } - - rets, err := resp.GetArray("results") - if err != nil { - return errors.Wrap(err, "elasticcache.FlushInstance") - } - - for _, r := range rets { - if ret, _ := r.GetString("result"); ret != "success" { - return fmt.Errorf("elasticcache.FlushInstance failed") - } - } - - return nil + _, err := self.region.put(SERVICE_DCS, "instances/status", params) + return err } // SElasticcacheAccount => ResetPassword diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/enterpriseprojects.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/enterpriseprojects.go index 673047fb04..46f13983fb 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/enterpriseprojects.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/enterpriseprojects.go @@ -15,10 +15,11 @@ package huawei import ( + "fmt" + "net/url" "strings" "time" - "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/cloudmux/pkg/apis/compute" @@ -26,7 +27,6 @@ import ( "yunion.io/x/cloudmux/pkg/multicloud" ) -// https://support.huaweicloud.com/api-em/zh-cn_topic_0121230880.html type SEnterpriseProject struct { multicloud.SProjectBase HuaweiTags @@ -40,16 +40,28 @@ type SEnterpriseProject struct { } func (self *SHuaweiClient) GetEnterpriseProjects() ([]SEnterpriseProject, error) { - projects := []SEnterpriseProject{} - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") + ret := []SEnterpriseProject{} + query := url.Values{} + for { + resp, err := self.list(SERVICE_EPS, "", "enterprise-projects", query) + if err != nil { + return nil, errors.Wrapf(err, "list") + } + part := struct { + EnterpriseProjects []SEnterpriseProject + TotalCount int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.EnterpriseProjects...) + if len(part.EnterpriseProjects) == 0 || len(ret) > part.TotalCount { + break + } + query.Set("offset", fmt.Sprintf("%d", len(ret))) } - err = doListAllWithOffset(client.EnterpriseProjects.List, map[string]string{}, &projects) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return projects, nil + return ret, nil } func (ep *SEnterpriseProject) GetId() string { @@ -72,17 +84,13 @@ func (ep *SEnterpriseProject) GetName() string { } func (self *SHuaweiClient) CreateExterpriseProject(name, desc string) (*SEnterpriseProject, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - params := map[string]string{ + params := map[string]interface{}{ "name": name, } if len(desc) > 0 { params["description"] = desc } - resp, err := client.EnterpriseProjects.Create(jsonutils.Marshal(params)) + resp, err := self.post(SERVICE_EPS, "", "enterprise-projects", params) if err != nil { if strings.Contains(err.Error(), "EPS.0004") { return nil, cloudprovider.ErrNotSupported @@ -92,12 +100,12 @@ func (self *SHuaweiClient) CreateExterpriseProject(name, desc string) (*SEnterpr } return nil, errors.Wrap(err, "EnterpriseProjects.Create") } - project := &SEnterpriseProject{} - err = resp.Unmarshal(&project) + ret := &SEnterpriseProject{} + err = resp.Unmarshal(&ret, "enterprise_project") if err != nil { return nil, errors.Wrap(err, "resp.Unmarshal") } - return project, nil + return ret, nil } func (self *SHuaweiClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/host.go index a2c5d2f207..761454a787 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/host.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/host.go @@ -16,13 +16,11 @@ package huawei import ( "fmt" - "strings" + "time" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/billing" - "yunion.io/x/pkg/util/osprofile" api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/cloudmux/pkg/cloudprovider" @@ -61,30 +59,28 @@ func (self *SHost) IsEmulated() bool { } func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms, err := self.zone.region.GetInstances() + vms, err := self.zone.region.GetInstances("") if err != nil { return nil, err } - filtedVms := make([]SInstance, 0) + ret := []cloudprovider.ICloudVM{} for i := range vms { if vms[i].OSEXTAZAvailabilityZone == self.zone.GetId() { - filtedVms = append(filtedVms, vms[i]) + vms[i].host = self + ret = append(ret, &vms[i]) } } - - ivms := make([]cloudprovider.ICloudVM, len(filtedVms)) - for i := 0; i < len(filtedVms); i += 1 { - filtedVms[i].host = self - ivms[i] = &filtedVms[i] - } - return ivms, nil + return ret, nil } func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := self.zone.region.GetInstanceByID(id) + vm, err := self.zone.region.GetInstance(id) + if err != nil { + return nil, err + } vm.host = self - return &vm, err + return vm, err } func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { @@ -161,35 +157,29 @@ func (self *SHost) GetVersion() string { return HUAWEI_API_VERSION } -func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) { - instance, err := self.zone.region.GetInstanceByID(instanceId) +func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + vmId, err := self._createVM(opts) if err != nil { return nil, err } - instance.host = self - return &instance, nil -} + cloudprovider.Wait(time.Second*5, time.Minute, func() (bool, error) { + _, err := self.zone.region.GetInstance(vmId) + if err == nil { + return true, nil + } + if errors.Cause(err) == cloudprovider.ErrNotFound { + return false, nil + } + return false, err + }) -func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - vmId, err := self._createVM( - desc.Name, desc.ExternalImageId, desc.SysDisk, - desc.Cpu, desc.MemoryMB, desc.InstanceType, - desc.ExternalNetworkId, desc.IpAddr, - desc.Description, desc.Account, - desc.Password, desc.DataDisks, - desc.PublicKey, desc.ExternalSecgroupIds, - desc.UserData, desc.BillingCycle, desc.ProjectId, desc.Tags) + vm, err := self.zone.region.GetInstance(vmId) if err != nil { return nil, err } - - vm, err := self.GetInstanceById(vmId) - if err != nil { - return nil, err - } - - return vm, err + vm.host = self + return vm, nil } func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { @@ -200,102 +190,55 @@ func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error return cloudprovider.GetHostNetifs(host, wires), nil } -func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, - networkId string, ipAddr string, desc string, account string, passwd string, - diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupIds []string, - userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (string, error) { - net := self.zone.getNetworkById(networkId) - if net == nil { - return "", fmt.Errorf("invalid network ID %s", networkId) - } - - if net.wire == nil { - log.Errorf("network's wire is empty") - return "", fmt.Errorf("network's wire is empty") - } - - if net.wire.vpc == nil { - log.Errorf("wire's vpc is empty") - return "", fmt.Errorf("wire's vpc is empty") - } - +func (self *SHost) _createVM(opts *cloudprovider.SManagedVMCreateConfig) (string, error) { // 同步keypair - var err error keypair := "" - if len(publicKey) > 0 { - keypair, err = self.zone.region.syncKeypair(publicKey) + var err error + if len(opts.PublicKey) > 0 { + keypair, err = self.zone.region.syncKeypair(opts.PublicKey) if err != nil { return "", err } } // 镜像及硬盘配置 - img, err := self.zone.region.GetImage(imgId) + img, err := self.zone.region.GetImage(opts.ExternalImageId) if err != nil { - log.Errorf("getiamge %s fail %s", imgId, err) - return "", err + return "", errors.Wrapf(err, "GetImage") } - if img.Status != ImageStatusActive { - log.Errorf("image %s status %s", imgId, img.Status) - return "", fmt.Errorf("image not ready") - } - // passwd, windows机型直接使用密码比较方便 - if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(passwd) > 0 { - keypair = "" - } - - if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) { - if u, err := updateWindowsUserData(userData, img.OSVersion, account, passwd); err == nil { - userData = u - } else { - return "", errors.Wrap(err, "SHost.CreateVM.updateWindowsUserData") - } - } - - disks := make([]SDisk, len(diskSizes)+1) - disks[0].SizeGB = img.SizeGB - if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.SizeGB { - disks[0].SizeGB = sysDisk.SizeGB - } - disks[0].VolumeType = sysDisk.StorageType - - for i, dataDisk := range diskSizes { - disks[i+1].SizeGB = dataDisk.SizeGB - disks[i+1].VolumeType = dataDisk.StorageType + if img.SizeGB > opts.SysDisk.SizeGB { + opts.SysDisk.SizeGB = img.SizeGB } // 创建实例 - if len(instanceType) > 0 { - log.Debugf("Try instancetype : %s", instanceType) - vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, networkId, secgroupIds, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) + if len(opts.InstanceType) > 0 { + log.Debugf("Try instancetype : %s", opts.InstanceType) + vmId, err := self.zone.region.CreateInstance(keypair, self.zone.ZoneName, opts) if err != nil { - log.Errorf("Failed for %s: %s", instanceType, err) - return "", fmt.Errorf("create %s failed:%s", instanceType, ErrMessage(err)) - } else { - return vmId, nil + return "", errors.Wrapf(err, "CreateInstance") } + return vmId, nil } // 匹配实例类型 - instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, self.zone.GetId()) + instanceTypes, err := self.zone.region.GetMatchInstanceTypes(opts.Cpu, opts.MemoryMB, self.zone.GetId()) if err != nil { return "", err } if len(instanceTypes) == 0 { - return "", fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB) + return "", fmt.Errorf("instance type %dC%dMB not avaiable", opts.Cpu, opts.MemoryMB) } var vmId string for _, instType := range instanceTypes { - instanceTypeId := instType.Name - log.Debugf("Try instancetype : %s", instanceTypeId) - vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupIds, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) + opts.InstanceType = instType.Name + log.Debugf("Try instancetype : %s", opts.InstanceType) + vmId, err = self.zone.region.CreateInstance(keypair, self.zone.ZoneName, opts) if err != nil { - log.Errorf("Failed for %s: %s", instanceTypeId, err) - } else { - return vmId, nil + log.Errorf("Failed for %s: %s", opts.InstanceType, err) } + return vmId, nil } - return "", fmt.Errorf("create failed: %s", ErrMessage(err)) + return "", errors.Wrapf(err, "CreateInstance") } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/huawei.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/huawei.go index 8b36d1884d..e41d7e260d 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/huawei.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/huawei.go @@ -35,20 +35,9 @@ import ( api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/cloudmux/pkg/cloudprovider" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials" "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs" ) -/* -待解决问题: -1.同步的子账户中有一条空记录.需要查原因 -2.安全组同步需要进一步确认 -3.实例接口需要进一步确认 -4.BGP type 目前是hard code在代码中。需要考虑从cloudmeta服务中查询 -*/ - const ( CLOUD_PROVIDER_HUAWEI = api.CLOUD_PROVIDER_HUAWEI CLOUD_PROVIDER_HUAWEI_CN = "华为云" @@ -62,13 +51,21 @@ const ( HUAWEI_API_VERSION = "2018-12-25" SERVICE_IAM = "iam" + SERVICE_IAM_V3 = "iam_v3" + SERVICE_IAM_V3_EXT = "iam_v3_ext" SERVICE_ELB = "elb" SERVICE_VPC = "vpc" + SERVICE_VPC_V2_0 = "vpc_v2.0" + SERVICE_VPC_V3 = "vpc_v3" SERVICE_CES = "ces" SERVICE_RDS = "rds" SERVICE_ECS = "ecs" + SERVICE_ECS_V1_1 = "ecs_v1.1" + SERVICE_ECS_V2_1 = "ecs_v2.1" SERVICE_EPS = "eps" SERVICE_EVS = "evs" + SERVICE_EVS_V1 = "evs_v1" + SERVICE_EVS_V2_1 = "evs_v2.1" SERVICE_BSS = "bss" SERVICE_SFS = "sfs-turbo" SERVICE_CTS = "cts" @@ -77,10 +74,12 @@ const ( SERVICE_CCI = "cci" SERVICE_CSBS = "csbs" SERVICE_IMS = "ims" + SERVICE_IMS_V1 = "ims_v1" SERVICE_AS = "as" SERVICE_CCE = "cce" SERVICE_DCS = "dcs" SERVICE_MODELARTS = "modelarts" + SERVICE_MODELARTS_V1 = "modelarts_v1" SERVICE_SCM = "scm" SERVICE_CDN = "cdn" SERVICE_GAUSSDB = "gaussdb" @@ -100,17 +99,15 @@ type HuaweiClientConfig struct { cpcfg cloudprovider.ProviderConfig projectId string // 华为云项目ID. - cloudEnv string // 服务区域 ChinaCloud | InternationalCloud accessKey string accessSecret string debug bool } -func NewHuaweiClientConfig(cloudEnv, accessKey, accessSecret, projectId string) *HuaweiClientConfig { +func NewHuaweiClientConfig(accessKey, accessSecret, projectId string) *HuaweiClientConfig { cfg := &HuaweiClientConfig{ projectId: projectId, - cloudEnv: cloudEnv, accessKey: accessKey, accessSecret: accessSecret, } @@ -130,8 +127,6 @@ func (cfg *HuaweiClientConfig) Debug(debug bool) *HuaweiClientConfig { type SHuaweiClient struct { *HuaweiClientConfig - signer auth.Signer - isMainProject bool // whether the project is the main project in the region clientRegion string @@ -147,6 +142,8 @@ type SHuaweiClient struct { regions []SRegion httpClient *http.Client + + orders map[string]SOrderResource } // 进行资源操作时参数account 对应数据库cloudprovider表中的account字段,由accessKey和projectID两部分组成,通过"/"分割。 @@ -169,10 +166,6 @@ func (self *SHuaweiClient) init() error { if err != nil { return err } - err = self.initSigner() - if err != nil { - return errors.Wrap(err, "initSigner") - } err = self.initOwner() if err != nil { return errors.Wrap(err, "fetchOwner") @@ -183,16 +176,6 @@ func (self *SHuaweiClient) init() error { return nil } -func (self *SHuaweiClient) initSigner() error { - var err error - cred := credentials.NewAccessKeyCredential(self.accessKey, self.accessKey) - self.signer, err = auth.NewSignerWithCredential(cred) - if err != nil { - return err - } - return nil -} - func (self *SHuaweiClient) getDefaultClient() *http.Client { if self.httpClient != nil { return self.httpClient @@ -221,30 +204,10 @@ func (self *SHuaweiClient) getDefaultClient() *http.Client { return self.httpClient } -func (self *SHuaweiClient) newRegionAPIClient(regionId string) (*client.Client, error) { - projectId := self.projectId - if len(regionId) == 0 { - projectId = "" - } - cli, err := client.NewPublicCloudClientWithAccessKey(regionId, self.ownerId, projectId, self.accessKey, self.accessSecret, self.debug) - if err != nil { - return nil, err - } - - httpClient := self.getDefaultClient() - cli.SetHttpClient(httpClient) - - return cli, nil -} - type sPageInfo struct { NextMarker string } -func (self *SHuaweiClient) newGeneralAPIClient() (*client.Client, error) { - return self.newRegionAPIClient("") -} - type akClient struct { client *http.Client aksk aksk.SignOptions @@ -287,6 +250,7 @@ func (self *SHuaweiClient) request(method httputils.THttpMethod, url string, que } if (strings.Contains(url, "/OS-CREDENTIAL/") || strings.Contains(url, "/users") || + strings.Contains(url, "/groups") || strings.Contains(url, "eps.myhuaweicloud.com")) && len(self.ownerId) > 0 { header.Set("X-Domain-Id", self.ownerId) } @@ -300,8 +264,8 @@ func (self *SHuaweiClient) request(method httputils.THttpMethod, url string, que return resp, err } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListRegions func (self *SHuaweiClient) fetchRegions() error { - huawei, _ := self.newGeneralAPIClient() if self.regions == nil { userId, err := self.GetUserId() if err != nil { @@ -309,12 +273,15 @@ func (self *SHuaweiClient) fetchRegions() error { } if regionsCache, ok := HUAWEI_REGION_CACHES.Load(userId); !ok || regionsCache.(*userRegionsCache).ExpireAt.Sub(time.Now()).Seconds() > 0 { - regions := make([]SRegion, 0) - err := doListAll(huawei.Regions.List, nil, ®ions) + resp, err := self.list(SERVICE_IAM_V3, "", "regions", nil) if err != nil { - return errors.Wrap(err, "Regions.List") + return errors.Wrapf(err, "list regions") + } + regions := make([]SRegion, 0) + err = resp.Unmarshal(®ions, "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}) } @@ -350,10 +317,6 @@ func (self *SHuaweiClient) fetchRegions() error { self.iregions = make([]cloudprovider.ICloudRegion, len(filtedRegions)) for i := 0; i < len(filtedRegions); i += 1 { filtedRegions[i].client = self - _, err := filtedRegions[i].getECSClient() - if err != nil { - return err - } self.iregions[i] = &filtedRegions[i] } return nil @@ -448,16 +411,6 @@ func (self *SHuaweiClient) GetCloudRegionExternalIdPrefix() string { } } -func (self *SHuaweiClient) UpdateAccount(accessKey, secret string) error { - if self.accessKey != accessKey || self.accessSecret != secret { - self.accessKey = accessKey - self.accessSecret = secret - return self.fetchRegions() - } else { - return nil - } -} - func (self *SHuaweiClient) GetRegions() []SRegion { regions := make([]SRegion, len(self.iregions)) for i := 0; i < len(regions); i += 1 { @@ -597,7 +550,6 @@ func (self *SHuaweiClient) GetIStorageById(id string) (cloudprovider.ICloudStora return nil, cloudprovider.ErrNotFound } -// https://console.huaweicloud.com/apiexplorer/#/openapi/BSS/debug?api=ShowCustomerAccountBalances type SBalance struct { Amount float64 `json:"amount"` Currency string `json:"currency"` @@ -608,7 +560,7 @@ type SBalance struct { MeasureUnit int64 `json:"measure_unit"` } -// 这里的余额指的是所有租户的总余额 +// https://console.huaweicloud.com/apiexplorer/#/openapi/BSS/doc?api=ShowCustomerAccountBalances func (self *SHuaweiClient) QueryAccountBalance() (*SBalance, error) { resp, err := self.list(SERVICE_BSS, "", "accounts/customer-accounts/balances", nil) if err != nil { @@ -645,17 +597,6 @@ func (self *SHuaweiClient) GetVersion() string { return HUAWEI_API_VERSION } -func (self *SHuaweiClient) GetAccessEnv() string { - switch self.cloudEnv { - case HUAWEI_INTERNATIONAL_CLOUDENV: - return api.CLOUD_ACCESS_ENV_HUAWEI_GLOBAL - case HUAWEI_CHINA_CLOUDENV: - return api.CLOUD_ACCESS_ENV_HUAWEI_CHINA - default: - return api.CLOUD_ACCESS_ENV_HUAWEI_GLOBAL - } -} - func (self *SHuaweiClient) GetCapabilities() []string { caps := []string{ cloudprovider.CLOUD_CAPABILITY_PROJECT, @@ -686,54 +627,56 @@ func (self *SHuaweiClient) GetCapabilities() []string { return caps } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=ShowPermanentAccessKey func (self *SHuaweiClient) GetUserId() (string, error) { if len(self.userId) > 0 { return self.userId, nil } - client, err := self.newGeneralAPIClient() - if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetUserId.newGeneralAPIClient") - } type cred struct { UserId string `json:"user_id"` } ret := &cred{} - err = DoGet(client.Credentials.Get, self.accessKey, nil, ret) + resp, err := self.list(SERVICE_IAM, "", "OS-CREDENTIAL/credentials/"+self.accessKey, nil) if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetUserId.DoGet") + return "", errors.Wrapf(err, "show credential") + } + err = resp.Unmarshal(ret, "credential") + if err != nil { + return "", errors.Wrapf(err, "Unmarshal") } self.userId = ret.UserId return self.userId, nil } // owner id == domain_id == account id +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=ShowUser func (self *SHuaweiClient) GetOwnerId() (string, error) { if len(self.ownerId) > 0 { return self.ownerId, nil } + userId, err := self.GetUserId() if err != nil { return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.GetUserId") } - client, err := self.newGeneralAPIClient() - if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.newGeneralAPIClient") - } - type user struct { DomainId string `json:"domain_id"` Name string `json:"name"` CreateTime string } - - ret := &user{} - err = DoGet(client.Users.Get, userId, nil, ret) + resp, err := self.list(SERVICE_IAM, "", "OS-USER/users/"+userId, nil) if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.DoGet") + return "", errors.Wrapf(err, "show user") } + ret := &user{} + err = resp.Unmarshal(ret, "user") + if err != nil { + return "", errors.Wrapf(err, "Unmarshal") + } + self.ownerName = ret.Name // 2021-02-02 02:43:28.0 self.ownerCreateTime, _ = timeutils.ParseTimeStr(strings.TrimSuffix(ret.CreateTime, ".0")) @@ -820,65 +763,57 @@ func (self *SHuaweiClient) getUrl(service, regionId, resource string, method htt switch service { case SERVICE_IAM: url = fmt.Sprintf("https://iam.myhuaweicloud.com/v3.0/%s", resource) - if !strings.HasPrefix(resource, "OS-") { - url = fmt.Sprintf("https://iam.myhuaweicloud.com/v3/%s", resource) - } + case SERVICE_IAM_V3: + url = fmt.Sprintf("https://iam.myhuaweicloud.com/v3/%s", resource) + 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) case SERVICE_VPC: - version := "v1" - if strings.HasPrefix(resource, "vpc/") || strings.HasPrefix(resource, "eip/") { - version = "v3" + url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) + case SERVICE_VPC_V2_0: + url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v2.0/%s/%s", regionId, self.projectId, resource) + if strings.Contains(resource, "/peerings") { + url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v2.0/%s", regionId, resource) } - url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/%s/%s/%s", regionId, version, self.projectId, resource) + case SERVICE_VPC_V3: + url = fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource) case SERVICE_CES: url = fmt.Sprintf("https://ces.%s.myhuaweicloud.com/v1.0/%s/%s", regionId, self.projectId, resource) case SERVICE_MODELARTS: url = fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) - if strings.HasPrefix(resource, "networks") || strings.HasPrefix(resource, "resourceflavors") { - url = fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) - } + case SERVICE_MODELARTS_V1: + url = fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) case SERVICE_RDS: url = fmt.Sprintf("https://rds.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource) case SERVICE_ECS: - version := "v1" - for _, prefix := range []string{ - "os-availability-zone", - "servers", - "os-keypairs", - } { - if strings.HasPrefix(resource, prefix) || strings.Contains(resource, "os-security-groups") { - version = "v2.1" - break - } - } - if strings.HasSuffix(resource, "action") && !gotypes.IsNil(params) { - for _, k := range []string{"addSecurityGroup", "removeSecurityGroup"} { - _, ok := params[k] - if ok { - version = "v2.1" - break - } - } - } - url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/%s/%s/%s", regionId, version, self.projectId, resource) + url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) + case SERVICE_ECS_V1_1: + url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/v1.1/%s/%s", regionId, self.projectId, resource) + case SERVICE_ECS_V2_1: + url = fmt.Sprintf("https://ecs.%s.myhuaweicloud.com/v2.1/%s/%s", regionId, self.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) case SERVICE_EVS: - version := "v2" - url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/%s/%s/%s", regionId, version, self.projectId, resource) + url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) + case SERVICE_EVS_V2_1: + url = fmt.Sprintf("https://evs.%s.myhuaweicloud.com/v2.1/%s/%s", regionId, self.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) 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) case SERVICE_CTS: url = fmt.Sprintf("https://cts.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource) case SERVICE_NAT: - url = fmt.Sprintf("https://nat.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) + url = fmt.Sprintf("https://nat.%s.myhuaweicloud.com/v3/%s/%s", regionId, self.projectId, resource) case SERVICE_SCM: url = fmt.Sprintf("https://scm.cn-north-4.myhuaweicloud.com/v3/%s", resource) case SERVICE_CDN: diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/image.go index 8ff01d297e..4cd0c689dc 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/image.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/image.go @@ -17,6 +17,7 @@ package huawei import ( "context" "fmt" + "net/url" "strings" "time" @@ -31,17 +32,6 @@ import ( "yunion.io/x/cloudmux/pkg/multicloud" ) -type TImageOwnerType string - -const ( - ImageOwnerPublic TImageOwnerType = "gold" // 公共镜像:gold - ImageOwnerSelf TImageOwnerType = "private" // 私有镜像:private - ImageOwnerShared TImageOwnerType = "shared" // 共享镜像:shared - - EnvFusionCompute = "FusionCompute" - EnvIronic = "Ironic" -) - const ( ImageStatusQueued = "queued" // queued:表示镜像元数据已经创建成功,等待上传镜像文件。 ImageStatusSaving = "saving" // saving:表示镜像正在上传文件到后端存储。 @@ -50,7 +40,6 @@ const ( ImageStatusActive = "active" // active:表示镜像可以正常使用 ) -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091565.html type SImage struct { multicloud.SImageBase HuaweiTags @@ -141,11 +130,11 @@ func (self *SImage) GetImageStatus() string { } func (self *SImage) Refresh() error { - new, err := self.storageCache.region.GetImage(self.GetId()) + image, err := self.storageCache.region.GetImage(self.GetId()) if err != nil { return err } - return jsonutils.Update(self, new) + return jsonutils.Update(self, image) } func (self *SImage) GetImageType() cloudprovider.TImageType { @@ -218,10 +207,6 @@ func (self *SImage) GetCreatedAt() time.Time { return self.CreatedAt } -func (self *SImage) IsEmulated() bool { - return false -} - func (self *SImage) Delete(ctx context.Context) error { return self.storageCache.region.DeleteImage(self.GetId()) } @@ -231,145 +216,101 @@ func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { } func (self *SRegion) GetImage(imageId string) (*SImage, error) { - image := &SImage{} - err := DoGet(self.ecsClient.Images.Get, imageId, nil, image) - if err != nil { - return nil, errors.Wrap(err, "DoGet") - } - return image, nil -} - -func excludeImage(image SImage) bool { - if image.VirtualEnvType == "Ironic" { - return true - } - - if len(image.SupportDiskIntensive) > 0 { - return true - } - - if len(image.SupportKVMFPGAType) > 0 || len(image.SupportKVMAscend310) > 0 { - return true - } - - if len(image.SupportKVMGPUType) > 0 { - return true - } - - if len(image.SupportKVMNVMEHIGHIO) > 0 { - return true - } - - if len(image.SupportGPUT4) > 0 { - return true - } - - if len(image.SupportXENGPUType) > 0 { - return true - } - - if len(image.SupportHighPerformance) > 0 { - return true - } - - if len(image.SupportArm) > 0 { - return true - } - - return false -} - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0060804959.html -func (self *SRegion) GetImages(status string, imagetype TImageOwnerType, name string, envType string) ([]SImage, error) { - queries := map[string]string{} - if len(status) > 0 { - queries["status"] = status - } - - if len(imagetype) > 0 { - queries["__imagetype"] = string(imagetype) - if imagetype == ImageOwnerPublic { - queries["protected"] = "True" - } - } - if len(envType) > 0 { - queries["virtual_env_type"] = envType - } - - if len(name) > 0 { - queries["name"] = name - } - - images := make([]SImage, 0) - err := doListAllWithMarker(self.ecsClient.Images.List, queries, &images) - - // 排除掉需要特定镜像才能创建的实例类型 - // https://support.huaweicloud.com/eu-west-0-api-ims/zh-cn_topic_0031617666.html#ZH-CN_TOPIC_0031617666__table48545918250 - // https://support.huaweicloud.com/productdesc-ecs/zh-cn_topic_0088142947.html - filtedImages := make([]SImage, 0) - for i := range images { - if !excludeImage(images[i]) { - filtedImages = append(filtedImages, images[i]) - } - } - - return filtedImages, err -} - -func (self *SRegion) DeleteImage(imageId string) error { - return DoDelete(self.ecsClient.OpenStackImages.Delete, imageId, nil, nil) -} - -func (self *SRegion) GetImageByName(name string) (*SImage, error) { - if len(name) == 0 { - return nil, fmt.Errorf("image name should not be empty") - } - - images, err := self.GetImages("", TImageOwnerType(""), name, "") + images, err := self.GetImages(imageId, "", "", "") if err != nil { return nil, err } - if len(images) == 0 { - return nil, cloudprovider.ErrNotFound + for i := range images { + if images[i].ID == imageId { + return &images[i], nil + } } - - log.Debugf("%d image found match name %s", len(images), name) - return &images[0], nil + return nil, errors.Wrapf(cloudprovider.ErrNotFound, imageId) } -/* https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html - os version 取值范围: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html - 用于创建私有镜像的源云服务器系统盘大小大于等于40GB且不超过1024GB。 - 目前支持vhd,zvhd、raw,qcow2 - todo: 考虑使用镜像快速导入。 https://support.huaweicloud.com/api-ims/zh-cn_topic_0133188204.html - 使用OBS文件创建镜像 +// https://console.huaweicloud.com/apiexplorer/#/openapi/IMS/doc?api=ListImages +func (self *SRegion) GetImages(id, status string, imagetype string, name string) ([]SImage, error) { + query := url.Values{} + query.Set("virtual_env_type", "FusionCompute") + if len(status) > 0 { + query.Set("status", status) + } + + if len(id) > 0 { + query.Set("id", id) + } + + if len(imagetype) > 0 { + query.Set("__imagetype", string(imagetype)) + if imagetype == "gold" { + query.Set("protected", "True") + } + } + + if len(name) > 0 { + query.Set("name", name) + } + + ret := []SImage{} + for { + resp, err := self.list(SERVICE_IMS, "cloudimages", query) + if err != nil { + return nil, err + } + part := struct { + Images []SImage + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + ret = append(ret, part.Images...) + if len(part.Images) == 0 { + break + } + query.Set("marker", part.Images[len(part.Images)-1].ID) + } + + return ret, nil +} + +func (self *SRegion) DeleteImage(imageId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetImageByName(name string) (*SImage, error) { + images, err := self.GetImages("", "", "", name) + if err != nil { + return nil, err + } + for i := range images { + if images[i].Name == name { + return &images[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) +} - * openstack原生接口支持的格式:https://support.huaweicloud.com/api-ims/zh-cn_topic_0031615566.html -*/ func (self *SRegion) ImportImageJob(name string, osDist string, osVersion string, osArch string, bucket string, key string, minDiskGB int64) (string, error) { - os_version, err := stdVersion(osDist, osVersion, osArch) - log.Debugf("%s %s %s: %s.min_disk %d GB", osDist, osVersion, osArch, os_version, minDiskGB) + osVersion, err := stdVersion(osDist, osVersion, osArch) + log.Debugf("%s %s %s: %s.min_disk %d GB", osDist, osVersion, osArch, osVersion, minDiskGB) + + imageUrl := fmt.Sprintf("%s:%s", bucket, key) + params := map[string]interface{}{ + "name": name, + "image_url": imageUrl, + "is_config_init": true, + "is_config": true, + "min_disk": minDiskGB, + } + if len(osVersion) > 0 { + params["os_version"] = osVersion + } + resp, err := self.post(SERVICE_IMS, "cloudimages/quickimport/action", params) if err != nil { - log.Debugln(err) + return "", errors.Wrapf(err, "import image") } - - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(name), "name") - image_url := fmt.Sprintf("%s:%s", bucket, key) - params.Add(jsonutils.NewString(image_url), "image_url") - if len(os_version) > 0 { - params.Add(jsonutils.NewString(os_version), "os_version") - } - params.Add(jsonutils.NewBool(true), "is_config_init") - params.Add(jsonutils.NewBool(true), "is_config") - params.Add(jsonutils.NewInt(minDiskGB), "min_disk") - - ret, err := self.ecsClient.Images.PerformAction2("action", "", params, "") - if err != nil { - return "", err - } - - return ret.GetString("job_id") + return resp.GetString("job_id") } func formatVersion(osDist string, osVersion string) (string, error) { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instance.go index 564a37ab99..5825b76ffc 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instance.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instance.go @@ -16,8 +16,8 @@ package huawei import ( "context" - "encoding/base64" "fmt" + "net/url" "sort" "strconv" "strings" @@ -27,7 +27,6 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/billing" - "yunion.io/x/pkg/util/cloudinit" "yunion.io/x/pkg/util/osprofile" "yunion.io/x/pkg/utils" @@ -98,8 +97,6 @@ type SysTag struct { Value string `json:"value"` } -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html -// https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0100166287.html v1.1 支持创建包年/包月的弹性云服务器 type SInstance struct { multicloud.SInstanceBase HuaweiTags @@ -240,22 +237,11 @@ func (ins *SInstance) GetPowerStates() string { } func (self *SInstance) Refresh() error { - new, err := self.host.zone.region.GetInstanceByID(self.GetId()) - new.host = self.host + vm, err := self.host.zone.region.GetInstance(self.GetId()) if err != nil { return err } - - if new.Status == InstanceStatusTerminated { - log.Debugf("Instance already terminated.") - return cloudprovider.ErrNotFound - } - - err = jsonutils.Update(self, new) - if err != nil { - return err - } - return nil + return jsonutils.Update(self, vm) } func (self *SInstance) GetInstanceType() string { @@ -270,24 +256,22 @@ func (self *SInstance) GetSecurityGroupIds() ([]string, error) { return ret, nil } -// https://support.huaweicloud.com/api-ecs/ecs_02_1002.html // key 相同时value不会替换 +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=BatchCreateServerTags func (self *SRegion) CreateServerTags(instanceId string, tags map[string]string) error { params := map[string]interface{}{ "action": "create", } - tagsObj := []map[string]string{} for k, v := range tags { tagsObj = append(tagsObj, map[string]string{"key": k, "value": v}) } params["tags"] = tagsObj - - _, err := self.ecsClient.Servers.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") + _, err := self.post(SERVICE_ECS, fmt.Sprintf("cloudservers/%s/tags/action", instanceId), params) return err } -// https://support.huaweicloud.com/api-ecs/ecs_02_1003.html +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=BatchDeleteServerTags func (self *SRegion) DeleteServerTags(instanceId string, tagsKey []string) error { params := map[string]interface{}{ "action": "delete", @@ -297,8 +281,7 @@ func (self *SRegion) DeleteServerTags(instanceId string, tagsKey []string) error tagsObj = append(tagsObj, map[string]string{"key": k}) } params["tags"] = tagsObj - - _, err := self.ecsClient.Servers.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") + _, err := self.post(SERVICE_ECS, fmt.Sprintf("cloudservers/%s/tags/action", instanceId), params) return err } @@ -320,26 +303,23 @@ func (self *SInstance) SetTags(tags map[string]string, replace bool) error { if len(deleteTagsKey) > 0 { err := self.host.zone.region.DeleteServerTags(self.GetId(), deleteTagsKey) if err != nil { - return errors.Wrapf(err, "self.host.zone.region.DeleteServerTags(%s,%s)", self.GetId(), deleteTagsKey) + return errors.Wrapf(err, "DeleteServerTags(%s,%s)", self.GetId(), deleteTagsKey) } } if len(tags) > 0 { err := self.host.zone.region.CreateServerTags(self.GetId(), tags) if err != nil { - return errors.Wrapf(err, "self.host.zone.region.CreateServerTags(%s,%s)", self.GetId(), jsonutils.Marshal(tags).String()) + return errors.Wrapf(err, "CreateServerTags(%s,%s)", self.GetId(), jsonutils.Marshal(tags).String()) } } return nil } func (self *SInstance) GetBillingType() string { - // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html - // charging_mode “0”:按需计费 “1”:按包年包月计费 if self.Metadata.ChargingMode == "1" { return billing_api.BILLING_TYPE_PREPAID - } else { - return billing_api.BILLING_TYPE_POSTPAID } + return billing_api.BILLING_TYPE_POSTPAID } func (self *SInstance) GetCreatedAt() time.Time { @@ -350,25 +330,16 @@ func (self *SInstance) GetDescription() string { return self.Description } -// charging_mode “0”:按需计费 “1”:按包年包月计费 func (self *SInstance) GetExpiredAt() time.Time { - if len(self.Metadata.MeteringOrderId) > 0 { - res, _ := self.host.zone.region.GetOrderResources(self.Metadata.MeteringOrderId, []string{self.ID}, true) - for i := range res { - return res[i].ExpireTime - } + orders, err := self.host.zone.region.client.GetOrderResources() + if err != nil { + return time.Time{} } - var expiredTime time.Time - if self.Metadata.ChargingMode == "1" { - res, err := self.host.zone.region.GetOrderResourceDetail(self.GetId()) - if err != nil { - log.Debugln(err) - } - - expiredTime = res.ExpireTime + order, ok := orders[self.ID] + if ok { + return order.ExpireTime } - - return expiredTime + return time.Time{} } func (self *SInstance) GetIHost() cloudprovider.ICloudHost { @@ -376,11 +347,6 @@ func (self *SInstance) GetIHost() cloudprovider.ICloudHost { } func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - err := self.Refresh() - if err != nil { - return nil, err - } - attached := self.OSExtendedVolumesVolumesAttached disks := make([]SDisk, 0) for _, vol := range attached { @@ -556,7 +522,7 @@ func (self *SInstance) GetMachine() string { } func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - ids, err := self.host.zone.region.GetInstanceSecrityGroupIds(self.GetId()) + ids, err := self.GetSecurityGroupIds() if err != nil { return err } @@ -582,126 +548,61 @@ func (self *SInstance) GetHypervisor() string { } func (self *SInstance) StartVM(ctx context.Context) error { - if self.Status == InstanceStatusRunning { - return nil - } - - timeout := 300 * time.Second - interval := 15 * time.Second - - startTime := time.Now() - for time.Now().Sub(startTime) < timeout { - err := self.Refresh() - if err != nil { - return err - } - - if self.GetStatus() == api.VM_RUNNING { - return nil - } else if self.GetStatus() == api.VM_READY { - err := self.host.zone.region.StartVM(self.GetId()) - if err != nil { - return err - } - } - time.Sleep(interval) - } - return cloudprovider.ErrTimeout + return self.host.zone.region.StartVM(self.GetId()) } func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - if self.Status == InstanceStatusStopped { - return nil - } - - if self.Status == InstanceStatusTerminated { - log.Debugf("Instance already terminated.") - return nil - } - - err := self.host.zone.region.StopVM(self.GetId(), opts.IsForce) - if err != nil { - return err - } - return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues + return self.host.zone.region.StopVM(self.GetId(), opts.IsForce) } func (self *SInstance) DeleteVM(ctx context.Context) error { - if self.Status == InstanceStatusTerminated { - return nil - } - - for { - err := self.host.zone.region.DeleteVM(self.GetId()) - if err != nil && self.Status != InstanceStatusTerminated { - log.Errorf("DeleteVM fail: %s", err) - return err - } else { - break - } - } - - return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes + return self.host.zone.region.DeleteVM(self.GetId()) } func (self *SInstance) UpdateVM(ctx context.Context, input cloudprovider.SInstanceUpdateOptions) error { return self.host.zone.region.UpdateVM(self.GetId(), input) } -// https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0032380449.html -// 创建云服务器过程中注入用户数据。支持注入文本、文本文件或gzip文件。 -// 注入内容,需要进行base64格式编码。注入内容(编码之前的内容)最大长度32KB。 -// 对于Linux弹性云服务器,adminPass参数传入时,user_data参数不生效。 func (self *SInstance) UpdateUserData(userData string) error { return cloudprovider.ErrNotSupported } -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html 使用原镜像重装 -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html 更换系统盘操作系统 -// 不支持调整系统盘大小 -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=ChangeServerOsWithoutCloudInit +func (self *SRegion) RebuildRoot(instanceId string, opts *cloudprovider.SManagedVMRebuildRootConfig) (jsonutils.JSONObject, error) { var err error - var jobId string - publicKeyName := "" - if len(desc.PublicKey) > 0 { - publicKeyName, err = self.host.zone.region.syncKeypair(desc.PublicKey) + keyName := "" + if len(opts.PublicKey) > 0 { + keyName, err = self.syncKeypair(opts.PublicKey) if err != nil { - return "", err + return nil, err } } + params := map[string]interface{}{ + "imageid": opts.ImageId, + } + if len(opts.Password) > 0 { + params["adminpass"] = opts.Password + } + if len(keyName) > 0 { + params["keyname"] = keyName + } + return self.post(SERVICE_ECS, fmt.Sprintf("cloudservers/%s/changeos", instanceId), map[string]interface{}{"os-change": params}) +} - image, err := self.host.zone.region.GetImage(desc.ImageId) +func (self *SInstance) RebuildRoot(ctx context.Context, opts *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + resp, err := self.host.zone.region.RebuildRoot(self.ID, opts) if err != nil { - return "", errors.Wrap(err, "SInstance.RebuildRoot.GetImage") + return "", errors.Wrapf(err, "change os") } - - // Password存在的情况下,windows 系统直接使用密码 - if strings.ToLower(image.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(desc.Password) > 0 { - publicKeyName = "" - } - - userData, err := updateUserData(self.OSEXTSRVATTRUserData, image.OSVersion, desc.Account, desc.Password, desc.PublicKey) + jobId, err := resp.GetString("job_id") if err != nil { - return "", errors.Wrap(err, "SInstance.RebuildRoot.updateUserData") + return "", errors.Wrapf(err, "get job_id") } - if self.Metadata.MeteringImageID == desc.ImageId { - jobId, err = self.host.zone.region.RebuildRoot(ctx, self.UserID, self.GetId(), desc.Password, publicKeyName, userData) - if err != nil { - return "", err - } - } else { - jobId, err = self.host.zone.region.ChangeRoot(ctx, self.UserID, self.GetId(), desc.ImageId, desc.Password, publicKeyName, userData) - if err != nil { - return "", err - } - } - - err = self.host.zone.region.waitTaskStatus(self.host.zone.region.ecsClient.Servers.ServiceType(), jobId, TASK_SUCCESS, 15*time.Second, 900*time.Second) + err = self.host.zone.region.waitTaskStatus(SERVICE_ECS, jobId, TASK_SUCCESS, 15*time.Second, 900*time.Second) if err != nil { - log.Errorf("RebuildRoot task error %s", err) - return "", err + return "", errors.Wrapf(err, "wait task") } err = self.Refresh() @@ -722,6 +623,9 @@ func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SMan } func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + if self.GetName() == name { + name = "" + } return self.host.zone.region.DeployVM(self.GetId(), name, password, publicKey, deleteKeypair, description) } @@ -753,7 +657,6 @@ func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.S return fmt.Errorf("Failed to change vm config, specification not supported") } -// todo:// 返回jsonobject感觉很诡异。不能直接知道内部细节 func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { return self.host.zone.region.GetInstanceVNCUrl(self.GetId()) } @@ -782,258 +685,181 @@ func (self *SInstance) NextDeviceName() (string, error) { func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { device, err := self.NextDeviceName() if err != nil { - return errors.Wrap(err, "Instance.AttachDisk.NextDeviceName") + return errors.Wrap(err, "NextDeviceName") } - err = self.host.zone.region.AttachDisk(self.GetId(), diskId, device) - if err != nil { - return errors.Wrap(err, "Instance.AttachDisk.AttachDisk") - } - - return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { - disk, err := self.host.zone.region.GetDisk(diskId) - if err != nil { - log.Debugf("Instance.AttachDisk.GetDisk %s", err) - return false, nil - } - - if disk.Status == "in-use" { - return true, nil - } - - return false, nil - }) + return self.host.zone.region.AttachDisk(self.GetId(), diskId, device) } func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - err := self.host.zone.region.DetachDisk(self.GetId(), diskId) - if err != nil { - return errors.Wrap(err, "Instance.DetachDisk") + for _, disk := range self.OSExtendedVolumesVolumesAttached { + if disk.ID == diskId { + return self.host.zone.region.DetachDisk(self.GetId(), diskId) + } } - - return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { - disk, err := self.host.zone.region.GetDisk(diskId) - if err != nil { - log.Debugf("Instance.DetachDisk.GetDisk %s", err) - return false, nil - } - - if disk.Status == "available" { - return true, nil - } - - return false, nil - }) + return nil } func (self *SInstance) Renew(bc billing.SBillingCycle) error { return self.host.zone.region.RenewInstance(self.GetId(), bc) } -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148850.html -func (self *SRegion) GetInstances() ([]SInstance, error) { - queries := make(map[string]string) - - if len(self.client.projectId) > 0 { - queries["project_id"] = self.client.projectId +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=ListServersDetails +func (self *SRegion) GetInstances(ip string) ([]SInstance, error) { + params := url.Values{} + params.Set("limit", "1000") + if len(ip) > 0 { + params.Set("ip", ip) } - - instances := make([]SInstance, 0) - err := doListAllWithPagerOffset(self.ecsClient.Servers.List, queries, &instances) - return instances, err -} - -func (self *SRegion) GetInstanceByID(instanceId string) (SInstance, error) { - instance := SInstance{} - err := DoGet(self.ecsClient.Servers.Get, instanceId, nil, &instance) - return instance, err -} - -func (self *SRegion) GetInstanceByIds(ids []string) ([]SInstance, int, error) { - instances := make([]SInstance, 0) - for _, instanceId := range ids { - instance, err := self.GetInstanceByID(instanceId) + ret := []SInstance{} + for { + resp, err := self.list(SERVICE_ECS, "cloudservers/detail", params) if err != nil { - return nil, 0, err + return nil, err } - instances = append(instances, instance) - } - - return instances, len(instances), nil -} - -/* -系统盘大小取值范围:1-1024 GB,且必须不小于镜像min_disk. -*/ -type SServerCreate struct { - AvailabilityZone string `json:"availability_zone"` - Name string `json:"name"` - ImageRef string `json:"imageRef"` - RootVolume RootVolume `json:"root_volume"` - DataVolumes []DataVolume `json:"data_volumes"` - FlavorRef string `json:"flavorRef"` - UserData string `json:"user_data"` - Vpcid string `json:"vpcid"` - SecurityGroups []SecGroup `json:"security_groups"` - Nics []NIC `json:"nics"` - KeyName string `json:"key_name"` - AdminPass string `json:"adminPass"` - Count int64 `json:"count"` - Extendparam ServerExtendparam `json:"extendparam"` - ServerTags []ServerTag `json:"server_tags"` - Description string `json:"description"` - Metadata map[string]string `json:"metadata"` -} - -type DataVolume struct { - Volumetype string `json:"volumetype"` - SizeGB int `json:"size"` - Extendparam *DataVolumeExtendparam `json:"extendparam,omitempty"` - Multiattach *bool `json:"multiattach,omitempty"` - HwPassthrough *string `json:"hw:passthrough,omitempty"` -} - -type DataVolumeExtendparam struct { - SnapshotID string `json:"snapshotId"` -} - -type ServerExtendparam struct { - ChargingMode string `json:"chargingMode"` // 计费模式 prePaid|postPaid - PeriodType string `json:"periodType"` // 周期类型:month|year - PeriodNum string `json:"periodNum"` // 订购周期数:periodType=month(周期类型为月)时,取值为[1,9]。periodType=year(周期类型为年)时,取值为1。 - IsAutoRenew string `json:"isAutoRenew"` // 是否自动续订 true|false - IsAutoPay string `json:"isAutoPay"` // 是否自动从客户的账户中支付 true|false - RegionID string `json:"regionID"` - EnterpriseProjectId string `json:"enterprise_project_id,omitempty"` -} - -type NIC struct { - SubnetID string `json:"subnet_id"` // 网络ID. 与 SNetwork里的ID对应。统一使用这个ID - IpAddress string `json:"ip_address"` -} - -type RootVolume struct { - Volumetype string `json:"volumetype"` - SizeGB int `json:"size"` -} - -type SecGroup struct { - ID string `json:"id"` -} - -type ServerTag struct { - Key string `json:"key"` - Value string `json:"value"` -} - -/* -包月机器退订规则: https://support.huaweicloud.com/usermanual-billing/zh-cn_topic_0083138805.html -5天无理由全额退订:新购资源(不包含续费资源)在开通的五天内且退订次数不超过10次(每账号每年10次)的符合5天无理由全额退订。 -非5天无理由退订:不符合5天无理由全额退订条件的退订,都属于非5天无理由退订。非5天无理由退订,不限制退订次数,但需要收取退订手续费。 - -退订资源的方法: https://support.huaweicloud.com/usermanual-billing/zh-cn_topic_0072297197.html -*/ -func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, SubnetId string, - securityGroupIds []string, vpcId string, zoneId string, desc string, disks []SDisk, ipAddr string, - keypair string, publicKey string, passwd string, userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (string, error) { - params := SServerCreate{} - params.AvailabilityZone = zoneId - params.Name = name - params.FlavorRef = instanceType - params.ImageRef = imageId - params.Description = desc - params.Count = 1 - params.Nics = []NIC{{SubnetID: SubnetId, IpAddress: ipAddr}} - groups := []SecGroup{} - for _, id := range securityGroupIds { - groups = append(groups, SecGroup{ID: id}) - } - params.SecurityGroups = groups - params.Vpcid = vpcId - params.Metadata = map[string]string{} - - for i, disk := range disks { - if i == 0 { - params.RootVolume.Volumetype = disk.VolumeType - params.RootVolume.SizeGB = disk.SizeGB - } else { - dataVolume := DataVolume{} - dataVolume.Volumetype = disk.VolumeType - dataVolume.SizeGB = disk.SizeGB - params.DataVolumes = append(params.DataVolumes, dataVolume) + part := struct { + Servers []SInstance + Count int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err } + ret = append(ret, part.Servers...) + if len(ret) >= part.Count || len(part.Servers) == 0 { + break + } + params.Set("offset", fmt.Sprintf("%d", len(ret))) } + return ret, nil +} - if len(projectId) > 0 { - params.Extendparam.EnterpriseProjectId = projectId +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=ShowServer +func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) { + resp, err := self.list(SERVICE_ECS, "cloudservers/"+instanceId, nil) + if err != nil { + return nil, err + } + ret := &SInstance{} + err = resp.Unmarshal(ret, "server") + if err != nil { + return nil, err + } + return ret, nil +} + +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=CreateServers +func (self *SRegion) CreateInstance(keypair, zoneId string, opts *cloudprovider.SManagedVMCreateConfig) (string, error) { + secgroups := []map[string]interface{}{} + for _, id := range opts.ExternalSecgroupIds { + secgroups = append(secgroups, map[string]interface{}{ + "id": id, + }) + } + dataDisks := []map[string]interface{}{} + for _, disk := range opts.DataDisks { + dataDisks = append(dataDisks, map[string]interface{}{ + "volumetype": disk.StorageType, + "size": disk.SizeGB, + }) + } + extendparam := map[string]interface{}{ + "regionID": self.GetId(), + "chargingMode": POST_PAID, + } + if len(opts.ProjectId) > 0 { + extendparam["enterprise_project_id"] = opts.ProjectId } // billing type - if bc != nil { - params.Extendparam.ChargingMode = PRE_PAID - if bc.GetMonths() <= 9 { - params.Extendparam.PeriodNum = strconv.Itoa(bc.GetMonths()) - params.Extendparam.PeriodType = "month" + if opts.BillingCycle != nil { + extendparam["chargingMode"] = PRE_PAID + extendparam["isAutoRenew"] = opts.BillingCycle.AutoRenew + extendparam["isAutoPay"] = true + if opts.BillingCycle.GetMonths() <= 9 { + extendparam["periodNum"] = opts.BillingCycle.GetMonths() + extendparam["periodType"] = "month" } else { - params.Extendparam.PeriodNum = strconv.Itoa(bc.GetYears()) - params.Extendparam.PeriodType = "year" + extendparam["periodNum"] = opts.BillingCycle.GetYears() + extendparam["periodType"] = "year" } - - params.Extendparam.RegionID = self.GetId() - if bc.AutoRenew { - params.Extendparam.IsAutoRenew = "true" - } else { - params.Extendparam.IsAutoRenew = "false" - } - params.Extendparam.IsAutoPay = "true" - params.Metadata["op_svc_userid"] = self.client.ownerId - } else { - params.Extendparam.ChargingMode = POST_PAID } - // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212668.html#ZH-CN_TOPIC_0020212668__table761103195216 + params := map[string]interface{}{ + "availability_zone": zoneId, + "name": opts.Name, + "flavorRef": opts.InstanceType, + "imageRef": opts.ExternalImageId, + "count": 1, + "nics": []map[string]interface{}{ + { + "subnet_id": opts.ExternalNetworkId, + "ip_address": opts.IpAddr, + }, + }, + "security_groups": secgroups, + "vpcid": opts.ExternalVpcId, + "root_volume": map[string]interface{}{ + "volumetype": opts.SysDisk.StorageType, + "size": opts.SysDisk.SizeGB, + }, + "data_volumes": dataDisks, + "extendparam": extendparam, + } + if len(keypair) > 0 { - params.KeyName = keypair + params["key_name"] = keypair } else { - params.AdminPass = passwd + params["adminPass"] = opts.Password } - if len(userData) > 0 { - params.UserData = userData + if len(opts.UserData) > 0 { + params["user_data"] = opts.UserData } - if len(tags) > 0 { - serverTags := []ServerTag{} - for k, v := range tags { - serverTags = append(serverTags, ServerTag{Key: k, Value: v}) + if len(opts.Tags) > 0 { + serverTags := []map[string]interface{}{} + for k, v := range opts.Tags { + serverTags = append(serverTags, map[string]interface{}{ + "key": k, + "value": v, + }) } - params.ServerTags = serverTags + params["server_tags"] = serverTags } - serverObj := jsonutils.Marshal(params) - createParams := jsonutils.NewDict() - createParams.Add(serverObj, "server") - _id, err := self.ecsClient.Servers.AsyncCreate(createParams) + resp, err := self.post(SERVICE_ECS_V1_1, "cloudservers", map[string]interface{}{"server": params}) if err != nil { return "", err } - ids, err := self.GetAllSubTaskEntityIDs(self.ecsClient.Servers.ServiceType(), _id, "server_id") + ret := struct { + JobId string + OrderId string + ServerIds []string `json:"serverIds"` + }{} + err = resp.Unmarshal(&ret) if err != nil { - return "", errors.Wrapf(err, "GetAllSubTaskEntityIDs(%s)", _id) + return "", err } - - if len(ids) == 0 { - return "", fmt.Errorf("CreateInstance job %s result is emtpy", _id) + for _, id := range ret.ServerIds { + return id, nil } - if len(ids) == 1 { - return ids[0], nil + if len(ret.JobId) > 0 { + ids, err := self.GetAllSubTaskEntityIDs(SERVICE_ECS, ret.JobId) + if err != nil { + return "", errors.Wrapf(err, "GetAllSubTaskEntityIDs(%s)", ret.JobId) + } + for _, id := range ids { + return id, nil + } } - return "", fmt.Errorf("CreateInstance job %s mutliple instance id returned. %s", _id, ids) + return "", fmt.Errorf("create server return empyte response %s", resp.String()) } +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=NovaAssociateSecurityGroup func (self *SRegion) assignSecurityGroup(instanceId, secgroupId string) error { - _, err := self.post(SERVICE_ECS, fmt.Sprintf("servers/%s/action", instanceId), map[string]interface{}{ + _, err := self.post(SERVICE_ECS_V2_1, fmt.Sprintf("servers/%s/action", instanceId), map[string]interface{}{ "addSecurityGroup": map[string]interface{}{ "name": secgroupId, }, @@ -1041,8 +867,9 @@ func (self *SRegion) assignSecurityGroup(instanceId, secgroupId string) error { return err } +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=NovaDisassociateSecurityGroup func (self *SRegion) unassignSecurityGroups(instanceId, secgroupId string) error { - _, err := self.post(SERVICE_ECS, fmt.Sprintf("servers/%s/action", instanceId), map[string]interface{}{ + _, err := self.post(SERVICE_ECS_V2_1, fmt.Sprintf("servers/%s/action", instanceId), map[string]interface{}{ "removeSecurityGroup": map[string]interface{}{ "name": secgroupId, }, @@ -1050,289 +877,138 @@ func (self *SRegion) unassignSecurityGroups(instanceId, secgroupId string) error return err } -func (self *SRegion) GetInstanceStatus(instanceId string) (string, error) { - instance, err := self.GetInstanceByID(instanceId) - if err != nil { - return "", err +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=NovaStartServer +func (self *SRegion) StartVM(instanceId string) error { + params := map[string]interface{}{ + "os-start": map[string]string{}, } - return instance.Status, nil + _, err := self.post(SERVICE_ECS_V2_1, fmt.Sprintf("servers/%s/action", instanceId), params) + return err } -func (self *SRegion) instanceStatusChecking(instanceId, status string) error { - remoteStatus, err := self.GetInstanceStatus(instanceId) - if err != nil { - log.Errorf("Fail to get instance status: %s", err) - return err +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=NovaStopServer +func (self *SRegion) StopVM(instanceId string, isForce bool) error { + stopType := "SOFT" + if isForce { + stopType = "HARD" } - if status != remoteStatus { - log.Errorf("instanceStatusChecking: vm status is %s expect %s", remoteStatus, status) - return cloudprovider.ErrInvalidStatus + params := map[string]interface{}{ + "os-stop": map[string]string{ + "type": stopType, + }, } + _, err := self.post(SERVICE_ECS_V2_1, fmt.Sprintf("servers/%s/action", instanceId), params) + return err +} +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=DeleteServers +func (self *SRegion) DeleteVM(instanceId string) error { + params := map[string]interface{}{ + "servers": []map[string]interface{}{ + { + "id": instanceId, + }, + }, + } + _, err := self.post(SERVICE_ECS, "cloudservers/delete", params) + return err +} + +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=UpdateServer +func (self *SRegion) UpdateVM(instanceId string, input cloudprovider.SInstanceUpdateOptions) error { + params := map[string]interface{}{ + "server": map[string]interface{}{ + "name": input.NAME, + "description": input.Description, + }, + } + _, err := self.put(SERVICE_ECS, "cloudservers/"+instanceId, params) + return err +} + +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=BatchResetServersPassword +func (self *SRegion) BatchResetServersPassword(instanceId string, password string) error { + params := map[string]interface{}{ + "new_password": password, + "servers": []map[string]interface{}{ + { + "id": instanceId, + }, + }, + } + _, err := self.put(SERVICE_ECS, "cloudservers/os-reset-passwords", params) + if err != nil { + return errors.Wrapf(err, "reset password") + } return nil } -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212207.html -func (self *SRegion) StartVM(instanceId string) error { - rstatus, err := self.GetInstanceStatus(instanceId) - if err != nil { - return err - } - - if rstatus == InstanceStatusRunning { - return nil - } - - if rstatus != InstanceStatusStopped { - log.Errorf("instanceStatusChecking: vm status is %s expect %s", rstatus, InstanceStatusStopped) - return cloudprovider.ErrInvalidStatus - } - - params := jsonutils.NewDict() - startObj := jsonutils.NewDict() - serversObj := jsonutils.NewArray() - serverObj := jsonutils.NewDict() - serverObj.Add(jsonutils.NewString(instanceId), "id") - serversObj.Add(serverObj) - startObj.Add(serversObj, "servers") - params.Add(startObj, "os-start") - _, err = self.ecsClient.Servers.PerformAction2("action", "", params, "") - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212651.html -func (self *SRegion) StopVM(instanceId string, isForce bool) error { - rstatus, err := self.GetInstanceStatus(instanceId) - if err != nil { - return err - } - - if rstatus == InstanceStatusStopped { - return nil - } - - if rstatus != InstanceStatusRunning { - log.Errorf("instanceStatusChecking: vm status is %s expect %s", rstatus, InstanceStatusRunning) - return cloudprovider.ErrInvalidStatus - } - - params := jsonutils.NewDict() - stopObj := jsonutils.NewDict() - serversObj := jsonutils.NewArray() - serverObj := jsonutils.NewDict() - serverObj.Add(jsonutils.NewString(instanceId), "id") - serversObj.Add(serverObj) - stopObj.Add(serversObj, "servers") - if isForce { - stopObj.Add(jsonutils.NewString("HARD"), "type") - } else { - stopObj.Add(jsonutils.NewString("SOFT"), "type") - } - params.Add(stopObj, "os-stop") - _, err = self.ecsClient.Servers.PerformAction2("action", "", params, "") - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212679.html -// 只删除主机。弹性IP和数据盘需要单独删除 -func (self *SRegion) DeleteVM(instanceId string) error { - remoteStatus, err := self.GetInstanceStatus(instanceId) - if err != nil { - return err - } - - if remoteStatus != InstanceStatusStopped { - log.Errorf("DeleteVM vm status is %s expect %s", remoteStatus, InstanceStatusStopped) - return cloudprovider.ErrInvalidStatus - } - - params := jsonutils.NewDict() - serversObj := jsonutils.NewArray() - serverObj := jsonutils.NewDict() - serverObj.Add(jsonutils.NewString(instanceId), "id") - serversObj.Add(serverObj) - params.Add(serversObj, "servers") - params.Add(jsonutils.NewBool(false), "delete_publicip") - params.Add(jsonutils.NewBool(false), "delete_volume") - - _, err = self.ecsClient.Servers.PerformAction2("delete", "", params, "") - return err -} - -func (self *SRegion) UpdateVM(instanceId string, input cloudprovider.SInstanceUpdateOptions) error { - params := jsonutils.NewDict() - serverObj := jsonutils.NewDict() - serverObj.Add(jsonutils.NewString(input.NAME), "name") - serverObj.Add(jsonutils.NewString(input.Description), "description") - params.Add(serverObj, "server") - - _, err := self.ecsClient.Servers.Update(instanceId, params) - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html -// 返回job id -func (self *SRegion) RebuildRoot(ctx context.Context, userId, instanceId, passwd, publicKeyName, userData string) (string, error) { - params := jsonutils.NewDict() - reinstallObj := jsonutils.NewDict() - - if len(publicKeyName) > 0 { - reinstallObj.Add(jsonutils.NewString(publicKeyName), "keyname") - } else if len(passwd) > 0 { - reinstallObj.Add(jsonutils.NewString(passwd), "adminpass") - } else { - return "", fmt.Errorf("both password and publicKey are empty.") - } - - if len(userData) > 0 { - meta := jsonutils.NewDict() - meta.Add(jsonutils.NewString(userData), "user_data") - reinstallObj.Add(meta, "metadata") - } - - if len(userId) > 0 { - reinstallObj.Add(jsonutils.NewString(userId), "userid") - } - - params.Add(reinstallObj, "os-reinstall") - ret, err := self.ecsClient.ServersV2.PerformAction2("reinstallos", instanceId, params, "") - if err != nil { - return "", err - } - - return ret.GetString("job_id") -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html -// 返回job id -func (self *SRegion) ChangeRoot(ctx context.Context, userId, instanceId, imageId, passwd, publicKeyName, userData string) (string, error) { - params := jsonutils.NewDict() - changeOsObj := jsonutils.NewDict() - - if len(publicKeyName) > 0 { - changeOsObj.Add(jsonutils.NewString(publicKeyName), "keyname") - } else if len(passwd) > 0 { - changeOsObj.Add(jsonutils.NewString(passwd), "adminpass") - } else { - return "", fmt.Errorf("both password and publicKey are empty.") - } - - if len(userData) > 0 { - meta := jsonutils.NewDict() - meta.Add(jsonutils.NewString(userData), "user_data") - changeOsObj.Add(meta, "metadata") - } - - if len(userId) > 0 { - changeOsObj.Add(jsonutils.NewString(userId), "userid") - } - - changeOsObj.Add(jsonutils.NewString(imageId), "imageid") - params.Add(changeOsObj, "os-change") - - ret, err := self.ecsClient.ServersV2.PerformAction2("changeos", instanceId, params, "") - if err != nil { - return "", err - } - - return ret.GetString("job_id") -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212692.html -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0110109377.html -// 一键式重置密码 需要安装安装一键式重置密码插件 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0068095385.html -// 目前不支持直接重置密钥 func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { - serverObj := jsonutils.NewDict() if len(name) > 0 { - serverObj.Add(jsonutils.NewString(name), "name") - } - - // if len(description) > 0 { - // serverObj.Add(jsonutils.NewString(description), "description") - // } - - if serverObj.Size() > 0 { - params := jsonutils.NewDict() - params.Add(serverObj, "server") - // 这里华为返回的image字段是字符串。和SInstance的定义的image是字典结构不一致。 - err := DoUpdate(self.ecsClient.NovaServers.Update, instanceId, params, nil) + err := self.UpdateVM(instanceId, cloudprovider.SInstanceUpdateOptions{ + NAME: name, + Description: description, + }) if err != nil { - return err + return errors.Wrapf(err, "update vm name") } } if len(password) > 0 { - params := jsonutils.NewDict() - passwdObj := jsonutils.NewDict() - passwdObj.Add(jsonutils.NewString(password), "new_password") - params.Add(passwdObj, "reset-password") - - err := DoUpdateWithSpec(self.ecsClient.NovaServers.UpdateInContextWithSpec, instanceId, "os-reset-password", params) + err := self.BatchResetServersPassword(instanceId, password) if err != nil { - return err + return errors.Wrapf(err, "BatchResetServersPassword") } } - return nil } -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212653.html +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=ResizeServer func (self *SRegion) ChangeVMConfig(instanceId string, instanceType string) error { - self.ecsClient.Servers.SetVersion("v1.1") - defer self.ecsClient.Servers.SetVersion("v1") - - params := jsonutils.NewDict() - resizeObj := jsonutils.NewDict() - resizeObj.Add(jsonutils.NewString(instanceType), "flavorRef") - params.Add(resizeObj, "resize") - _, err := self.ecsClient.Servers.PerformAction2("resize", instanceId, params, "") - return errors.Wrapf(err, "PerformAction2(resize)") -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0142763126.html 微版本2.6及以上? -// https://support.huaweicloud.com/api-ecs/ecs_02_0208.html -func (self *SRegion) GetInstanceVNCUrl(instanceId string) (*cloudprovider.ServerVncOutput, error) { - params := jsonutils.NewDict() - vncObj := jsonutils.NewDict() - vncObj.Add(jsonutils.NewString("novnc"), "type") - vncObj.Add(jsonutils.NewString("vnc"), "protocol") - params.Add(vncObj, "remote_console") - - ret, err := self.ecsClient.Servers.PerformAction2("remote_console", instanceId, params, "remote_console") - if err != nil { - return nil, err + params := map[string]interface{}{ + "resize": map[string]interface{}{ + "flavorRef": instanceType, + }, } - - result := &cloudprovider.ServerVncOutput{ - Hypervisor: api.HYPERVISOR_HUAWEI, - } - ret.Unmarshal(result) - result.Protocol = "huawei" - return result, nil -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0022472987.html -// XEN平台虚拟机device为必选参数。 -func (self *SRegion) AttachDisk(instanceId string, diskId string, device string) error { - params := jsonutils.NewDict() - volumeObj := jsonutils.NewDict() - volumeObj.Add(jsonutils.NewString(diskId), "volumeId") - if len(device) > 0 { - volumeObj.Add(jsonutils.NewString(device), "device") - } - - params.Add(volumeObj, "volumeAttachment") - - _, err := self.ecsClient.Servers.PerformAction2("attachvolume", instanceId, params, "") + _, err := self.post(SERVICE_ECS_V1_1, fmt.Sprintf("cloudservers/%s/resize", instanceId), params) return err } -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0022472988.html -// 默认非强制卸载。delete_flag=0 +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=ShowServerRemoteConsole +func (self *SRegion) GetInstanceVNCUrl(instanceId string) (*cloudprovider.ServerVncOutput, error) { + params := map[string]interface{}{ + "remote_console": map[string]interface{}{ + "type": "novnc", + "protocol": "vnc", + }, + } + resp, err := self.post(SERVICE_ECS, fmt.Sprintf("cloudservers/%s/remote_console", instanceId), params) + if err != nil { + return nil, err + } + result := &cloudprovider.ServerVncOutput{ + Hypervisor: api.HYPERVISOR_HUAWEI, + } + resp.Unmarshal(result, "remote_console") + result.Protocol = api.HYPERVISOR_HUAWEI + return result, nil +} + +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=AttachServerVolume +func (self *SRegion) AttachDisk(instanceId string, diskId string, device string) error { + params := map[string]interface{}{ + "volumeAttachment": map[string]interface{}{ + "volumeId": diskId, + "device": device, + }, + } + _, err := self.post(SERVICE_ECS, fmt.Sprintf("cloudservers/%s/attachvolume", instanceId), params) + return err +} + +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=DetachServerVolume func (self *SRegion) DetachDisk(instanceId string, diskId string) error { - path := fmt.Sprintf("detachvolume/%s", diskId) - err := DoDeleteWithSpec(self.ecsClient.Servers.DeleteInContextWithSpec, nil, instanceId, path, nil, nil) + _, err := self.delete(SERVICE_ECS, fmt.Sprintf("cloudservers/%s/detachvolume/%s", instanceId, diskId)) //volume a2091934-2669-4fca-8eb4-a950c1836b3c is not in server 49b053d2-f798-432f-af55-76eb6ef2c769 attach volume list => 磁盘已经被卸载了 if err != nil && strings.Contains(err.Error(), fmt.Sprintf("is not in server")) && strings.Contains(err.Error(), fmt.Sprintf("attach volume list")) { return nil @@ -1340,76 +1016,30 @@ func (self *SRegion) DetachDisk(instanceId string, diskId string) error { return err } -// // https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0082522029.html -// 只支持传入主资源ID, 根据“查询客户包周期资源列表”接口响应参数中的“is_main_resource”来标识。 -// expire_mode 0:进入宽限期 1:转按需 2:自动退订 3:自动续订(当前只支持ECS、EVS和VPC) +// https://console.huaweicloud.com/apiexplorer/#/openapi/BSS/doc?api=RenewalResources func (self *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle) error { - params := jsonutils.NewDict() - res := jsonutils.NewArray() - res.Add(jsonutils.NewString(instanceId)) - params.Add(res, "resource_ids") - params.Add(jsonutils.NewInt(EXPIRE_MODE_AUTO_UNSUBSCRIBE), "expire_mode") // 自动退订 - params.Add(jsonutils.NewInt(AUTO_PAY_TRUE), "isAutoPay") // 自动支付 + params := map[string]interface{}{ + "resource_ids": []string{instanceId}, + "expire_policy": 3, + "is_auto_pay": 1, + } + month := int64(bc.GetMonths()) year := int64(bc.GetYears()) if month >= 1 && month <= 11 { - params.Add(jsonutils.NewInt(PERIOD_TYPE_MONTH), "period_type") - params.Add(jsonutils.NewInt(month), "period_num") + params["period_type"] = 2 + params["period_num"] = month } else if year >= 1 && year <= 3 { - params.Add(jsonutils.NewInt(PERIOD_TYPE_YEAR), "period_type") - params.Add(jsonutils.NewInt(year), "period_num") + params["period_type"] = 3 + params["period_num"] = year } else { return fmt.Errorf("invalid renew period %d month,must be 1~11 month or 1~3 year", month) } - - domainId, err := self.getDomianId() - if err != nil { - return err - } - - err = self.ecsClient.Orders.SetDomainId(domainId) - if err != nil { - return err - } - - _, err = self.ecsClient.Orders.RenewPeriodResource(params) + _, err := self.post(SERVICE_BSS, "orders/subscriptions/resources/renew", params) return err } -func (self *SRegion) GetInstanceSecrityGroupIds(instanceId string) ([]string, error) { - resp, err := self.list(SERVICE_ECS, fmt.Sprintf("servers/%s/os-security-groups", instanceId), nil) - if err != nil { - return nil, err - } - ret := []struct { - Id string - }{} - err = resp.Unmarshal(&ret, "security_groups") - if err != nil { - return nil, err - } - ids := []string{} - for _, sec := range ret { - ids = append(ids, sec.Id) - } - return ids, nil -} - -// https://support.huaweicloud.com/api-oce/zh-cn_topic_0082522030.html -func (self *SRegion) UnsubscribeInstance(instanceId string, domianId string) (jsonutils.JSONObject, error) { - unsubObj := jsonutils.NewDict() - unsubObj.Add(jsonutils.NewInt(1), "unSubType") - unsubObj.Add(jsonutils.NewInt(5), "unsubscribeReasonType") - unsubObj.Add(jsonutils.NewString("no reason"), "unsubscribeReason") - resList := jsonutils.NewArray() - resList.Add(jsonutils.NewString(instanceId)) - unsubObj.Add(resList, "resourceIds") - - self.ecsClient.Orders.SetDomainId(domianId) - return self.ecsClient.Orders.PerformAction("resources/delete", "", unsubObj) -} - func (self *SInstance) GetProjectId() string { return self.EnterpriseProjectId } @@ -1418,81 +1048,9 @@ func (self *SInstance) GetError() error { return nil } -func updateUserData(userData, osVersion, username, password, publicKey string) (string, error) { - winOS := strings.ToLower(osprofile.OS_TYPE_WINDOWS) - osVersion = strings.ToLower(osVersion) - config := &cloudinit.SCloudConfig{} - if strings.Contains(osVersion, winOS) { - if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { - config = _config - } else { - log.Debugf("updateWindowsUserData invalid userdata %s", userData) - } - } else { - if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { - config = _config - } else { - return "", fmt.Errorf("updateLinuxUserData invalid userdata %s", userData) - } - } - - user := cloudinit.NewUser(username) - config.RemoveUser(user) - config.DisableRoot = 0 - if len(password) > 0 { - config.SshPwauth = cloudinit.SSH_PASSWORD_AUTH_ON - user.Password(password) - config.MergeUser(user) - } - - if len(publicKey) > 0 { - user.SshKey(publicKey) - config.MergeUser(user) - } - - if strings.Contains(osVersion, winOS) { - userData, err := updateWindowsUserData(config.UserDataPowerShell(), osVersion, username, password) - if err != nil { - return "", errors.Wrap(err, "updateUserData.updateWindowsUserData") - } - return userData, nil - } else { - return config.UserDataBase64(), nil - } -} - -func updateWindowsUserData(userData string, osVersion string, username, password string) (string, error) { - // Windows Server 2003, Windows Vista, Windows Server 2008, Windows Server 2003 R2, Windows Server 2000, Windows Server 2012, Windows Server 2003 with SP1, Windows 8 - oldVersions := []string{"2000", "2003", "2008", "2012", "Vista"} - isOldVersion := false - for i := range oldVersions { - if strings.Contains(osVersion, oldVersions[i]) { - isOldVersion = true - } - } - - shells := "" - if isOldVersion { - shells += fmt.Sprintf("rem cmd\n") - if username == "Administrator" { - shells += fmt.Sprintf("net user %s %s\n", username, password) - } else { - shells += fmt.Sprintf("net user %s %s /add\n", username, password) - shells += fmt.Sprintf("net localgroup administrators %s /add\n", username) - } - - shells += fmt.Sprintf("net user %s /active:yes", username) - } else { - if !strings.HasPrefix(userData, "#ps1") { - shells = fmt.Sprintf("#ps1\n%s", userData) - } - } - - return base64.StdEncoding.EncodeToString([]byte(shells)), nil -} - +// https://console.huaweicloud.com/apiexplorer/#/openapi/IMS/doc?api=CreateImage func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { - params := map[string]string{ + params := map[string]interface{}{ "name": opts.Name, "instance_id": instanceId, } @@ -1507,19 +1065,19 @@ func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageO return opts.Notes }() } - resp, err := self.ecsClient.Images.CreateInContextWithSpec(nil, "action", jsonutils.Marshal(params), "") + resp, err := self.post(SERVICE_IMS, "cloudimages/action", params) if err != nil { - return nil, errors.Wrapf(err, "Images.Create") + return nil, errors.Wrapf(err, "crate image") } jobId, err := resp.GetString("job_id") if err != nil { - return nil, errors.Wrapf(err, "resp.GetString(job_id)") + return nil, errors.Wrapf(err, "get job_id") } - err = self.waitTaskStatus(self.ecsClient.Images.ServiceType(), jobId, TASK_SUCCESS, 15*time.Second, 10*time.Minute) + err = self.waitTaskStatus(SERVICE_IMS_V1, jobId, TASK_SUCCESS, 15*time.Second, 10*time.Minute) if err != nil { return nil, errors.Wrapf(err, "waitTaskStatus") } - imageId, err := self.GetTaskEntityID(self.ecsClient.Images.ServiceType(), jobId, "image_id") + imageId, err := self.GetTaskEntityID(SERVICE_IMS, jobId, "image_id") if err != nil { return nil, errors.Wrapf(err, "GetTaskEntityID") } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancenic.go index ebbc192bdc..bcc6aefe3b 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancenic.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancenic.go @@ -15,46 +15,13 @@ package huawei import ( - "yunion.io/x/log" + "fmt" + + "yunion.io/x/pkg/errors" "yunion.io/x/cloudmux/pkg/cloudprovider" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" ) -// =========================================== -type Interface struct { - PortState string `json:"port_state"` - FixedIPS []FixedIP `json:"fixed_ips"` - NetID string `json:"net_id"` // 网络ID. 与 SNetwork里的ID对应。统一使用这个ID - PortID string `json:"port_id"` - MACAddr string `json:"mac_addr"` -} - -/* -subnet: {id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233", name: "subnet-149c", cidr: "192.168.0.0/24",…} -availability_zone: "cn-north-1b" -cidr: "192.168.0.0/24" -dhcp_enable: true -dnsList: ["100.125.1.250", "100.125.21.250"] -gateway_ip: "192.168.0.1" -id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233" -ipv6_enable: false -name: "subnet-149c" -neutron_network_id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233" -neutron_subnet_id: "81fcfaa0-8e73-4472-9eba-3b2b7736d3a7" -primary_dns: "100.125.1.250" -secondary_dns: "100.125.21.250" -status: "ACTIVE" -tags: [] -vpc_id: "877f1feb-3dc8-4c2d-92e9-0d94fd7d79dd"} -*/ -type FixedIP struct { - SubnetID string `json:"subnet_id"` // 子网ID, 与SNetwork中的 neutron_subnet_id对应. 注意!!! 并不是SNetwork ID。 - IPAddress string `json:"ip_address"` -} - -// =========================================== - type SInstanceNic struct { instance *SInstance ipAddr string @@ -89,28 +56,31 @@ func (self *SInstanceNic) InClassicNetwork() bool { } func (self *SInstanceNic) GetINetworkId() string { - instanceId := self.instance.GetId() - subnets, err := self.instance.host.zone.region.getSubnetIdsByInstanceId(instanceId) - if err != nil || len(subnets) == 0 { - log.Errorf("getSubnetIdsByInstanceId error: %s", err.Error()) - return "" + subnets, _ := self.instance.host.zone.region.getSubnetIdsByInstanceId(self.instance.GetId()) + for _, id := range subnets { + return id } - - return subnets[0] + return "" } +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=ListServerInterfaces func (self *SRegion) getSubnetIdsByInstanceId(instanceId string) ([]string, error) { - ctx := &modules.SManagerContext{InstanceManager: self.ecsClient.NovaServers, InstanceId: instanceId} - interfaces := make([]Interface, 0) - err := DoListInContext(self.ecsClient.Interface.ListInContext, ctx, nil, &interfaces) + resp, err := self.list(SERVICE_ECS, fmt.Sprintf("cloudservers/%s/os-interface", instanceId), nil) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "list os interface") } - - subnets := make([]string, 0) - for _, i := range interfaces { - subnets = append(subnets, i.NetID) + ret := struct { + InterfaceAttachments []struct { + NetId string + } + }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + subnets := []string{} + for _, att := range ret.InterfaceAttachments { + subnets = append(subnets, att.NetId) } - return subnets, nil } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancetype.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancetype.go index 8a014dc292..20c560d64e 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancetype.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancetype.go @@ -15,10 +15,12 @@ package huawei import ( + "net/url" "strconv" + + "yunion.io/x/pkg/errors" ) -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212656.html type SInstanceType struct { ID string `json:"id"` Name string `json:"name"` @@ -31,27 +33,33 @@ type OSExtraSpecs struct { EcsPerformancetype string `json:"ecs:performancetype"` } -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212656.html -func (self *SRegion) fetchInstanceTypes(zoneId string) ([]SInstanceType, error) { - querys := map[string]string{} +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=ListFlavors +func (self *SRegion) GetInstanceTypes(zoneId string) ([]SInstanceType, error) { + query := url.Values{} if len(zoneId) > 0 { - querys["availability_zone"] = zoneId + query.Set("available_zone", zoneId) } - - instanceTypes := make([]SInstanceType, 0) - err := doListAll(self.ecsClient.Flavors.List, querys, &instanceTypes) - return instanceTypes, err + resp, err := self.list(SERVICE_ECS, "cloudservers/flavors", query) + if err != nil { + return nil, errors.Wrapf(err, "list flavors") + } + ret := []SInstanceType{} + err = resp.Unmarshal(&ret, "flavors") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + return ret, nil } func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, zoneId string) ([]SInstanceType, error) { - instanceTypes, err := self.fetchInstanceTypes(zoneId) + instanceTypes, err := self.GetInstanceTypes(zoneId) if err != nil { return nil, err } ret := make([]SInstanceType, 0) for _, t := range instanceTypes { - // cpu & mem & disk都匹配才行 + // cpu & mem 都匹配才行 if t.Vcpus == strconv.Itoa(cpu) && t.RamMB == memMB { ret = append(ret, t) } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/keypair.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/keypair.go index 65c551ab32..e71d114196 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/keypair.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/keypair.go @@ -45,10 +45,11 @@ func (self *SRegion) getFingerprint(publicKey string) (string, error) { return fingerprint, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=NovaListKeypairs func (self *SRegion) GetKeypairs() ([]SKeypair, error) { ret := []SKeypair{} query := url.Values{} - resp, err := self.list(SERVICE_ECS, "os-keypairs", query) + resp, err := self.list(SERVICE_ECS_V2_1, "os-keypairs", query) if err != nil { return nil, errors.Wrapf(err, "list os-keypairs") } @@ -85,7 +86,7 @@ func (self *SRegion) ImportKeypair(name, publicKey string) (*SKeypair, error) { "name": name, "public_key": publicKey, } - resp, err := self.post(SERVICE_ECS, "os-keypairs", map[string]interface{}{"keypair": params}) + resp, err := self.post(SERVICE_ECS_V2_1, "os-keypairs", map[string]interface{}{"keypair": params}) if err != nil { return nil, errors.Wrapf(err, "create os-keypairs") } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer.go index 408de23571..689ab9006b 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer.go @@ -167,7 +167,7 @@ func (self *SLoadbalancer) GetNetwork() *SNetwork { if self.subnet == nil { port, err := self.region.GetPort(self.VipPortId) if err == nil { - net, err := self.region.getNetwork(port.NetworkID) + net, err := self.region.GetNetwork(port.NetworkID) if err == nil { self.subnet = net } else { @@ -225,7 +225,7 @@ func (self *SLoadbalancer) GetEgressMbps() int { return 0 } -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0141008275.html +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=DeleteLoadBalancer func (self *SLoadbalancer) Delete(ctx context.Context) error { for _, res := range self.Pools { backends, err := self.region.getLoadBalancerBackends(res.Id) @@ -312,13 +312,12 @@ func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(opts *cloudprovider.S return ret, err } -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561563.html func (self *SLoadbalancer) CreateHealthCheck(backendGroupId string, healthcheck *cloudprovider.SLoadbalancerHealthCheck) error { _, err := self.region.CreateLoadBalancerHealthCheck(backendGroupId, healthcheck) return err } -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561548.html +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=ShowPool func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { ret := &SElbBackendGroup{lb: self, region: self.region} resp, err := self.region.list(SERVICE_ELB, "elb/pools/"+groupId, nil) @@ -337,6 +336,7 @@ func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, opts return ret, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=ShowListener func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { ret := &SElbListener{lb: self} resp, err := self.region.list(SERVICE_ELB, "elb/listeners/"+listenerId, nil) @@ -346,6 +346,7 @@ func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (clou return ret, resp.Unmarshal(ret, "listener") } +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=ShowLoadBalancer func (self *SRegion) GetLoadbalancer(id string) (*SLoadbalancer, error) { resp, err := self.list(SERVICE_ELB, "elb/loadbalancers/"+id, nil) if err != nil { @@ -355,12 +356,14 @@ func (self *SRegion) GetLoadbalancer(id string) (*SLoadbalancer, error) { return ret, resp.Unmarshal(ret, "loadbalancer") } +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=DeleteLoadBalancer func (self *SRegion) DeleteLoadBalancer(elbId string) error { resource := fmt.Sprintf("elb/loadbalancers/%s", elbId) _, err := self.delete(SERVICE_ELB, resource) return err } +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=ListListeners func (self *SRegion) GetLoadBalancerListeners(lbId string) ([]SElbListener, error) { ret := []SElbListener{} params := url.Values{} @@ -370,6 +373,7 @@ func (self *SRegion) GetLoadBalancerListeners(lbId string) ([]SElbListener, erro return ret, self.lbListAll("elb/listeners", params, "listeners", &ret) } +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=CreateLoadBalancer func (self *SRegion) CreateLoadBalancerListener(listener *cloudprovider.SLoadbalancerListenerCreateOptions, lbId string) (*SElbListener, error) { params := map[string]interface{}{ "name": listener.Name, @@ -408,7 +412,7 @@ func (self *SRegion) CreateLoadBalancerListener(listener *cloudprovider.SLoadbal return ret, resp.Unmarshal(&ret, "listener") } -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=ListPools func (self *SRegion) GetLoadBalancerBackendGroups(elbId string) ([]SElbBackendGroup, error) { query := url.Values{} if len(elbId) > 0 { @@ -419,6 +423,7 @@ func (self *SRegion) GetLoadBalancerBackendGroups(elbId string) ([]SElbBackendGr return ret, self.lbListAll("elb/pools", query, "pools", &ret) } +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=CreatePool func (self *SRegion) CreateLoadBalancerBackendGroup(lbId string, opts *cloudprovider.SLoadbalancerBackendGroup) (*SElbBackendGroup, error) { params := map[string]interface{}{ "name": opts.Name, @@ -455,6 +460,7 @@ func (self *SRegion) CreateLoadBalancerBackendGroup(lbId string, opts *cloudprov return ret, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=CreateHealthMonitor func (self *SRegion) CreateLoadBalancerHealthCheck(backendGroupId string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { params := map[string]interface{}{ "delay": healthCheck.HealthCheckInterval, @@ -486,7 +492,7 @@ func (self *SRegion) CreateLoadBalancerHealthCheck(backendGroupId string, health return ret, resp.Unmarshal(&ret, "healthmonitor") } -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561564.html +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=UpdateHealthMonitor func (self *SRegion) UpdateLoadBalancerHealthCheck(healthCheckId string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { params := map[string]interface{}{ "delay": healthCheck.HealthCheckInterval, @@ -515,7 +521,7 @@ func (self *SRegion) UpdateLoadBalancerHealthCheck(healthCheckId string, healthC return ret, resp.Unmarshal(&ret, "healthmonitor") } -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561565.html +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=DeleteHealthMonitor func (self *SRegion) DeleteLoadbalancerHealthCheck(healthCheckId string) error { _, err := self.delete(SERVICE_ELB, "elb/healthmonitors/"+healthCheckId) return err @@ -546,8 +552,9 @@ func (self *SRegion) lbListAll(resource string, query url.Values, respKey string return ret.Unmarshal(retVal) } +// https://console.huaweicloud.com/apiexplorer/#/openapi/ELB/doc?version=v3&api=CreateLoadBalancer func (self *SRegion) CreateLoadBalancer(opts *cloudprovider.SLoadbalancerCreateOptions) (*SLoadbalancer, error) { - subnet, err := self.getNetwork(opts.NetworkIds[0]) + subnet, err := self.GetNetwork(opts.NetworkIds[0]) if err != nil { return nil, errors.Wrap(err, "getNetwork") } @@ -581,13 +588,13 @@ func (self *SRegion) CreateLoadBalancer(opts *cloudprovider.SLoadbalancerCreateO if len(opts.EipId) > 0 { params["publicip_ids"] = []string{opts.EipId} } - err = self.fetchZones() + zones, err := self.GetZones() if err != nil { - return nil, errors.Wrapf(err, "fetchZones") + return nil, errors.Wrapf(err, "GetZones") } zoneIds := []string{} - for i := range self.izones { - zone := self.izones[i].(*SZone) + for i := range zones { + zone := zones[i] zoneIds = append(zoneIds, zone.ZoneName) } params["availability_zone_list"] = zoneIds diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backend.go index e1f630af9a..97cedaab17 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backend.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backend.go @@ -22,7 +22,6 @@ import ( "yunion.io/x/log" api "yunion.io/x/cloudmux/pkg/apis/compute" - "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/cloudmux/pkg/multicloud" ) @@ -94,15 +93,13 @@ func (self *SElbBackend) GetBackendRole() string { } func (self *SElbBackend) GetBackendId() string { - i, err := self.lb.region.getInstanceByIP(self.Address) + vms, err := self.region.GetInstances(self.Address) if err != nil { - log.Errorf("ElbBackend GetBackendId %s", err) + return "" } - - if i != nil { - return i.GetId() + for _, vm := range vms { + return vm.GetId() } - return "" } @@ -123,33 +120,6 @@ func (self *SElbBackend) SyncConf(ctx context.Context, port, weight int) error { return err } -func (self *SRegion) getInstanceByIP(privateIP string) (*SInstance, error) { - queries := make(map[string]string) - - if len(self.client.projectId) > 0 { - queries["project_id"] = self.client.projectId - } - - if len(privateIP) > 0 { - queries["ip"] = privateIP - } - - instances := make([]SInstance, 0) - err := doListAllWithOffset(self.ecsClient.Servers.List, queries, &instances) - if err != nil { - return nil, err - } - - if len(instances) == 1 { - return &instances[0], nil - } else if len(instances) > 1 { - log.Warningf("SRegion.getInstanceByIP %s result: multiple server find", privateIP) - return &instances[0], nil - } - - return nil, cloudprovider.ErrNotFound -} - func (self *SRegion) GetElbBackend(pool, id string) (*SElbBackend, error) { res := fmt.Sprintf("elb/pools/%s/members/%s", pool, id) resp, err := self.list(SERVICE_ELB, res, nil) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backendgroup.go index 58eeda999e..593583e40e 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backendgroup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backendgroup.go @@ -249,7 +249,7 @@ func (self *SElbBackendGroup) GetILoadbalancerBackendById(serverId string) (clou } func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - instance, err := self.lb.region.GetInstanceByID(serverId) + instance, err := self.lb.region.GetInstance(serverId) if err != nil { return nil, err } @@ -268,7 +268,7 @@ func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port return nil, fmt.Errorf("AddBackendServer %s no subnet found", serverId) } - net, err := self.lb.region.getNetwork(subnets[0]) + net, err := self.lb.region.GetNetwork(subnets[0]) if err != nil { return nil, err } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool.go index c088f05820..5b9aa64017 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool.go @@ -156,7 +156,7 @@ func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreat } netId, _ = createNetObj.GetString("metadata", "name") for i := 0; i < 10; i++ { - netDetailObj, err := self.list(SERVICE_MODELARTS, "networks/"+netId, nil) + netDetailObj, err := self.list(SERVICE_MODELARTS_V1, "networks/"+netId, nil) if err != nil { return nil, errors.Wrap(err, "SHuaweiClient.NetworkDetail") } @@ -291,7 +291,7 @@ type ModelartsStatistics struct { } func (self *SHuaweiClient) GetPoolNetworks(poolName string) (jsonutils.JSONObject, error) { - return self.list(SERVICE_MODELARTS, self.clientRegion, "networks", nil) + return self.list(SERVICE_MODELARTS_V1, self.clientRegion, "networks", nil) } func (self *SHuaweiClient) CreatePoolNetworks(cidr string) (jsonutils.JSONObject, error) { @@ -308,7 +308,7 @@ func (self *SHuaweiClient) CreatePoolNetworks(cidr string) (jsonutils.JSONObject "cidr": cidr, }, } - return self.post(SERVICE_MODELARTS, self.clientRegion, "networks", params) + return self.post(SERVICE_MODELARTS_V1, self.clientRegion, "networks", params) } func (self *SModelartsPool) GetCreatedAt() time.Time { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool_sku.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool_sku.go index 53bdae980f..7b16ce21d5 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool_sku.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool_sku.go @@ -62,7 +62,7 @@ type SModelartsResourceflavorsStatus struct { func (self *SRegion) GetIModelartsPoolSku() ([]cloudprovider.ICloudModelartsPoolSku, error) { resourceflavors := make([]SModelartsPoolSku, 0) - obj, err := self.list(SERVICE_MODELARTS, "resourceflavors", nil) + obj, err := self.list(SERVICE_MODELARTS_V1, "resourceflavors", nil) if err != nil { return nil, errors.Wrap(err, "list") } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/monitor.go index e922524b06..3560c31dbd 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/monitor.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/monitor.go @@ -25,17 +25,8 @@ import ( api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/cloudmux/pkg/cloudprovider" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" ) -func (r *SRegion) GetMetrics() ([]modules.SMetricMeta, error) { - return r.ecsClient.CloudEye.ListMetrics() -} - -func (r *SRegion) GetMetricsData(metrics []modules.SMetricMeta, since time.Time, until time.Time) ([]modules.SMetricData, error) { - return r.ecsClient.CloudEye.GetMetricsData(metrics, since, until) -} - type MetricData struct { Namespace string MetricName string diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natdtable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natdtable.go index 6fabc7e407..f52bbd745b 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natdtable.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natdtable.go @@ -15,8 +15,9 @@ package huawei import ( + "net/url" + "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" "yunion.io/x/cloudmux/pkg/multicloud" ) @@ -91,41 +92,43 @@ func (gateway *SNatGateway) getNatDTable() ([]SNatDEntry, error) { return ret, nil } -func (region *SRegion) GetNatDTable(natGatewayID string) ([]SNatDEntry, error) { - queuies := map[string]string{ - "nat_gateway_id": natGatewayID, +func (region *SRegion) GetNatDTable(natId string) ([]SNatDEntry, error) { + query := url.Values{} + if len(natId) > 0 { + query.Set("gateway_id", natId) } - dNatSTableEntries := make([]SNatDEntry, 0, 2) - // can't make true that restapi support marker para in Huawei Cloud - err := doListAllWithMarker(region.ecsClient.DNatRules.List, queuies, &dNatSTableEntries) - if err != nil { - return nil, errors.Wrapf(err, `get dnat rule of gateway %q`, natGatewayID) - } - for i := range dNatSTableEntries { - nat := &dNatSTableEntries[i] - if len(nat.InternalIP) == 0 { - port, err := region.GetPort(nat.PortID) - if err != nil { - return nil, errors.Wrapf(err, `get port info for transfer to ip of port_id %q error`, nat.PortID) - } - nat.InternalIP = port.FixedIps[0].IpAddress + ret := []SNatDEntry{} + for { + resp, err := region.list(SERVICE_NAT, "private-nat/dnat-rules", query) + if err != nil { + return nil, err } + part := struct { + DnatRules []SNatDEntry + PageInfo sPageInfo + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.DnatRules...) + if len(part.PageInfo.NextMarker) == 0 || len(part.DnatRules) == 0 { + break + } + query.Set("marker", part.PageInfo.NextMarker) } - return dNatSTableEntries, nil + return ret, nil } -func (region *SRegion) DeleteNatDEntry(entryID string) error { - _, err := region.ecsClient.DNatRules.Delete(entryID, nil) - if err != nil { - return errors.Wrapf(err, `delete dnat rule %q failed`, entryID) - } - return nil +func (region *SRegion) DeleteNatDEntry(id string) error { + _, err := region.delete(SERVICE_NAT, "private-nat/dnat-rules/"+id) + return err } func (nat *SNatDEntry) Refresh() error { - new, err := nat.gateway.region.GetNatDEntryByID(nat.ID) + ret, err := nat.gateway.region.GetNatDEntryByID(nat.ID) if err != nil { return err } - return jsonutils.Update(nat, new) + return jsonutils.Update(nat, ret) } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natgateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natgateway.go index 5fd425460d..ad35559437 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natgateway.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natgateway.go @@ -15,6 +15,7 @@ package huawei import ( + "net/url" "strings" "time" @@ -155,7 +156,7 @@ func (gateway *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (clou return nil, err } dnat.gateway = gateway - return &dnat, nil + return dnat, nil } func (gateway *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { @@ -164,7 +165,7 @@ func (gateway *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (clou return nil, err } snat.gateway = gateway - return &snat, nil + return snat, nil } func (gateway *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { @@ -173,7 +174,7 @@ func (gateway *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNa return nil, err } dnat.gateway = gateway - return &dnat, nil + return dnat, nil } func (gateway *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { @@ -182,29 +183,41 @@ func (gateway *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNa return nil, err } snat.gateway = gateway - return &snat, nil + return snat, nil } -func (region *SRegion) GetNatGateways(vpcID, natGatewayID string) ([]SNatGateway, error) { - queues := make(map[string]string) - if len(natGatewayID) != 0 { - queues["id"] = natGatewayID +func (region *SRegion) GetNatGateways(vpcId, id string) ([]SNatGateway, error) { + query := url.Values{} + if len(id) != 0 { + query.Set("id", id) } - if len(vpcID) != 0 { - queues["router_id"] = vpcID + if len(vpcId) != 0 { + query.Set("vpc_id", vpcId) } - natGateways := make([]SNatGateway, 0, 2) - err := doListAllWithMarker(region.ecsClient.NatGateways.List, queues, &natGateways) - if err != nil { - return nil, errors.Wrapf(err, "get nat gateways error by natgatewayid") + ret := []SNatGateway{} + for { + resp, err := region.list(SERVICE_NAT, "private-nat/gateways", query) + if err != nil { + return nil, err + } + part := struct { + Gateways []SNatGateway + PageInfo sPageInfo + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.Gateways...) + if len(part.PageInfo.NextMarker) == 0 || len(part.Gateways) == 0 { + break + } + query.Set("marker", part.PageInfo.NextMarker) } - for i := range natGateways { - natGateways[i].region = region - } - return natGateways, nil + return ret, nil } -func (region *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayID string) (SNatDEntry, error) { +func (region *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayID string) (*SNatDEntry, error) { params := make(map[string]interface{}) params["nat_gateway_id"] = gatewayID params["private_ip"] = rule.InternalIP @@ -213,21 +226,21 @@ func (region *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayID s params["external_service_port"] = rule.ExternalPort params["protocol"] = rule.Protocol - packParams := map[string]map[string]interface{}{ - "dnat_rule": params, - } - - ret := SNatDEntry{} - err := DoCreate(region.ecsClient.DNatRules.Create, jsonutils.Marshal(packParams), &ret) + resp, err := region.post(SERVICE_NAT, "private-nat/dnat-rules", map[string]interface{}{"dnat_rule": params}) if err != nil { - return SNatDEntry{}, errors.Wrapf(err, `create dnat rule of nat gateway %q failed`, gatewayID) + return nil, errors.Wrapf(err, "create dnat") + } + ret := &SNatDEntry{} + err = resp.Unmarshal(ret, "dnat_rule") + if err != nil { + return nil, err } return ret, nil } -func (region *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayID string) (SNatSEntry, error) { +func (region *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayId string) (*SNatSEntry, error) { params := make(map[string]interface{}) - params["nat_gateway_id"] = gatewayID + params["nat_gateway_id"] = gatewayId if len(rule.NetworkID) != 0 { params["network_id"] = rule.NetworkID } @@ -235,36 +248,42 @@ func (region *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayID s params["cidr"] = rule.SourceCIDR } params["floating_ip_id"] = rule.ExternalIPID - - packParams := map[string]map[string]interface{}{ - "snat_rule": params, - } - - ret := SNatSEntry{} - err := DoCreate(region.ecsClient.SNatRules.Create, jsonutils.Marshal(packParams), &ret) + resp, err := region.post(SERVICE_NAT, "private-nat/snat-rules", map[string]interface{}{"snat_rule": params}) if err != nil { - return SNatSEntry{}, errors.Wrapf(err, `create snat rule of nat gateway %q failed`, gatewayID) + return nil, errors.Wrapf(err, "create snat") + } + ret := &SNatSEntry{} + err = resp.Unmarshal(ret, "snat_rule") + if err != nil { + return nil, err } return ret, nil } -func (region *SRegion) GetNatDEntryByID(id string) (SNatDEntry, error) { - dnat := SNatDEntry{} - err := DoGet(region.ecsClient.DNatRules.Get, id, map[string]string{}, &dnat) - +func (region *SRegion) GetNatDEntryByID(id string) (*SNatDEntry, error) { + resp, err := region.list(SERVICE_NAT, "private-nat/dnat-rules/"+id, nil) if err != nil { - return SNatDEntry{}, err + return nil, err } - return dnat, nil + ret := &SNatDEntry{} + err = resp.Unmarshal(ret, "dnat_rule") + if err != nil { + return nil, err + } + return ret, nil } -func (region *SRegion) GetNatSEntryByID(id string) (SNatSEntry, error) { - snat := SNatSEntry{} - err := DoGet(region.ecsClient.SNatRules.Get, id, map[string]string{}, &snat) +func (region *SRegion) GetNatSEntryByID(id string) (*SNatSEntry, error) { + resp, err := region.list(SERVICE_NAT, "private-nat/snat-rules/"+id, nil) if err != nil { - return SNatSEntry{}, cloudprovider.ErrNotFound + return nil, err } - return snat, nil + ret := &SNatSEntry{} + err = resp.Unmarshal(ret, "snat_rule") + if err != nil { + return nil, err + } + return ret, nil } func NatResouceStatusTransfer(status string) string { @@ -283,13 +302,16 @@ func NatResouceStatusTransfer(status string) string { } func (self *SRegion) GetNatGateway(id string) (*SNatGateway, error) { - resp, err := self.ecsClient.NatGateways.Get(id, nil) + resp, err := self.list(SERVICE_NAT, "private-nat/gateways/"+id, nil) if err != nil { - return nil, errors.Wrapf(err, "NatGateways.Get(%s)", id) + return nil, err } nat := &SNatGateway{region: self} - err = resp.Unmarshal(nat) - return nat, errors.Wrap(err, "resp.Unmarshal") + err = resp.Unmarshal(nat, "gateway") + if err != nil { + return nil, err + } + return nat, nil } func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) { @@ -312,7 +334,7 @@ func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOption case api.NAT_SPEC_XLARGE: spec = "4" } - params := jsonutils.Marshal(map[string]map[string]interface{}{ + params := map[string]interface{}{ "nat_gateway": map[string]interface{}{ "name": opts.Name, "description": opts.Desc, @@ -320,13 +342,13 @@ func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOption "internal_network_id": opts.NetworkId, "spec": spec, }, - }) - resp, err := self.ecsClient.NatGateways.Create(params) + } + resp, err := self.post(SERVICE_NAT, "private-nat/gateways", params) if err != nil { - return nil, errors.Wrap(err, "AsyncCreate") + return nil, errors.Wrap(err, "create nat") } nat := &SNatGateway{region: self} - err = resp.Unmarshal(nat) + err = resp.Unmarshal(nat, "gateway") if err != nil { return nil, errors.Wrapf(err, "resp.Unmarshal") } @@ -334,6 +356,6 @@ func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOption } func (self *SRegion) DeleteNatGateway(id string) error { - _, err := self.ecsClient.NatGateways.Delete(id, nil) - return errors.Wrapf(err, "NatGateways.Delete(%s)", id) + _, err := self.delete(SERVICE_NAT, "private-nat/gateways/"+id) + return err } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natstable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natstable.go index 3659eee4fa..dd0ee09331 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natstable.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natstable.go @@ -15,8 +15,9 @@ package huawei import ( + "net/url" + "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" "yunion.io/x/cloudmux/pkg/multicloud" ) @@ -68,7 +69,6 @@ func (nat *SNatSEntry) Delete() error { return nat.gateway.region.DeleteNatSEntry(nat.GetId()) } -// getNatSTable return all snat rules of gateway func (gateway *SNatGateway) getNatSTable() ([]SNatSEntry, error) { ret, err := gateway.region.GetNatSTable(gateway.GetId()) if err != nil { @@ -80,42 +80,43 @@ func (gateway *SNatGateway) getNatSTable() ([]SNatSEntry, error) { return ret, nil } -func (region *SRegion) GetNatSTable(natGatewayID string) ([]SNatSEntry, error) { - queuies := map[string]string{ - "nat_gateway_id": natGatewayID, +func (region *SRegion) GetNatSTable(natId string) ([]SNatSEntry, error) { + query := url.Values{} + if len(natId) > 0 { + query.Set("gateway_id", natId) } - sNatSTableEntris := make([]SNatSEntry, 0, 2) - err := doListAllWithMarker(region.ecsClient.SNatRules.List, queuies, &sNatSTableEntris) - if err != nil { - return nil, errors.Wrapf(err, `get snat rule of gateway %q`, natGatewayID) - } - for i := range sNatSTableEntris { - nat := &sNatSTableEntris[i] - if len(nat.SourceCIDR) != 0 { - continue - } - subnet := SNetwork{} - err := DoGet(region.ecsClient.Subnets.Get, nat.NetworkID, map[string]string{}, &subnet) + ret := []SNatSEntry{} + for { + resp, err := region.list(SERVICE_NAT, "private-nat/snat-rules", query) if err != nil { - return nil, errors.Wrapf(err, `get cidr of subnet %q`, nat.NetworkID) + return nil, err } - nat.SourceCIDR = subnet.CIDR + part := struct { + SnatRules []SNatSEntry + PageInfo sPageInfo + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.SnatRules...) + if len(part.PageInfo.NextMarker) == 0 || len(part.SnatRules) == 0 { + break + } + query.Set("marker", part.PageInfo.NextMarker) } - return sNatSTableEntris, nil + return ret, nil } -func (region *SRegion) DeleteNatSEntry(entryID string) error { - _, err := region.ecsClient.SNatRules.Delete(entryID, nil) - if err != nil { - return errors.Wrapf(err, `delete snat rule %q failed`, entryID) - } - return nil +func (region *SRegion) DeleteNatSEntry(id string) error { + _, err := region.delete(SERVICE_NAT, "private-nat/snat-rules/"+id) + return err } func (nat *SNatSEntry) Refresh() error { - new, err := nat.gateway.region.GetNatSEntryByID(nat.ID) + ret, err := nat.gateway.region.GetNatSEntryByID(nat.ID) if err != nil { return err } - return jsonutils.Update(nat, new) + return jsonutils.Update(nat, ret) } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/network.go index 61943753b2..163a49c9d3 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/network.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/network.go @@ -15,15 +15,17 @@ package huawei import ( + "fmt" + "net/url" + "yunion.io/x/jsonutils" - "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/netutils" "yunion.io/x/pkg/util/rbacscope" api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/cloudmux/pkg/multicloud" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" ) /* @@ -81,16 +83,11 @@ func (self *SNetwork) GetStatus() string { } func (self *SNetwork) Refresh() error { - log.Debugf("network refresh %s", self.GetId()) - new, err := self.wire.region.getNetwork(self.GetId()) + net, err := self.wire.vpc.region.GetNetwork(self.GetId()) if err != nil { return err } - return jsonutils.Update(self, new) -} - -func (self *SNetwork) IsEmulated() bool { - return false + return jsonutils.Update(self, net) } func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { @@ -139,34 +136,58 @@ func (self *SNetwork) GetPublicScope() rbacscope.TRbacScope { } func (self *SNetwork) Delete() error { - return self.wire.region.deleteNetwork(self.VpcID, self.GetId()) + return self.wire.vpc.region.deleteNetwork(self.VpcID, self.GetId()) } func (self *SNetwork) GetAllocTimeoutSeconds() int { return 120 // 2 minutes } -func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) { - network := SNetwork{} - err := DoGet(self.ecsClient.Subnets.Get, networkId, nil, &network) - return &network, err -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090592.html -func (self *SRegion) GetNetwroks(vpcId string) ([]SNetwork, error) { - querys := map[string]string{} - if len(vpcId) > 0 { - querys["vpc_id"] = vpcId +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=ShowSubnet +func (self *SRegion) GetNetwork(networkId string) (*SNetwork, error) { + resp, err := self.list(SERVICE_VPC, "subnets/"+networkId, nil) + if err != nil { + return nil, errors.Wrapf(err, "show subnet") } - - networks := make([]SNetwork, 0) - err := doListAllWithMarker(self.ecsClient.Subnets.List, querys, &networks) - return networks, err + network := &SNetwork{} + err = resp.Unmarshal(&network, "subnet") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + return network, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=ListSubnets +func (self *SRegion) GetNetworks(vpcId string) ([]SNetwork, error) { + ret := []SNetwork{} + query := url.Values{} + if len(vpcId) > 0 { + query.Set("vpc_id", vpcId) + } + for { + resp, err := self.list(SERVICE_VPC, "subnets", query) + if err != nil { + return nil, err + } + part := []SNetwork{} + err = resp.Unmarshal(&part, "subnets") + if err != nil { + return nil, err + } + ret = append(ret, part...) + if len(part) == 0 { + break + } + query.Set("marker", part[len(part)-1].ID) + } + return ret, nil +} + +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=DeleteSubnet func (self *SRegion) deleteNetwork(vpcId string, networkId string) error { - ctx := &modules.SManagerContext{InstanceId: vpcId, InstanceManager: self.ecsClient.Vpcs} - return DoDeleteWithSpec(self.ecsClient.Subnets.DeleteInContextWithSpec, ctx, networkId, "", nil, nil) + res := fmt.Sprintf("vpcs/%s/subnets/%s", vpcId, networkId) + _, err := self.delete(SERVICE_VPC, res) + return err } func (self *SNetwork) GetProjectId() string { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/order.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/order.go index 5c024b4678..6924be87c7 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/order.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/order.go @@ -14,180 +14,48 @@ package huawei -import ( - "fmt" - "strings" - "time" +import "time" - "yunion.io/x/log" - - "yunion.io/x/cloudmux/pkg/cloudprovider" -) - -type SOrder struct { - ErrorCode *string `json:"error_code"` // 只有失败时才返回此参数 - ErrorMsg *string `json:"error_msg"` //只有失败时才返回此参数 - TotalSize int `json:"totalSize"` // 只有成功时才返回此参数 - Resources []SResource `json:"resources"` +type SOrderResource struct { + Id string + ResourceId string + ExpireTime time.Time } -type SResource struct { - ResourceID string `json:"resourceId"` - CloudServiceType string `json:"cloudServiceType"` - RegionCode string `json:"regionCode"` - ResourceType string `json:"resourceType"` - ResourceSpecCode string `json:"resourceSpecCode"` - Status int64 `json:"status"` -} - -type SResourceDetail struct { - ID string `json:"id"` - Status int64 `json:"status"` - ResourceID string `json:"resource_id"` - ResourceName string `json:"resource_name"` - RegionCode string `json:"region_code"` - CloudServiceTypeCode string `json:"cloud_service_type_code"` - ResourceTypeCode string `json:"resource_type_code"` - ResourceSpecCode string `json:"resource_spec_code"` - ProjectCode string `json:"project_code"` - ProductID string `json:"product_id"` - MainResourceID string `json:"main_resource_id"` - IsMainResource int64 `json:"is_main_resource"` - ValidTime time.Time `json:"valid_time"` - ExpireTime time.Time `json:"expire_time"` - NextOperationPolicy string `json:"next_operation_policy"` -} - -func (self *SRegion) getDomianId() (string, error) { - domains, err := self.client.getEnabledDomains() - if err != nil { - return "", err +func (self *SHuaweiClient) GetOrderResources() (map[string]SOrderResource, error) { + if len(self.orders) > 0 { + return self.orders, nil } - - if domains == nil || len(domains) == 0 { - return "", fmt.Errorf("GetAllResByOrderId domain is empty") - } else if len(domains) > 1 { - // not supported?? - return "", fmt.Errorf("GetAllResByOrderId mutliple domain(%d) found", len(domains)) + params := map[string]interface{}{ + "limit": 500, + "only_main_resource": 1, + "status_list": []int{ + 2, 4, + }, } - - return domains[0].ID, nil -} - -/* -获取订单信息 https://support.huaweicloud.com/api-oce/api_order_00001.html -*/ -func (self *SRegion) GetOrder(orderId string) (SOrder, error) { - var order SOrder - domain, err := self.getDomianId() - if err != nil { - return order, err - } - - err = self.ecsClient.Orders.SetDomainId(domain) - if err != nil { - return order, err - } - - err = DoGet(self.ecsClient.Orders.Get, orderId, nil, &order) - return order, err -} - -/* -获取订单资源详情列表 https://support.huaweicloud.com/api-oce/zh-cn_topic_0084961226.html -*/ -func (self *SRegion) GetOrderResources(orderId string, resource_ids []string, only_main_resource bool) ([]SResourceDetail, error) { - domain, err := self.getDomianId() - if err != nil { - return nil, err - } - - err = self.ecsClient.Orders.SetDomainId(domain) - if err != nil { - return nil, err - } - - resources := make([]SResourceDetail, 0) - queries := map[string]string{"customer_id": domain} - if len(orderId) > 0 { - queries["order_id"] = orderId - } - - if len(resource_ids) > 0 { - queries["resource_ids"] = strings.Join(resource_ids, ",") - } - - if only_main_resource { - queries["only_main_resource"] = "1" - } - - err = doListAll(self.ecsClient.Orders.GetPeriodResourceList, queries, &resources) - return resources, err -} - -/* -获取资源详情 https://support.huaweicloud.com/api-oce/zh-cn_topic_0084961226.html -*/ -func (self *SRegion) GetOrderResourceDetail(resourceId string) (SResourceDetail, error) { - var res SResourceDetail - if len(resourceId) == 0 { - return res, fmt.Errorf("GetOrderResourceDetail resource id should not be empty") - } - - resources, err := self.GetOrderResources("", []string{resourceId}, false) - if err != nil { - return res, err - } - - switch len(resources) { - case 0: - return res, cloudprovider.ErrNotFound - case 1: - return resources[0], nil - default: - return res, fmt.Errorf("%d resources with id %s found, Expect 1", len(resources), resourceId) - } -} - -func (self *SRegion) GetAllResByOrderId(orderId string) ([]SResource, error) { - order, err := self.GetOrder(orderId) - if err != nil { - return nil, err - } - - log.Debugf("GetAllResByOrderId %#v", order.Resources) - return order.Resources, nil -} - -func (self *SRegion) getAllResByType(orderId string, resourceType string) ([]SResource, error) { - res, err := self.GetAllResByOrderId(orderId) - if err != nil { - return nil, err - } - - ret := make([]SResource, 0) - for i := range res { - r := res[i] - if r.ResourceType == resourceType { - ret = append(ret, r) + ret, cnt := map[string]SOrderResource{}, 0 + for { + resp, err := self.post(SERVICE_BSS, "", "orders/suscriptions/resources/query", params) + if err != nil { + return nil, err } - } - - return ret, nil -} - -func (self *SRegion) getAllResIdsByType(orderId string, resourceType string) ([]string, error) { - res, err := self.getAllResByType(orderId, resourceType) - if err != nil { - return nil, err - } - - ids := make([]string, 0) - for _, r := range res { - if len(r.ResourceID) > 0 { - ids = append(ids, r.ResourceID) + part := struct { + Data []SOrderResource + TotalCount int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err } + cnt += len(part.Data) + for _, order := range part.Data { + ret[order.Id] = order + } + if cnt >= part.TotalCount || len(part.Data) == 0 { + break + } + params["offset"] = cnt } - - return ids, nil + self.orders = ret + return self.orders, nil } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/port.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/port.go index 6bbcd96970..0349f8f390 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/port.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/port.go @@ -15,8 +15,10 @@ package huawei import ( + "net/url" "strings" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" api "yunion.io/x/cloudmux/pkg/apis/compute" @@ -142,20 +144,42 @@ func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInt return ret, nil } -func (self *SRegion) GetPort(portId string) (Port, error) { - port := Port{} - err := DoGet(self.ecsClient.Port.Get, portId, nil, &port) - return port, err -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html -func (self *SRegion) GetPorts(instanceId string) ([]Port, error) { - ports := make([]Port, 0) - querys := map[string]string{} - if len(instanceId) > 0 { - querys["device_id"] = instanceId +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=ShowPort +func (self *SRegion) GetPort(id string) (*Port, error) { + resp, err := self.list(SERVICE_VPC, "ports/"+id, nil) + if err != nil { + return nil, errors.Wrapf(err, "get port") } + port := &Port{} + err = resp.Unmarshal(port, "port") + if err != nil { + return nil, err + } + return port, nil +} - err := doListAllWithMarker(self.ecsClient.Port.List, querys, &ports) - return ports, err +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=ListPorts +func (self *SRegion) GetPorts(instanceId string) ([]Port, error) { + ret := []Port{} + query := url.Values{} + if len(instanceId) > 0 { + query.Set("device_id", instanceId) + } + for { + resp, err := self.list(SERVICE_VPC, "ports", query) + if err != nil { + return nil, err + } + part := []Port{} + err = resp.Unmarshal(&part, "ports") + if err != nil { + return nil, err + } + ret = append(ret, part...) + if len(part) == 0 { + break + } + query.Set("marker", part[len(part)-1].ID) + } + return ret, nil } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/project.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/project.go index f65fa961c9..3e08aec480 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/project.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/project.go @@ -19,6 +19,7 @@ import ( "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 @@ -51,18 +52,20 @@ func (self *SProject) GetHealthStatus() string { } func (self *SHuaweiClient) fetchProjects() ([]SProject, error) { - if self.projects != nil { + if len(self.projects) > 0 { return self.projects, nil } - - huawei, _ := self.newGeneralAPIClient() - projects := make([]SProject, 0) - err := doListAll(huawei.Projects.List, nil, &projects) - if err == nil { - self.projects = projects + projects := []SProject{} + resp, err := self.list(SERVICE_IAM_V3, "", "auth/projects", nil) + if err != nil { + return nil, errors.Wrapf(err, "list projects") } - - return projects, err + err = resp.Unmarshal(&projects, "projects") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + self.projects = projects + return self.projects, nil } // obs 权限必须赋予到mos project之上 diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/provider/provider.go index fbf1b1ee2a..e3bcafcb32 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/provider/provider.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/provider/provider.go @@ -90,13 +90,8 @@ func (self *SHuaweiProviderFactory) ValidateCreateCloudaccountData(ctx context.C if len(input.AccessKeySecret) == 0 { return output, errors.Wrap(cloudprovider.ErrMissingParameter, "access_key_secret") } - if len(input.Environment) == 0 { - return output, errors.Wrap(cloudprovider.ErrMissingParameter, "environment") - } - output.Account = input.AccessKeyId output.Secret = input.AccessKeySecret - output.AccessUrl = input.Environment return output, nil } @@ -133,7 +128,7 @@ func (self *SHuaweiProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig accessKey, projectId := parseAccount(cfg.Account) client, err := huawei.NewHuaweiClient( huawei.NewHuaweiClientConfig( - cfg.URL, accessKey, cfg.Secret, projectId, + accessKey, cfg.Secret, projectId, ).CloudproviderConfig(cfg), ) if err != nil { @@ -152,7 +147,6 @@ func (self *SHuaweiProviderFactory) GetClientRC(info cloudprovider.SProviderInfo info.Region = strings.Join(data[len(data)-3:], "-") } return map[string]string{ - "HUAWEI_CLOUD_ENV": info.Url, "HUAWEI_ACCESS_KEY": accessKey, "HUAWEI_SECRET": info.Secret, "HUAWEI_REGION": info.Region, diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/region.go index a9642547a0..e24e8ee5df 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/region.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/region.go @@ -27,7 +27,6 @@ import ( api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/cloudmux/pkg/multicloud" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client" "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs" ) @@ -41,7 +40,6 @@ type SRegion struct { multicloud.SRegion client *SHuaweiClient - ecsClient *client.Client obsClient *obs.ObsClient // 对象存储client.请勿直接引用。 Description string `json:"description"` @@ -50,9 +48,6 @@ type SRegion struct { ParentRegionID string `json:"parent_region_id"` Type string `json:"type"` - izones []cloudprovider.ICloudZone - ivpcs []cloudprovider.ICloudVpc - storageCache *SStoragecache } @@ -80,30 +75,6 @@ func (self *SRegion) patch(service, resource string, query url.Values, params ma return self.client.patch(service, self.ID, resource, query, params) } -func (self *SRegion) getECSClient() (*client.Client, error) { - var err error - - if len(self.client.projectId) > 0 { - project, err := self.client.GetProjectById(self.client.projectId) - if err != nil { - return nil, err - } - - if !strings.Contains(project.Name, self.ID) { - return nil, errors.Errorf("region %s and project %s mismatch", self.ID, project.Name) - } - } - - if self.ecsClient == nil { - self.ecsClient, err = self.client.newRegionAPIClient(self.ID) - if err != nil { - return nil, err - } - } - - return self.ecsClient, err -} - func (self *SRegion) getOBSEndpoint() string { return getOBSEndpoint(self.GetId()) } @@ -121,52 +92,26 @@ func (self *SRegion) getOBSClient(signType obs.SignatureType) (*obs.ObsClient, e return self.obsClient, nil } -func (self *SRegion) fetchZones() error { - zones := make([]SZone, 0) - err := doListAll(self.ecsClient.Zones.List, nil, &zones) - if err != nil { - return err - } - - self.izones = make([]cloudprovider.ICloudZone, 0) - for i := range zones { - zone := zones[i] - zone.region = self - self.izones = append(self.izones, &zone) - } - return nil -} - -func (self *SRegion) fetchIVpcs() error { - // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html - vpcs := make([]SVpc, 0) - querys := map[string]string{ - "limit": "2048", - } - err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs) - if err != nil { - return err - } - - self.ivpcs = make([]cloudprovider.ICloudVpc, 0) - for i := range vpcs { - vpc := vpcs[i] - vpc.region = self - self.ivpcs = append(self.ivpcs, &vpc) - } - return nil -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - if len(id) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetIVMById") - } - - instance, err := self.GetInstanceByID(id) +// https://console.huaweicloud.com/apiexplorer/#/openapi/ECS/doc?api=NovaListAvailabilityZones +func (self *SRegion) GetZones() ([]SZone, error) { + resp, err := self.list(SERVICE_ECS_V2_1, "os-availability-zone", nil) if err != nil { return nil, err } - return &instance, err + ret := []SZone{} + err = resp.Unmarshal(&ret, "availabilityZoneInfo") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return ret, nil +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + instance, err := self.GetInstance(id) + if err != nil { + return nil, err + } + return instance, err } func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { @@ -278,7 +223,7 @@ func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { } func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.ID) + return fmt.Sprintf("%s/%s", api.CLOUD_PROVIDER_HUAWEI, self.ID) } func (self *SRegion) GetStatus() string { @@ -307,52 +252,30 @@ func (self *SRegion) GetLongitude() float32 { return 0.0 } -func (self *SRegion) fetchInfrastructure() error { - _, err := self.getECSClient() - if err != nil { - return err - } - - if err := self.fetchZones(); err != nil { - return err - } - - if err := self.fetchIVpcs(); err != nil { - return err - } - - for i := 0; i < len(self.ivpcs); i += 1 { - vpc := self.ivpcs[i].(*SVpc) - wire := SWire{region: self, vpc: vpc} - vpc.addWire(&wire) - - for j := 0; j < len(self.izones); j += 1 { - zone := self.izones[j].(*SZone) - zone.addWire(&wire) - } - } - return nil -} - func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if self.izones == nil { - var err error - err = self.fetchInfrastructure() - if err != nil { - return nil, err - } + zones, err := self.GetZones() + if err != nil { + return nil, err } - return self.izones, nil + ret := []cloudprovider.ICloudZone{} + for i := range zones { + zones[i].region = self + ret = append(ret, &zones[i]) + } + return ret, nil } func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - if self.ivpcs == nil { - err := self.fetchInfrastructure() - if err != nil { - return nil, err - } + vpcs, err := self.GetVpcs() + if err != nil { + return nil, errors.Wrapf(err, "GetVpcs") } - return self.ivpcs, nil + ret := []cloudprovider.ICloudVpc{} + for i := range vpcs { + vpcs[i].region = self + ret = append(ret, &vpcs[i]) + } + return ret, nil } func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { @@ -404,7 +327,7 @@ func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) } func (self *SRegion) DeleteSecurityGroup(id string) error { - _, err := self.delete(SERVICE_VPC, "vpc/security-groups/"+id) + _, err := self.delete(SERVICE_VPC_V3, "vpc/security-groups/"+id) return err } @@ -413,7 +336,7 @@ func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICl } func (self *SRegion) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - groups, err := self.GetSecurityGroups("", "") + groups, err := self.GetSecurityGroups("") if err != nil { return nil, errors.Wrapf(err, "GetSecurityGroups") } @@ -429,7 +352,6 @@ func (self *SRegion) CreateISecurityGroup(opts *cloudprovider.SecurityGroupCreat return self.CreateSecurityGroup(opts) } -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090608.html func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { return self.CreateVpc(opts.NAME, opts.CIDR, opts.Desc) } @@ -443,7 +365,15 @@ func (self *SRegion) CreateVpc(name, cidr, desc string) (*SVpc, error) { }, } vpc := &SVpc{region: self} - return vpc, DoCreate(self.ecsClient.Vpcs.Create, jsonutils.Marshal(params), vpc) + resp, err := self.post(SERVICE_VPC, "vpcs", params) + if err != nil { + return nil, errors.Wrapf(err, "create vpc") + } + err = resp.Unmarshal(vpc, "vpc") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + return vpc, nil } // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html @@ -478,9 +408,12 @@ func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { return ret, nil } -func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := self.GetSnapshotById(snapshotId) - return &snapshot, err +func (self *SRegion) GetISnapshotById(id string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := self.GetSnapshot(id) + if err != nil { + return nil, err + } + return snapshot, nil } func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { @@ -554,7 +487,7 @@ func (self *SRegion) GetProvider() string { } func (self *SRegion) GetCloudEnv() string { - return self.client.cloudEnv + return CLOUD_PROVIDER_HUAWEI } func (self *SRegion) CreateSecurityGroup(opts *cloudprovider.SecurityGroupCreateInput) (*SSecurityGroup, error) { @@ -563,7 +496,7 @@ func (self *SRegion) CreateSecurityGroup(opts *cloudprovider.SecurityGroupCreate "description": opts.Desc, "enterprise_project_id": opts.ProjectId, } - resp, err := self.post(SERVICE_VPC, "vpc/security-groups", map[string]interface{}{"security_group": params}) + resp, err := self.post(SERVICE_VPC_V3, "vpc/security-groups", map[string]interface{}{"security_group": params}) if err != nil { return nil, err } @@ -728,19 +661,16 @@ func (region *SRegion) GetCapabilities() []string { } func (self *SRegion) GetDiskTypes() ([]SDiskType, error) { - ret, err := self.ecsClient.Disks.GetDiskTypes() + resp, err := self.list(SERVICE_EVS, "types", nil) if err != nil { - return nil, errors.Wrap(err, "GetDiskTypes") + return nil, err } - - dts := []SDiskType{} - _ret := jsonutils.NewArray(ret.Data...) - err = _ret.Unmarshal(&dts) + ret := []SDiskType{} + err = resp.Unmarshal(&ret, "volume_types") if err != nil { - return nil, errors.Wrap(err, "Unmarshal") + return nil, errors.Wrapf(err, "Unmarshal") } - - return dts, nil + return ret, nil } func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error) { @@ -760,7 +690,7 @@ func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error) } func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms, err := region.GetInstances() + vms, err := region.GetInstances("") if err != nil { return nil, errors.Wrap(err, "GetInstances") } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/roles.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/roles.go index 783f2c1fd1..d6b549805b 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/roles.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/roles.go @@ -15,6 +15,9 @@ package huawei import ( + "fmt" + "net/url" + "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -76,24 +79,40 @@ func (self *SHuaweiClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpoli return ret, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListPermissions func (self *SHuaweiClient) GetRoles(domainId, name string) ([]SRole, error) { - params := map[string]string{} + params := url.Values{} if len(domainId) > 0 { - params["domain_id"] = self.ownerId + params.Set("domain_id", self.ownerId) } if len(name) > 0 { - params["name"] = name + params.Set("name", name) } - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") + query := url.Values{} + query.Set("per_page", "300") + page := 1 + query.Set("page", fmt.Sprintf("%d", page)) + ret := []SRole{} + for { + resp, err := self.list(SERVICE_IAM_V3, "", "roles", query) + if err != nil { + return nil, err + } + part := struct { + Roles []SRole + TotalNumber int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.Roles...) + if len(ret) >= part.TotalNumber || len(part.Roles) == 0 { + break + } + page++ + query.Set("page", fmt.Sprintf("%d", page)) } - - roles := []SRole{} - err = doListAllWithNextLink(client.Roles.List, params, &roles) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return roles, nil + return ret, nil } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/routetables.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/routetables.go index ade73920be..eb91d974bb 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/routetables.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/routetables.go @@ -16,6 +16,7 @@ package huawei import ( "fmt" + "net/url" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -157,61 +158,70 @@ func (self *SRoute) GetNextHop() string { } func (self *SRegion) GetRouteTables(vpcId string) ([]SRouteTable, error) { - params := map[string]string{} + params := url.Values{} if len(vpcId) > 0 { - params["vpc_id"] = vpcId + params.Set("vpc_id", vpcId) } rtbs := make([]SRouteTable, 0) - err := doListAllWithMarker(self.ecsClient.RouteTables.List, params, &rtbs) - return rtbs, err + for { + resp, err := self.list(SERVICE_VPC, "routetables", params) + if err != nil { + return nil, errors.Wrapf(err, "list routetables") + } + part := struct { + Routetables []SRouteTable + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + rtbs = append(rtbs, part.Routetables...) + if len(part.Routetables) == 0 { + break + } + params.Set("marker", part.Routetables[len(part.Routetables)-1].Id) + } + return rtbs, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=ShowRouteTable func (self *SRegion) GetRouteTable(id string) (*SRouteTable, error) { - resp, err := self.ecsClient.RouteTables.Get(id, nil) + resp, err := self.list(SERVICE_VPC, "routetables/"+id, nil) + if err != nil { + return nil, errors.Wrapf(err, "show routetable") + } + ret := &SRouteTable{} + err = resp.Unmarshal(&ret, "routetable") if err != nil { return nil, err } - tb := &SRouteTable{} - return tb, resp.Unmarshal(tb) + return ret, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=CreateRouteTable func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { routeType, ok := hoptypes[route.NextHopType] if !ok { return errors.Wrapf(cloudprovider.ErrNotSupported, route.NextHopType) } params := map[string]interface{}{ - "routes": map[string]interface{}{ - "add": []map[string]interface{}{ - { - "type": routeType, - "destination": route.Destination, - "nexthop": route.NextHop, - }, - }, + "route": map[string]interface{}{ + "type": routeType, + "destination": route.Destination, + "nexthop": route.NextHop, + "vpc_id": self.vpc.ID, }, } - _, err := self.vpc.region.ecsClient.VpcRoutes.Update(self.Id, jsonutils.Marshal(params)) + _, err := self.vpc.region.post(SERVICE_VPC, "vpc/routes", params) return err } func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { - routeType, ok := hoptypes[route.NextHopType] + _, ok := hoptypes[route.NextHopType] if !ok { return errors.Wrapf(cloudprovider.ErrNotSupported, route.NextHopType) } - params := map[string]interface{}{ - "routes": map[string]interface{}{ - "mod": []map[string]interface{}{ - { - "type": routeType, - "destination": route.Destination, - "nexthop": route.NextHop, - }, - }, - }, - } - _, err := self.vpc.region.ecsClient.VpcRoutes.Update(self.Id, jsonutils.Marshal(params)) + _, err := self.vpc.region.delete(SERVICE_VPC, "vpc/routes/"+route.RouteId) return err } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/saml_provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/saml_provider.go index e94d73d1c5..7895aa1663 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/saml_provider.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/saml_provider.go @@ -21,13 +21,13 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/httputils" "yunion.io/x/pkg/util/samlutils" "yunion.io/x/pkg/util/stringutils" api "yunion.io/x/cloudmux/pkg/apis/cloudid" "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/cloudmux/pkg/multicloud" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" ) type SAMLProviderLinks struct { @@ -89,17 +89,18 @@ func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) er return self.client.UpdateSAMLProviderMetadata(self.Id, metadata.String()) } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListIdentityProviders func (self *SHuaweiClient) ListSAMLProviders() ([]SAMLProvider, error) { - client, err := self.newGeneralAPIClient() + resp, err := self.list(SERVICE_IAM_V3, "", "OS-FEDERATION/identity_providers", nil) if err != nil { - return nil, errors.Wrapf(err, "newGeneralAPIClient") + return nil, err } - samls := []SAMLProvider{} - err = doListAllWithNextLink(client.SAMLProviders.List, nil, &samls) + ret := []SAMLProvider{} + err = resp.Unmarshal(&ret, "identity_providers") if err != nil { - return nil, errors.Wrapf(err, "doListAll") + return nil, err } - return samls, nil + return ret, nil } type SAMLProviderProtocol struct { @@ -107,25 +108,24 @@ type SAMLProviderProtocol struct { Id string } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneShowProtocol func (self *SHuaweiClient) GetSAMLProviderProtocols(id string) ([]SAMLProviderProtocol, error) { - client, err := self.newGeneralAPIClient() + resp, err := self.list(SERVICE_IAM_V3, "", fmt.Sprintf("OS-FEDERATION/identity_providers/%s/protocols", id), nil) if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") + return nil, err } - resp, err := client.SAMLProviders.ListInContextWithSpec(nil, fmt.Sprintf("%s/protocols", id), nil, "protocols") + ret := []SAMLProviderProtocol{} + err = resp.Unmarshal(&ret, "protocols") if err != nil { - return nil, errors.Wrapf(err, "ListInContextWithSpec") + return nil, err } - protocols := []SAMLProviderProtocol{} - return protocols, jsonutils.Update(&protocols, resp.Data) + return ret, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneDeleteProtocol func (self *SHuaweiClient) DeleteSAMLProviderProtocol(spId, id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.SAMLProviders.DeleteInContextWithSpec(nil, spId, fmt.Sprintf("protocols/%s", id), nil, nil, "") + res := fmt.Sprintf("OS-FEDERATION/identity_providers/%s/protocols/%s", spId, id) + _, err := self.delete(SERVICE_IAM_V3, "", res) return err } @@ -140,17 +140,12 @@ type SAMLProviderMetadata struct { XaccountType string } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=ShowMetadata func (self *SHuaweiClient) GetSAMLProviderMetadata(id string) (*SAMLProviderMetadata, error) { - client, err := self.newGeneralAPIClient() + resp, err := self.list(SERVICE_IAM_V3_EXT, "", fmt.Sprintf("OS-FEDERATION/identity_providers/%s/protocols/saml/metadata", id), nil) if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") + return nil, errors.Wrapf(err, "show metadata") } - client.SAMLProviders.SetVersion("v3-ext/OS-FEDERATION") - resp, err := client.SAMLProviders.GetInContextWithSpec(nil, id, fmt.Sprintf("protocols/saml/metadata"), nil, "") - if err != nil { - return nil, err - } - metadata := &SAMLProviderMetadata{} err = resp.Unmarshal(metadata) if err != nil { @@ -159,22 +154,15 @@ func (self *SHuaweiClient) GetSAMLProviderMetadata(id string) (*SAMLProviderMeta return metadata, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=CreateMetadata func (self *SHuaweiClient) UpdateSAMLProviderMetadata(id, metadata string) error { - params := map[string]string{ + params := map[string]interface{}{ "domain_id": self.ownerId, "xaccount_type": "", "metadata": metadata, } - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - client.SAMLProviders.SetVersion("v3-ext/OS-FEDERATION") - _, err = client.SAMLProviders.PerformAction2("protocols/saml/metadata", id, jsonutils.Marshal(params), "") - if err != nil { - return errors.Wrapf(err, "SAMLProvider.PerformAction") - } - return nil + _, err := self.post(SERVICE_IAM_V3_EXT, "", fmt.Sprintf("OS-FEDERATION/identity_providers/%s/protocols/saml/metadata", id), params) + return err } func (self *SHuaweiClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { @@ -190,26 +178,20 @@ func (self *SHuaweiClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLP return ret, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneDeleteIdentityProvider func (self *SHuaweiClient) DeleteSAMLProvider(id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.SAMLProviders.Delete(id, nil) + _, err := self.delete(SERVICE_IAM_V3, "", "OS-FEDERATION/identity_providers/"+id) return err } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneCreateIdentityProvider func (self *SHuaweiClient) CreateSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (*SAMLProvider, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - params := jsonutils.Marshal(map[string]interface{}{ + params := map[string]interface{}{ "identity_provider": map[string]interface{}{ "description": opts.Name, "enabled": true, }, - }) + } name := []byte{} for _, c := range opts.Name { if unicode.IsLetter(c) || unicode.IsNumber(c) || c == '-' || c == '_' { @@ -219,14 +201,15 @@ func (self *SHuaweiClient) CreateSAMLProvider(opts *cloudprovider.SAMLProviderCr } } samlName := string(name) + var err error err = func() error { idx := 1 for { - _, err = client.SAMLProviders.Update(samlName, params) + _, err = self.put(SERVICE_IAM_V3, "", "OS-FEDERATION/identity_providers/"+samlName, params) if err == nil { return nil } - he, ok := err.(*modules.HuaweiClientError) + he, ok := errors.Cause(err).(*httputils.JSONClientError) if !ok { return errors.Wrapf(err, "SAMLProviders.Update") } @@ -284,17 +267,18 @@ var ( }) ) +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListMappings func (self *SHuaweiClient) ListSAMLProviderMappings() ([]SAMLProviderMapping, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - mappings := []SAMLProviderMapping{} - err = doListAllWithNextLink(client.SAMLProviderMappings.List, nil, &mappings) + resp, err := self.list(SERVICE_IAM_V3, "", "OS-FEDERATION/mappings", nil) if err != nil { return nil, err } - return mappings, nil + ret := []SAMLProviderMapping{} + err = resp.Unmarshal(&ret, "mappings") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + return ret, nil } func (self *SHuaweiClient) findMapping() (*SAMLProviderMapping, error) { @@ -310,12 +294,8 @@ func (self *SHuaweiClient) findMapping() (*SAMLProviderMapping, error) { return nil, cloudprovider.ErrNotFound } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneCreateMapping func (self *SHuaweiClient) InitSAMLProviderMapping(spId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - mapping, err := self.findMapping() if err != nil { if errors.Cause(err) != cloudprovider.ErrNotFound { @@ -325,7 +305,7 @@ func (self *SHuaweiClient) InitSAMLProviderMapping(spId string) error { params := map[string]interface{}{ "mapping": onecloudMappingRules, } - _, err = client.SAMLProviderMappings.Update(mappingId, jsonutils.Marshal(params)) + _, err := self.put(SERVICE_IAM_V3, "", "OS-FEDERATION/mappings/"+mappingId, params) if err != nil { return errors.Wrapf(err, "create mapping") } @@ -348,20 +328,17 @@ func (self *SHuaweiClient) InitSAMLProviderMapping(spId string) error { if protocols[i].MappingId == mapping.Id { return nil } - _, err = client.SAMLProviders.PatchInContextWithSpec(nil, spId, "protocols/saml", jsonutils.Marshal(params), "") + // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneUpdateMapping + _, err := self.patch(SERVICE_IAM_V3, "", fmt.Sprintf("OS-FEDERATION/identity_providers/%s/protocols/saml", spId), nil, params) return err } } - _, err = client.SAMLProviders.UpdateInContextWithSpec(nil, spId, "protocols/saml", jsonutils.Marshal(params), "") + _, err = self.patch(SERVICE_IAM, "", fmt.Sprintf("OS-FEDERATION/identity_providers/%s/protocols/saml", spId), nil, params) return err } +// https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneDeleteMapping func (self *SHuaweiClient) DeleteSAMLProviderMapping(id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - - _, err = client.SAMLProviderMappings.Delete(id, nil) + _, err := self.delete(SERVICE_IAM_V3, "", "OS-FEDERATION/mappings/"+id) return err } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/secgrouprule.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/secgrouprule.go index ed9247afd0..cca56a11fd 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/secgrouprule.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/secgrouprule.go @@ -101,18 +101,20 @@ func (self *SecurityGroupRule) Delete() error { return self.secgroup.region.DeleteSecurityGroupRule(self.Id) } +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v3&api=DeleteSecurityGroupRule func (self *SRegion) DeleteSecurityGroupRule(id string) error { - _, err := self.delete(SERVICE_VPC, "vpc/security-group-rules/"+id) + _, err := self.delete(SERVICE_VPC_V3, "vpc/security-group-rules/"+id) return err } +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v3&api=ListSecurityGroupRules func (self *SRegion) GetSecurityGroupRules(groupId string) ([]SecurityGroupRule, error) { params := url.Values{} params.Set("security_group_id", groupId) ret := []SecurityGroupRule{} for { - resp, err := self.list(SERVICE_VPC, "vpc/security-group-rules", params) + resp, err := self.list(SERVICE_VPC_V3, "vpc/security-group-rules", params) if err != nil { return nil, err } @@ -133,6 +135,7 @@ func (self *SRegion) GetSecurityGroupRules(groupId string) ([]SecurityGroupRule, return ret, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v3&api=CreateSecurityGroupRule func (self *SRegion) CreateSecurityGroupRule(groupId string, opts *cloudprovider.SecurityGroupRuleCreateOptions) (*SecurityGroupRule, error) { rule := map[string]interface{}{ "security_group_id": groupId, @@ -161,7 +164,7 @@ func (self *SRegion) CreateSecurityGroupRule(groupId string, opts *cloudprovider params := map[string]interface{}{ "security_group_rule": rule, } - resp, err := self.post(SERVICE_VPC, "vpc/security-group-rules", params) + resp, err := self.post(SERVICE_VPC_V3, "vpc/security-group-rules", params) if err != nil { return nil, errors.Wrapf(err, "create rule") } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/securitygroup.go index 7b77fa7ca1..dd529ead96 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/securitygroup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/securitygroup.go @@ -90,27 +90,25 @@ func (self *SSecurityGroup) GetRules() ([]cloudprovider.ISecurityGroupRule, erro return ret, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v3&api=ShowSecurityGroup func (self *SRegion) GetSecurityGroup(id string) (*SSecurityGroup, error) { ret := &SSecurityGroup{region: self} - resp, err := self.list(SERVICE_VPC, "vpc/security-groups/"+id, nil) + resp, err := self.list(SERVICE_VPC_V3, "vpc/security-groups/"+id, nil) if err != nil { return nil, err } return ret, resp.Unmarshal(ret, "security_group") } -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090617.html -func (self *SRegion) GetSecurityGroups(vpcId string, name string) ([]SSecurityGroup, error) { +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v3&api=ListSecurityGroups +func (self *SRegion) GetSecurityGroups(name string) ([]SSecurityGroup, error) { ret := []SSecurityGroup{} params := url.Values{} if len(name) > 0 { params.Set("name", name) } - if len(vpcId) > 0 && vpcId != "default" { - params.Set("vc_id", vpcId) - } for { - resp, err := self.list(SERVICE_VPC, "vpc/security-groups", params) + resp, err := self.list(SERVICE_VPC_V3, "vpc/security-groups", params) if err != nil { return nil, err } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/sfs-turbo.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/sfs-turbo.go index 6868d09df2..e820a61a73 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/sfs-turbo.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/sfs-turbo.go @@ -16,6 +16,7 @@ package huawei import ( "fmt" + "net/url" "strings" "time" @@ -173,27 +174,53 @@ func (self *SRegion) GetICloudFileSystemById(id string) (cloudprovider.ICloudFil } func (self *SRegion) GetSfsTurbos() ([]SfsTurbo, error) { - queues := make(map[string]string) - sfs := make([]SfsTurbo, 0, 2) - err := doListAllWithOffset(self.ecsClient.SfsTurbos.List, queues, &sfs) - if err != nil { - return nil, errors.Wrapf(err, "doListAllWithOffset") + query := url.Values{} + sfs := []SfsTurbo{} + for { + resp, err := self.list(SERVICE_SFS, "sfs-turbo/shares/detail", query) + if err != nil { + return nil, err + } + part := struct { + Shares []SfsTurbo + Count int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + sfs = append(sfs, part.Shares...) + if len(part.Shares) == 0 || len(sfs) >= part.Count { + break + } + query.Set("offset", fmt.Sprintf("%d", len(sfs))) } return sfs, nil } func (self *SRegion) GetSfsTurbo(id string) (*SfsTurbo, error) { + resp, err := self.list(SERVICE_SFS, "sfs-turbo/shares/"+id, nil) + if err != nil { + return nil, err + } sf := &SfsTurbo{region: self} - err := DoGet(self.ecsClient.SfsTurbos.Get, id, nil, &sf) - return sf, errors.Wrapf(err, "self.ecsClient.SfsTurbos.Get") + err = resp.Unmarshal(sf) + if err != nil { + return nil, err + } + return sf, nil } func (self *SRegion) DeleteSfsTurbo(id string) error { - return DoDelete(self.ecsClient.SfsTurbos.Delete, id, nil, nil) + _, err := self.delete(SERVICE_SFS, "sfs-turbo/shares/"+id) + if err != nil { + return err + } + return nil } func (self *SRegion) GetSysDefaultSecgroupId() (string, error) { - secs, err := self.GetSecurityGroups("default", "") + secs, err := self.GetSecurityGroups("") if err != nil { return "", errors.Wrapf(err, "GetSecurityGroups") } @@ -234,7 +261,7 @@ func (self *SRegion) CreateSfsTurbo(opts *cloudprovider.FileSystemCraeteOptions) "metadata": metadata, }, } - resp, err := self.ecsClient.SfsTurbos.Create(jsonutils.Marshal(params)) + resp, err := self.post(SERVICE_SFS, "sfs-turbo/shares", params) if err != nil { return nil, errors.Wrapf(err, "Create") } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/snapshot.go index 566851157e..455fa7a97c 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/snapshot.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/snapshot.go @@ -16,8 +16,10 @@ package huawei import ( "fmt" + "net/url" "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/cloudmux/pkg/multicloud" @@ -46,7 +48,6 @@ type Metadata struct { SystemEnableActive string `json:"__system__enableActive"` // 如果为true。则表明是系统盘快照 } -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html type SSnapshot struct { multicloud.SResourceBase HuaweiTags @@ -95,16 +96,11 @@ func (self *SSnapshot) GetStatus() string { } func (self *SSnapshot) Refresh() error { - snapshot, err := self.region.GetSnapshotById(self.GetId()) + snapshot, err := self.region.GetSnapshot(self.GetId()) if err != nil { return err } - - if err := jsonutils.Update(self, snapshot); err != nil { - return err - } - - return nil + return jsonutils.Update(self, snapshot) } func (self *SSnapshot) IsEmulated() bool { @@ -134,54 +130,73 @@ func (self *SSnapshot) Delete() error { return self.region.DeleteSnapshot(self.GetId()) } -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408627.html func (self *SRegion) GetSnapshots(diskId string, snapshotName string) ([]SSnapshot, error) { - params := make(map[string]string) - + params := url.Values{} if len(diskId) > 0 { - params["volume_id"] = diskId + params.Set("volume_id", diskId) } if len(snapshotName) > 0 { - params["name"] = snapshotName + params.Set("name", snapshotName) } - - snapshots := make([]SSnapshot, 0) - err := doListAllWithOffset(self.ecsClient.Snapshots.List, params, &snapshots) - for i := range snapshots { - snapshots[i].region = self + ret := []SSnapshot{} + for { + resp, err := self.list(SERVICE_EVS, "cloudsnapshots/detail", params) + if err != nil { + return nil, err + } + part := struct { + Snapshots []SSnapshot + Count int + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.Snapshots...) + if len(ret) >= part.Count || len(part.Snapshots) == 0 { + break + } + params.Set("offset", fmt.Sprintf("%d", len(ret))) } - - return snapshots, err + return ret, nil } -func (self *SRegion) GetSnapshotById(snapshotId string) (SSnapshot, error) { - var snapshot SSnapshot - err := DoGet(self.ecsClient.Snapshots.Get, snapshotId, nil, &snapshot) - snapshot.region = self - return snapshot, err +func (self *SRegion) GetSnapshot(id string) (*SSnapshot, error) { + resp, err := self.list(SERVICE_EVS, "cloudsnapshots/"+id, nil) + if err != nil { + return nil, err + } + ret := &SSnapshot{region: self} + err = resp.Unmarshal(ret, "snapshot") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + return ret, nil } -// 不能删除以autobk_snapshot_为前缀的快照。 -// 当快照状态为available、error状态时,才可以删除。 -func (self *SRegion) DeleteSnapshot(snapshotId string) error { - return DoDelete(self.ecsClient.Snapshots.Delete, snapshotId, nil, nil) +func (self *SRegion) DeleteSnapshot(id string) error { + _, err := self.delete(SERVICE_EVS, "cloudsnapshots/"+id) + return err } -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html -// 目前已设置force字段。云硬盘处于挂载状态时,能强制创建快照。 -func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { - params := jsonutils.NewDict() - snapshotObj := jsonutils.NewDict() - snapshotObj.Add(jsonutils.NewString(name), "name") - snapshotObj.Add(jsonutils.NewString(desc), "description") - snapshotObj.Add(jsonutils.NewString(diskId), "volume_id") - snapshotObj.Add(jsonutils.JSONTrue, "force") - params.Add(snapshotObj, "snapshot") - - snapshot := SSnapshot{} - err := DoCreate(self.ecsClient.Snapshots.Create, params, &snapshot) - return snapshot.ID, err +func (self *SRegion) CreateSnapshot(diskId, name, desc string) (*SSnapshot, error) { + params := map[string]interface{}{ + "name": name, + "description": desc, + "volume_id": diskId, + "force": true, + } + resp, err := self.post(SERVICE_EVS, "cloudsnapshots", map[string]interface{}{"snapshot": params}) + if err != nil { + return nil, err + } + ret := &SSnapshot{region: self} + err = resp.Unmarshal(ret, "snapshot") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + return ret, nil } func (self *SSnapshot) GetProjectId() string { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storage.go index 40770f94a4..82e3f14727 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storage.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storage.go @@ -19,7 +19,7 @@ import ( "time" "yunion.io/x/jsonutils" - "yunion.io/x/log" + "yunion.io/x/pkg/errors" api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/cloudmux/pkg/cloudprovider" @@ -120,13 +120,11 @@ func (self *SStorage) GetEnabled() bool { func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { diskId, err := self.zone.region.CreateDisk(self.zone.GetId(), self.storageType, conf.Name, conf.SizeGb, "", conf.Desc, conf.ProjectId) if err != nil { - log.Errorf("createDisk fail %s", err) - return nil, err + return nil, errors.Wrapf(err, "CreateDisk") } disk, err := self.zone.region.GetDisk(diskId) if err != nil { - log.Errorf("getDisk fail %s", err) - return nil, err + return nil, errors.Wrapf(err, "GetDisk") } disk.storage = self @@ -139,17 +137,12 @@ func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudpr } func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { - if len(idStr) == 0 { - log.Debugf("GetIDiskById disk id should not be empty") - return nil, cloudprovider.ErrNotFound - } - - if disk, err := self.zone.region.GetDisk(idStr); err != nil { + disk, err := self.zone.region.GetDisk(idStr) + if err != nil { return nil, err - } else { - disk.storage = self - return disk, nil } + disk.storage = self + return disk, nil } func (self *SStorage) GetMountPoint() string { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storagecache.go index 7e779886a9..a7f03cb29e 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storagecache.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storagecache.go @@ -21,12 +21,10 @@ import ( "strings" "time" - "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/qemuimgfmt" - api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/cloudmux/pkg/multicloud" ) @@ -70,7 +68,7 @@ func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error } func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - imagesSelf, err := self.region.GetImages("", ImageOwnerSelf, "", EnvFusionCompute) + imagesSelf, err := self.region.GetImages("", "", "private", "") if err != nil { return nil, errors.Wrapf(err, "GetImages") } @@ -169,8 +167,7 @@ func (self *SStoragecache) uploadImage(ctx context.Context, image *cloudprovider } // timeout: 1hour = 3600 seconds - serviceType := self.region.ecsClient.Images.ServiceType() - err = self.region.waitTaskStatus(serviceType, jobId, TASK_SUCCESS, 15*time.Second, 3600*time.Second) + err = self.region.waitTaskStatus(SERVICE_IMS_V1, jobId, TASK_SUCCESS, 15*time.Second, 3600*time.Second) if err != nil { log.Errorf("waitTaskStatus %s", err) return "", err @@ -180,8 +177,7 @@ func (self *SStoragecache) uploadImage(ctx context.Context, image *cloudprovider callback(100) } - // https://support.huaweicloud.com/api-ims/zh-cn_topic_0022473688.html - return self.region.GetTaskEntityID(serviceType, jobId, "image_id") + return self.region.GetTaskEntityID(SERVICE_IMS, jobId, "image_id") } func (self *SRegion) getStoragecache() *SStoragecache { @@ -191,68 +187,6 @@ func (self *SRegion) getStoragecache() *SStoragecache { return self.storageCache } -type SJob struct { - Status string `json:"status"` - Entities map[string]string `json:"entities"` - JobID string `json:"job_id"` - JobType string `json:"job_type"` - BeginTime string `json:"begin_time"` - EndTime string `json:"end_time"` - ErrorCode string `json:"error_code"` - FailReason string `json:"fail_reason"` -} - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html -func (self *SRegion) createIImage(snapshotId, imageName, imageDesc string) (string, error) { - snapshot, err := self.GetSnapshotById(snapshotId) - if err != nil { - return "", err - } - - disk, err := self.GetDisk(snapshot.VolumeID) - if err != nil { - return "", err - } - - if disk.GetDiskType() != api.DISK_TYPE_SYS { - return "", fmt.Errorf("disk type err, expected disk type %s", api.DISK_TYPE_SYS) - } - - if len(disk.Attachments) == 0 { - return "", fmt.Errorf("disk is not attached.") - } - - imageObj := jsonutils.NewDict() - imageObj.Add(jsonutils.NewString(disk.Attachments[0].ServerID), "instance_id") - imageObj.Add(jsonutils.NewString(imageName), "name") - imageObj.Add(jsonutils.NewString(imageDesc), "description") - - ret, err := self.ecsClient.Images.PerformAction2("action", "", imageObj, "") - if err != nil { - return "", err - } - - job := SJob{} - jobId, err := ret.GetString("job_id") - querys := map[string]string{"service_type": self.ecsClient.Images.ServiceType()} - err = DoGet(self.ecsClient.Jobs.Get, jobId, querys, &job) - if err != nil { - return "", err - } - - if job.Status == "SUCCESS" { - imageId, exists := job.Entities["image_id"] - if exists { - return imageId, nil - } else { - return "", fmt.Errorf("image id not found in create image job %s", job.JobID) - } - } else { - return "", fmt.Errorf("create image failed, %s", job.FailReason) - } - -} - func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { storageCache := self.getStoragecache() return []cloudprovider.ICloudStoragecache{storageCache}, nil diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/task.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/task.go index a47effaea6..b77900a9fd 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/task.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/task.go @@ -18,7 +18,7 @@ import ( "fmt" "time" - "yunion.io/x/log" + "yunion.io/x/pkg/errors" ) func (self *SRegion) waitTaskStatus(serviceType string, taskId string, targetStatus string, interval time.Duration, timeout time.Duration) error { @@ -39,66 +39,79 @@ func (self *SRegion) waitTaskStatus(serviceType string, taskId string, targetSta return nil } +type SJob struct { + Status string + Entities struct { + SubJobs []struct { + VolumeId string + ServerId string + } + VolumeId string + ImageId string + } +} + +func (self *SRegion) GetJob(serviceType string, jobId string) (*SJob, error) { + resp, err := self.list(serviceType, "jobs/"+jobId, nil) + if err != nil { + return nil, err + } + ret := &SJob{} + err = resp.Unmarshal(ret) + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + return ret, nil +} + func (self *SRegion) GetTaskStatus(serviceType string, taskId string) (string, error) { - querys := map[string]string{"service_type": serviceType} - task, err := self.ecsClient.Jobs.Get(taskId, querys) + job, err := self.GetJob(serviceType, taskId) if err != nil { return "", err } - - status, err := task.GetString("status") - if status == TASK_FAIL { - log.Debugf("task %s failed: %s", taskId, task.String()) - } - - return status, err + return job.Status, nil } // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0022225398.html // 数据结构 entities -> []job -func (self *SRegion) GetAllSubTaskEntityIDs(serviceType string, taskId string, entityKeyName string) ([]string, error) { +func (self *SRegion) GetAllSubTaskEntityIDs(serviceType string, taskId string) ([]string, error) { err := self.waitTaskStatus(serviceType, taskId, TASK_SUCCESS, 10*time.Second, 600*time.Second) if err != nil { return nil, err } - - querys := map[string]string{"service_type": serviceType} - ret, err := self.ecsClient.Jobs.Get(taskId, querys) + job, err := self.GetJob(serviceType, taskId) if err != nil { return nil, err } - - entities, err := ret.GetArray("entities", "sub_jobs") - if err != nil { - return nil, err - } - - ids := make([]string, 0) - for i := range entities { - entity := entities[i] - rid, err := entity.GetString("entities", entityKeyName) - if err != nil { - return nil, err + ret := []string{} + for _, entity := range job.Entities.SubJobs { + if len(entity.VolumeId) > 0 { + ret = append(ret, entity.VolumeId) + } + if len(entity.ServerId) > 0 { + ret = append(ret, entity.ServerId) } - - ids = append(ids, rid) } - - return ids, nil + return ret, nil } // 数据结构 entities -> job -func (self *SRegion) GetTaskEntityID(serviceType string, taskId string, entityKeyName string) (string, error) { +func (self *SRegion) GetTaskEntityID(serviceType string, taskId string, key string) (string, error) { err := self.waitTaskStatus(serviceType, taskId, TASK_SUCCESS, 10*time.Second, 600*time.Second) if err != nil { return "", err } - querys := map[string]string{"service_type": serviceType} - ret, err := self.ecsClient.Jobs.Get(taskId, querys) + job, err := self.GetJob(serviceType, taskId) if err != nil { return "", err } - - return ret.GetString("entities", entityKeyName) + switch key { + case "volume_id": + return job.Entities.VolumeId, nil + case "image_id": + return job.Entities.ImageId, nil + default: + return "", fmt.Errorf("unknown %s", key) + } } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/traces.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/traces.go index 4b6f549072..24ee2aa2a5 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/traces.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/traces.go @@ -16,6 +16,7 @@ package huawei import ( "fmt" + "net/url" "strconv" "time" @@ -112,20 +113,39 @@ func (self *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEve } func (self *SRegion) GetEvents(start time.Time, end time.Time) ([]SEvent, error) { - events := []SEvent{} - params := map[string]string{} + params := url.Values{} if start.IsZero() { start = time.Now().AddDate(0, 0, -7) } if end.IsZero() { end = time.Now() } - params["from"] = fmt.Sprintf("%d000", start.Unix()) - params["to"] = fmt.Sprintf("%d000", end.Unix()) + params.Set("trace_type", "system") + params.Set("from", fmt.Sprintf("%d000", start.Unix())) + params.Set("to", fmt.Sprintf("%d000", end.Unix())) - err := doListAllWithMarker(self.ecsClient.Traces.List, params, &events) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithMarker") + events := []SEvent{} + for { + resp, err := self.list(SERVICE_CTS, "traces", params) + if err != nil { + return nil, errors.Wrapf(err, "list events") + } + part := struct { + Traces []SEvent + MetaData struct { + Marker string + Count int + } + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + events = append(events, part.Traces...) + if len(part.MetaData.Marker) == 0 || len(part.Traces) == 0 || len(events) >= part.MetaData.Count { + break + } + params.Set("marker", part.MetaData.Marker) } return events, nil } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/utils.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/utils.go deleted file mode 100644 index 0475d3242e..0000000000 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/utils.go +++ /dev/null @@ -1,270 +0,0 @@ -// 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 huawei - -import ( - "fmt" - "reflect" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/httputils" - "yunion.io/x/pkg/utils" - - "yunion.io/x/cloudmux/pkg/cloudprovider" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" - "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" -) - -// 常用的方法 -type listFunc func(querys map[string]string) (*responses.ListResult, error) -type getFunc func(id string, querys map[string]string) (jsonutils.JSONObject, error) -type createFunc func(params jsonutils.JSONObject) (jsonutils.JSONObject, error) -type updateFunc func(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) -type updateFunc2 func(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) -type deleteFunc func(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) -type deleteFunc2 func(ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) -type listInCtxFunc func(ctx manager.IManagerContext, querys map[string]string) (*responses.ListResult, error) -type listInCtxWithSpecFunc func(ctx manager.IManagerContext, spec string, querys map[string]string, responseKey string) (*responses.ListResult, error) - -func unmarshalResult(resp jsonutils.JSONObject, respErr error, result interface{}, method string) error { - if respErr != nil { - switch e := respErr.(type) { - case *httputils.JSONClientError: - if (e.Code == 404 || utils.IsInStringArray(e.Class, NOT_FOUND_CODES)) && method != "POST" { - return cloudprovider.ErrNotFound - } - return e - default: - return e - } - } - - if result == nil { - return nil - } - - err := resp.Unmarshal(result) - if err != nil { - log.Errorf("unmarshal json error %s", err) - } - - return err -} - -var pageLimit = 100 - -// offset 表示的是页码 -func doListAllWithPagerOffset(doList listFunc, queries map[string]string, result interface{}) error { - startIndex := 0 - resultValue := reflect.Indirect(reflect.ValueOf(result)) - queries["limit"] = fmt.Sprintf("%d", pageLimit) - queries["offset"] = fmt.Sprintf("%d", startIndex) - for { - total, part, err := doListPart(doList, queries, result) - if err != nil { - return err - } - if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { - break - } - - startIndex++ - queries["offset"] = fmt.Sprintf("%d", startIndex) - } - return nil -} - -func doListAllWithNextLink(doList listFunc, querys map[string]string, result interface{}) error { - values := []jsonutils.JSONObject{} - for { - ret, err := doList(querys) - if err != nil { - return errors.Wrap(err, "doList") - } - values = append(values, ret.Data...) - if len(ret.NextLink) == 0 || ret.NextLink == "null" { - break - } - } - if result != nil { - return jsonutils.Update(result, values) - } - return nil -} - -func doListAllWithOffset(doList listFunc, queries map[string]string, result interface{}) error { - startIndex := 0 - resultValue := reflect.Indirect(reflect.ValueOf(result)) - queries["limit"] = fmt.Sprintf("%d", pageLimit) - queries["offset"] = fmt.Sprintf("%d", startIndex) - for { - total, part, err := doListPart(doList, queries, result) - if err != nil { - return err - } - if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { - break - } - queries["offset"] = fmt.Sprintf("%d", startIndex+resultValue.Len()) - } - return nil -} - -func doListAllWithPage(doList listFunc, queries map[string]string, result interface{}) error { - startIndex := 1 - resultValue := reflect.Indirect(reflect.ValueOf(result)) - queries["limit"] = fmt.Sprintf("%d", pageLimit) - queries["page"] = fmt.Sprintf("%d", startIndex) - for { - total, part, err := doListPart(doList, queries, result) - if err != nil { - return err - } - if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { - break - } - queries["page"] = fmt.Sprintf("%d", startIndex+resultValue.Len()) - } - return nil -} - -func doListAllWithMarker(doList listFunc, queries map[string]string, result interface{}) error { - resultValue := reflect.Indirect(reflect.ValueOf(result)) - queries["limit"] = fmt.Sprintf("%d", pageLimit) - for { - total, part, err := doListPart(doList, queries, result) - if err != nil { - return err - } - if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { - break - } - lastValue := resultValue.Index(resultValue.Len() - 1) - markerValue := lastValue.FieldByNameFunc(func(key string) bool { - if strings.ToLower(key) == "id" { - return true - } - return false - }) - queries["marker"] = markerValue.String() - } - return nil -} - -func doListAll(doList listFunc, queries map[string]string, result interface{}) error { - total, _, err := doListPart(doList, queries, result) - if err != nil { - return err - } - resultValue := reflect.Indirect(reflect.ValueOf(result)) - if total > 0 && resultValue.Len() < total { - log.Warningf("INCOMPLETE QUERY, total %d queried %d", total, resultValue.Len()) - } - return nil -} - -func doListPart(doList listFunc, queries map[string]string, result interface{}) (int, int, error) { - ret, err := doList(queries) - if err != nil { - return 0, 0, err - } - resultValue := reflect.Indirect(reflect.ValueOf(result)) - elemType := resultValue.Type().Elem() - for i := range ret.Data { - elemPtr := reflect.New(elemType) - err = ret.Data[i].Unmarshal(elemPtr.Interface()) - if err != nil { - return 0, 0, err - } - resultValue.Set(reflect.Append(resultValue, elemPtr.Elem())) - } - return ret.Total, len(ret.Data), nil -} - -func DoGet(doGet getFunc, id string, queries map[string]string, result interface{}) error { - if len(id) == 0 { - resultType := reflect.Indirect(reflect.ValueOf(result)).Type() - return errors.Wrap(cloudprovider.ErrNotFound, fmt.Sprintf(" Get %s id should not be empty", resultType.Name())) - } - - ret, err := doGet(id, queries) - return unmarshalResult(ret, err, result, "GET") -} - -func DoListInContext(listFunc listInCtxFunc, ctx manager.IManagerContext, querys map[string]string, result interface{}) error { - ret, err := listFunc(ctx, querys) - if err != nil { - return err - } - - obj := responses.ListResult2JSON(ret) - err = obj.Unmarshal(result, "data") - if err != nil { - log.Errorf("unmarshal json error %s", err) - return err - } - - return nil -} - -func DoCreate(createFunc createFunc, params jsonutils.JSONObject, result interface{}) error { - ret, err := createFunc(params) - return unmarshalResult(ret, err, result, "POST") -} - -func DoUpdate(updateFunc updateFunc, id string, params jsonutils.JSONObject, result interface{}) error { - ret, err := updateFunc(id, params) - return unmarshalResult(ret, err, result, "PUT") -} - -func DoUpdateWithSpec(updateFunc updateFunc2, id string, spec string, params jsonutils.JSONObject) error { - _, err := updateFunc(nil, id, spec, params, "") - return err -} - -func DoUpdateWithSpec2(updateFunc updateFunc2, id string, spec string, params jsonutils.JSONObject, result interface{}) error { - ret, err := updateFunc(nil, id, spec, params, "") - return unmarshalResult(ret, err, result, "PUT") -} - -func DoDelete(deleteFunc deleteFunc, id string, params jsonutils.JSONObject, result interface{}) error { - if len(id) == 0 { - return fmt.Errorf(" id should not be empty") - } - - ret, err := deleteFunc(id, params) - return unmarshalResult(ret, err, result, "DELETE") -} - -func DoDeleteWithSpec(deleteFunc deleteFunc2, ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject) error { - if len(id) == 0 { - return fmt.Errorf(" id should not be empty") - } - - _, err := deleteFunc(ctx, id, spec, queries, params, "") - return err -} - -func ErrMessage(err error) string { - switch v := err.(type) { - case *httputils.JSONClientError: - return fmt.Sprintf("%d(%s):%s", v.Code, v.Class, v.Details) - default: - return err.Error() - } -} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc.go index 497025d16c..e73d2a4ec0 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc.go @@ -15,7 +15,7 @@ package huawei import ( - "strings" + "net/url" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -32,8 +32,6 @@ type SVpc struct { region *SRegion - iwires []cloudprovider.ICloudWire - ID string `json:"id"` Name string `json:"name"` CIDR string `json:"cidr"` @@ -41,49 +39,6 @@ type SVpc struct { EnterpriseProjectID string `json:"enterprise_project_id"` } -func (self *SVpc) addWire(wire *SWire) { - if self.iwires == nil { - self.iwires = make([]cloudprovider.ICloudWire, 0) - } - self.iwires = append(self.iwires, wire) -} - -func (self *SVpc) getWireByRegionId(regionId string) *SWire { - if len(regionId) == 0 { - return nil - } - - for i := 0; i < len(self.iwires); i++ { - wire := self.iwires[i].(*SWire) - - if wire.region.GetId() == regionId { - return wire - } - } - - return nil -} - -func (self *SVpc) fetchNetworks() error { - networks, err := self.region.GetNetwroks(self.ID) - if err != nil { - return err - } - - // ??????? - if len(networks) == 0 { - self.iwires = append(self.iwires, &SWire{region: self.region, vpc: self}) - return nil - } - - for i := 0; i < len(networks); i += 1 { - wire := self.getWireByRegionId(self.region.GetId()) - networks[i].wire = wire - wire.addNetwork(&networks[i]) - } - return nil -} - func (self *SVpc) GetId() string { return self.ID } @@ -104,15 +59,11 @@ func (self *SVpc) GetStatus() string { } func (self *SVpc) Refresh() error { - new, err := self.region.getVpc(self.GetId()) + vpc, err := self.region.GetVpc(self.GetId()) if err != nil { return err } - return jsonutils.Update(self, new) -} - -func (self *SVpc) IsEmulated() bool { - return false + return jsonutils.Update(self, vpc) } func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { @@ -120,7 +71,6 @@ func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { } func (self *SVpc) GetIsDefault() bool { - // 华为云没有default vpc. return false } @@ -129,13 +79,7 @@ func (self *SVpc) GetCidrBlock() string { } func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - if self.iwires == nil { - err := self.fetchNetworks() - if err != nil { - return nil, err - } - } - return self.iwires, nil + return []cloudprovider.ICloudWire{&SWire{vpc: self}}, nil } func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { @@ -165,23 +109,20 @@ func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudR } func (self *SVpc) Delete() error { - // todo: 确定删除VPC的逻辑 return self.region.DeleteVpc(self.GetId()) } func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { - if self.iwires == nil { - err := self.fetchNetworks() - if err != nil { - return nil, err + wires, err := self.GetIWires() + if err != nil { + return nil, err + } + for i := range wires { + if wires[i].GetGlobalId() == wireId { + return wires[i], nil } } - for i := 0; i < len(self.iwires); i += 1 { - if self.iwires[i].GetGlobalId() == wireId { - return self.iwires[i], nil - } - } - return nil, cloudprovider.ErrNotFound + return nil, errors.Wrapf(cloudprovider.ErrNotFound, wireId) } func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { @@ -191,6 +132,7 @@ func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { } ret := make([]cloudprovider.ICloudNatGateway, len(nats)) for i := 0; i < len(nats); i++ { + nats[i].region = self.region ret[i] = &nats[i] } return ret, nil @@ -297,44 +239,48 @@ func (self *SVpc) getVpcPeeringConnectionById(id string) (*SVpcPeering, error) { return svpcPC, nil } -func (self *SRegion) getVpc(vpcId string) (*SVpc, error) { - vpc := SVpc{} - err := DoGet(self.ecsClient.Vpcs.Get, vpcId, nil, &vpc) - if err != nil && strings.Contains(err.Error(), "RouterNotFound") { - return nil, cloudprovider.ErrNotFound - } - vpc.region = self - return &vpc, err -} - -func (self *SRegion) DeleteVpc(vpcId string) error { - if vpcId != "default" { - secgroups, err := self.GetSecurityGroups(vpcId, "") - if err != nil { - return errors.Wrap(err, "GetSecurityGroups") - } - for _, secgroup := range secgroups { - err = self.DeleteSecurityGroup(secgroup.Id) - if err != nil { - return errors.Wrapf(err, "DeleteSecurityGroup(%s)", secgroup.Id) - } - } - } - return DoDelete(self.ecsClient.Vpcs.Delete, vpcId, nil, nil) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html -func (self *SRegion) GetVpcs() ([]SVpc, error) { - querys := make(map[string]string) - - vpcs := make([]SVpc, 0) - err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs) +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v3&api=ShowVpc +func (self *SRegion) GetVpc(vpcId string) (*SVpc, error) { + resp, err := self.list(SERVICE_VPC_V3, "vpc/vpcs/"+vpcId, nil) if err != nil { return nil, err } - - for i := range vpcs { - vpcs[i].region = self + ret := &SVpc{region: self} + err = resp.Unmarshal(ret, "vpc") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") } - return vpcs, err + return ret, nil +} + +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=DeleteVpc +func (self *SRegion) DeleteVpc(vpcId string) error { + _, err := self.delete(SERVICE_VPC, "vpcs/"+vpcId) + return err +} + +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v3&api=ListVpcs +func (self *SRegion) GetVpcs() ([]SVpc, error) { + ret := make([]SVpc, 0) + query := url.Values{} + for { + resp, err := self.list(SERVICE_VPC_V3, "vpc/vpcs", query) + if err != nil { + return nil, err + } + part := struct { + Vpcs []SVpc + PageInfo sPageInfo + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, err + } + ret = append(ret, part.Vpcs...) + if len(part.Vpcs) == 0 || len(part.PageInfo.NextMarker) == 0 { + break + } + query.Set("marker", part.PageInfo.NextMarker) + } + return ret, nil } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc_peering.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc_peering.go index 841c385b2a..9c89ff374a 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc_peering.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc_peering.go @@ -15,6 +15,9 @@ package huawei import ( + "fmt" + "net/url" + "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -43,64 +46,85 @@ type SVpcPeering struct { Status string `json:"status"` } +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=ListVpcPeerings func (self *SRegion) GetVpcPeerings(vpcId string) ([]SVpcPeering, error) { - querys := make(map[string]string) - querys["vpc_id"] = vpcId - vpcPeerings := make([]SVpcPeering, 0) - err := doListAllWithMarker(self.ecsClient.VpcPeerings.List, querys, &vpcPeerings) - if err != nil { - return nil, errors.Wrapf(err, "oListAllWithMarker(self.ecsClient.VpcPeerings.List, %s, &vpcPeerings)", jsonutils.Marshal(querys).String()) + query := url.Values{} + if len(vpcId) > 0 { + query.Set("vpc_id", vpcId) } - return vpcPeerings, nil + ret := make([]SVpcPeering, 0) + for { + resp, err := self.list(SERVICE_VPC_V2_0, "vpc/peerings", query) + if err != nil { + return nil, err + } + part := []SVpcPeering{} + err = resp.Unmarshal(&part, "peerings") + if err != nil { + return nil, err + } + ret = append(ret, part...) + if len(part) == 0 { + break + } + query.Set("marker", part[len(part)-1].ID) + } + return ret, nil } -func (self *SRegion) GetVpcPeering(vpcPeeringId string) (*SVpcPeering, error) { - if len(vpcPeeringId) == 0 { - return nil, cloudprovider.ErrNotFound - } - vpcPeering := SVpcPeering{} - err := DoGet(self.ecsClient.VpcPeerings.Get, vpcPeeringId, nil, &vpcPeering) +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=ListVpcPeerings +func (self *SRegion) GetVpcPeering(id string) (*SVpcPeering, error) { + ret := &SVpcPeering{} + resp, err := self.list(SERVICE_VPC_V2_0, "vpc/peerings/"+id, nil) if err != nil { - return nil, errors.Wrapf(err, "DoGet(self.ecsClient.VpcPeerings.Get, %s, nil, &vpcPeering)", vpcPeeringId) + return nil, err } - return &vpcPeering, nil + err = resp.Unmarshal(ret, "peering") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + return ret, nil } +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=CreateVpcPeering func (self *SRegion) CreateVpcPeering(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPeering, error) { - params := jsonutils.NewDict() - vpcPeeringObj := jsonutils.NewDict() - requestVpcObj := jsonutils.NewDict() - acceptVpcObj := jsonutils.NewDict() - vpcPeeringObj.Set("name", jsonutils.NewString(opts.Name)) - requestVpcObj.Set("vpc_id", jsonutils.NewString(vpcId)) - requestVpcObj.Set("tenant_id", jsonutils.NewString(self.client.projectId)) - vpcPeeringObj.Set("request_vpc_info", requestVpcObj) - acceptVpcObj.Set("vpc_id", jsonutils.NewString(opts.PeerVpcId)) - acceptVpcObj.Set("tenant_id", jsonutils.NewString(opts.PeerAccountId)) - vpcPeeringObj.Set("accept_vpc_info", acceptVpcObj) - params.Set("peering", vpcPeeringObj) - ret := SVpcPeering{} - err := DoCreate(self.ecsClient.VpcPeerings.Create, params, &ret) - if err != nil { - return nil, errors.Wrapf(err, "DoCreate(self.ecsClient.VpcPeerings.Create, %s, &ret)", jsonutils.Marshal(params).String()) + 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, + }, + "accept_vpc_info": map[string]interface{}{ + "vpc_id": opts.PeerVpcId, + "tenant_id": opts.PeerAccountId, + }, + }, } - return &ret, nil + resp, err := self.post(SERVICE_VPC_V2_0, "vpc/peerings", params) + if err != nil { + return nil, err + } + ret := &SVpcPeering{} + err = resp.Unmarshal(ret, "peering") + if err != nil { + return nil, err + } + return ret, nil } -func (self *SRegion) AcceptVpcPeering(vpcPeeringId string) error { - err := DoUpdateWithSpec(self.ecsClient.VpcPeerings.UpdateInContextWithSpec, vpcPeeringId, "accept", nil) - if err != nil { - return errors.Wrapf(err, "DoUpdateWithSpec(self.ecsClient.VpcPeerings.UpdateInContextWithSpec, %s, accept, nil)", vpcPeeringId) - } - return nil +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=AcceptVpcPeering +func (self *SRegion) AcceptVpcPeering(id string) error { + res := fmt.Sprintf("vpc/peerings/%s/accept", id) + _, err := self.put(SERVICE_VPC_V2_0, res, nil) + return err } -func (self *SRegion) DeleteVpcPeering(vpcPeeringId string) error { - err := DoDelete(self.ecsClient.VpcPeerings.Delete, vpcPeeringId, nil, nil) - if err != nil { - return errors.Wrapf(err, "DoDelete(self.ecsClient.VpcPeerings.Delete,%s,nil)", vpcPeeringId) - } - return nil +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=DeleteVpcPeering +func (self *SRegion) DeleteVpcPeering(id string) error { + _, err := self.delete(SERVICE_VPC_V2_0, "vpc/peerings/"+id) + return err } func (self *SVpcPeering) GetId() string { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/wire.go index e2fa7b02bd..bd23a3f454 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/wire.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/wire.go @@ -16,10 +16,7 @@ package huawei import ( "fmt" - "time" - "yunion.io/x/jsonutils" - "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/netutils" @@ -32,14 +29,12 @@ import ( type SWire struct { multicloud.SResourceBase HuaweiTags - region *SRegion - vpc *SVpc - inetworks []cloudprovider.ICloudNetwork + vpc *SVpc } func (self *SWire) GetId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId()) + return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.vpc.region.GetId()) } func (self *SWire) GetName() string { @@ -47,7 +42,7 @@ func (self *SWire) GetName() string { } func (self *SWire) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId()) + return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.vpc.region.GetGlobalId()) } func (self *SWire) GetStatus() string { @@ -71,93 +66,39 @@ func (self *SWire) GetIZone() cloudprovider.ICloudZone { } func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - if self.inetworks == nil { - err := self.vpc.fetchNetworks() - if err != nil { - return nil, err - } + networks, err := self.vpc.region.GetNetworks(self.vpc.ID) + if err != nil { + return nil, errors.Wrapf(err, "GetNetwroks") } - return self.inetworks, nil + ret := []cloudprovider.ICloudNetwork{} + for i := range networks { + networks[i].wire = self + ret = append(ret, &networks[i]) + } + return ret, nil } func (self *SWire) GetBandwidth() int { return 10000 } -func (self *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { - networks, err := self.GetINetworks() +func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { + network, err := self.vpc.region.GetNetwork(id) if err != nil { return nil, err } - for i := 0; i < len(networks); i += 1 { - if networks[i].GetGlobalId() == netid { - return networks[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -/* -华为云子网可用区,类似一个zone标签。即使指定了zone子网在整个region依然是可用。 -通过华为web控制台创建子网需要指定可用区。这里是不指定的。 -*/ -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - networkId, err := self.region.createNetwork(self.vpc.GetId(), opts.Name, opts.Cidr, opts.Desc) - if err != nil { - log.Errorf("createNetwork error %s", err) - return nil, err - } - - var network *SNetwork - err = cloudprovider.WaitCreated(5*time.Second, 60*time.Second, func() bool { - self.inetworks = nil - network = self.getNetworkById(networkId) - if network == nil { - return false - } else { - return true - } - }) - - if err != nil { - log.Errorf("cannot find network after create????") - return nil, err - } - network.wire = self return network, nil } -func (self *SWire) addNetwork(network *SNetwork) { - if self.inetworks == nil { - self.inetworks = make([]cloudprovider.ICloudNetwork, 0) - } - find := false - for i := 0; i < len(self.inetworks); i += 1 { - if self.inetworks[i].GetId() == network.ID { - find = true - break - } - } - if !find { - self.inetworks = append(self.inetworks, network) - } -} - -func (self *SWire) getNetworkById(networkId string) *SNetwork { - networks, err := self.GetINetworks() +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + network, err := self.vpc.region.CreateNetwork(self.vpc.ID, opts) if err != nil { - return nil + return nil, errors.Wrapf(err, "CreateNetwork") } - log.Debugf("search for networks %d", len(networks)) - for i := 0; i < len(networks); i += 1 { - log.Debugf("search %s", networks[i].GetName()) - network := networks[i] - if network.GetId() == networkId { - return network.(*SNetwork) - } - } - return nil + + network.wire = self + return network, nil } func getDefaultGateWay(cidr string) (string, error) { @@ -170,23 +111,28 @@ func getDefaultGateWay(cidr string) (string, error) { return startIp.String(), nil } -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html -// cidr 掩码长度不能大于28 -func (self *SRegion) createNetwork(vpcId string, name string, cidr string, desc string) (string, error) { - gateway, err := getDefaultGateWay(cidr) +// https://console.huaweicloud.com/apiexplorer/#/openapi/VPC/doc?version=v2&api=ListSubnets +func (self *SRegion) CreateNetwork(vpcId string, opts *cloudprovider.SNetworkCreateOptions) (*SNetwork, error) { + gateway, err := getDefaultGateWay(opts.Cidr) if err != nil { - return "", err + return nil, err } - params := jsonutils.NewDict() - subnetObj := jsonutils.NewDict() - subnetObj.Add(jsonutils.NewString(name), "name") - subnetObj.Add(jsonutils.NewString(vpcId), "vpc_id") - subnetObj.Add(jsonutils.NewString(cidr), "cidr") - subnetObj.Add(jsonutils.NewString(gateway), "gateway_ip") - params.Add(subnetObj, "subnet") - - subnet := SNetwork{} - err = DoCreate(self.ecsClient.Subnets.Create, params, &subnet) - return subnet.ID, err + params := map[string]interface{}{ + "name": opts.Name, + "description": opts.Desc, + "vpc_id": vpcId, + "cidr": opts.Cidr, + "gateway_ip": gateway, + } + resp, err := self.post(SERVICE_VPC, "subnets", map[string]interface{}{"subnet": params}) + if err != nil { + return nil, errors.Wrapf(err, "create subnet") + } + subnet := &SNetwork{} + err = resp.Unmarshal(subnet, "subnet") + if err != nil { + return nil, err + } + return subnet, nil } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/zone.go index e9ccd74d46..83a5fc11a5 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/zone.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/zone.go @@ -42,7 +42,6 @@ type SZone struct { region *SRegion host *SHost - iwires []cloudprovider.ICloudWire istorages []cloudprovider.ICloudStorage ZoneState ZoneState `json:"zoneState"` @@ -52,13 +51,6 @@ type SZone struct { storageTypes []string } -func (self *SZone) addWire(wire *SWire) { - if self.iwires == nil { - self.iwires = make([]cloudprovider.ICloudWire, 0) - } - self.iwires = append(self.iwires, wire) -} - func (self *SZone) getStorageType() { if len(self.storageTypes) == 0 { if sts, err := self.region.GetZoneSupportedDiskTypes(self.GetId()); err == nil { @@ -161,7 +153,16 @@ func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, erro } func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { - return self.iwires, nil + vpcs, err := self.region.GetVpcs() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudWire{} + for i := range vpcs { + vpcs[i].region = self.region + ret = append(ret, &SWire{vpc: &vpcs[i]}) + } + return ret, nil } func (self *SZone) getStorageByCategory(category string) (*SStorage, error) { @@ -191,14 +192,3 @@ func (self *SRegion) getZoneById(id string) (*SZone, error) { } return nil, fmt.Errorf("no such zone %s", id) } - -func (self *SZone) getNetworkById(networkId string) *SNetwork { - for i := 0; i < len(self.iwires); i += 1 { - wire := self.iwires[i].(*SWire) - net := wire.getNetworkById(networkId) - if net != nil { - return net - } - } - return nil -}