diff --git a/pkg/compute/guestdrivers/aliyun.go b/pkg/compute/guestdrivers/aliyun.go index fb40d59827..3817cf5704 100644 --- a/pkg/compute/guestdrivers/aliyun.go +++ b/pkg/compute/guestdrivers/aliyun.go @@ -77,8 +77,8 @@ func (self *SAliyunGuestDriver) GetStorageTypes() []string { } } -func (self *SAliyunGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { - return self.chooseHostStorage(self, host, backend, storageIds) +func (self *SAliyunGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) { + return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil } func (self *SAliyunGuestDriver) GetDetachDiskStatus() ([]string, error) { diff --git a/pkg/compute/guestdrivers/aws.go b/pkg/compute/guestdrivers/aws.go index 71f9efc27e..ad8db01b36 100644 --- a/pkg/compute/guestdrivers/aws.go +++ b/pkg/compute/guestdrivers/aws.go @@ -131,8 +131,8 @@ func (self *SAwsGuestDriver) GetStorageTypes() []string { } } -func (self *SAwsGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { - return self.chooseHostStorage(self, host, backend, storageIds) +func (self *SAwsGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) { + return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil } func (self *SAwsGuestDriver) GetDetachDiskStatus() ([]string, error) { diff --git a/pkg/compute/guestdrivers/azure.go b/pkg/compute/guestdrivers/azure.go index dedd114ebb..9e9944b6c4 100644 --- a/pkg/compute/guestdrivers/azure.go +++ b/pkg/compute/guestdrivers/azure.go @@ -79,8 +79,8 @@ func (self *SAzureGuestDriver) GetStorageTypes() []string { } } -func (self *SAzureGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { - return self.chooseHostStorage(self, host, backend, storageIds) +func (self *SAzureGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) { + return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil } func (self *SAzureGuestDriver) GetMaxSecurityGroupCount() int { diff --git a/pkg/compute/guestdrivers/baremetals.go b/pkg/compute/guestdrivers/baremetals.go index bbd0186bd8..636dfe9ee9 100644 --- a/pkg/compute/guestdrivers/baremetals.go +++ b/pkg/compute/guestdrivers/baremetals.go @@ -249,15 +249,15 @@ func (self *SBaremetalGuestDriver) GetStorageTypes() []string { } } -func (self *SBaremetalGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { +func (self *SBaremetalGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) { if len(storageIds) != 0 { - return models.StorageManager.FetchStorageById(storageIds[0]) + return models.StorageManager.FetchStorageById(storageIds[0]), nil } bs := host.GetBaremetalstorage() if bs == nil { - return nil + return nil, nil } - return bs.GetStorage() + return bs.GetStorage(), nil } func (self *SBaremetalGuestDriver) RequestGuestCreateAllDisks(ctx context.Context, guest *models.SGuest, task taskman.ITask) error { diff --git a/pkg/compute/guestdrivers/esxi.go b/pkg/compute/guestdrivers/esxi.go index 6bcd90379a..b7aaf74ddb 100644 --- a/pkg/compute/guestdrivers/esxi.go +++ b/pkg/compute/guestdrivers/esxi.go @@ -79,6 +79,46 @@ func (self *SESXiGuestDriver) GetDefaultSysDiskBackend() string { return api.STORAGE_LOCAL } +func (self *SESXiGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) { + if !options.Options.LockStorageFromCachedimage || len(diskConfig.ImageId) == 0 { + return self.SVirtualizedGuestDriver.ChooseHostStorage(host, diskConfig, storageIds) + } + var ( + image *cloudprovider.SImage + err error + ) + obj, err := models.CachedimageManager.FetchById(diskConfig.ImageId) + if err != nil { + return nil, errors.Wrapf(err, "unable to fetch cachedimage %s", diskConfig.ImageId) + } + cachedimage := obj.(*models.SCachedimage) + if len(cachedimage.ExternalId) > 0 || cachedimage.ImageType != cloudprovider.CachedImageTypeSystem { + return self.SVirtualizedGuestDriver.ChooseHostStorage(host, diskConfig, storageIds) + } + storages, err := cachedimage.GetStorages() + if err != nil { + return nil, errors.Wrapf(err, "unable to GetStorages of cachedimage %s", diskConfig.ImageId) + } + if len(storages) == 0 { + log.Warningf("there no storage associated with cachedimage %q", image.Id) + return self.SVirtualizedGuestDriver.ChooseHostStorage(host, diskConfig, storageIds) + } + if len(storages) > 1 { + log.Warningf("there are multiple storageCache associated with caheimage %q", image.Id) + } + wantStorageIds := make([]string, len(storages)) + for i := range wantStorageIds { + wantStorageIds[i] = storages[i].GetId() + } + for i := range wantStorageIds { + if utils.IsInStringArray(wantStorageIds[i], storageIds) { + log.Infof("use storage %q in where cachedimage %q", wantStorageIds[i], image.Id) + return &storages[i], nil + } + } + return self.SVirtualizedGuestDriver.ChooseHostStorage(host, diskConfig, storageIds) +} + func (self *SESXiGuestDriver) GetMinimalSysDiskSizeGb() int { return options.Options.DefaultDiskSizeMB / 1024 } diff --git a/pkg/compute/guestdrivers/google.go b/pkg/compute/guestdrivers/google.go index 5b9be59eb9..652412d541 100644 --- a/pkg/compute/guestdrivers/google.go +++ b/pkg/compute/guestdrivers/google.go @@ -81,8 +81,8 @@ func (self *SGoogleGuestDriver) GetStorageTypes() []string { } } -func (self *SGoogleGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { - return self.chooseHostStorage(self, host, backend, storageIds) +func (self *SGoogleGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) { + return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil } func (self *SGoogleGuestDriver) GetGuestInitialStateAfterCreate() string { diff --git a/pkg/compute/guestdrivers/huawei.go b/pkg/compute/guestdrivers/huawei.go index 0c040228dc..a12e897a41 100644 --- a/pkg/compute/guestdrivers/huawei.go +++ b/pkg/compute/guestdrivers/huawei.go @@ -67,8 +67,8 @@ func (self *SHuaweiGuestDriver) GetStorageTypes() []string { return []string{api.STORAGE_HUAWEI_SATA, api.STORAGE_HUAWEI_SAS, api.STORAGE_HUAWEI_SSD} } -func (self *SHuaweiGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { - return self.chooseHostStorage(self, host, backend, storageIds) +func (self *SHuaweiGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) { + return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil } func (self *SHuaweiGuestDriver) GetDetachDiskStatus() ([]string, error) { diff --git a/pkg/compute/guestdrivers/openstack.go b/pkg/compute/guestdrivers/openstack.go index cddff6285b..ad5ca8a996 100644 --- a/pkg/compute/guestdrivers/openstack.go +++ b/pkg/compute/guestdrivers/openstack.go @@ -91,8 +91,8 @@ func (self *SOpenStackGuestDriver) GetStorageTypes() []string { return storages } -func (self *SOpenStackGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { - return self.chooseHostStorage(self, host, backend, storageIds) +func (self *SOpenStackGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) { + return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil } func (self *SOpenStackGuestDriver) GetDetachDiskStatus() ([]string, error) { diff --git a/pkg/compute/guestdrivers/qcloud.go b/pkg/compute/guestdrivers/qcloud.go index 082e67a302..a2f48173cf 100644 --- a/pkg/compute/guestdrivers/qcloud.go +++ b/pkg/compute/guestdrivers/qcloud.go @@ -75,8 +75,8 @@ func (self *SQcloudGuestDriver) GetStorageTypes() []string { } } -func (self *SQcloudGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { - return self.chooseHostStorage(self, host, backend, storageIds) +func (self *SQcloudGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) { + return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil } func (self *SQcloudGuestDriver) GetDetachDiskStatus() ([]string, error) { diff --git a/pkg/compute/guestdrivers/virtualization.go b/pkg/compute/guestdrivers/virtualization.go index 31538e33d7..490a7c936a 100644 --- a/pkg/compute/guestdrivers/virtualization.go +++ b/pkg/compute/guestdrivers/virtualization.go @@ -174,11 +174,11 @@ func (self *SVirtualizedGuestDriver) GetStorageTypes() []string { return nil } -func (self *SVirtualizedGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { +func (self *SVirtualizedGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) { if len(storageIds) == 0 { - return host.GetLeastUsedStorage(backend) + return host.GetLeastUsedStorage(diskConfig.Backend), nil } - return models.StorageManager.FetchStorageById(storageIds[0]) + return models.StorageManager.FetchStorageById(storageIds[0]), nil } func (self *SVirtualizedGuestDriver) RequestGuestCreateInsertIso(ctx context.Context, imageId string, guest *models.SGuest, task taskman.ITask) error { diff --git a/pkg/compute/guestdrivers/zstack.go b/pkg/compute/guestdrivers/zstack.go index faaf4443da..4dd4d6864a 100644 --- a/pkg/compute/guestdrivers/zstack.go +++ b/pkg/compute/guestdrivers/zstack.go @@ -85,8 +85,8 @@ func (self *SZStackGuestDriver) GetMaxSecurityGroupCount() int { return 1 } -func (self *SZStackGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { - return self.chooseHostStorage(self, host, backend, storageIds) +func (self *SZStackGuestDriver) ChooseHostStorage(host *models.SHost, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) { + return self.chooseHostStorage(self, host, diskConfig.Backend, storageIds), nil } func (self *SZStackGuestDriver) GetDetachDiskStatus() ([]string, error) { diff --git a/pkg/compute/models/cachedimages.go b/pkg/compute/models/cachedimages.go index 68f495b738..4d414765ff 100644 --- a/pkg/compute/models/cachedimages.go +++ b/pkg/compute/models/cachedimages.go @@ -272,6 +272,18 @@ func (manager *SCachedimageManager) cacheGlanceImageInfo(ctx context.Context, us } } +func (image *SCachedimage) GetStorages() ([]SStorage, error) { + sq := StorageManager.Query() + storagecacheimageSubq := StoragecachedimageManager.Query("storagecache_id").Equals("cachedimage_id", image.GetId()).SubQuery() + sq.Join(storagecacheimageSubq, sqlchemy.Equals(sq.Field("storagecache_id"), storagecacheimageSubq.Field("storagecache_id"))) + storages := make([]SStorage, 0, 1) + err := db.FetchModelObjects(StorageManager, sq, &storages) + if err != nil { + return nil, errors.Wrap(err, "FetchModelObjects") + } + return storages, nil +} + func (manager *SCachedimageManager) GetImageById(ctx context.Context, userCred mcclient.TokenCredential, imageId string, refresh bool) (*cloudprovider.SImage, error) { imgObj, _ := manager.FetchById(imageId) if imgObj != nil { diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index 9822acb665..7318a1a6e6 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -73,7 +73,7 @@ type IGuestDriver interface { GetRandomNetworkTypes() []string GetStorageTypes() []string - ChooseHostStorage(host *SHost, backend string, storageIds []string) *SStorage + ChooseHostStorage(host *SHost, diskConfig *api.DiskConfig, storageIds []string) (*SStorage, error) StartGuestCreateTask(guest *SGuest, ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, pendingUsage quotas.IQuota, parentTaskId string) error diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index f629482f53..f3d86fbf2b 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -3426,11 +3426,11 @@ func (self *SGuest) createDiskOnStorage(ctx context.Context, userCred mcclient.T return disk, nil } -func (self *SGuest) ChooseHostStorage(host *SHost, backend string, candidate *schedapi.CandidateDisk) *SStorage { +func (self *SGuest) ChooseHostStorage(host *SHost, diskConfig *api.DiskConfig, candidate *schedapi.CandidateDisk) (*SStorage, error) { if candidate == nil || len(candidate.StorageIds) == 0 { - return self.GetDriver().ChooseHostStorage(host, backend, nil) + return self.GetDriver().ChooseHostStorage(host, diskConfig, nil) } - return self.GetDriver().ChooseHostStorage(host, backend, candidate.StorageIds) + return self.GetDriver().ChooseHostStorage(host, diskConfig, candidate.StorageIds) } func (self *SGuest) createDiskOnHost( @@ -3445,7 +3445,10 @@ func (self *SGuest) createDiskOnHost( backupCandidate *schedapi.CandidateDisk, autoAttach bool, ) (*SDisk, error) { - var storage *SStorage + var ( + storage *SStorage + err error + ) if len(diskConfig.Storage) > 0 { _storage, err := StorageManager.FetchByIdOrName(userCred, diskConfig.Storage) if err != nil { @@ -3456,7 +3459,10 @@ func (self *SGuest) createDiskOnHost( } storage = _storage.(*SStorage) } else { - storage = self.ChooseHostStorage(host, diskConfig.Backend, candidate) + storage, err = self.ChooseHostStorage(host, diskConfig, candidate) + if err != nil { + return nil, errors.Wrap(err, "ChooseHostStorage") + } } if storage == nil { return nil, fmt.Errorf("No storage on %s to create disk for %s", host.GetName(), diskConfig.Backend) @@ -3468,7 +3474,10 @@ func (self *SGuest) createDiskOnHost( } if len(self.BackupHostId) > 0 { backupHost := HostManager.FetchHostById(self.BackupHostId) - backupStorage := self.ChooseHostStorage(backupHost, diskConfig.Backend, backupCandidate) + backupStorage, err := self.ChooseHostStorage(backupHost, diskConfig, backupCandidate) + if err != nil { + return nil, errors.Wrap(err, "ChooseHostStorage") + } diff, err := db.Update(disk, func() error { disk.BackupStorageId = backupStorage.Id return nil diff --git a/pkg/compute/models/helper.go b/pkg/compute/models/helper.go index cba5561de7..2d9270c139 100644 --- a/pkg/compute/models/helper.go +++ b/pkg/compute/models/helper.go @@ -100,7 +100,10 @@ func ValidateScheduleCreateData(ctx context.Context, userCred mcclient.TokenCred return nil, err } - defaultStorage := GetDriver(hypervisor).ChooseHostStorage(baremetal, "", nil) + defaultStorage, err := GetDriver(hypervisor).ChooseHostStorage(baremetal, &api.DiskConfig{}, nil) + if err != nil { + return nil, errors.Wrap(err, "ChooseHostStorage") + } if defaultStorage == nil { return nil, httperrors.NewInsufficientResourceError("no valid storage on host") } diff --git a/pkg/compute/options/options.go b/pkg/compute/options/options.go index a8bb69ebce..14ba767354 100644 --- a/pkg/compute/options/options.go +++ b/pkg/compute/options/options.go @@ -146,6 +146,8 @@ type ComputeOptions struct { SyncStorageCapacityUsedIntervalMinutes int `help:"interval sync storage capacity used" default:"10"` + LockStorageFromCachedimage bool `help:"must use storage in where selected cachedimage when creating vm"` + SCapabilityOptions SASControllerOptions common_options.CommonOptions diff --git a/pkg/compute/tasks/guest_backup_tasks.go b/pkg/compute/tasks/guest_backup_tasks.go index 9444636bae..012e761aa9 100644 --- a/pkg/compute/tasks/guest_backup_tasks.go +++ b/pkg/compute/tasks/guest_backup_tasks.go @@ -328,7 +328,12 @@ func (self *GuestCreateBackupTask) StartCreateBackupDisks(ctx context.Context, g if len(candidateDisks) >= i { candidateDisk = candidateDisks[i] } - storage := guest.ChooseHostStorage(host, api.STORAGE_LOCAL, candidateDisk) + diskConfig := &api.DiskConfig{Backend: api.STORAGE_LOCAL} + storage, err := guest.ChooseHostStorage(host, diskConfig, candidateDisk) + if err != nil { + self.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("unable to ChooseHostStorage: %v", err))) + return + } if storage == nil { self.TaskFailed(ctx, guest, jsonutils.NewString("Get backup storage error")) return