diff --git a/pkg/cloudprovider/retry.go b/pkg/cloudprovider/retry.go index 7fb70fd6da..daee86d8bf 100644 --- a/pkg/cloudprovider/retry.go +++ b/pkg/cloudprovider/retry.go @@ -29,3 +29,19 @@ func RetryOnError(tryFunc func() error, errs []string, maxTries int) error { } return ErrTimeout } + +func RetryUntil(tryFunc func() (bool, error), maxTries int) error { + tried := 0 + for tried < maxTries { + stop, err := tryFunc() + if stop { + return nil + } + if err != nil { + return err + } + tried += 1 + time.Sleep(10 * time.Duration(tried) * time.Second) + } + return ErrTimeout +} diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index 9edf528541..add0898dbc 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -353,6 +353,11 @@ func (self *SManagedVirtualizedGuestDriver) RequestDiskSnapshot(ctx context.Cont func (self *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error { + uuid, _ := data.GetString("uuid") + if len(uuid) > 0 { + guest.SetExternalId(uuid) + } + recycle := false if guest.IsPrepaidRecycle() { recycle = true @@ -367,7 +372,7 @@ func (self *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx co disks := guest.GetDisks() if len(disks) != len(diskInfo) { - msg := fmt.Sprintf("inconsistent disk number: have %d want %d", len(disks), len(diskInfo)) + msg := fmt.Sprintf("inconsistent disk number: guest have %d disks, data contains %d disks", len(disks), len(diskInfo)) log.Errorf(msg) return fmt.Errorf(msg) } @@ -419,10 +424,6 @@ func (self *SManagedVirtualizedGuestDriver) OnGuestDeployTaskDataReceived(ctx co } } } - uuid, _ := data.GetString("uuid") - if len(uuid) > 0 { - guest.SetExternalId(uuid) - } if metaData, _ := data.Get("metadata"); metaData != nil { meta := make(map[string]string, 0) diff --git a/pkg/compute/guestdrivers/qcloud.go b/pkg/compute/guestdrivers/qcloud.go index e816c9e248..f42713951d 100644 --- a/pkg/compute/guestdrivers/qcloud.go +++ b/pkg/compute/guestdrivers/qcloud.go @@ -200,13 +200,30 @@ func (self *SQcloudGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu if err != nil { return nil, err } - log.Debugf("VMcreated %s, and status is ready", iVM.GetGlobalId()) + log.Debugf("VMcreated %s, and status is running", iVM.GetGlobalId()) iVM, err = ihost.GetIVMById(iVM.GetGlobalId()) if err != nil { log.Errorf("cannot find vm %s", err) return nil, err } + + err = cloudprovider.RetryUntil(func() (bool, error) { + idisks, err := iVM.GetIDisks() + if err != nil { + log.Errorf("cannot find vm disks %s", err) + return false, err + } + if len(idisks) == len(desc.DataDisks)+1 { + return true, nil + } else { + return false, nil + } + }, 10) + if err != nil { + return nil, err + } + data := fetchIVMinfo(desc, iVM, guest.Id, "root", passwd, action) return data, nil }) diff --git a/pkg/mcclient/modules/mod_cachedimages.go b/pkg/mcclient/modules/mod_cachedimages.go index 6d7aa561b6..8915b21462 100644 --- a/pkg/mcclient/modules/mod_cachedimages.go +++ b/pkg/mcclient/modules/mod_cachedimages.go @@ -10,6 +10,7 @@ func init() { "OS_Type", "OS_Distribution", "OS_version", "Hypervisor", "Host_count", "Status", "Ref_Count", "cached_count", "image_type", + "External_Id", }, []string{}) diff --git a/pkg/util/aws/image.go b/pkg/util/aws/image.go index 3372f950af..36be876cba 100644 --- a/pkg/util/aws/image.go +++ b/pkg/util/aws/image.go @@ -388,4 +388,4 @@ func (self *SRegion) addTags(resId string, key string, value string) error { return err } return nil -} \ No newline at end of file +} diff --git a/pkg/util/azure/disk.go b/pkg/util/azure/disk.go index a8410ccd59..e9dfc53f6d 100644 --- a/pkg/util/azure/disk.go +++ b/pkg/util/azure/disk.go @@ -26,9 +26,10 @@ type ImageDiskReference struct { type CreationData struct { CreateOption string `json:"createOption,omitempty"` StorageAccountID string - ImageReference *ImageDiskReference `json:"imageReference,omitempty"` - SourceURI string `json:"sourceUri,omitempty"` - SourceResourceID string `json:"sourceResourceId,omitempty"` + // ImageReference *ImageDiskReference `json:"imageReference,omitempty"` + ImageReference *ImageReference `json:"imageReference,omitempty"` + SourceURI string `json:"sourceUri,omitempty"` + SourceResourceID string `json:"sourceResourceId,omitempty"` } type DiskProperties struct { @@ -71,19 +72,25 @@ func (self *SRegion) CreateDisk(storageType string, name string, sizeGb int32, d Type: "Microsoft.Compute/disks", } if len(imageId) > 0 { - // TODO: need to fix scenarios where image is a public image - // XXX Qiu Jian - image, err := self.getPrivateImage(imageId) + image, err := self.GetImageById(imageId) if err != nil { return nil, err } - blobUrl := image.GetBlobUri() - if len(blobUrl) == 0 { - return nil, fmt.Errorf("failed to find blobUri for image %s", image.Name) - } - disk.Properties.CreationData = CreationData{ - CreateOption: "Import", - SourceURI: blobUrl, + if isPrivateImageID(image.ID) { + blobUrl := image.GetBlobUri() + if len(blobUrl) == 0 { + return nil, fmt.Errorf("failed to find blobUri for image %s", image.Name) + } + disk.Properties.CreationData = CreationData{ + CreateOption: "Import", + SourceURI: blobUrl, + } + } else { + imgRef := image.getImageReference() + disk.Properties.CreationData = CreationData{ + CreateOption: "FromImage", + ImageReference: &imgRef, + } } disk.Properties.OsType = image.GetOsType() } diff --git a/pkg/util/azure/host.go b/pkg/util/azure/host.go index 559fe15f6c..380884ba0e 100644 --- a/pkg/util/azure/host.go +++ b/pkg/util/azure/host.go @@ -131,8 +131,6 @@ func (self *SHost) CreateVM2(name string, imgId string, sysDiskSize int, instanc } func (self *SHost) _createVM(name string, imgId string, sysDiskSize int32, cpu int, memMB int, instanceType string, nicId string, ipAddr string, desc string, passwd string, storageType string, diskSizes []int, publicKey string, userData string) (string, error) { - // TODO: need to fix scenarios where image is a public image - // XXX Qiu Jian image, err := self.zone.region.GetImageById(imgId) if err != nil { log.Errorf("Get Image %s fail %s", imgId, err) @@ -169,9 +167,7 @@ func (self *SHost) _createVM(name string, imgId string, sysDiskSize int32, cpu i }, }, StorageProfile: StorageProfile{ - ImageReference: ImageReference{ - ID: image.ID, - }, + ImageReference: image.getImageReference(), OsDisk: OSDisk{ Name: fmt.Sprintf("vdisk_%s_%d", name, time.Now().UnixNano()), Caching: "ReadWrite", diff --git a/pkg/util/azure/image.go b/pkg/util/azure/image.go index 02ecccd12f..c29f57c94d 100644 --- a/pkg/util/azure/image.go +++ b/pkg/util/azure/image.go @@ -202,8 +202,12 @@ func (self *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) { } } +func isPrivateImageID(imageId string) bool { + return strings.HasPrefix(strings.ToLower(imageId), "/subscriptions/") +} + func (self *SRegion) GetImageById(imageId string) (SImage, error) { - if strings.HasPrefix(strings.ToLower(imageId), "/subscriptions/") { + if isPrivateImageID(imageId) { return self.getPrivateImage(imageId) } else { return self.getOfferedImage(imageId) @@ -491,3 +495,18 @@ func (region *SRegion) getOfferedImage(offerId string) (SImage, error) { image.Properties.ProvisioningState = ImageStatusAvailable return image, nil } + +func (image *SImage) getImageReference() ImageReference { + if isPrivateImageID(image.ID) { + return ImageReference{ + ID: image.ID, + } + } else { + return ImageReference{ + Sku: image.Sku, + Publisher: image.Publisher, + Version: image.Version, + Offer: image.Offer, + } + } +} diff --git a/pkg/util/azure/instance.go b/pkg/util/azure/instance.go index 62f0a2d14d..38e07c1f50 100644 --- a/pkg/util/azure/instance.go +++ b/pkg/util/azure/instance.go @@ -696,9 +696,7 @@ func (region *SRegion) ReplaceSystemDisk(instanceId, imageId, passwd, publicKey if err != nil { return "", err } - // TODO: need to fix scenarios where image is a public image - // XXX Qiu Jian - image, err := region.getPrivateImage(imageId) + image, err := region.GetImageById(imageId) if err != nil { return "", err } diff --git a/pkg/util/qcloud/image.go b/pkg/util/qcloud/image.go index 92c5a55e78..269df6358e 100644 --- a/pkg/util/qcloud/image.go +++ b/pkg/util/qcloud/image.go @@ -106,7 +106,7 @@ func (self *SImage) IsEmulated() bool { } func (self *SImage) GetGlobalId() string { - return fmt.Sprintf("%s-%s") + return self.ImageId } func (self *SImage) Delete(ctx context.Context) error { diff --git a/pkg/util/qcloud/instance.go b/pkg/util/qcloud/instance.go index 4bf14fe318..dd5c841c34 100644 --- a/pkg/util/qcloud/instance.go +++ b/pkg/util/qcloud/instance.go @@ -199,23 +199,8 @@ func (self *SInstance) getVpc() (*SVpc, error) { } func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, total, err := self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, 0, 50) - if err != nil { - log.Errorf("fetchDisks fail %s", err) - return nil, err - } - if total > len(disks) { - disks, _, err = self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, 0, total) - } - idisks := make([]cloudprovider.ICloudDisk, len(disks)) - for i := 0; i < len(disks); i += 1 { - store, err := self.host.zone.getStorageByCategory(disks[i].DiskType) - if err != nil { - return nil, err - } - disks[i].storage = store - idisks[i] = &disks[i] - } + idisks := make([]cloudprovider.ICloudDisk, 0) + if utils.IsInStringArray(self.SystemDisk.DiskType, []string{"LOCAL_BASIC", "LOCAL_SSD"}) { storage := SLocalStorage{zone: self.host.zone, storageType: self.SystemDisk.DiskType} disk := SLocalDisk{ @@ -242,6 +227,29 @@ func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { } } + disks := make([]SDisk, 0) + totalDisk := -1 + for totalDisk < 0 || len(disks) < totalDisk { + parts, total, err := self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, len(disks), 50) + if err != nil { + log.Errorf("fetchDisks fail %s", err) + return nil, err + } + if len(parts) > 0 { + disks = append(disks, parts...) + } + totalDisk = total + } + + for i := 0; i < len(disks); i += 1 { + store, err := self.host.zone.getStorageByCategory(disks[i].DiskType) + if err != nil { + return nil, err + } + disks[i].storage = store + idisks = append(idisks, &disks[i]) + } + return idisks, nil } @@ -453,6 +461,13 @@ func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) { if len(instances) == 0 { return nil, cloudprovider.ErrNotFound } + if len(instances) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + if instances[0].InstanceState == "LAUNCH_FAILED" { + return nil, cloudprovider.ErrNotFound + } + log.Debugf("%s", instances) return &instances[0], nil } @@ -542,7 +557,11 @@ func (self *SRegion) doStopVM(instanceId string, isForce bool) error { func (self *SRegion) doDeleteVM(instanceId string) error { params := make(map[string]string) - return self.instanceOperation(instanceId, "TerminateInstances", params) + err := self.instanceOperation(instanceId, "TerminateInstances", params) + if err != nil && cloudprovider.IsError(err, []string{"InvalidInstanceId.NotFound"}) { + return nil + } + return err } func (self *SRegion) StartVM(instanceId string) error { diff --git a/pkg/util/qcloud/storagecache.go b/pkg/util/qcloud/storagecache.go index 120c6c694e..99b10a61b7 100644 --- a/pkg/util/qcloud/storagecache.go +++ b/pkg/util/qcloud/storagecache.go @@ -119,7 +119,7 @@ func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImag if len(parts) == 0 { return nil, cloudprovider.ErrNotFound } - parts[1].storageCache = self + parts[0].storageCache = self return &parts[0], nil }