diff --git a/pkg/compute/guestdrivers/aliyun.go b/pkg/compute/guestdrivers/aliyun.go index 09bfd307ee..51b80b1a34 100644 --- a/pkg/compute/guestdrivers/aliyun.go +++ b/pkg/compute/guestdrivers/aliyun.go @@ -68,6 +68,19 @@ func (self *SAliyunGuestDriver) GetDeployStatus() ([]string, error) { return []string{models.VM_READY, models.VM_RUNNING}, nil } +func (self *SAliyunGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *models.SDisk, storage *models.SStorage) error { + if !utils.IsInStringArray(guest.Status, []string{models.VM_READY, models.VM_RUNNING}) { + return fmt.Errorf("Cannot resize disk when guest in status %s", guest.Status) + } + if disk.DiskType == models.DISK_TYPE_SYS { + return fmt.Errorf("Cannot resize system disk") + } + if !utils.IsInStringArray(storage.StorageType, []string{models.STORAGE_PUBLIC_CLOUD, models.STORAGE_CLOUD_SSD, models.STORAGE_CLOUD_EFFICIENCY}) { + return fmt.Errorf("Cannot resize %s disk", storage.StorageType) + } + return nil +} + func (self *SAliyunGuestDriver) RequestDetachDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error { return guest.StartSyncTask(ctx, task.GetUserCred(), false, task.GetTaskId()) } diff --git a/pkg/compute/guestdrivers/baremetals.go b/pkg/compute/guestdrivers/baremetals.go index e372e4a959..f5525dbdbd 100644 --- a/pkg/compute/guestdrivers/baremetals.go +++ b/pkg/compute/guestdrivers/baremetals.go @@ -61,6 +61,10 @@ func (self *SBaremetalGuestDriver) GetDeployStatus() ([]string, error) { return []string{models.VM_READY, models.VM_ADMIN}, nil } +func (self *SBaremetalGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *models.SDisk, storage *models.SStorage) error { + return httperrors.NewUnsupportOperationError("Cannot resize disk for baremtal") +} + func (self *SBaremetalGuestDriver) GetNamedNetworkConfiguration(guest *models.SGuest, userCred mcclient.TokenCredential, host *models.SHost, netConfig *models.SNetworkConfig) (*models.SNetwork, string, int8, models.IPAddlocationDirection) { net, _ := host.GetNetworkWithIdAndCredential(netConfig.Network, userCred, netConfig.Reserved) return net, netConfig.Mac, -1, models.IPAllocationStepdown diff --git a/pkg/compute/guestdrivers/base.go b/pkg/compute/guestdrivers/base.go index 08205e10d8..3f51a26c11 100644 --- a/pkg/compute/guestdrivers/base.go +++ b/pkg/compute/guestdrivers/base.go @@ -111,6 +111,10 @@ func (self *SBaseGuestDriver) GetChangeConfigStatus() ([]string, error) { return []string{}, fmt.Errorf("This Guest driver dose not implement GetChangeConfigStatus") } +func (self *SBaseGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *models.SDisk, storage *models.SStorage) error { + return fmt.Errorf("This Guest driver dose not implement ValidateResizeDisk") +} + func (self *SBaseGuestDriver) GetDeployStatus() ([]string, error) { return []string{}, fmt.Errorf("This Guest driver dose not implement GetDeployStatus") } diff --git a/pkg/compute/guestdrivers/kvm.go b/pkg/compute/guestdrivers/kvm.go index 203d11f519..04a3e9dd25 100644 --- a/pkg/compute/guestdrivers/kvm.go +++ b/pkg/compute/guestdrivers/kvm.go @@ -9,6 +9,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" @@ -295,6 +296,13 @@ func (self *SKVMGuestDriver) GetDeployStatus() ([]string, error) { return []string{models.VM_READY}, nil } +func (self *SKVMGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *models.SDisk, storage *models.SStorage) error { + if !utils.IsInStringArray(guest.Status, []string{models.VM_READY, models.VM_RUNNING}) { + return fmt.Errorf("Cannot resize disk when guest in status %s", guest.Status) + } + return nil +} + func (self *SKVMGuestDriver) RequestDeleteDetachedDisk(ctx context.Context, disk *models.SDisk, task taskman.ITask, isPurge bool) error { return disk.StartDiskDeleteTask(ctx, task.GetUserCred(), task.GetTaskId(), isPurge) } diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index cb20a7f09a..81be9e7eee 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -477,28 +477,38 @@ func (self *SDisk) AllowPerformResize(ctx context.Context, userCred mcclient.Tok } func (self *SDisk) PerformResize(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if sizeStr, err := data.GetString("size"); err != nil { + sizeStr, err := data.GetString("size") + if err != nil { return nil, err - } else if size, err := fileutils.GetSizeMb(sizeStr, 'M', 1024); err != nil { - return nil, err - } else if self.Status != DISK_READY { - return nil, httperrors.NewResourceNotReadyError("Resize disk when disk is READY") - } else if size < self.DiskSize { - return nil, httperrors.NewUnsupportOperationError("Disk cannot be thrink") - } else if size == self.DiskSize { - return nil, nil - } else { - addDisk := size - self.DiskSize - storage := self.GetStorage() - if addDisk > storage.GetFreeCapacity() && !storage.IsEmulated { - return nil, httperrors.NewOutOfResourceError("Not enough free space") - } - pendingUsage := SQuota{Storage: int(addDisk)} - if err := QuotaManager.CheckSetPendingQuota(ctx, userCred, userCred.GetProjectId(), &pendingUsage); err != nil { - return nil, httperrors.NewOutOfQuotaError(err.Error()) - } - return nil, self.StartDiskResizeTask(ctx, userCred, int64(size), "", &pendingUsage) } + size, err := fileutils.GetSizeMb(sizeStr, 'M', 1024) + if err != nil { + return nil, err + } + if self.Status != DISK_READY { + return nil, httperrors.NewResourceNotReadyError("Resize disk when disk is READY") + } + if size < self.DiskSize { + return nil, httperrors.NewUnsupportOperationError("Disk cannot be thrink") + } + if size == self.DiskSize { + return nil, nil + } + addDisk := size - self.DiskSize + storage := self.GetStorage() + if addDisk > storage.GetFreeCapacity() && !storage.IsEmulated { + return nil, httperrors.NewOutOfResourceError("Not enough free space") + } + if guests := self.GetGuests(); len(guests) > 0 { + if err := guests[0].ValidateResizeDisk(self, storage); err != nil { + return nil, httperrors.NewInputParameterError(err.Error()) + } + } + pendingUsage := SQuota{Storage: int(addDisk)} + if err := QuotaManager.CheckSetPendingQuota(ctx, userCred, userCred.GetProjectId(), &pendingUsage); err != nil { + return nil, httperrors.NewOutOfQuotaError(err.Error()) + } + return nil, self.StartDiskResizeTask(ctx, userCred, int64(size), "", &pendingUsage) } func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index 1c19fb36a1..4881724058 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -85,6 +85,7 @@ type IGuestDriver interface { GetRebuildRootStatus() ([]string, error) GetChangeConfigStatus() ([]string, error) GetDeployStatus() ([]string, error) + ValidateResizeDisk(guest *SGuest, disk *SDisk, storage *SStorage) error CanKeepDetachDisk() bool RequestDeleteDetachedDisk(ctx context.Context, disk *SDisk, task taskman.ITask, isPurge bool) error diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 3f0e8b5e61..bc55354e8c 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -497,6 +497,10 @@ func (guest *SGuest) SetHostId(hostId string) error { return err } +func (guest *SGuest) ValidateResizeDisk(disk *SDisk, storage *SStorage) error { + return guest.GetDriver().ValidateResizeDisk(guest, disk, storage) +} + func validateMemCpuData(data jsonutils.JSONObject) (int, int, error) { vmemSize := 0 vcpuCount := 0