From 9a583c832360f4cc859f4273a9c71ab9541dce6a Mon Sep 17 00:00:00 2001 From: ioito Date: Sat, 15 Jun 2019 18:41:00 +0800 Subject: [PATCH] fix zstack cdrome error --- pkg/cloudprovider/resources.go | 2 + pkg/compute/guestdrivers/managedvirtual.go | 18 ++++ pkg/compute/guestdrivers/utils.go | 26 +++--- pkg/compute/models/guest_actions.go | 4 +- pkg/multicloud/disk_base.go | 4 + pkg/multicloud/instance_base.go | 23 +++++ pkg/util/aliyun/instance.go | 3 + pkg/util/aws/instance.go | 4 + pkg/util/azure/classic_instance.go | 3 + pkg/util/azure/instance.go | 2 + pkg/util/esxi/virtualmachine.go | 4 + pkg/util/huawei/instance.go | 3 + pkg/util/openstack/instance.go | 4 + pkg/util/qcloud/instance.go | 3 + pkg/util/qcloud/region.go | 2 +- pkg/util/ucloud/instance.go | 3 + pkg/util/zstack/disk.go | 15 ++++ pkg/util/zstack/host.go | 98 ++++++++++++++-------- pkg/util/zstack/image_server.go | 2 +- pkg/util/zstack/instance.go | 7 ++ 20 files changed, 180 insertions(+), 50 deletions(-) create mode 100644 pkg/multicloud/instance_base.go diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index 0cbd4612a7..3d2968d997 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -215,6 +215,7 @@ type ICloudVM interface { GetCreateTime() time.Time GetIHost() ICloudHost + GetIHostId() string GetIDisks() ([]ICloudDisk, error) GetINics() ([]ICloudNic, error) @@ -331,6 +332,7 @@ type ICloudDisk interface { IVirtualResource GetIStorage() (ICloudStorage, error) + GetIStorageId() string // GetStatus() string GetDiskFormat() string diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index 023a51232d..7c1d072309 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -317,6 +317,15 @@ func (self *SManagedVirtualizedGuestDriver) RemoteDeployGuestForCreate(ctx conte } db.SetExternalId(guest, userCred, iVM.GetGlobalId()) + if hostId := iVM.GetIHostId(); len(hostId) > 0 { + host, err := db.FetchByExternalId(models.HostManager, hostId) + if err != nil { + log.Warningf("failed to found new hostId(%s) for ivm %s(%s) error: %v", hostId, guest.Name, guest.Id, err) + } else if host.GetId() != guest.HostId { + guest.OnScheduleToHost(ctx, userCred, host.GetId()) + } + } + return iVM, nil }() @@ -705,6 +714,15 @@ func (self *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx co disk.ExpiredAt = diskInfo[i].ExpiredAt } + if len(diskInfo[i].StorageExternalId) > 0 { + storage, err := db.FetchByExternalId(models.StorageManager, diskInfo[i].StorageExternalId) + if err != nil { + log.Warningf("failed to found storage by externalId %s error: %v", diskInfo[i].StorageExternalId, err) + } else if disk.StorageId != storage.GetId() { + disk.StorageId = storage.GetId() + } + } + if len(diskInfo[i].Metadata) > 0 { for key, value := range diskInfo[i].Metadata { if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil { diff --git a/pkg/compute/guestdrivers/utils.go b/pkg/compute/guestdrivers/utils.go index 5289e86d23..fc49685910 100644 --- a/pkg/compute/guestdrivers/utils.go +++ b/pkg/compute/guestdrivers/utils.go @@ -26,18 +26,19 @@ import ( ) type SDiskInfo struct { - DiskType string - Size int - Uuid string - BillingType string - FsFromat string - AutoDelete bool - TemplateId string - DiskFormat string - Path string - Driver string - CacheMode string - ExpiredAt time.Time + DiskType string + Size int + Uuid string + BillingType string + FsFromat string + AutoDelete bool + TemplateId string + DiskFormat string + Path string + Driver string + CacheMode string + ExpiredAt time.Time + StorageExternalId string Metadata map[string]string } @@ -86,6 +87,7 @@ func fetchIVMinfo(desc cloudprovider.SManagedVMCreateConfig, iVM cloudprovider.I dinfo.TemplateId = idisks[i].GetTemplateId() dinfo.FsFromat = idisks[i].GetFsFormat() dinfo.ExpiredAt = idisks[i].GetExpiredAt() + dinfo.StorageExternalId = idisks[i].GetIStorageId() if metaData := idisks[i].GetMetadata(); metaData != nil { dinfo.Metadata = make(map[string]string, 0) metadata := map[string]string{} diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index bc4128d989..2136193135 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -1946,14 +1946,14 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T } provider, e := self.GetHost().GetProviderFactory() - if e != nil || provider.IsOnPremise() { + if e != nil || !provider.IsPublicCloud() { for storageId, needSize := range diskSizes { iStorage, err := StorageManager.FetchById(storageId) if err != nil { return nil, httperrors.NewBadRequestError("Fetch storage error: %s", err) } storage := iStorage.(*SStorage) - if storage.GetFreeCapacity() < int64(needSize) { + if storage.GetFreeCapacity() > 0 && storage.GetFreeCapacity() < int64(needSize) { return nil, httperrors.NewInsufficientResourceError("Not enough free space") } } diff --git a/pkg/multicloud/disk_base.go b/pkg/multicloud/disk_base.go index 01cfc0f86e..e5b12195da 100644 --- a/pkg/multicloud/disk_base.go +++ b/pkg/multicloud/disk_base.go @@ -19,3 +19,7 @@ type SDisk struct{} func (self *SDisk) GetExtSnapshotPolicyId() string { return "" } + +func (self *SDisk) GetIStorageId() string { + return "" +} diff --git a/pkg/multicloud/instance_base.go b/pkg/multicloud/instance_base.go new file mode 100644 index 0000000000..36296498fb --- /dev/null +++ b/pkg/multicloud/instance_base.go @@ -0,0 +1,23 @@ +// 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 multicloud + +type SInstanceBase struct { + SResourceBase +} + +func (instance *SInstanceBase) GetIHostId() string { + return "" +} diff --git a/pkg/util/aliyun/instance.go b/pkg/util/aliyun/instance.go index 8f20d74a11..0cf48abc2e 100644 --- a/pkg/util/aliyun/instance.go +++ b/pkg/util/aliyun/instance.go @@ -28,6 +28,7 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" "yunion.io/x/onecloud/pkg/util/billing" ) @@ -80,6 +81,8 @@ type SVpcAttributes struct { } type SInstance struct { + multicloud.SInstanceBase + host *SHost // idisks []cloudprovider.ICloudDisk diff --git a/pkg/util/aws/instance.go b/pkg/util/aws/instance.go index b43a57a228..420129f192 100644 --- a/pkg/util/aws/instance.go +++ b/pkg/util/aws/instance.go @@ -21,6 +21,8 @@ import ( "strings" "time" + "yunion.io/x/onecloud/pkg/multicloud" + "github.com/aws/aws-sdk-go/service/ec2" "yunion.io/x/jsonutils" @@ -70,6 +72,8 @@ type SVpcAttributes struct { } type SInstance struct { + multicloud.SInstanceBase + host *SHost RegionId string ZoneId string diff --git a/pkg/util/azure/classic_instance.go b/pkg/util/azure/classic_instance.go index b2a0d11113..c0c15d3f5f 100644 --- a/pkg/util/azure/classic_instance.go +++ b/pkg/util/azure/classic_instance.go @@ -27,6 +27,7 @@ import ( billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" "yunion.io/x/onecloud/pkg/util/billing" ) @@ -131,6 +132,8 @@ type ClassicVirtualMachineProperties struct { } type SClassicInstance struct { + multicloud.SInstanceBase + host *SClassicHost idisks []cloudprovider.ICloudDisk diff --git a/pkg/util/azure/instance.go b/pkg/util/azure/instance.go index 8d8ae7c7cb..8a39182c66 100644 --- a/pkg/util/azure/instance.go +++ b/pkg/util/azure/instance.go @@ -27,6 +27,7 @@ import ( billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" "yunion.io/x/onecloud/pkg/util/billing" ) @@ -177,6 +178,7 @@ type VirtualMachineProperties struct { } type SInstance struct { + multicloud.SInstanceBase host *SHost Properties VirtualMachineProperties diff --git a/pkg/util/esxi/virtualmachine.go b/pkg/util/esxi/virtualmachine.go index 47af785b8a..b25d90d7da 100644 --- a/pkg/util/esxi/virtualmachine.go +++ b/pkg/util/esxi/virtualmachine.go @@ -176,6 +176,10 @@ func (self *SVirtualMachine) GetIHost() cloudprovider.ICloudHost { return self.ihost } +func (self *SVirtualMachine) GetIHostId() string { + return "" +} + func (self *SVirtualMachine) getIHost() cloudprovider.ICloudHost { vm := self.getVmObj() diff --git a/pkg/util/huawei/instance.go b/pkg/util/huawei/instance.go index 6b595663b3..d7a52a7c5e 100644 --- a/pkg/util/huawei/instance.go +++ b/pkg/util/huawei/instance.go @@ -30,6 +30,7 @@ import ( billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" "yunion.io/x/onecloud/pkg/util/billing" "yunion.io/x/onecloud/pkg/util/huawei/client/modules" ) @@ -95,6 +96,8 @@ type SysTag struct { // 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 + host *SHost ID string `json:"id"` diff --git a/pkg/util/openstack/instance.go b/pkg/util/openstack/instance.go index 206dd38698..3ae85c2383 100644 --- a/pkg/util/openstack/instance.go +++ b/pkg/util/openstack/instance.go @@ -20,6 +20,8 @@ import ( "fmt" "time" + "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/utils" @@ -92,6 +94,8 @@ type SFault struct { } type SInstance struct { + multicloud.SInstanceBase + host *SHost DiskConfig string `json:"OS-DCF:diskConfig,omitempty"` diff --git a/pkg/util/qcloud/instance.go b/pkg/util/qcloud/instance.go index 213fefe8d2..048c5167f7 100644 --- a/pkg/util/qcloud/instance.go +++ b/pkg/util/qcloud/instance.go @@ -27,6 +27,7 @@ import ( billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" "yunion.io/x/onecloud/pkg/util/billing" ) @@ -92,6 +93,8 @@ type Tag struct { } type SInstance struct { + multicloud.SInstanceBase + host *SHost image *SImage diff --git a/pkg/util/qcloud/region.go b/pkg/util/qcloud/region.go index f923efc554..c48e62a685 100644 --- a/pkg/util/qcloud/region.go +++ b/pkg/util/qcloud/region.go @@ -173,7 +173,7 @@ func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalanc "VpcId": loadbalancer.VpcID, } - if loadbalancer.AddressType != api.LB_ADDR_TYPE_INTERNET { + if loadbalancer.AddressType != api.LB_ADDR_TYPE_INTERNET { params["SubnetId"] = loadbalancer.NetworkID } diff --git a/pkg/util/ucloud/instance.go b/pkg/util/ucloud/instance.go index bd1ce70624..077838d2e8 100644 --- a/pkg/util/ucloud/instance.go +++ b/pkg/util/ucloud/instance.go @@ -20,6 +20,7 @@ import ( "fmt" "strings" "time" + "yunion.io/x/pkg/utils" "yunion.io/x/jsonutils" @@ -34,6 +35,8 @@ import ( ) type SInstance struct { + multicloud.SInstanceBase + host *SHost UHostID string `json:"UHostId"` diff --git a/pkg/util/zstack/disk.go b/pkg/util/zstack/disk.go index f860404cb2..c0886d5c7f 100644 --- a/pkg/util/zstack/disk.go +++ b/pkg/util/zstack/disk.go @@ -169,6 +169,21 @@ func (disk *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { return nil, cloudprovider.ErrNotFound } +func (disk *SDisk) GetIStorageId() string { + storage, err := disk.region.GetStorage(disk.PrimaryStorageUUID) + if err != nil { + return disk.PrimaryStorageUUID + } else if storage.Type == StorageTypeLocal && len(disk.VMInstanceUUID) > 0 { + instnace, err := disk.region.GetInstance(disk.VMInstanceUUID) + if err != nil { + log.Warningf("failed to get instance %s for disk %s(%s) error: %v", disk.VMInstanceUUID, disk.Name, disk.UUID, err) + return "" + } + return fmt.Sprintf("%s/%s", disk.PrimaryStorageUUID, instnace.LastHostUUID) + } + return disk.PrimaryStorageUUID +} + func (disk *SDisk) GetStatus() string { switch disk.Status { case "Ready": diff --git a/pkg/util/zstack/host.go b/pkg/util/zstack/host.go index c87581edf6..b4cef4d8f0 100644 --- a/pkg/util/zstack/host.go +++ b/pkg/util/zstack/host.go @@ -250,8 +250,25 @@ func (region *SRegion) cleanDisks(diskIds []string) { } } -func (region *SRegion) createDataDisks(disks []cloudprovider.SDiskInfo) ([]string, error) { +func (region *SRegion) createDataDisks(disks []cloudprovider.SDiskInfo, hostId string) ([]string, error) { diskIds := []string{} + + storages, err := region.GetStorages("", "", "") + if err != nil { + return nil, errors.Wrapf(err, "createDataDisks.GetStorages") + } + + localstorages := []SLocalStorage{} + + for _, storage := range storages { + if storage.Type == StorageTypeLocal { + localstorage, _ := region.GetLocalStorage(storage.UUID, hostId) + if localstorage != nil { + localstorages = append(localstorages, *localstorage) + } + } + } + for i := 0; i < len(disks); i++ { storageInfo := strings.Split(disks[i].StorageExternalId, "/") if len(storageInfo) == 0 { @@ -262,9 +279,9 @@ func (region *SRegion) createDataDisks(disks []cloudprovider.SDiskInfo) ([]strin return diskIds, errors.Wrapf(err, "createDataDisks") } - hostId, poolName := "", "" switch storage.Type { case StorageTypeCeph: + poolName := "" for _, pool := range storage.Pools { if pool.Type == CephPoolTypeData { poolName = pool.PoolName @@ -273,36 +290,49 @@ func (region *SRegion) createDataDisks(disks []cloudprovider.SDiskInfo) ([]strin if len(poolName) == 0 { return diskIds, fmt.Errorf("failed to found ceph data pool for storage %s to createDataDisk", storage.Name) } + disk, err := region.CreateDisk(disks[i].Name, storage.UUID, "", poolName, disks[i].SizeGB, "") + if err != nil { + return diskIds, err + } + diskIds = append(diskIds, disk.UUID) case StorageTypeLocal: - hostId = storageInfo[1] + if len(localstorages) == 0 { + return nil, fmt.Errorf("No validate localstorage") + } + var disk *SDisk + var err error + for _, localstorage := range localstorages { + disk, err = region.CreateDisk(disks[i].Name, localstorage.primaryStorageID, hostId, "", disks[i].SizeGB, "") + if err != nil { + log.Warningf("createDataDisks error: %v", err) + } else { + diskIds = append(diskIds, disk.UUID) + break + } + } + if err != nil { + return diskIds, err + } default: return diskIds, fmt.Errorf("not support storageType %s", disks[i].StorageType) } - - disk, err := region.CreateDisk(disks[i].Name, storage.UUID, hostId, poolName, disks[i].SizeGB, "") - if err != nil { - return diskIds, err - } - diskIds = append(diskIds, disk.UUID) } return diskIds, nil } func (host *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - diskIds, err := host.zone.region.createDataDisks(desc.DataDisks) + instance, err := host.zone.region._createVM(desc, host.ZoneUUID) + if err != nil { + return nil, errors.Wrapf(err, "host.zone.region._createVM") + } + + diskIds, err := host.zone.region.createDataDisks(desc.DataDisks, instance.HostUUID) if err != nil { defer host.zone.region.cleanDisks(diskIds) - return nil, err - } - if len(desc.SysDisk.StorageExternalId) == 0 { - return nil, fmt.Errorf("invalidate root disk storage externalId") - } - rootStorageId := strings.Split(desc.SysDisk.StorageExternalId, "/")[0] - instance, err := host.zone.region._createVM(desc, host.UUID, rootStorageId) - if err != nil { - defer host.zone.region.cleanDisks(diskIds) - return nil, err + defer host.zone.region.DeleteVM(instance.UUID) + return nil, errors.Wrapf(err, "host.zone.region.createDataDisks") } + for i := 0; i < len(diskIds); i++ { err = host.zone.region.AttachDisk(instance.UUID, diskIds[i]) if err != nil { @@ -316,7 +346,7 @@ func (host *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudpr return host.GetIVMById(instance.UUID) } -func (region *SRegion) _createVM(desc *cloudprovider.SManagedVMCreateConfig, hostId string, rootStorageId string) (*SInstance, error) { +func (region *SRegion) _createVM(desc *cloudprovider.SManagedVMCreateConfig, zoneId string) (*SInstance, error) { l3Id := strings.Split(desc.ExternalNetworkId, "/")[0] if len(l3Id) == 0 { return nil, fmt.Errorf("invalid networkid: %s", desc.ExternalNetworkId) @@ -345,13 +375,13 @@ func (region *SRegion) _createVM(desc *cloudprovider.SManagedVMCreateConfig, hos return nil, fmt.Errorf("instance type %dC%dMB not avaiable", desc.Cpu, desc.MemoryMB) } } - return region.CreateInstance(desc, l3Id, hostId, rootStorageId, offerings) + return region.CreateInstance(desc, l3Id, zoneId, offerings) } -func (region *SRegion) CreateInstance(desc *cloudprovider.SManagedVMCreateConfig, l3Id, hostId, rootStorageId string, offerings map[string]string) (*SInstance, error) { +func (region *SRegion) CreateInstance(desc *cloudprovider.SManagedVMCreateConfig, l3Id, zoneId string, offerings map[string]string) (*SInstance, error) { instance := &SInstance{} systemTags := []string{ - "cdroms::Empty::None::None", + "createWithoutCdRom::true", "usbRedirect::false", fmt.Sprintf("staticIp::%s::%s", l3Id, desc.IpAddr), "vmConsoleMode::vnc", @@ -374,18 +404,18 @@ func (region *SRegion) CreateInstance(desc *cloudprovider.SManagedVMCreateConfig "l3NetworkUuids": []string{ l3Id, }, - "hostUuid": hostId, - "dataVolumeSystemTags": []string{}, - "rootVolumeSystemTags": []string{}, - "vmMachineType": "", - "tagUuids": []string{}, - "defaultL3NetworkUuid": l3Id, - "primaryStorageUuidForRootVolume": rootStorageId, - "dataDiskOfferingUuids": []string{}, - "systemTags": systemTags, - "vmNicConfig": []string{}, + "zoneUuid": zoneId, + "dataVolumeSystemTags": []string{}, + "rootVolumeSystemTags": []string{}, + "vmMachineType": "", + "tagUuids": []string{}, + "defaultL3NetworkUuid": l3Id, + "dataDiskOfferingUuids": []string{}, + "systemTags": systemTags, + "vmNicConfig": []string{}, }, } + log.Debugf("Try instanceOffering : %s", offerName) err = region.client.create("vm-instances", jsonutils.Marshal(params), instance) if err == nil { diff --git a/pkg/util/zstack/image_server.go b/pkg/util/zstack/image_server.go index 0588df13f1..fed09c0c3f 100644 --- a/pkg/util/zstack/image_server.go +++ b/pkg/util/zstack/image_server.go @@ -49,7 +49,7 @@ func (v ImageServers) Less(i, j int) bool { func (region *SRegion) GetImageServers(zoneId string) ([]SImageServer, error) { servers := []SImageServer{} - params := []string{"q=state=Enabled", "q=status=Connected", "q=type=ImageStoreBackupStorage"} + params := []string{"q=state=Enabled", "q=status=Connected"} if SkipEsxi { params = append(params, "q=type!=VCenter") } diff --git a/pkg/util/zstack/instance.go b/pkg/util/zstack/instance.go index 6617611362..7696a46ff9 100644 --- a/pkg/util/zstack/instance.go +++ b/pkg/util/zstack/instance.go @@ -108,6 +108,13 @@ func (instance *SInstance) GetIHost() cloudprovider.ICloudHost { return instance.host } +func (instance *SInstance) GetIHostId() string { + if len(instance.LastHostUUID) > 0 { + return instance.LastHostUUID + } + return instance.HostUUID +} + func (instance *SInstance) GetId() string { return instance.UUID }