From 7848a36f325b1e3dc43137b5898578a346751e77 Mon Sep 17 00:00:00 2001 From: Zexi Date: Wed, 17 Apr 2019 17:30:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E8=B0=83=E5=BA=A6=E5=99=A8?= =?UTF-8?q?=20disk=20=E9=80=89=E6=8B=A9=20storage=20=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调度器选择 disk 对应一组 storages - 主备机磁盘选择 storage - 减少公有云选择 storage 的重复代码 --- pkg/apis/scheduler/api.go | 4 +- pkg/compute/guestdrivers/aliyun.go | 17 +----- pkg/compute/guestdrivers/aws.go | 18 +------ pkg/compute/guestdrivers/azure.go | 17 +----- pkg/compute/guestdrivers/baremetals.go | 5 +- pkg/compute/guestdrivers/huawei.go | 18 +------ pkg/compute/guestdrivers/managedvirtual.go | 25 +++++++++ pkg/compute/guestdrivers/openstack.go | 17 +----- pkg/compute/guestdrivers/qcloud.go | 17 +----- pkg/compute/guestdrivers/virtualization.go | 7 ++- pkg/compute/models/disks.go | 6 ++- pkg/compute/models/guest_actions.go | 6 +-- pkg/compute/models/guestdrivers.go | 2 +- pkg/compute/models/guests.go | 16 ++++-- pkg/compute/models/helper.go | 2 +- pkg/compute/tasks/disk_batch_create_task.go | 9 +++- pkg/compute/tasks/guest_backup_tasks.go | 21 ++++---- pkg/compute/tasks/guest_batch_create_task.go | 2 +- .../predicates/disk_schedtag_predicate.go | 54 ++++++++++++------- 19 files changed, 122 insertions(+), 141 deletions(-) diff --git a/pkg/apis/scheduler/api.go b/pkg/apis/scheduler/api.go index c86aded4af..6ef75c756e 100644 --- a/pkg/apis/scheduler/api.go +++ b/pkg/apis/scheduler/api.go @@ -80,8 +80,8 @@ func (input ScheduleInput) ToConditionInput() *jsonutils.JSONDict { } type CandidateDisk struct { - Index int `json:"index"` - StorageId string `json:"storage_id"` + Index int `json:"index"` + StorageIds []string `json:"storage_ids"` } type CandidateResource struct { diff --git a/pkg/compute/guestdrivers/aliyun.go b/pkg/compute/guestdrivers/aliyun.go index 79178480aa..059177c4e5 100644 --- a/pkg/compute/guestdrivers/aliyun.go +++ b/pkg/compute/guestdrivers/aliyun.go @@ -60,21 +60,8 @@ func (self *SAliyunGuestDriver) GetStorageTypes() []string { } } -func (self *SAliyunGuestDriver) ChooseHostStorage(host *models.SHost, backend string) *models.SStorage { - storages := host.GetAttachedStorages("") - for i := 0; i < len(storages); i += 1 { - if storages[i].StorageType == backend { - return &storages[i] - } - } - for _, stype := range self.GetStorageTypes() { - for i := 0; i < len(storages); i += 1 { - if storages[i].StorageType == stype { - return &storages[i] - } - } - } - return nil +func (self *SAliyunGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { + return self.chooseHostStorage(self, host, backend, storageIds) } func (self *SAliyunGuestDriver) GetDetachDiskStatus() ([]string, error) { diff --git a/pkg/compute/guestdrivers/aws.go b/pkg/compute/guestdrivers/aws.go index 159a84c5ad..fb278060b0 100644 --- a/pkg/compute/guestdrivers/aws.go +++ b/pkg/compute/guestdrivers/aws.go @@ -94,22 +94,8 @@ func (self *SAwsGuestDriver) GetStorageTypes() []string { } } -func (self *SAwsGuestDriver) ChooseHostStorage(host *models.SHost, backend string) *models.SStorage { - storages := host.GetAttachedStorages("") - for i := 0; i < len(storages); i += 1 { - if storages[i].StorageType == backend { - return &storages[i] - } - } - - for _, stype := range self.GetStorageTypes() { - for i := 0; i < len(storages); i += 1 { - if storages[i].StorageType == stype { - return &storages[i] - } - } - } - return nil +func (self *SAwsGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { + return self.chooseHostStorage(self, host, backend, storageIds) } func (self *SAwsGuestDriver) GetDetachDiskStatus() ([]string, error) { diff --git a/pkg/compute/guestdrivers/azure.go b/pkg/compute/guestdrivers/azure.go index 1a6e5c91b7..2f85124870 100644 --- a/pkg/compute/guestdrivers/azure.go +++ b/pkg/compute/guestdrivers/azure.go @@ -64,21 +64,8 @@ func (self *SAzureGuestDriver) GetStorageTypes() []string { } } -func (self *SAzureGuestDriver) ChooseHostStorage(host *models.SHost, backend string) *models.SStorage { - storages := host.GetAttachedStorages("") - for i := 0; i < len(storages); i += 1 { - if storages[i].StorageType == backend { - return &storages[i] - } - } - for _, stype := range self.GetStorageTypes() { - for i := 0; i < len(storages); i += 1 { - if storages[i].StorageType == stype { - return &storages[i] - } - } - } - return nil +func (self *SAzureGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { + return self.chooseHostStorage(self, host, backend, storageIds) } func (self *SAzureGuestDriver) GetMaxSecurityGroupCount() int { diff --git a/pkg/compute/guestdrivers/baremetals.go b/pkg/compute/guestdrivers/baremetals.go index c859faa8f4..094f8d0e37 100644 --- a/pkg/compute/guestdrivers/baremetals.go +++ b/pkg/compute/guestdrivers/baremetals.go @@ -213,7 +213,10 @@ func (self *SBaremetalGuestDriver) GetStorageTypes() []string { } } -func (self *SBaremetalGuestDriver) ChooseHostStorage(host *models.SHost, backend string) *models.SStorage { +func (self *SBaremetalGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { + if len(storageIds) != 0 { + return models.StorageManager.FetchStorageById(storageIds[0]) + } bs := host.GetBaremetalstorage() if bs == nil { return nil diff --git a/pkg/compute/guestdrivers/huawei.go b/pkg/compute/guestdrivers/huawei.go index f6e79ef0be..0195bc5706 100644 --- a/pkg/compute/guestdrivers/huawei.go +++ b/pkg/compute/guestdrivers/huawei.go @@ -52,22 +52,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) *models.SStorage { - storages := host.GetAttachedStorages("") - for i := 0; i < len(storages); i += 1 { - if storages[i].StorageType == backend { - return &storages[i] - } - } - - for _, stype := range self.GetStorageTypes() { - for i := 0; i < len(storages); i += 1 { - if storages[i].StorageType == stype { - return &storages[i] - } - } - } - return nil +func (self *SHuaweiGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { + return self.chooseHostStorage(self, host, backend, storageIds) } func (self *SHuaweiGuestDriver) GetDetachDiskStatus() ([]string, error) { diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index be0f82750b..6c5a9fac5b 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -778,3 +778,28 @@ func (self *SManagedVirtualizedGuestDriver) RequestRenewInstance(guest *models.S func (self *SManagedVirtualizedGuestDriver) IsSupportEip() bool { return true } + +func (self *SManagedVirtualizedGuestDriver) chooseHostStorage( + drv models.IGuestDriver, + host *models.SHost, + backend string, + storageIds []string, +) *models.SStorage { + if len(storageIds) != 0 { + return models.StorageManager.FetchStorageById(storageIds[0]) + } + storages := host.GetAttachedStorages("") + for i := 0; i < len(storages); i += 1 { + if storages[i].StorageType == backend { + return &storages[i] + } + } + for _, stype := range drv.GetStorageTypes() { + for i := 0; i < len(storages); i += 1 { + if storages[i].StorageType == stype { + return &storages[i] + } + } + } + return nil +} diff --git a/pkg/compute/guestdrivers/openstack.go b/pkg/compute/guestdrivers/openstack.go index b6f8824e68..87800f8fb5 100644 --- a/pkg/compute/guestdrivers/openstack.go +++ b/pkg/compute/guestdrivers/openstack.go @@ -61,21 +61,8 @@ func (self *SOpenStackGuestDriver) GetStorageTypes() []string { return []string{api.STORAGE_OPENSTACK_ISCSI} } -func (self *SOpenStackGuestDriver) ChooseHostStorage(host *models.SHost, backend string) *models.SStorage { - storages := host.GetAttachedStorages("") - for i := 0; i < len(storages); i++ { - if storages[i].StorageType == backend { - return &storages[i] - } - } - for _, stype := range self.GetStorageTypes() { - for i := 0; i < len(storages); i++ { - if storages[i].StorageType == stype { - return &storages[i] - } - } - } - return nil +func (self *SOpenStackGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { + return self.chooseHostStorage(self, host, backend, storageIds) } func (self *SOpenStackGuestDriver) GetDetachDiskStatus() ([]string, error) { diff --git a/pkg/compute/guestdrivers/qcloud.go b/pkg/compute/guestdrivers/qcloud.go index d5a0f54dae..b04823d7d3 100644 --- a/pkg/compute/guestdrivers/qcloud.go +++ b/pkg/compute/guestdrivers/qcloud.go @@ -63,21 +63,8 @@ func (self *SQcloudGuestDriver) GetStorageTypes() []string { } } -func (self *SQcloudGuestDriver) ChooseHostStorage(host *models.SHost, backend string) *models.SStorage { - storages := host.GetAttachedStorages("") - for i := 0; i < len(storages); i++ { - if storages[i].StorageType == backend { - return &storages[i] - } - } - for _, stype := range self.GetStorageTypes() { - for i := 0; i < len(storages); i++ { - if storages[i].StorageType == stype { - return &storages[i] - } - } - } - return nil +func (self *SQcloudGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { + return self.chooseHostStorage(self, host, backend, storageIds) } func (self *SQcloudGuestDriver) GetDetachDiskStatus() ([]string, error) { diff --git a/pkg/compute/guestdrivers/virtualization.go b/pkg/compute/guestdrivers/virtualization.go index ea9e22d47f..9f5b48cd6e 100644 --- a/pkg/compute/guestdrivers/virtualization.go +++ b/pkg/compute/guestdrivers/virtualization.go @@ -134,8 +134,11 @@ func (self *SVirtualizedGuestDriver) GetStorageTypes() []string { return nil } -func (self *SVirtualizedGuestDriver) ChooseHostStorage(host *models.SHost, backend string) *models.SStorage { - return host.GetLeastUsedStorage(backend) +func (self *SVirtualizedGuestDriver) ChooseHostStorage(host *models.SHost, backend string, storageIds []string) *models.SStorage { + if len(storageIds) == 0 { + return host.GetLeastUsedStorage(backend) + } + return models.StorageManager.FetchStorageById(storageIds[0]) } func (self *SVirtualizedGuestDriver) RequestGuestCreateInsertIso(ctx context.Context, imageId string, guest *models.SGuest, task taskman.ITask) error { diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index aec9034c51..588bd12668 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -452,14 +452,16 @@ func (disk *SDisk) SetStorage(storageId string, diskConfig *api.DiskConfig) erro return err } -func (disk *SDisk) SetStorageByHost(hostId string, diskConfig *api.DiskConfig) error { +func (disk *SDisk) SetStorageByHost(hostId string, diskConfig *api.DiskConfig, storageIds []string) error { host := HostManager.FetchHostById(hostId) backend := diskConfig.Backend if backend == "" { return fmt.Errorf("Backend is empty") } var storage *SStorage - if utils.IsInStringArray(backend, api.STORAGE_LIMITED_TYPES) { + if len(storageIds) != 0 { + storage = StorageManager.FetchStorageById(storageIds[0]) + } else if utils.IsInStringArray(backend, api.STORAGE_LIMITED_TYPES) { storage = host.GetLeastUsedStorage(backend) } else { // unlimited pulic cloud storages diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 6f099dc9b8..47d956e60d 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -1269,7 +1269,7 @@ func (self *SGuest) PerformCreatedisk(ctx context.Context, userCred mcclient.Tok lockman.LockObject(ctx, host) defer lockman.ReleaseObject(ctx, host) - err = self.CreateDisksOnHost(ctx, userCred, host, disksConf, pendingUsage, false, false, nil) + err = self.CreateDisksOnHost(ctx, userCred, host, disksConf, pendingUsage, false, false, nil, nil) if err != nil { QuotaManager.CancelPendingUsage(ctx, userCred, self.ProjectId, nil, pendingUsage) logclient.AddActionLogWithContext(ctx, self, logclient.ACT_CREATE, err.Error(), userCred, false) @@ -1924,7 +1924,7 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T } if len(newDisks) > 0 { - err := self.CreateDisksOnHost(ctx, userCred, host, newDisks, pendingUsage, false, false, nil) + err := self.CreateDisksOnHost(ctx, userCred, host, newDisks, pendingUsage, false, false, nil, nil) if err != nil { QuotaManager.CancelPendingUsage(ctx, userCred, self.ProjectId, nil, pendingUsage) return nil, httperrors.NewBadRequestError("Create disk on host error: %s", err) @@ -2925,7 +2925,7 @@ func (self *SGuest) importDisks(ctx context.Context, userCred mcclient.TokenCred return httperrors.NewInputParameterError("Empty import disks") } for _, disk := range disks { - disk, err := self.createDiskOnHost(ctx, userCred, self.GetHost(), ToDiskConfig(&disk), nil, true, true, nil) + disk, err := self.createDiskOnHost(ctx, userCred, self.GetHost(), ToDiskConfig(&disk), nil, true, true, nil, nil) if err != nil { return err } diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index 232bf05d27..dbfcd971a7 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -59,7 +59,7 @@ type IGuestDriver interface { GetRandomNetworkTypes() []string GetStorageTypes() []string - ChooseHostStorage(host *SHost, backend string) *SStorage + ChooseHostStorage(host *SHost, backend string, storageIds []string) *SStorage 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 580d7d35ea..0b7f21b5b1 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -2567,6 +2567,7 @@ func (self *SGuest) CreateDisksOnHost( inheritBilling bool, isWithServerCreate bool, candidate *schedapi.CandidateResource, + backupCandidate *schedapi.CandidateResource, ) error { for idx := 0; idx < len(disks); idx += 1 { diskConfig, err := parseDiskInfo(ctx, userCred, disks[idx]) @@ -2574,10 +2575,14 @@ func (self *SGuest) CreateDisksOnHost( return err } var candidateDisk *schedapi.CandidateDisk + var backupCandidateDisk *schedapi.CandidateDisk if candidate != nil && len(candidate.Disks) >= idx { candidateDisk = candidate.Disks[idx] } - disk, err := self.createDiskOnHost(ctx, userCred, host, diskConfig, pendingUsage, inheritBilling, isWithServerCreate, candidateDisk) + if backupCandidate != nil && len(backupCandidate.Disks) >= idx { + backupCandidateDisk = backupCandidate.Disks[idx] + } + disk, err := self.createDiskOnHost(ctx, userCred, host, diskConfig, pendingUsage, inheritBilling, isWithServerCreate, candidateDisk, backupCandidateDisk) if err != nil { return err } @@ -2624,10 +2629,10 @@ func (self *SGuest) createDiskOnStorage(ctx context.Context, userCred mcclient.T func (self *SGuest) ChooseHostStorage(host *SHost, backend string, candidate *schedapi.CandidateDisk) *SStorage { log.Infof("==========candidate %#v", candidate) - if candidate == nil { - return self.GetDriver().ChooseHostStorage(host, backend) + if candidate == nil || len(candidate.StorageIds) == 0 { + return self.GetDriver().ChooseHostStorage(host, backend, nil) } - return StorageManager.FetchStorageById(candidate.StorageId) + return self.GetDriver().ChooseHostStorage(host, backend, candidate.StorageIds) } func (self *SGuest) createDiskOnHost( @@ -2639,6 +2644,7 @@ func (self *SGuest) createDiskOnHost( inheritBilling bool, isWithServerCreate bool, candidate *schedapi.CandidateDisk, + backupCandidate *schedapi.CandidateDisk, ) (*SDisk, error) { storage := self.ChooseHostStorage(host, diskConfig.Backend, candidate) log.Debugf("Choose storage %s:%s for disk %#v", storage.Name, storage.Id, diskConfig) @@ -2652,7 +2658,7 @@ func (self *SGuest) createDiskOnHost( // TODO: use scheduler candidate storage if len(self.BackupHostId) > 0 { backupHost := HostManager.FetchHostById(self.BackupHostId) - backupStorage := self.GetDriver().ChooseHostStorage(backupHost, diskConfig.Backend) + backupStorage := self.GetDriver().ChooseHostStorage(backupHost, diskConfig.Backend, backupCandidate.StorageIds) 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 a548d14c80..cee21e3acb 100644 --- a/pkg/compute/models/helper.go +++ b/pkg/compute/models/helper.go @@ -97,7 +97,7 @@ func ValidateScheduleCreateData(ctx context.Context, userCred mcclient.TokenCred return nil, err } - defaultStorage := GetDriver(hypervisor).ChooseHostStorage(baremetal, "") + defaultStorage := GetDriver(hypervisor).ChooseHostStorage(baremetal, "", nil) if defaultStorage == nil { return nil, httperrors.NewInsufficientResourceError("no valid storage on host") } diff --git a/pkg/compute/tasks/disk_batch_create_task.go b/pkg/compute/tasks/disk_batch_create_task.go index 7dbce2fb19..d5a2b57cc8 100644 --- a/pkg/compute/tasks/disk_batch_create_task.go +++ b/pkg/compute/tasks/disk_batch_create_task.go @@ -108,8 +108,13 @@ func (self *DiskBatchCreateTask) SaveScheduleResult(ctx context.Context, obj ISc return } - //err = disk.SetStorageByHost(hostId, &diskConfig) - err = disk.SetStorage(candidate.Disks[0].StorageId, diskConfig) + storageIds := []string{} + var hostId string + if candidate != nil && len(candidate.Disks) != 0 { + hostId = candidate.HostId + storageIds = candidate.Disks[0].StorageIds + } + err = disk.SetStorageByHost(hostId, diskConfig, storageIds) if err != nil { models.QuotaManager.CancelPendingUsage(ctx, self.UserCred, disk.ProjectId, &pendingUsage, "aStorage) disk.SetStatus(self.UserCred, api.DISK_ALLOC_FAILED, err.Error()) diff --git a/pkg/compute/tasks/guest_backup_tasks.go b/pkg/compute/tasks/guest_backup_tasks.go index c41372061e..0038b7a241 100644 --- a/pkg/compute/tasks/guest_backup_tasks.go +++ b/pkg/compute/tasks/guest_backup_tasks.go @@ -231,21 +231,24 @@ func (self *GuestCreateBackupTask) SaveScheduleResult(ctx context.Context, obj I guest.SetHostIdWithBackup(self.UserCred, guest.HostId, targetHostId) db.OpsLog.LogEvent(guest, db.ACT_CREATE_BACKUP, fmt.Sprintf("guest backup start create on host %s", targetHostId), self.UserCred) - // backup disk only support disk backend local - storage := guest.GetDriver().ChooseHostStorage(targetHost, api.STORAGE_LOCAL) - if storage == nil { - self.TaskFailed(ctx, guest, "Get backup storage error") - return - } - self.StartCreateBackupDisks(ctx, guest, storage.Id) + self.StartCreateBackupDisks(ctx, guest, targetHost, candidate.Disks) } -func (self *GuestCreateBackupTask) StartCreateBackupDisks(ctx context.Context, guest *models.SGuest, storageId string) { +func (self *GuestCreateBackupTask) StartCreateBackupDisks(ctx context.Context, guest *models.SGuest, host *models.SHost, candidateDisks []*schedapi.CandidateDisk) { guestDisks := guest.GetDisks() for i := 0; i < len(guestDisks); i++ { + var candidateDisk *schedapi.CandidateDisk + if len(candidateDisks) >= i { + candidateDisk = candidateDisks[i] + } + storage := guest.ChooseHostStorage(host, api.STORAGE_LOCAL, candidateDisk) + if storage == nil { + self.TaskFailed(ctx, guest, "Get backup storage error") + return + } disk := guestDisks[i].GetDisk() db.Update(disk, func() error { - disk.BackupStorageId = storageId + disk.BackupStorageId = storage.Id return nil }) } diff --git a/pkg/compute/tasks/guest_batch_create_task.go b/pkg/compute/tasks/guest_batch_create_task.go index 7cf633716f..d67f3e7187 100644 --- a/pkg/compute/tasks/guest_batch_create_task.go +++ b/pkg/compute/tasks/guest_batch_create_task.go @@ -101,7 +101,7 @@ func (self *GuestBatchCreateTask) allocateGuestOnHost(ctx context.Context, guest } guest.GetDriver().PrepareDiskRaidConfig(self.UserCred, host, input.BaremetalDiskConfigs) - err = guest.CreateDisksOnHost(ctx, self.UserCred, host, input.Disks, &pendingUsage, true, true, candidate) + err = guest.CreateDisksOnHost(ctx, self.UserCred, host, input.Disks, &pendingUsage, true, true, candidate, candidate.BackupCandidate) self.SetPendingUsage(&pendingUsage) if err != nil { diff --git a/pkg/scheduler/algorithm/predicates/disk_schedtag_predicate.go b/pkg/scheduler/algorithm/predicates/disk_schedtag_predicate.go index 1f4f59b4f5..8ae7a24c49 100644 --- a/pkg/scheduler/algorithm/predicates/disk_schedtag_predicate.go +++ b/pkg/scheduler/algorithm/predicates/disk_schedtag_predicate.go @@ -16,6 +16,7 @@ package predicates import ( "fmt" + "sort" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -266,15 +267,19 @@ func (p *DiskSchedtagPredicate) OnSelectEnd(u *core.Unit, c core.Candidater, cou } func (p *DiskSchedtagPredicate) allocatedDiskResource(c core.Candidater, disk *computeapi.DiskConfig, storages []*PredicatedStorage) *schedapi.CandidateDisk { - storage := p.selectStorage(disk, storages) - log.Debugf("Select %s storage %s:%s for disk: %d", c.Getter().Name(), storage.Id, storage.Name, disk.Index) + sortStorages := p.selectStorages(disk, storages) + storageIds := []string{} + for _, s := range sortStorages { + storageIds = append(storageIds, s.Id) + } + log.Debugf("Suggestion %s storages %v for disk: %d", c.Getter().Name(), storageIds, disk.Index) return &schedapi.CandidateDisk{ - Index: disk.Index, - StorageId: storage.Id, + Index: disk.Index, + StorageIds: storageIds, } } -func (p *DiskSchedtagPredicate) selectStorage(d *computeapi.DiskConfig, storages []*PredicatedStorage) *api.CandidateStorage { +func (p *DiskSchedtagPredicate) selectStorages(d *computeapi.DiskConfig, storages []*PredicatedStorage) []*api.CandidateStorage { preferStorages := []*api.CandidateStorage{} noTagStorages := []*api.CandidateStorage{} avoidStorages := []*api.CandidateStorage{} @@ -292,10 +297,10 @@ func (p *DiskSchedtagPredicate) selectStorage(d *computeapi.DiskConfig, storages sortStorages = append(sortStorages, preferStorages...) sortStorages = append(sortStorages, noTagStorages...) sortStorages = append(sortStorages, avoidStorages...) - return p.GetLeastUsedStorage(sortStorages, d.Backend) + return p.SortLeastUsedStorage(sortStorages, d.Backend) } -func (p *DiskSchedtagPredicate) GetLeastUsedStorage(storages []*api.CandidateStorage, backend string) *api.CandidateStorage { +func (p *DiskSchedtagPredicate) SortLeastUsedStorage(storages []*api.CandidateStorage, backend string) []*api.CandidateStorage { backendStorages := make([]*api.CandidateStorage, 0) if backend != "" { for _, s := range storages { @@ -309,21 +314,30 @@ func (p *DiskSchedtagPredicate) GetLeastUsedStorage(storages []*api.CandidateSto if len(backendStorages) == 0 { backendStorages = storages } - return p.getLeastUsedStorage(backendStorages) + return p.sortByLeastUsedStorages(backendStorages) } -func (p *DiskSchedtagPredicate) getLeastUsedStorage(storages []*api.CandidateStorage) *api.CandidateStorage { - var best *api.CandidateStorage - var bestCap int - for i := 0; i < len(storages); i++ { - s := storages[i] - capa := s.GetFreeCapacity() - if best == nil || bestCap < capa { - bestCap = capa - best = s - } - } - return best +type sortStorages []*api.CandidateStorage + +func (s sortStorages) Len() int { + return len(s) +} + +func (s sortStorages) Less(i, j int) bool { + s1, s2 := s[i], s[j] + cap1 := s1.GetFreeCapacity() + cap2 := s2.GetFreeCapacity() + return cap1 > cap2 +} + +func (s sortStorages) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (p *DiskSchedtagPredicate) sortByLeastUsedStorages(storages []*api.CandidateStorage) []*api.CandidateStorage { + ss := sortStorages(storages) + sort.Sort(ss) + return []*api.CandidateStorage(ss) } func (p *DiskSchedtagPredicate) GetHypervisorDriver() models.IGuestDriver {