diff --git a/pkg/compute/hostdrivers/aliyun.go b/pkg/compute/hostdrivers/aliyun.go index 6d7fc57c7d..6b1c4f6776 100644 --- a/pkg/compute/hostdrivers/aliyun.go +++ b/pkg/compute/hostdrivers/aliyun.go @@ -1,6 +1,10 @@ package hostdrivers import ( + "fmt" + + "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/compute/models" ) @@ -16,3 +20,18 @@ func init() { func (self *SAliyunHostDriver) GetHostType() string { return models.HOST_TYPE_ALIYUN } + +func (self *SAliyunHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { + if utils.IsInStringArray(storage.StorageType, []string{models.STORAGE_CLOUD_EFFICIENCY, models.STORAGE_CLOUD_SSD, models.STORAGE_CLOUD_ESSD}) { + if sizeGb < 20 || sizeGb > 32768 { + return fmt.Errorf("The %s disk size must be in the range of 20G ~ 32768GB", storage.StorageType) + } + } else if storage.StorageType == models.STORAGE_PUBLIC_CLOUD { + if sizeGb < 5 || sizeGb > 2000 { + return fmt.Errorf("The %s disk size must be in the range of 5G ~ 2000GB", storage.StorageType) + } + } else { + return fmt.Errorf("Not support create %s disk", storage.StorageType) + } + return nil +} diff --git a/pkg/compute/hostdrivers/aws.go b/pkg/compute/hostdrivers/aws.go index 4a7fa74563..63d5d95312 100644 --- a/pkg/compute/hostdrivers/aws.go +++ b/pkg/compute/hostdrivers/aws.go @@ -1,6 +1,10 @@ package hostdrivers import ( + "fmt" + + "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/compute/models" ) @@ -8,11 +12,29 @@ type SAwsHostDriver struct { SManagedVirtualizationHostDriver } -func init() { - driver := SAwsHostDriver{} - models.RegisterHostDriver(&driver) -} - func (self *SAwsHostDriver) GetHostType() string { return models.HOST_TYPE_AWS } + +func (self *SAwsHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { + if storage.StorageType == models.STORAGE_GP2_SSD { + if sizeGb < 1 || sizeGb > 16384 { + return fmt.Errorf("The %s disk size must be in the range of 1G ~ 16384GB", storage.StorageType) + } + } else if storage.StorageType == models.STORAGE_IO1_SSD { + if sizeGb < 4 || sizeGb > 16384 { + return fmt.Errorf("The %s disk size must be in the range of 4G ~ 16384GB", storage.StorageType) + } + } else if utils.IsInStringArray(storage.StorageType, []string{models.STORAGE_ST1_HDD, models.STORAGE_SC1_SSD}) { + if sizeGb < 500 || sizeGb > 16384 { + return fmt.Errorf("The %s disk size must be in the range of 500G ~ 16384GB", storage.StorageType) + } + } else if storage.StorageType == models.STORAGE_STANDARD_SSD { + if sizeGb < 1 || sizeGb > 1024 { + return fmt.Errorf("The %s disk size must be in the range of 1G ~ 1024GB", storage.StorageType) + } + } else { + return fmt.Errorf("Not support create %s disk", storage.StorageType) + } + return nil +} diff --git a/pkg/compute/hostdrivers/azure.go b/pkg/compute/hostdrivers/azure.go index d2552d309c..7dca157a16 100644 --- a/pkg/compute/hostdrivers/azure.go +++ b/pkg/compute/hostdrivers/azure.go @@ -2,7 +2,11 @@ package hostdrivers import ( "context" + "fmt" + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" @@ -29,6 +33,17 @@ func (self *SAzureHostDriver) ValidateUpdateDisk(ctx context.Context, userCred m return data, nil } +func (self *SAzureHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { + if utils.IsInStringArray(storage.StorageType, []string{models.STORAGE_STANDARD_LRS, models.STORAGE_STANDARDSSD_LRS, models.STORAGE_PREMIUM_LRS}) { + if sizeGb < 1 || sizeGb > 4095 { + return fmt.Errorf("The %s disk size must be in the range of 1G ~ 4095GB", storage.StorageType) + } + } else { + return fmt.Errorf("Not support create %s disk", storage.StorageType) + } + return nil +} + func (self *SAzureHostDriver) RequestDeleteSnapshotWithStorage(ctx context.Context, host *models.SHost, snapshot *models.SSnapshot, task taskman.ITask) error { return httperrors.NewNotImplementedError("not implement") } diff --git a/pkg/compute/hostdrivers/base.go b/pkg/compute/hostdrivers/base.go index fc254c05e4..6dcaea62f9 100644 --- a/pkg/compute/hostdrivers/base.go +++ b/pkg/compute/hostdrivers/base.go @@ -20,6 +20,10 @@ func (self *SBaseHostDriver) ValidateUpdateDisk(ctx context.Context, userCred mc return data, nil } +func (self *SBaseHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { + return fmt.Errorf("Not Implement ValidateDiskSize") +} + func (self *SBaseHostDriver) RequestDeleteSnapshotsWithStorage(ctx context.Context, host *models.SHost, snapshot *models.SSnapshot, task taskman.ITask) error { return fmt.Errorf("Not Implement") } diff --git a/pkg/compute/hostdrivers/kvm.go b/pkg/compute/hostdrivers/kvm.go index 0eb2149043..cea2e28bee 100644 --- a/pkg/compute/hostdrivers/kvm.go +++ b/pkg/compute/hostdrivers/kvm.go @@ -28,6 +28,10 @@ func (self *SKVMHostDriver) GetHostType() string { return models.HOST_TYPE_HYPERVISOR } +func (self *SKVMHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { + return nil +} + func (self *SKVMHostDriver) CheckAndSetCacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { params := task.GetParams() imageId, err := params.GetString("image_id") diff --git a/pkg/compute/hostdrivers/qcloud.go b/pkg/compute/hostdrivers/qcloud.go index 0cacf12199..d5f83cd43e 100644 --- a/pkg/compute/hostdrivers/qcloud.go +++ b/pkg/compute/hostdrivers/qcloud.go @@ -2,6 +2,8 @@ package hostdrivers import ( "context" + "fmt" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" @@ -20,6 +22,28 @@ func (self *SQcloudHostDriver) GetHostType() string { return models.HOST_TYPE_QCLOUD } +func (self *SQcloudHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { + if sizeGb%10 != 0 { + return fmt.Errorf("The disk size must be a multiple of 10Gb") + } + if storage.StorageType == models.STORAGE_CLOUD_BASIC { + if sizeGb < 10 || sizeGb > 16000 { + return fmt.Errorf("The %s disk size must be in the range of 10 ~ 16000GB", storage.StorageType) + } + } else if storage.StorageType == models.STORAGE_CLOUD_PREMIUM { + if sizeGb < 50 || sizeGb > 16000 { + return fmt.Errorf("The %s disk size must be in the range of 50 ~ 16000GB", storage.StorageType) + } + } else if storage.StorageType == models.STORAGE_CLOUD_SSD { + if sizeGb < 100 || sizeGb > 16000 { + return fmt.Errorf("The %s disk size must be in the range of 100 ~ 16000GB", storage.StorageType) + } + } else { + return fmt.Errorf("Not support create %s disk", storage.StorageType) + } + return nil +} + func (self *SQcloudHostDriver) RequestDeleteSnapshotWithStorage(ctx context.Context, host *models.SHost, snapshot *models.SSnapshot, task taskman.ITask) error { return httperrors.NewNotImplementedError("not implement") } diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 3f62117d96..9a4106adad 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -296,7 +296,7 @@ func (manager *SDiskManager) ValidateCreateData(ctx context.Context, userCred mc if _, err := manager.SSharableVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerProjId, query, data); err != nil { return nil, err } - pendingUsage := SQuota{Storage: diskConfig.Size} + pendingUsage := SQuota{Storage: diskConfig.SizeMb} if err := QuotaManager.CheckSetPendingQuota(ctx, userCred, userCred.GetProjectId(), &pendingUsage); err != nil { return nil, err } @@ -313,14 +313,10 @@ func (manager *SDiskManager) validateDiskOnStorage(diskConfig *SDiskConfig, stor if storage.StorageType != diskConfig.Backend { return httperrors.NewInputParameterError("Storage type[%s] not match backend %s", storage.StorageType, diskConfig.Backend) } - size := diskConfig.Size >> 10 - if storage.StorageType == STORAGE_CLOUD_EFFICIENCY || storage.StorageType == STORAGE_CLOUD_SSD { - if size < 20 || size > 32768 { - return httperrors.NewInputParameterError("cloud_ssd or cloud_efficiency disk only support 20G ~ 32768G") - } - } else if storage.StorageType == STORAGE_PUBLIC_CLOUD { - if size < 5 || size > 2000 { - return httperrors.NewInputParameterError("cloud disk only support 5G ~ 2000G") + if host := storage.GetMasterHost(); host != nil { + //公有云磁盘大小检查。 + if err := host.GetHostDriver().ValidateDiskSize(storage, diskConfig.SizeMb>>10); err != nil { + return httperrors.NewInputParameterError(err.Error()) } } hoststorages := HoststorageManager.Query().SubQuery() @@ -331,7 +327,7 @@ func (manager *SDiskManager) validateDiskOnStorage(diskConfig *SDiskConfig, stor if len(hoststorage) == 0 { return httperrors.NewInputParameterError("Storage[%s] must attach to a host", storage.Name) } - if diskConfig.Size > storage.GetFreeCapacity() && !storage.IsEmulated { + if diskConfig.SizeMb > storage.GetFreeCapacity() && !storage.IsEmulated { return httperrors.NewInputParameterError("Not enough free space") } return nil @@ -571,21 +567,26 @@ func (self *SDisk) PerformResize(ctx context.Context, userCred mcclient.TokenCre if err != nil { return nil, err } - size, err := fileutils.GetSizeMb(sizeStr, 'M', 1024) + sizeMb, 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 { + if sizeMb < self.DiskSize { return nil, httperrors.NewUnsupportOperationError("Disk cannot be thrink") } - if size == self.DiskSize { + if sizeMb == self.DiskSize { return nil, nil } - addDisk := size - self.DiskSize + addDisk := sizeMb - self.DiskSize storage := self.GetStorage() + if host := storage.GetMasterHost(); host != nil { + if err := host.GetHostDriver().ValidateDiskSize(storage, sizeMb>>10); err != nil { + return nil, httperrors.NewInputParameterError(err.Error()) + } + } if addDisk > storage.GetFreeCapacity() && !storage.IsEmulated { return nil, httperrors.NewOutOfResourceError("Not enough free space") } @@ -598,7 +599,7 @@ func (self *SDisk) PerformResize(ctx context.Context, userCred mcclient.TokenCre 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) + return nil, self.StartDiskResizeTask(ctx, userCred, int64(sizeMb), "", &pendingUsage) } func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { @@ -980,7 +981,7 @@ func totalDiskSize(projectId string, active tristate.TriState, ready tristate.Tr type SDiskConfig struct { ImageId string // ImageDiskFormat string - Size int // MB + SizeMb int // MB Fs string // file system Format string // Driver string // @@ -1018,7 +1019,7 @@ func parseDiskInfo(ctx context.Context, userCred mcclient.TokenCredential, info continue } if regutils.MatchSize(p) { - diskConfig.Size, _ = fileutils.GetSizeMb(p, 'M', 1024) + diskConfig.SizeMb, _ = fileutils.GetSizeMb(p, 'M', 1024) } else if utils.IsInStringArray(p, osprofile.FS_TYPES) { diskConfig.Fs = p } else if utils.IsInStringArray(p, osprofile.IMAGE_FORMAT_TYPES) { @@ -1032,7 +1033,7 @@ func parseDiskInfo(ctx context.Context, userCred mcclient.TokenCredential, info } else if p[0] == '/' { diskConfig.Mountpoint = p } else if p == "autoextend" { - diskConfig.Size = -1 + diskConfig.SizeMb = -1 } else if utils.IsInStringArray(p, STORAGE_TYPES) { diskConfig.Backend = p } else if len(p) > 0 { @@ -1054,15 +1055,15 @@ func parseDiskInfo(ctx context.Context, userCred mcclient.TokenCredential, info } // diskConfig.ImageDiskFormat = image.DiskFormat CachedimageManager.ImageAddRefCount(image.Id) - if diskConfig.Size == 0 { - diskConfig.Size = image.MinDisk // MB + if diskConfig.SizeMb == 0 { + diskConfig.SizeMb = image.MinDisk // MB } } } } - if len(diskConfig.ImageId) > 0 && diskConfig.Size == 0 { - diskConfig.Size = options.Options.DefaultDiskSize // MB - } else if len(diskConfig.ImageId) == 0 && diskConfig.Size == 0 { + if len(diskConfig.ImageId) > 0 && diskConfig.SizeMb == 0 { + diskConfig.SizeMb = options.Options.DefaultDiskSize // MB + } else if len(diskConfig.ImageId) == 0 && diskConfig.SizeMb == 0 { return nil, httperrors.NewInputParameterError("Diskinfo not contains either imageID or size") } return &diskConfig, nil @@ -1098,7 +1099,7 @@ func (self *SDisk) fetchDiskInfo(diskConfig *SDiskConfig) { self.Nonpersistent = false } self.DiskFormat = diskConfig.Format - self.DiskSize = diskConfig.Size + self.DiskSize = diskConfig.SizeMb } type DiskInfo struct { diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 13c6309056..1946597c7f 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -839,11 +839,11 @@ func (self *SGuest) PerformCreatedisk(ctx context.Context, userCred mcclient.Tok } disksConf.Set(diskSeq, jsonutils.Marshal(diskInfo)) if _, ok := diskSizes[diskInfo.Backend]; !ok { - diskSizes[diskInfo.Backend] = diskInfo.Size + diskSizes[diskInfo.Backend] = diskInfo.SizeMb } else { - diskSizes[diskInfo.Backend] += diskInfo.Size + diskSizes[diskInfo.Backend] += diskInfo.SizeMb } - diskSize += diskInfo.Size + diskSize += diskInfo.SizeMb diskIdx += 1 diskSeq = fmt.Sprintf("disk.%d", diskIdx) } @@ -1224,11 +1224,11 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T if len(diskConf.Backend) == 0 { diskConf.Backend = self.getDefaultStorageType() } - if diskConf.Size > 0 { + if diskConf.SizeMb > 0 { if diskIdx >= len(disks) { newDisks.Add(jsonutils.Marshal(diskConf), fmt.Sprintf("disk.%d", newDiskIdx)) newDiskIdx += 1 - addDisk += diskConf.Size + addDisk += diskConf.SizeMb storage := host.GetLeastUsedStorage(diskConf.Backend) if storage == nil { return nil, httperrors.NewResourceNotReadyError("host not connect storage %s", diskConf.Backend) @@ -1237,22 +1237,22 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T if !ok { diskSizes[storage.Id] = 0 } - diskSizes[storage.Id] = diskSizes[storage.Id] + diskConf.Size + diskSizes[storage.Id] = diskSizes[storage.Id] + diskConf.SizeMb } else { disk := disks[diskIdx].GetDisk() oldSize := disk.DiskSize - if diskConf.Size < oldSize { + if diskConf.SizeMb < oldSize { return nil, httperrors.NewInputParameterError("Cannot reduce disk size") - } else if diskConf.Size > oldSize { - arr := jsonutils.NewArray(jsonutils.NewString(disks[diskIdx].DiskId), jsonutils.NewInt(int64(diskConf.Size))) + } else if diskConf.SizeMb > oldSize { + arr := jsonutils.NewArray(jsonutils.NewString(disks[diskIdx].DiskId), jsonutils.NewInt(int64(diskConf.SizeMb))) resizeDisks.Add(arr) - addDisk += diskConf.Size - oldSize + addDisk += diskConf.SizeMb - oldSize storage := disks[diskIdx].GetDisk().GetStorage() _, ok := diskSizes[storage.Id] if !ok { diskSizes[storage.Id] = 0 } - diskSizes[storage.Id] = diskSizes[storage.Id] + diskConf.Size - oldSize + diskSizes[storage.Id] = diskSizes[storage.Id] + diskConf.SizeMb - oldSize } } } diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 9eb5e37e69..2cd3d5ce89 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -874,7 +874,7 @@ func getGuestResourceRequirements(ctx context.Context, userCred mcclient.TokenCr for idx := 0; data.Contains(fmt.Sprintf("disk.%d", idx)); idx += 1 { dataJson, _ := data.Get(fmt.Sprintf("disk.%d", idx)) diskConfig, _ := parseDiskInfo(ctx, userCred, dataJson) - diskSize += diskConfig.Size + diskSize += diskConfig.SizeMb } devCount := 0 diff --git a/pkg/compute/models/hostdrivers.go b/pkg/compute/models/hostdrivers.go index 2e490fc365..b005d9cfc5 100644 --- a/pkg/compute/models/hostdrivers.go +++ b/pkg/compute/models/hostdrivers.go @@ -17,6 +17,7 @@ type IHostDriver interface { RequestUncacheImage(ctx context.Context, host *SHost, storageCache *SStoragecache, task taskman.ITask) error ValidateUpdateDisk(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) + ValidateDiskSize(storage *SStorage, sizeGb int) error RequestPrepareSaveDiskOnHost(ctx context.Context, host *SHost, disk *SDisk, imageId string, task taskman.ITask) error RequestSaveUploadImageOnHost(ctx context.Context, host *SHost, disk *SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error RequestAllocateDiskOnStorage(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, task taskman.ITask, content *jsonutils.JSONDict) error