mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
hotfix: validate resize disk when change config
This commit is contained in:
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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, "")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user