hotfix: validate resize disk when change config

This commit is contained in:
ioito
2019-07-29 21:49:30 +08:00
parent ed2804da68
commit 5712dceb6f
5 changed files with 112 additions and 0 deletions
+8
View File
@@ -132,6 +132,14 @@ func (self *SBaseGuestDriver) GetChangeConfigStatus() ([]string, error) {
return []string{}, fmt.Errorf("This Guest driver dose not implement GetChangeConfigStatus")
}
func (self *SBaseGuestDriver) ValidateChangeConfig(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, cpuChanged bool, memChanged bool, newDisks []*api.DiskConfig) error {
return nil
}
func (self *SBaseGuestDriver) ValidateDetachDisk(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, disk *models.SDisk) error {
return nil
}
func (self *SBaseGuestDriver) ValidateCreateEip(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) error {
return httperrors.NewInputParameterError("Not Implement ValidateCreateEip")
}
+60
View File
@@ -105,6 +105,9 @@ func (self *SQcloudGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *m
if utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_LOCAL_BASIC, api.STORAGE_LOCAL_SSD}) {
return fmt.Errorf("Cannot resize %s disk", storage.StorageType)
}
if disk.DiskSize/1024%10 > 0 {
return fmt.Errorf("Resize disk size must be an integer multiple of 10G")
}
return nil
}
@@ -145,10 +148,67 @@ func (self *SQcloudGuestDriver) ValidateCreateData(ctx context.Context, userCred
return nil, httperrors.NewInputParameterError("The %s disk size must be in the range of 100GB ~ 16000GB", disk.Backend)
}
}
if disk.SizeMb/1024%10 > 0 {
return nil, httperrors.NewInputParameterError("Data disk size must be an integer multiple of 10G")
}
}
return input, nil
}
func (self *SQcloudGuestDriver) ValidateChangeConfig(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, cpuChanged bool, memChanged bool, newDisks []*api.DiskConfig) error {
if cpuChanged || memChanged {
disk, err := guest.GetSystemDisk()
if err != nil {
return httperrors.NewResourceNotFoundError("failed to found system disk error: %v", err)
}
storage := disk.GetStorage()
if storage == nil {
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}) {
return httperrors.NewUnsupportOperationError("The system disk is locally stored and does not support changing configuration")
}
}
for _, newDisk := range newDisks {
switch newDisk.Backend {
case api.STORAGE_CLOUD_BASIC:
if newDisk.SizeMb < 10*1024 || newDisk.SizeMb > 16000*1024 {
return httperrors.NewInputParameterError("The %s disk size must be in the range of 10GB ~ 16000GB", newDisk.Backend)
}
case api.STORAGE_CLOUD_PREMIUM:
if newDisk.SizeMb < 50*1024 || newDisk.SizeMb > 16000*1024 {
return httperrors.NewInputParameterError("The %s disk size must be in the range of 50GB ~ 16000GB", newDisk.Backend)
}
case api.STORAGE_CLOUD_SSD:
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:
return httperrors.NewUnsupportOperationError("Not support create local storage disks")
case "": //这里Backend为空有可能会导致创建出来还是local storage,依然会出错,需要用户显式指定
return httperrors.NewInputParameterError("Please input new disk backend type")
}
if newDisk.SizeMb/1024%10 > 0 {
return httperrors.NewInputParameterError("Data disk size must be an integer multiple of 10G")
}
}
return nil
}
func (self *SQcloudGuestDriver) ValidateDetachDisk(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, disk *models.SDisk) error {
storage := disk.GetStorage()
if storage == nil {
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}) {
return httperrors.NewUnsupportOperationError("The disk is locally stored and does not support detach")
}
return nil
}
func (self *SQcloudGuestDriver) GetGuestInitialStateAfterCreate() string {
return api.VM_RUNNING
}
+16
View File
@@ -1443,6 +1443,12 @@ func (self *SGuest) PerformDetachdisk(ctx context.Context, userCred mcclient.Tok
if keepDisk && !self.GetDriver().CanKeepDetachDisk() {
return nil, httperrors.NewInputParameterError("Cannot keep detached disk")
}
err = self.GetDriver().ValidateDetachDisk(ctx, userCred, self, disk)
if err != nil {
return nil, err
}
if utils.IsInStringArray(self.Status, detachDiskStatus) {
self.SetStatus(userCred, api.VM_DETACH_DISK, "")
err = self.StartGuestDetachdiskTask(ctx, userCred, disk, keepDisk, "", false)
@@ -1984,6 +1990,7 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
}
if diskConf.SizeMb > 0 {
if diskIdx >= len(disks) {
// 这里backeend为空时,qcloud有可能会选择local_ssd作为后端存储,会导致报错(主要是climc)
storage := host.GetLeastUsedStorage(diskConf.Backend)
if storage == nil {
return nil, httperrors.NewResourceNotReadyError("host not connect storage %s", diskConf.Backend)
@@ -2011,6 +2018,10 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
if !ok {
diskSizes[storage.Id] = 0
}
err = self.ValidateResizeDisk(disk, storage)
if err != nil {
return nil, httperrors.NewUnsupportOperationError(err.Error())
}
diskSizes[storage.Id] = diskSizes[storage.Id] + diskConf.SizeMb - oldSize
}
}
@@ -2044,6 +2055,11 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
confs.Set("guest_online", jsonutils.JSONTrue)
}
err = self.GetDriver().ValidateChangeConfig(ctx, userCred, self, cpuChanged, memChanged, newDisks)
if err != nil {
return nil, err
}
// schedulr forecast
schedDesc := self.confToSchedDesc(addCpu, addMem, addDisk)
s := auth.GetAdminSession(ctx, options.Options.Region, "")
+3
View File
@@ -168,6 +168,9 @@ type IGuestDriver interface {
OnGuestChangeCpuMemFailed(ctx context.Context, guest *SGuest, data *jsonutils.JSONDict, task taskman.ITask) error
IsSupportGuestClone() bool
ValidateChangeConfig(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, cpuChanged bool, memChanged bool, newDisks []*api.DiskConfig) error
ValidateDetachDisk(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, disk *SDisk) error
IsNeedInjectPasswordByCloudInit(desc *cloudprovider.SManagedVMCreateConfig) bool
GetUserDataType() string
}
+25
View File
@@ -521,6 +521,31 @@ func (guest *SGuest) DiskCount() (int, error) {
return guest.GetDisksQuery().CountWithError()
}
func (guest *SGuest) GetSystemDisk() (*SDisk, error) {
q := DiskManager.Query().Equals("disk_type", api.DISK_TYPE_SYS)
gs := GuestdiskManager.Query().SubQuery()
q = q.Join(gs, sqlchemy.Equals(gs.Field("disk_id"), q.Field("id"))).
Filter(sqlchemy.Equals(gs.Field("guest_id"), guest.Id))
count, err := q.CountWithError()
if err != nil {
return nil, err
}
if count > 1 {
return nil, sqlchemy.ErrDuplicateEntry
}
if count == 0 {
return nil, sql.ErrNoRows
}
disk := &SDisk{}
err = q.First(disk)
if err != nil {
return nil, errors.Wrap(err, "q.First(disk)")
}
disk.SetModelManager(DiskManager, disk)
return disk, nil
}
func (guest *SGuest) GetDisks() []SGuestdisk {
disks := make([]SGuestdisk, 0)
q := guest.GetDisksQuery().Asc("index")