From 73dc3a6a383424abe7fc8fce0aa67cc0984ea8bc Mon Sep 17 00:00:00 2001 From: Qu Xuan Date: Thu, 26 Dec 2019 18:23:46 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=94=AF=E6=8C=81=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E7=BB=8F=E5=85=B8=E7=BD=91=E7=BB=9Cip=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/apis/compute/storage_const.go | 1 + pkg/cloudprovider/resources.go | 1 + pkg/compute/guestdrivers/qcloud.go | 10 ++- pkg/compute/models/guests.go | 12 ++++ pkg/compute/models/networks.go | 37 ++++++++++ pkg/compute/models/vpcs.go | 37 ++++++++++ pkg/compute/models/wires.go | 49 +++++++++++++ pkg/multicloud/aliyun/instancenic.go | 4 ++ pkg/multicloud/aws/instancenic.go | 4 ++ pkg/multicloud/azure/classic_instancenic.go | 4 ++ pkg/multicloud/azure/classic_network.go | 2 +- pkg/multicloud/azure/classic_vpc.go | 6 +- pkg/multicloud/azure/instancenic.go | 4 ++ pkg/multicloud/ctyun/instancenic.go | 4 ++ pkg/multicloud/esxi/vnic.go | 4 ++ pkg/multicloud/google/instancenic.go | 4 ++ pkg/multicloud/huawei/instancenic.go | 4 ++ pkg/multicloud/openstack/instancenic.go | 4 ++ pkg/multicloud/qcloud/instance.go | 10 ++- pkg/multicloud/qcloud/instancenic.go | 5 ++ pkg/multicloud/qcloud/instancetype.go | 76 ++++++++++++++++++++- pkg/multicloud/qcloud/shell/zone.go | 14 ++++ pkg/multicloud/qcloud/zone.go | 25 ++++--- pkg/multicloud/ucloud/instancenic.go | 4 ++ pkg/multicloud/zstack/instancenic.go | 4 ++ 25 files changed, 308 insertions(+), 21 deletions(-) diff --git a/pkg/apis/compute/storage_const.go b/pkg/apis/compute/storage_const.go index 752aa6f827..0b538be322 100644 --- a/pkg/apis/compute/storage_const.go +++ b/pkg/apis/compute/storage_const.go @@ -49,6 +49,7 @@ const ( // STORAGE_CLOUD_SSD ="cloud_ssd" STORAGE_LOCAL_BASIC = "local_basic" STORAGE_LOCAL_SSD = "local_ssd" + STORAGE_LOCAL_PRO = "local_pro" STORAGE_CLOUD_BASIC = "cloud_basic" STORAGE_CLOUD_PREMIUM = "cloud_premium" diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index 999c2d7bea..a9f176e79e 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -305,6 +305,7 @@ type ICloudVM interface { type ICloudNic interface { GetIP() string GetMAC() string + InClassicNetwork() bool GetDriver() string GetINetwork() ICloudNetwork } diff --git a/pkg/compute/guestdrivers/qcloud.go b/pkg/compute/guestdrivers/qcloud.go index 7abc0e5eb2..983510ec35 100644 --- a/pkg/compute/guestdrivers/qcloud.go +++ b/pkg/compute/guestdrivers/qcloud.go @@ -107,7 +107,7 @@ func (self *SQcloudGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *m if disk.DiskType == api.DISK_TYPE_SYS { return fmt.Errorf("Cannot resize system disk") } - if utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_LOCAL_BASIC, api.STORAGE_LOCAL_SSD}) { + if utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_LOCAL_BASIC, api.STORAGE_LOCAL_SSD, api.STORAGE_LOCAL_PRO}) { return fmt.Errorf("Cannot resize %s disk", storage.StorageType) } if disk.DiskSize/1024%10 > 0 { @@ -135,6 +135,8 @@ func (self *SQcloudGuestDriver) ValidateCreateData(ctx context.Context, userCred if sysDisk.SizeMb > 1024*1024 { return nil, fmt.Errorf("The %s system disk size must be less than 1024GB", sysDisk.Backend) } + case api.STORAGE_LOCAL_PRO: + return nil, fmt.Errorf("storage %s can not be system disk", sysDisk.Backend) } for i := 1; i < len(input.Disks); i++ { @@ -152,6 +154,8 @@ func (self *SQcloudGuestDriver) ValidateCreateData(ctx context.Context, userCred if disk.SizeMb < 100*1024 || disk.SizeMb > 16000*1024 { return nil, httperrors.NewInputParameterError("The %s disk size must be in the range of 100GB ~ 16000GB", disk.Backend) } + case api.STORAGE_LOCAL_PRO: + return nil, httperrors.NewInputParameterError("storage %s can not be data disk") } if disk.SizeMb/1024%10 > 0 { return nil, httperrors.NewInputParameterError("Data disk size must be an integer multiple of 10G") @@ -171,7 +175,7 @@ func (self *SQcloudGuestDriver) ValidateChangeConfig(ctx context.Context, userCr return httperrors.NewResourceNotFoundError("failed to found storage for disk %s(%s)", disk.Name, disk.Id) } // 腾讯云系统盘为本地存储,不支持调整配置 - if utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_LOCAL_BASIC, api.STORAGE_LOCAL_SSD}) { + if utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_LOCAL_BASIC, api.STORAGE_LOCAL_SSD, api.STORAGE_LOCAL_PRO}) { return httperrors.NewUnsupportOperationError("The system disk is locally stored and does not support changing configuration") } } @@ -190,7 +194,7 @@ func (self *SQcloudGuestDriver) ValidateChangeConfig(ctx context.Context, userCr if newDisk.SizeMb < 100*1024 || newDisk.SizeMb > 16000*1024 { return httperrors.NewInputParameterError("The %s disk size must be in the range of 100GB ~ 16000GB", newDisk.Backend) } - case api.STORAGE_LOCAL_BASIC, api.STORAGE_LOCAL_SSD: + case api.STORAGE_LOCAL_BASIC, api.STORAGE_LOCAL_SSD, api.STORAGE_LOCAL_PRO: return httperrors.NewUnsupportOperationError("Not support create local storage disks") case "": //这里Backend为空有可能会导致创建出来还是local storage,依然会出错,需要用户显式指定 return httperrors.NewInputParameterError("Please input new disk backend type") diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 1c14eb1f0b..c727703465 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -2623,6 +2623,18 @@ type sAddGuestnic struct { func getCloudNicNetwork(vnic cloudprovider.ICloudNic, host *SHost, ipList []string, index int) (*SNetwork, error) { vnet := vnic.GetINetwork() if vnet == nil { + if vnic.InClassicNetwork() { + vpc, err := VpcManager.NewVpcForClassicNetwork(host) + if err != nil { + return nil, errors.Wrap(err, "NewVpcForClassicNetwork") + } + zone := host.GetZone() + wire, err := WireManager.NewWireForClassicNetwork(vpc, zone) + if err != nil { + return nil, errors.Wrap(err, "NewWireForClassicNetwork") + } + return NetworkManager.NewClassicNetwork(wire) + } ip := vnic.GetIP() if len(ip) == 0 { if index < len(ipList) { diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index 3b6610a670..8074d59776 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -275,6 +275,39 @@ func (self *SNetwork) GetNetworkInterfacesCount() (int, error) { return NetworkInterfaceManager.Query().In("id", sq).CountWithError() } +func (manager *SNetworkManager) NewClassicNetwork(wire *SWire) (*SNetwork, error) { + _network, err := db.FetchByExternalId(manager, wire.Id) + if err == nil { + return _network.(*SNetwork), nil + } + if errors.Cause(err) != sql.ErrNoRows { + return nil, errors.Wrap(err, "db.FetchByExternalId") + } + network := SNetwork{ + GuestIpStart: "0.0.0.0", + GuestIpEnd: "255.255.255.255", + GuestIpMask: 0, + GuestGateway: "0.0.0.0", + WireId: wire.Id, + ServerType: api.NETWORK_TYPE_GUEST, + } + network.SetModelManager(manager, &network) + network.Name = fmt.Sprintf("emulate network for classic network with wire %s", wire.Id) + network.ExternalId = wire.Id + network.IsEmulated = true + network.IsPublic = true + network.PublicScope = "system" + admin := auth.AdminCredential() + network.DomainId = admin.GetProjectDomainId() + network.ProjectId = admin.GetProjectId() + network.Status = api.NETWORK_STATUS_UNAVAILABLE + err = manager.TableSpec().Insert(&network) + if err != nil { + return nil, errors.Wrap(err, "Insert classic network") + } + return &network, nil +} + func (self *SNetwork) GetUsedAddresses() map[string]bool { used := make(map[string]bool) @@ -588,6 +621,10 @@ func (self *SNetwork) syncRemoveCloudNetwork(ctx context.Context, userCred mccli lockman.LockObject(ctx, self) defer lockman.ReleaseObject(ctx, self) + if self.ExternalId == self.WireId { + return nil + } + err := self.ValidateDeleteCondition(ctx) if err != nil { // cannot delete err = self.SetStatus(userCred, api.NETWORK_STATUS_UNKNOWN, "Sync to remove") diff --git a/pkg/compute/models/vpcs.go b/pkg/compute/models/vpcs.go index d8d55ef6cb..f66f8c898f 100644 --- a/pkg/compute/models/vpcs.go +++ b/pkg/compute/models/vpcs.go @@ -176,6 +176,39 @@ func (self *SVpc) GetWires() []SWire { return wires } +func (manager *SVpcManager) getVpcExternalIdForClassicNetwork(regionId, cloudproviderId string) string { + return fmt.Sprintf("%s-%s", regionId, cloudproviderId) +} + +func (manager *SVpcManager) NewVpcForClassicNetwork(host *SHost) (*SVpc, error) { + region := host.GetRegion() + cloudprovider := host.GetCloudprovider() + externalId := manager.getVpcExternalIdForClassicNetwork(region.Id, cloudprovider.Id) + _vpc, err := db.FetchByExternalId(manager, externalId) + if err == nil { + return _vpc.(*SVpc), nil + } + if errors.Cause(err) != sql.ErrNoRows { + return nil, errors.Wrap(err, "db.FetchByExternalId") + } + vpc := &SVpc{ + IsDefault: false, + CloudregionId: region.Id, + } + vpc.SetModelManager(manager, vpc) + vpc.Name = fmt.Sprintf("emulated vpc for %s %s classic network", region.Name, cloudprovider.Name) + vpc.IsEmulated = true + vpc.Enabled = false + vpc.Status = api.VPC_STATUS_UNAVAILABLE + vpc.ExternalId = externalId + vpc.ManagerId = host.ManagerId + err = manager.TableSpec().Insert(vpc) + if err != nil { + return nil, errors.Wrap(err, "Insert vpc for classic network") + } + return vpc, nil +} + func (self *SVpc) getNetworkQuery() *sqlchemy.SQuery { q := NetworkManager.Query() wireQ := self.getWireQuery().SubQuery() @@ -383,6 +416,10 @@ func (self *SVpc) syncRemoveCloudVpc(ctx context.Context, userCred mcclient.Toke lockman.LockObject(ctx, self) defer lockman.ReleaseObject(ctx, self) + if VpcManager.getVpcExternalIdForClassicNetwork(self.CloudregionId, self.ManagerId) == self.ExternalId { //为经典网络虚拟的vpc + return nil + } + err := self.ValidateDeleteCondition(ctx) if err != nil { // cannot delete self.markAllNetworksUnknown(userCred) diff --git a/pkg/compute/models/wires.go b/pkg/compute/models/wires.go index 302e91de41..5272ac3237 100644 --- a/pkg/compute/models/wires.go +++ b/pkg/compute/models/wires.go @@ -25,6 +25,7 @@ import ( "yunion.io/x/pkg/tristate" "yunion.io/x/pkg/util/compare" "yunion.io/x/pkg/util/netutils" + "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/apis" @@ -171,6 +172,48 @@ func (wire *SWire) ValidateDeleteCondition(ctx context.Context) error { return wire.SStandaloneResourceBase.ValidateDeleteCondition(ctx) } +func (manager *SWireManager) getWireExternalIdForClassicNetwork(provider string, vpcId string, zoneId string) string { + if !utils.IsInStringArray(provider, api.REGIONAL_NETWORK_PROVIDERS) { + return fmt.Sprintf("%s-%s", vpcId, zoneId) + } + return vpcId +} + +func (manager *SWireManager) NewWireForClassicNetwork(vpc *SVpc, zone *SZone) (*SWire, error) { + cloudprovider := vpc.GetCloudprovider() + if cloudprovider == nil { + return nil, fmt.Errorf("failed to found cloudprovider for vpc %s(%s)", vpc.Id, vpc.Id) + } + externalId := manager.getWireExternalIdForClassicNetwork(cloudprovider.Provider, vpc.Id, zone.Id) + name := fmt.Sprintf("emulate for vpc %s classic network", vpc.Id) + zoneId := zone.Id + if utils.IsInStringArray(cloudprovider.Provider, api.REGIONAL_NETWORK_PROVIDERS) { //reginal network + zoneId = "" + } else { + name = fmt.Sprintf("emulate for zone %s vpc %s classic network", zone.Name, vpc.Id) + } + _wire, err := db.FetchByExternalId(manager, externalId) + if err == nil { + return _wire.(*SWire), nil + } + if errors.Cause(err) != sql.ErrNoRows { + return nil, errors.Wrap(err, "db.FetchByExternalId") + } + wire := &SWire{ + VpcId: vpc.Id, + ZoneId: zoneId, + } + wire.SetModelManager(manager, wire) + wire.ExternalId = externalId + wire.IsEmulated = true + wire.Name = name + err = manager.TableSpec().Insert(wire) + if err != nil { + return nil, errors.Wrap(err, "Insert wire for classic network") + } + return wire, nil +} + func (wire *SWire) getHostwireQuery() *sqlchemy.SQuery { return HostwireManager.Query().Equals("wire_id", wire.Id) } @@ -289,6 +332,12 @@ func (self *SWire) syncRemoveCloudWire(ctx context.Context, userCred mcclient.To lockman.LockObject(ctx, self) defer lockman.ReleaseObject(ctx, self) + vpc := self.getVpc() + cloudprovider := vpc.GetCloudprovider() + if self.ExternalId == WireManager.getWireExternalIdForClassicNetwork(cloudprovider.Provider, self.VpcId, self.ZoneId) { + return nil + } + err := self.ValidateDeleteCondition(ctx) if err != nil { // cannot delete err = self.markNetworkUnknown(userCred) diff --git a/pkg/multicloud/aliyun/instancenic.go b/pkg/multicloud/aliyun/instancenic.go index 0dae78ff76..e8d2cd7b85 100644 --- a/pkg/multicloud/aliyun/instancenic.go +++ b/pkg/multicloud/aliyun/instancenic.go @@ -34,6 +34,10 @@ func (self *SInstanceNic) GetMAC() string { return ip.ToMac("00:16:") } +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + func (self *SInstanceNic) GetDriver() string { return "virtio" } diff --git a/pkg/multicloud/aws/instancenic.go b/pkg/multicloud/aws/instancenic.go index 2b19d29ce4..5ebe2b7b11 100644 --- a/pkg/multicloud/aws/instancenic.go +++ b/pkg/multicloud/aws/instancenic.go @@ -34,6 +34,10 @@ func (self *SInstanceNic) GetMAC() string { return ip.ToMac("00:16:") } +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + func (self *SInstanceNic) GetDriver() string { return "virtio" } diff --git a/pkg/multicloud/azure/classic_instancenic.go b/pkg/multicloud/azure/classic_instancenic.go index eb949b4638..6c40bcf9e6 100644 --- a/pkg/multicloud/azure/classic_instancenic.go +++ b/pkg/multicloud/azure/classic_instancenic.go @@ -48,6 +48,10 @@ func (self *SClassicInstanceNic) GetDriver() string { return "virtio" } +func (self *SClassicInstanceNic) InClassicNetwork() bool { + return true +} + func (self *SClassicInstanceNic) GetINetwork() cloudprovider.ICloudNetwork { wires, err := self.instance.host.GetIWires() if err != nil { diff --git a/pkg/multicloud/azure/classic_network.go b/pkg/multicloud/azure/classic_network.go index d286d7e728..b569466c60 100644 --- a/pkg/multicloud/azure/classic_network.go +++ b/pkg/multicloud/azure/classic_network.go @@ -54,7 +54,7 @@ func (self *SClassicNetwork) IsEmulated() bool { } func (self *SClassicNetwork) GetStatus() string { - return "available" + return api.NETWORK_STATUS_UNAVAILABLE } func (self *SClassicNetwork) Delete() error { diff --git a/pkg/multicloud/azure/classic_vpc.go b/pkg/multicloud/azure/classic_vpc.go index 691219488d..9bb32ae4a1 100644 --- a/pkg/multicloud/azure/classic_vpc.go +++ b/pkg/multicloud/azure/classic_vpc.go @@ -20,6 +20,7 @@ import ( "yunion.io/x/jsonutils" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/multicloud" ) @@ -200,10 +201,7 @@ func (self *SClassicVpc) GetRegion() cloudprovider.ICloudRegion { } func (self *SClassicVpc) GetStatus() string { - if strings.ToLower(self.Properties.Status) == "created" { - return "available" - } - return "disabled" + return api.VPC_STATUS_UNAVAILABLE } func (self *SClassicVpc) Refresh() error { diff --git a/pkg/multicloud/azure/instancenic.go b/pkg/multicloud/azure/instancenic.go index 7a35af2f48..66b6fde441 100644 --- a/pkg/multicloud/azure/instancenic.go +++ b/pkg/multicloud/azure/instancenic.go @@ -91,6 +91,10 @@ func (self *SInstanceNic) GetDriver() string { return "virtio" } +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + func (self *SInstanceNic) updateSecurityGroup(secgroupId string) error { region := self.instance.host.zone.region self.Properties.NetworkSecurityGroup = nil diff --git a/pkg/multicloud/ctyun/instancenic.go b/pkg/multicloud/ctyun/instancenic.go index 5882cc116f..d376939bc3 100644 --- a/pkg/multicloud/ctyun/instancenic.go +++ b/pkg/multicloud/ctyun/instancenic.go @@ -54,6 +54,10 @@ func (self *SInstanceNic) GetDriver() string { return "virtio" } +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + func (self *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork { network, err := self.instance.host.zone.region.GetNetwork(self.NetID) if err != nil { diff --git a/pkg/multicloud/esxi/vnic.go b/pkg/multicloud/esxi/vnic.go index 68810d8d7d..d328dde25f 100644 --- a/pkg/multicloud/esxi/vnic.go +++ b/pkg/multicloud/esxi/vnic.go @@ -54,6 +54,10 @@ func (nic *SVirtualNIC) GetMAC() string { return netutils.FormatMacAddr(nic.getVirtualEthernetCard().MacAddress) } +func (nic *SVirtualNIC) InClassicNetwork() bool { + return false +} + func (nic *SVirtualNIC) GetINetwork() cloudprovider.ICloudNetwork { return nil } diff --git a/pkg/multicloud/google/instancenic.go b/pkg/multicloud/google/instancenic.go index f4519686d4..e2d01e3f95 100644 --- a/pkg/multicloud/google/instancenic.go +++ b/pkg/multicloud/google/instancenic.go @@ -46,6 +46,10 @@ func (nic *SNetworkInterface) GetDriver() string { return "virtio" } +func (nic *SNetworkInterface) InClassicNetwork() bool { + return false +} + func (nic *SNetworkInterface) GetINetwork() cloudprovider.ICloudNetwork { network, err := nic.instance.host.zone.region.GetNetwork(nic.Subnetwork) if err != nil { diff --git a/pkg/multicloud/huawei/instancenic.go b/pkg/multicloud/huawei/instancenic.go index e24547864c..3965da8cbe 100644 --- a/pkg/multicloud/huawei/instancenic.go +++ b/pkg/multicloud/huawei/instancenic.go @@ -74,6 +74,10 @@ func (self *SInstanceNic) GetDriver() string { return "virtio" } +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + func (self *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork { instanceId := self.instance.GetId() subnets, err := self.instance.host.zone.region.getSubnetIdsByInstanceId(instanceId) diff --git a/pkg/multicloud/openstack/instancenic.go b/pkg/multicloud/openstack/instancenic.go index 5ae21f6519..7a18c851da 100644 --- a/pkg/multicloud/openstack/instancenic.go +++ b/pkg/multicloud/openstack/instancenic.go @@ -38,6 +38,10 @@ func (nic *SInstanceNic) GetDriver() string { return "virtio" } +func (nic *SInstanceNic) InClassicNetwork() bool { + return false +} + func (nic *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork { ports, err := nic.instance.host.zone.region.GetPorts(nic.MacAddr) if err == nil { diff --git a/pkg/multicloud/qcloud/instance.go b/pkg/multicloud/qcloud/instance.go index 70a9b049ab..e1c35f7fd4 100644 --- a/pkg/multicloud/qcloud/instance.go +++ b/pkg/multicloud/qcloud/instance.go @@ -216,7 +216,7 @@ func (self *SInstance) getVpc() (*SVpc, error) { func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { idisks := make([]cloudprovider.ICloudDisk, 0) - if utils.IsInStringArray(self.SystemDisk.DiskType, []string{"LOCAL_BASIC", "LOCAL_SSD"}) { + if utils.IsInStringArray(self.SystemDisk.DiskType, self.host.zone.localstorages) { storage := SLocalStorage{zone: self.host.zone, storageType: self.SystemDisk.DiskType} disk := SLocalDisk{ storage: &storage, @@ -229,7 +229,7 @@ func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { } for i := 0; i < len(self.DataDisks); i++ { - if utils.IsInStringArray(self.DataDisks[i].DiskType, []string{"LOCAL_BASIC", "LOCAL_SSD"}) { + if utils.IsInStringArray(self.DataDisks[i].DiskType, self.host.zone.localstorages) { storage := SLocalStorage{zone: self.host.zone, storageType: self.DataDisks[i].DiskType} disk := SLocalDisk{ storage: &storage, @@ -270,12 +270,16 @@ func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { nics := make([]cloudprovider.ICloudNic, 0) + classic := false + if len(self.VirtualPrivateCloud.VpcId) == 0 { + classic = true + } for _, ip := range self.VirtualPrivateCloud.PrivateIpAddresses { nic := SInstanceNic{instance: self, ipAddr: ip} nics = append(nics, &nic) } for _, ip := range self.PrivateIpAddresses { - nic := SInstanceNic{instance: self, ipAddr: ip} + nic := SInstanceNic{instance: self, ipAddr: ip, classic: classic} nics = append(nics, &nic) } return nics, nil diff --git a/pkg/multicloud/qcloud/instancenic.go b/pkg/multicloud/qcloud/instancenic.go index 354a735697..ed4c968ce6 100644 --- a/pkg/multicloud/qcloud/instancenic.go +++ b/pkg/multicloud/qcloud/instancenic.go @@ -23,6 +23,7 @@ import ( type SInstanceNic struct { instance *SInstance ipAddr string + classic bool } func (self *SInstanceNic) GetIP() string { @@ -38,6 +39,10 @@ func (self *SInstanceNic) GetDriver() string { return "virtio" } +func (self *SInstanceNic) InClassicNetwork() bool { + return self.classic +} + func (self *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork { networkId := self.instance.VirtualPrivateCloud.SubnetId wires, err := self.instance.host.GetIWires() diff --git a/pkg/multicloud/qcloud/instancetype.go b/pkg/multicloud/qcloud/instancetype.go index 52be02073b..2daa4c90bd 100644 --- a/pkg/multicloud/qcloud/instancetype.go +++ b/pkg/multicloud/qcloud/instancetype.go @@ -14,7 +14,11 @@ package qcloud -import "yunion.io/x/log" +import ( + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" +) // "time" @@ -54,3 +58,73 @@ func (self *SRegion) GetInstanceTypes() ([]SInstanceType, error) { func (self *SInstanceType) memoryMB() int { return int(self.Memory * 1024) } + +type SLocalDiskType struct { + Type string + PartitionType string + MinSize int + MaxSize int +} + +type SStorageBlockAttr struct { + Type string + MinSize int + MaxSize int +} + +type SExternal struct { + ReleaseAddress string + UnsupportNetworks []string + StorageBlockAttr SStorageBlockAttr +} + +type SZoneInstanceType struct { + Zone string + InstanceType string + InstanceChargeType string + NetworkCard int + Externals SExternal + Cpu int + Memory int + InstanceFamily string + TypeName string + LocalDiskTypeList []SLocalDiskType + Status string +} + +func (self *SRegion) GetZoneInstanceTypes(zoneId string) ([]SZoneInstanceType, error) { + params := map[string]string{} + params["Region"] = self.Region + params["Filters.0.Name"] = "zone" + params["Filters.0.Values.0"] = zoneId + body, err := self.cvmRequest("DescribeZoneInstanceConfigInfos", params, true) + if err != nil { + return nil, errors.Wrap(err, "DescribeZoneInstanceConfigInfos") + } + instanceTypes := []SZoneInstanceType{} + err = body.Unmarshal(&instanceTypes, "InstanceTypeQuotaSet") + if err != nil { + return nil, errors.Wrap(err, "body.Unmarshal") + } + return instanceTypes, nil +} + +func (self *SRegion) GetZoneLocalStorages(zoneId string) ([]string, error) { + instanceTypes, err := self.GetZoneInstanceTypes(zoneId) + if err != nil { + return nil, errors.Wrap(err, "GetZoneInstanceTypes") + } + storages := []string{} + for _, instanceType := range instanceTypes { + storage := instanceType.Externals.StorageBlockAttr.Type + if len(storage) > 0 && !utils.IsInStringArray(storage, storages) { + storages = append(storages, storage) + } + for _, localstorage := range instanceType.LocalDiskTypeList { + if len(localstorage.Type) > 0 && !utils.IsInStringArray(localstorage.Type, storages) { + storages = append(storages, localstorage.Type) + } + } + } + return storages, nil +} diff --git a/pkg/multicloud/qcloud/shell/zone.go b/pkg/multicloud/qcloud/shell/zone.go index 0833853771..553ed6f011 100644 --- a/pkg/multicloud/qcloud/shell/zone.go +++ b/pkg/multicloud/qcloud/shell/zone.go @@ -32,4 +32,18 @@ func init() { printList(zones, len(zones), args.Offset, args.Limit, []string{}) return nil }) + + type ZoneInstanceTypeListOptions struct { + ZONE string + } + + shellutils.R(&ZoneInstanceTypeListOptions{}, "zone-instance-type-list", "List zone instance type", func(cli *qcloud.SRegion, args *ZoneInstanceTypeListOptions) error { + instanceTypes, err := cli.GetZoneInstanceTypes(args.ZONE) + if err != nil { + return err + } + printList(instanceTypes, 0, 0, 0, []string{}) + return nil + }) + } diff --git a/pkg/multicloud/qcloud/zone.go b/pkg/multicloud/qcloud/zone.go index 428c9a2237..f2dec63c68 100644 --- a/pkg/multicloud/qcloud/zone.go +++ b/pkg/multicloud/qcloud/zone.go @@ -47,6 +47,8 @@ type SZone struct { instanceTypes []string refreshTime time.Time + localstorages []string + cloudstorages []string Zone string ZoneName string @@ -139,22 +141,27 @@ func (self *SZone) fetchStorages() error { if err != nil { return err } - storageTypes := []string{} + self.cloudstorages = []string{} for _, diskConfig := range diskConfigSet { - if !utils.IsInStringArray(strings.ToUpper(diskConfig.DiskType), storageTypes) { - storageTypes = append(storageTypes, strings.ToUpper(diskConfig.DiskType)) + if !utils.IsInStringArray(strings.ToUpper(diskConfig.DiskType), self.cloudstorages) { + self.cloudstorages = append(self.cloudstorages, strings.ToUpper(diskConfig.DiskType)) storage := SStorage{zone: self, storageType: diskConfig.DiskType, available: diskConfig.Available} self.istorages = append(self.istorages, &storage) } } for _, storageType := range []string{"CLOUD_PREMIUM", "CLOUD_SSD", "CLOUD_BASIC"} { - if !utils.IsInStringArray(storageType, storageTypes) { + if !utils.IsInStringArray(storageType, self.cloudstorages) { + self.cloudstorages = append(self.cloudstorages, storageType) storage := SStorage{zone: self, storageType: storageType, available: false} self.istorages = append(self.istorages, &storage) } } - for _, localstorageType := range []string{"LOCAL_BASIC", "LOCAL_SSD"} { - storage := SLocalStorage{zone: self, storageType: localstorageType, available: self.region.GetId() == "ap-hongkong"} //仅有香港本地存储可用 + self.localstorages, err = self.region.GetZoneLocalStorages(self.Zone) + if err != nil { + log.Errorf("falied to fetch local storage for zone %s", self.Zone) + } + for _, localstorageType := range self.localstorages { + storage := SLocalStorage{zone: self, storageType: localstorageType, available: true} self.istorages = append(self.istorages, &storage) } return nil @@ -168,14 +175,14 @@ func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { } func (self *SZone) getLocalStorageByCategory(category string) (*SLocalStorage, error) { - if utils.IsInStringArray(strings.ToLower(category), []string{"local_basic", "local_ssd"}) { + if utils.IsInStringArray(strings.ToUpper(category), self.localstorages) { return &SLocalStorage{zone: self, storageType: strings.ToUpper(category)}, nil } return nil, fmt.Errorf("No such storage %s", category) } func (self *SZone) validateStorageType(category string) error { - if utils.IsInStringArray(strings.ToLower(category), []string{"local_basic", "local_ssd", "cloud_basic", "cloud_ssd", "cloud_premium"}) { + if utils.IsInStringArray(strings.ToUpper(category), self.localstorages) || utils.IsInStringArray(strings.ToUpper(category), self.cloudstorages) { return nil } return fmt.Errorf("No such storage %s", category) @@ -187,7 +194,7 @@ func (self *SZone) getStorageByCategory(category string) (*SStorage, error) { return nil, err } for i := 0; i < len(storages); i++ { - if utils.IsInStringArray(storages[i].GetStorageType(), []string{"local_basic", "local_ssd"}) { + if utils.IsInStringArray(storages[i].GetStorageType(), self.localstorages) { continue //return &SStorage{zone: self, storageType: strings.ToUpper(storages[i].GetStorageType())}, nil } diff --git a/pkg/multicloud/ucloud/instancenic.go b/pkg/multicloud/ucloud/instancenic.go index 8c08e5da2e..e1b1e994ea 100644 --- a/pkg/multicloud/ucloud/instancenic.go +++ b/pkg/multicloud/ucloud/instancenic.go @@ -38,6 +38,10 @@ func (self *SInstanceNic) GetDriver() string { return "virtio" } +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + func (self *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork { for _, ip := range self.instance.IPSet { if ip.IP == self.ipAddr { diff --git a/pkg/multicloud/zstack/instancenic.go b/pkg/multicloud/zstack/instancenic.go index 8bbfd5f9bd..a6f7ebb615 100644 --- a/pkg/multicloud/zstack/instancenic.go +++ b/pkg/multicloud/zstack/instancenic.go @@ -49,6 +49,10 @@ func (nic *SInstanceNic) GetDriver() string { return "virtio" } +func (nic *SInstanceNic) InClassicNetwork() bool { + return false +} + func (nic *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork { networks, err := nic.instance.host.zone.region.GetNetworks(nic.instance.host.zone.UUID, "", nic.L3NetworkUUID, "") if err != nil {