mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 02:37:24 +08:00
改进:允许kvm虚拟机在不关机状态下调整磁盘
This commit is contained in:
@@ -324,3 +324,7 @@ func (self *SAzureGuestDriver) RequestSyncConfigOnHost(ctx context.Context, gues
|
||||
func (self *SAzureGuestDriver) IsSupportedBillingCycle(bc billing.SBillingCycle) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SAzureGuestDriver) NeedStopForChangeSpec() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ func (self *SBaseGuestDriver) DoGuestCreateDisksTask(ctx context.Context, guest
|
||||
return fmt.Errorf("Not Implement")
|
||||
}
|
||||
|
||||
func (self *SBaseGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, vcpuCount, vmemSize int64) error {
|
||||
func (self *SBaseGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, instanceType string, vcpuCount, vmemSize int64) error {
|
||||
return fmt.Errorf("Not Implement")
|
||||
}
|
||||
|
||||
@@ -224,3 +224,7 @@ func (self *SBaseGuestDriver) RequestRenewInstance(guest *models.SGuest, bc bill
|
||||
func (self *SBaseGuestDriver) IsSupportEip() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SBaseGuestDriver) NeedStopForChangeSpec() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ func (self *SContainerDriver) DoGuestCreateDisksTask(ctx context.Context, guest
|
||||
return self.newUnsupportOperationError("create disk")
|
||||
}
|
||||
|
||||
func (self *SContainerDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, vcpuCount, vmemSize int64) error {
|
||||
func (self *SContainerDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, instanceType string, vcpuCount, vmemSize int64) error {
|
||||
return self.newUnsupportOperationError("change config")
|
||||
}
|
||||
|
||||
|
||||
@@ -242,8 +242,9 @@ func (self *SKVMGuestDriver) OnDeleteGuestFinalCleanup(ctx context.Context, gues
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, vcpuCount, vmemSize int64) error {
|
||||
func (self *SKVMGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, instanceType string, vcpuCount, vmemSize int64) error {
|
||||
// pass
|
||||
task.ScheduleRun(nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -273,7 +274,7 @@ func (self *SKVMGuestDriver) GetRebuildRootStatus() ([]string, error) {
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) GetChangeConfigStatus() ([]string, error) {
|
||||
return []string{models.VM_READY}, nil
|
||||
return []string{models.VM_READY, models.VM_RUNNING}, nil
|
||||
}
|
||||
|
||||
func (self *SKVMGuestDriver) GetDeployStatus() ([]string, error) {
|
||||
|
||||
@@ -295,38 +295,25 @@ type SManagedVMChangeConfig struct {
|
||||
Memory int
|
||||
}
|
||||
|
||||
func (self *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, vcpuCount, vmemSize int64) error {
|
||||
config := SManagedVMChangeConfig{}
|
||||
config.InstanceId = guest.GetExternalId()
|
||||
if instanceType, err := task.GetParams().GetString("instance_type"); err == nil {
|
||||
config.InstanceType = instanceType
|
||||
}
|
||||
|
||||
config.Cpu = int(vcpuCount)
|
||||
config.Memory = int(vmemSize)
|
||||
func (self *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Context, guest *models.SGuest, task taskman.ITask, instanceType string, vcpuCount, vmemSize int64) error {
|
||||
ihost, err := guest.GetHost().GetIHost()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
iVM, err := ihost.GetIVMById(config.InstanceId)
|
||||
iVM, err := ihost.GetIVMById(guest.GetExternalId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if int(guest.VcpuCount) != config.Cpu || guest.VmemSize != config.Memory {
|
||||
if len(config.InstanceType) > 0 {
|
||||
err = iVM.ChangeConfig2(ctx, config.InstanceType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
||||
if len(instanceType) > 0 {
|
||||
return nil, iVM.ChangeConfig2(ctx, instanceType)
|
||||
} else {
|
||||
err = iVM.ChangeConfig(ctx, config.Cpu, config.Memory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil, iVM.ChangeConfig(ctx, int(vcpuCount), int(vmemSize))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ import (
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/compute/options"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/httputils"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
)
|
||||
|
||||
type SKVMHostDriver struct {
|
||||
@@ -163,33 +163,47 @@ func (self *SKVMHostDriver) RequestDeallocateDiskOnHost(ctx context.Context, hos
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SKVMHostDriver) RequestResizeDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, sizeMb int64, task taskman.ITask) error {
|
||||
func (self *SKVMHostDriver) RequestResizeDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, guest *models.SGuest, sizeMb int64, task taskman.ITask) error {
|
||||
header := task.GetTaskRequestHeader()
|
||||
|
||||
url := fmt.Sprintf("/disks/%s/resize/%s", storage.Id, disk.Id)
|
||||
body := jsonutils.NewDict()
|
||||
content := jsonutils.NewDict()
|
||||
content.Add(jsonutils.NewInt(sizeMb), "size")
|
||||
if guest != nil {
|
||||
content.Add(jsonutils.NewString(guest.Id), "server_id")
|
||||
}
|
||||
body.Add(content, "disk")
|
||||
_, err := host.Request(ctx, task.GetUserCred(), "POST", url, header, body)
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
func (self *SKVMHostDriver) RequestResizeDiskOnHostOnline(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, sizeMb int64, task taskman.ITask) error {
|
||||
self.RequestResizeDiskOnHost(ctx, host, storage, disk, sizeMb, task)
|
||||
|
||||
header := task.GetTaskRequestHeader()
|
||||
|
||||
for _, guest := range disk.GetAttachedGuests() {
|
||||
guestdisk := guest.GetGuestDisk(disk.GetId())
|
||||
url := fmt.Sprintf("/servers/%s/monitor", guest.GetId())
|
||||
body := jsonutils.NewDict()
|
||||
cmd := fmt.Sprintf("block_resize drive_%d %dM", guestdisk.Index, sizeMb)
|
||||
body.Add(jsonutils.NewString(cmd), "cmd")
|
||||
host.Request(ctx, task.GetUserCred(), "POST", url, header, body)
|
||||
guests := disk.GetAttachedGuests()
|
||||
if len(guests) == 0 {
|
||||
return fmt.Errorf("no valid guest")
|
||||
}
|
||||
if len(guests) > 1 {
|
||||
return fmt.Errorf("cannot resize across more than 1 guest")
|
||||
}
|
||||
guest := guests[0]
|
||||
|
||||
guestdisk := guest.GetGuestDisk(disk.GetId())
|
||||
url := fmt.Sprintf("/servers/%s/monitor", guest.GetId())
|
||||
body := jsonutils.NewDict()
|
||||
cmd := fmt.Sprintf("block_resize drive_%d %dM", guestdisk.Index, sizeMb)
|
||||
body.Add(jsonutils.NewString(cmd), "cmd")
|
||||
|
||||
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
||||
return host.Request(ctx, task.GetUserCred(), "POST", url, header, body)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
func (self *SKVMHostDriver) RequestPrepareSaveDiskOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask) error {
|
||||
body := jsonutils.NewDict()
|
||||
|
||||
@@ -190,11 +190,7 @@ func (self *SManagedVirtualizationHostDriver) RequestSaveUploadImageOnHost(ctx c
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SManagedVirtualizationHostDriver) RequestResizeDiskOnHostOnline(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error {
|
||||
return self.RequestResizeDiskOnHost(ctx, host, storage, disk, size, task)
|
||||
}
|
||||
|
||||
func (self *SManagedVirtualizationHostDriver) RequestResizeDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, sizeMb int64, task taskman.ITask) error {
|
||||
func (self *SManagedVirtualizationHostDriver) RequestResizeDiskOnHost(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, guest *models.SGuest, sizeMb int64, task taskman.ITask) error {
|
||||
iCloudStorage, err := storage.GetIStorage()
|
||||
if err != nil {
|
||||
log.Errorf("storage.GetIStorage fail %s", err)
|
||||
|
||||
@@ -685,7 +685,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(sizeMb), "", &pendingUsage)
|
||||
return nil, self.StartDiskResizeTask(ctx, userCred, int64(sizeMb), "", &pendingUsage, nil)
|
||||
}
|
||||
|
||||
func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) {
|
||||
@@ -1399,9 +1399,12 @@ func (self *SDisk) GetCustomizeColumns(ctx context.Context, userCred mcclient.To
|
||||
return self.getMoreDetails(extra)
|
||||
}
|
||||
|
||||
func (self *SDisk) StartDiskResizeTask(ctx context.Context, userCred mcclient.TokenCredential, sizeMb int64, parentTaskId string, pendingUsage quotas.IQuota) error {
|
||||
func (self *SDisk) StartDiskResizeTask(ctx context.Context, userCred mcclient.TokenCredential, sizeMb int64, parentTaskId string, pendingUsage quotas.IQuota, guest *SGuest) error {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewInt(sizeMb), "size")
|
||||
if guest != nil {
|
||||
params.Add(jsonutils.NewString(guest.Id), "guest_id")
|
||||
}
|
||||
if task, err := taskman.TaskManager.NewTask(ctx, "DiskResizeTask", self, userCred, params, parentTaskId, "", pendingUsage); err != nil {
|
||||
return err
|
||||
} else {
|
||||
|
||||
@@ -1421,6 +1421,10 @@ func (self *SGuest) AllowPerformChangeConfig(ctx context.Context, userCred mccli
|
||||
}
|
||||
|
||||
func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
if !self.GetDriver().AllowReconfigGuest() {
|
||||
return nil, httperrors.NewInvalidStatusError("Not allow to change config")
|
||||
}
|
||||
|
||||
changeStatus, err := self.GetDriver().GetChangeConfigStatus()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError(err.Error())
|
||||
@@ -1428,15 +1432,15 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
|
||||
if !utils.IsInStringArray(self.Status, changeStatus) {
|
||||
return nil, httperrors.NewInvalidStatusError("Cannot change config in %s", self.Status)
|
||||
}
|
||||
if !self.GetDriver().AllowReconfigGuest() {
|
||||
return nil, httperrors.NewInvalidStatusError("Not allow to change config")
|
||||
}
|
||||
|
||||
host := self.GetHost()
|
||||
if host == nil {
|
||||
return nil, httperrors.NewInvalidStatusError("No valid host")
|
||||
}
|
||||
|
||||
var addCpu, addMem int
|
||||
var cpuChanged, memChanged bool
|
||||
|
||||
confs := jsonutils.NewDict()
|
||||
skuId := jsonutils.GetAnyString(data, []string{"instance_type", "sku", "flavor"})
|
||||
if len(skuId) > 0 {
|
||||
@@ -1444,11 +1448,22 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addCpu = sku.CpuCoreCount - int(self.VcpuCount)
|
||||
addMem = sku.MemorySizeMB - self.VmemSize
|
||||
confs.Add(jsonutils.NewString(sku.ExternalId), "sku_id")
|
||||
confs.Add(jsonutils.NewInt(int64(sku.CpuCoreCount)), "vcpu_count")
|
||||
confs.Add(jsonutils.NewInt(int64(sku.MemorySizeMB)), "vmem_size")
|
||||
|
||||
if sku.GetName() != self.InstanceType {
|
||||
confs.Add(jsonutils.NewString(sku.GetName()), "instance_type")
|
||||
confs.Add(jsonutils.NewInt(int64(sku.CpuCoreCount)), "vcpu_count")
|
||||
confs.Add(jsonutils.NewInt(int64(sku.MemorySizeMB)), "vmem_size")
|
||||
|
||||
if sku.CpuCoreCount != int(self.VcpuCount) {
|
||||
cpuChanged = true
|
||||
addCpu = sku.CpuCoreCount - int(self.VcpuCount)
|
||||
}
|
||||
if sku.MemorySizeMB != self.VmemSize {
|
||||
memChanged = true
|
||||
addMem = sku.MemorySizeMB - self.VmemSize
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
vcpuCount, err := data.GetString("vcpu_count")
|
||||
if err == nil {
|
||||
@@ -1456,13 +1471,14 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
|
||||
if err != nil {
|
||||
return nil, httperrors.NewBadRequestError("Params vcpu_count parse error")
|
||||
}
|
||||
err = confs.Add(jsonutils.NewInt(nVcpu), "vcpu_count")
|
||||
if err != nil {
|
||||
return nil, httperrors.NewBadRequestError("Params vcpu_count parse error")
|
||||
}
|
||||
addCpu = int(nVcpu - int64(self.VcpuCount))
|
||||
if addCpu < 0 {
|
||||
addCpu = 0
|
||||
|
||||
if nVcpu != int64(self.VcpuCount) {
|
||||
cpuChanged = true
|
||||
addCpu = int(nVcpu - int64(self.VcpuCount))
|
||||
err = confs.Add(jsonutils.NewInt(nVcpu), "vcpu_count")
|
||||
if err != nil {
|
||||
return nil, httperrors.NewBadRequestError("Params vcpu_count parse error")
|
||||
}
|
||||
}
|
||||
}
|
||||
vmemSize, err := data.GetString("vmem_size")
|
||||
@@ -1474,17 +1490,28 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
|
||||
if err != nil {
|
||||
httperrors.NewBadRequestError("Params vmem_size parse error")
|
||||
}
|
||||
err = confs.Add(jsonutils.NewInt(int64(nVmem)), "vmem_size")
|
||||
if err != nil {
|
||||
return nil, httperrors.NewBadRequestError("Params vmem_size parse error")
|
||||
}
|
||||
addMem = nVmem - self.VmemSize
|
||||
if addMem < 0 {
|
||||
addMem = 0
|
||||
if nVmem != self.VmemSize {
|
||||
memChanged = true
|
||||
addMem = nVmem - self.VmemSize
|
||||
err = confs.Add(jsonutils.NewInt(int64(nVmem)), "vmem_size")
|
||||
if err != nil {
|
||||
return nil, httperrors.NewBadRequestError("Params vmem_size parse error")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.Status == VM_RUNNING && (cpuChanged || memChanged) && self.GetDriver().NeedStopForChangeSpec() {
|
||||
return nil, httperrors.NewInvalidStatusError("cannot change CPU/Memory spec in status %s", self.Status)
|
||||
}
|
||||
|
||||
if addCpu < 0 {
|
||||
addCpu = 0
|
||||
}
|
||||
if addMem < 0 {
|
||||
addMem = 0
|
||||
}
|
||||
|
||||
disks := self.GetDisks()
|
||||
var addDisk int
|
||||
var diskIdx = 1
|
||||
@@ -1562,7 +1589,7 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
|
||||
if resizeDisks.Length() > 0 {
|
||||
confs.Add(resizeDisks, "resize")
|
||||
}
|
||||
if jsonutils.QueryBoolean(data, "auto_start", false) {
|
||||
if self.Status == VM_RUNNING && jsonutils.QueryBoolean(data, "auto_start", false) {
|
||||
confs.Add(jsonutils.NewBool(true), "auto_start")
|
||||
}
|
||||
|
||||
@@ -1584,6 +1611,7 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
|
||||
return nil, httperrors.NewOutOfQuotaError("Check set pending quota error %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if newDisks.Length() > 0 {
|
||||
err := self.CreateDisksOnHost(ctx, userCred, host, newDisks, pendingUsage, false)
|
||||
if err != nil {
|
||||
|
||||
@@ -108,7 +108,7 @@ type IGuestDriver interface {
|
||||
|
||||
AllowReconfigGuest() bool
|
||||
DoGuestCreateDisksTask(ctx context.Context, guest *SGuest, task taskman.ITask) error
|
||||
RequestChangeVmConfig(ctx context.Context, guest *SGuest, task taskman.ITask, vcpuCount, vmemSize int64) error
|
||||
RequestChangeVmConfig(ctx context.Context, guest *SGuest, task taskman.ITask, instanceType string, vcpuCount, vmemSize int64) error
|
||||
|
||||
RequestGuestHotAddIso(ctx context.Context, guest *SGuest, path string, task taskman.ITask) error
|
||||
RequestRebuildRootDisk(ctx context.Context, guest *SGuest, task taskman.ITask) error
|
||||
@@ -120,6 +120,8 @@ type IGuestDriver interface {
|
||||
RequestSyncToBackup(ctx context.Context, guest *SGuest, task taskman.ITask) error
|
||||
|
||||
IsSupportEip() bool
|
||||
|
||||
NeedStopForChangeSpec() bool
|
||||
}
|
||||
|
||||
var guestDrivers map[string]IGuestDriver
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
"yunion.io/x/sqlchemy"
|
||||
@@ -20,6 +19,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
|
||||
"yunion.io/x/onecloud/pkg/compute/options"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -946,12 +946,13 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m
|
||||
data.Add(jsonutils.NewString("default"), "secgrp_id")
|
||||
}
|
||||
|
||||
if data.Contains("eip") || data.Contains("eip_bw") {
|
||||
eipStr, _ := data.GetString("eip")
|
||||
eipBw, _ := data.Int("eip_bw")
|
||||
if len(eipStr) > 0 || eipBw > 0 {
|
||||
if !GetDriver(hypervisor).IsSupportEip() {
|
||||
return nil, httperrors.NewNotImplementedError("eip not supported for %s", hypervisor)
|
||||
}
|
||||
if data.Contains("eip") {
|
||||
eipStr, _ := data.GetString("eip")
|
||||
if len(eipStr) > 0 {
|
||||
eipObj, err := ElasticipManager.FetchByIdOrName(userCred, eipStr)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
|
||||
@@ -25,8 +25,11 @@ type IHostDriver interface {
|
||||
RequestRebuildDiskOnStorage(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, task taskman.ITask, content *jsonutils.JSONDict) error
|
||||
|
||||
RequestDeallocateDiskOnHost(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, task taskman.ITask) error
|
||||
RequestResizeDiskOnHostOnline(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, size int64, task taskman.ITask) error
|
||||
RequestResizeDiskOnHost(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, size int64, task taskman.ITask) error
|
||||
|
||||
//RequestResizeDiskOnHostOnline(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, size int64, task taskman.ITask) error
|
||||
|
||||
RequestResizeDiskOnHost(ctx context.Context, host *SHost, storage *SStorage, disk *SDisk, guest *SGuest, size int64, task taskman.ITask) error
|
||||
|
||||
RequestDeleteSnapshotsWithStorage(ctx context.Context, host *SHost, snapshot *SSnapshot, task taskman.ITask) error
|
||||
RequestResetDisk(ctx context.Context, host *SHost, disk *SDisk, params *jsonutils.JSONDict, task taskman.ITask) error
|
||||
RequestCleanUpDiskSnapshots(ctx context.Context, host *SHost, disk *SDisk, params *jsonutils.JSONDict, task taskman.ITask) error
|
||||
|
||||
@@ -23,38 +23,43 @@ func init() {
|
||||
|
||||
func (self *DiskResizeTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
disk := obj.(*models.SDisk)
|
||||
|
||||
guestId, _ := self.Params.GetString("guest_id")
|
||||
var masterGuest *models.SGuest
|
||||
if len(guestId) > 0 {
|
||||
masterGuest = models.GuestManager.FetchGuestById(guestId)
|
||||
}
|
||||
|
||||
storage := disk.GetStorage()
|
||||
host := storage.GetMasterHost()
|
||||
online := disk.GetRuningGuestCount() > 0
|
||||
if online {
|
||||
for _, guest := range disk.GetGuests() {
|
||||
host = guest.GetHost()
|
||||
}
|
||||
|
||||
if masterGuest != nil {
|
||||
host = masterGuest.GetHost()
|
||||
}
|
||||
|
||||
reason := "Cannot find host for disk"
|
||||
if host == nil || host.HostStatus != models.HOST_ONLINE {
|
||||
disk.SetDiskReady(ctx, self.GetUserCred(), reason)
|
||||
self.SetStageFailed(ctx, reason)
|
||||
db.OpsLog.LogEvent(disk, db.ACT_RESIZE_FAIL, reason, self.GetUserCred())
|
||||
logclient.AddActionLog(disk, logclient.ACT_RESIZE, reason, self.UserCred, false)
|
||||
} else {
|
||||
disk.SetStatus(self.GetUserCred(), models.DISK_START_RESIZE, "")
|
||||
return
|
||||
}
|
||||
|
||||
disk.SetStatus(self.GetUserCred(), models.DISK_START_RESIZE, "")
|
||||
if masterGuest == nil {
|
||||
for _, guest := range disk.GetGuests() {
|
||||
guest.SetStatus(self.GetUserCred(), models.VM_RESIZE_DISK, "")
|
||||
}
|
||||
self.StartResizeDisk(ctx, host, storage, disk, online)
|
||||
}
|
||||
self.StartResizeDisk(ctx, host, storage, disk, masterGuest)
|
||||
}
|
||||
|
||||
func (self *DiskResizeTask) StartResizeDisk(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, online bool) {
|
||||
func (self *DiskResizeTask) StartResizeDisk(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, guest *models.SGuest) {
|
||||
log.Infof("Resizing disk on host %s ...", host.GetName())
|
||||
self.SetStage("on_disk_resize_complete", nil)
|
||||
sizeMb, _ := self.GetParams().Int("size")
|
||||
proc := host.GetHostDriver().RequestResizeDiskOnHost
|
||||
if online {
|
||||
proc = host.GetHostDriver().RequestResizeDiskOnHostOnline
|
||||
}
|
||||
if err := proc(ctx, host, storage, disk, sizeMb, self); err != nil {
|
||||
if err := host.GetHostDriver().RequestResizeDiskOnHost(ctx, host, storage, disk, guest, sizeMb, self); err != nil {
|
||||
log.Errorf("request_resize_disk_on_host: %v", err)
|
||||
self.OnStartResizeDiskFailed(ctx, disk, err)
|
||||
return
|
||||
|
||||
@@ -81,7 +81,7 @@ func (self *GuestChangeConfigTask) OnDisksResizeComplete(ctx context.Context, ob
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("self.GetPendingUsage(&pendingUsage) fail %s", err))
|
||||
return
|
||||
}
|
||||
err = disk.StartDiskResizeTask(ctx, self.UserCred, size, self.GetTaskId(), &pendingUsage)
|
||||
err = disk.StartDiskResizeTask(ctx, self.UserCred, size, self.GetTaskId(), &pendingUsage, guest)
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("disk.StartDiskResizeTask fail %s", err))
|
||||
return
|
||||
@@ -111,109 +111,109 @@ func (self *GuestChangeConfigTask) OnCreateDisksCompleteFailed(ctx context.Conte
|
||||
|
||||
func (self *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
guest := obj.(*models.SGuest)
|
||||
var vcpuCount, vmemSize int64
|
||||
var paramsError error
|
||||
var err error
|
||||
iSku, paramsError := self.Params.GetString("sku_id")
|
||||
if paramsError == nil {
|
||||
isku, err := models.ServerSkuManager.FetchById(iSku)
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("Sku_id fail %s", err))
|
||||
logclient.AddActionLog(guest, logclient.ACT_VM_CHANGE_FLAVOR, err, self.UserCred, false)
|
||||
return
|
||||
}
|
||||
|
||||
sku := isku.(*models.SServerSku)
|
||||
self.Params.Set("instance_type", jsonutils.NewString(sku.GetName()))
|
||||
vcpuCount = int64(sku.CpuCoreCount)
|
||||
vmemSize = int64(sku.MemorySizeMB)
|
||||
if self.Params.Contains("instance_type") || self.Params.Contains("vcpu_count") || self.Params.Contains("vmem_size") {
|
||||
self.SetStage("OnGuestChangeCpuMemSpecComplete", nil)
|
||||
instanceType, _ := self.Params.GetString("instance_type")
|
||||
vcpuCount, _ := self.Params.Int("vcpu_count")
|
||||
vmemSize, _ := self.Params.Int("vmem_size")
|
||||
if vcpuCount == 0 {
|
||||
vcpuCount = int64(guest.VcpuCount)
|
||||
}
|
||||
if vmemSize == 0 {
|
||||
vmemSize = int64(guest.VmemSize)
|
||||
}
|
||||
self.startGuestChangeCpuMemSpec(ctx, guest, instanceType, vcpuCount, vmemSize)
|
||||
} else {
|
||||
iVcpuCount, cpuError := self.Params.Get("vcpu_count")
|
||||
if iVcpuCount != nil {
|
||||
vcpuCount, err = iVcpuCount.Int()
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("iVcpuCount.Int() fail %s", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
iVmemSize, memError := self.Params.Get("vmem_size")
|
||||
if iVmemSize != nil {
|
||||
vmemSize, err = iVmemSize.Int()
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("iVmemSize.Int fail %s", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if cpuError == nil || memError == nil {
|
||||
paramsError = nil
|
||||
}
|
||||
self.OnGuestChangeCpuMemSpecComplete(ctx, obj, data)
|
||||
}
|
||||
}
|
||||
|
||||
if paramsError == nil {
|
||||
err = guest.GetDriver().RequestChangeVmConfig(ctx, guest, self, vcpuCount, vmemSize)
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("guest.GetDriver().RequestChangeVmConfig fail %s", err))
|
||||
return
|
||||
}
|
||||
var addCpu, addMem = 0, 0
|
||||
func (self *GuestChangeConfigTask) startGuestChangeCpuMemSpec(ctx context.Context, guest *models.SGuest, instanceType string, vcpuCount int64, vmemSize int64) {
|
||||
err := guest.GetDriver().RequestChangeVmConfig(ctx, guest, self, instanceType, vcpuCount, vmemSize)
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("guest.GetDriver().RequestChangeVmConfig fail %s", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (self *GuestChangeConfigTask) OnGuestChangeCpuMemSpecCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) {
|
||||
guest := obj.(*models.SGuest)
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("guest.GetDriver().RequestChangeVmConfig fail %s", err))
|
||||
}
|
||||
|
||||
func (self *GuestChangeConfigTask) OnGuestChangeCpuMemSpecComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
guest := obj.(*models.SGuest)
|
||||
|
||||
instanceType, _ := self.Params.GetString("instance_type")
|
||||
vcpuCount, _ := self.Params.Int("vcpu_count")
|
||||
vmemSize, _ := self.Params.Int("vmem_size")
|
||||
|
||||
addCpu := int(vcpuCount - int64(guest.VcpuCount))
|
||||
addMem := int(vmemSize - int64(guest.VmemSize))
|
||||
|
||||
_, err := guest.GetModelManager().TableSpec().Update(guest, func() error {
|
||||
if vcpuCount > 0 {
|
||||
addCpu = int(vcpuCount - int64(guest.VcpuCount))
|
||||
if addCpu < 0 {
|
||||
addCpu = 0
|
||||
}
|
||||
guest.VcpuCount = int8(vcpuCount)
|
||||
}
|
||||
if vmemSize > 0 {
|
||||
addMem = int(vmemSize - int64(guest.VmemSize))
|
||||
if addMem < 0 {
|
||||
addMem = 0
|
||||
}
|
||||
guest.VmemSize = int(vmemSize)
|
||||
}
|
||||
_, err = guest.GetModelManager().TableSpec().Update(guest, func() error {
|
||||
if vcpuCount > 0 {
|
||||
guest.VcpuCount = int8(vcpuCount)
|
||||
}
|
||||
if vmemSize > 0 {
|
||||
guest.VmemSize = int(vmemSize)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("Update fail %s", err))
|
||||
return
|
||||
}
|
||||
var pendingUsage models.SQuota
|
||||
err = self.GetPendingUsage(&pendingUsage)
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("GetPendingUsage %s", err))
|
||||
return
|
||||
}
|
||||
// ownerCred := guest.GetOwnerUserCred()
|
||||
var cancelUsage models.SQuota
|
||||
if addCpu > 0 {
|
||||
cancelUsage.Cpu = addCpu
|
||||
}
|
||||
if addMem > 0 {
|
||||
cancelUsage.Memory = addMem
|
||||
}
|
||||
|
||||
lockman.LockClass(ctx, guest.GetModelManager(), guest.ProjectId)
|
||||
defer lockman.ReleaseClass(ctx, guest.GetModelManager(), guest.ProjectId)
|
||||
|
||||
err = models.QuotaManager.CancelPendingUsage(ctx, self.UserCred, guest.ProjectId, &pendingUsage, &cancelUsage)
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("CancelPendingUsage fail %s", err))
|
||||
return
|
||||
}
|
||||
err = self.SetPendingUsage(&pendingUsage)
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("SetPendingUsage fail %s", err))
|
||||
return
|
||||
if len(instanceType) > 0 {
|
||||
guest.InstanceType = instanceType
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("Update fail %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
var pendingUsage models.SQuota
|
||||
err = self.GetPendingUsage(&pendingUsage)
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("GetPendingUsage %s", err))
|
||||
return
|
||||
}
|
||||
var cancelUsage models.SQuota
|
||||
if addCpu > 0 {
|
||||
cancelUsage.Cpu = addCpu
|
||||
}
|
||||
if addMem > 0 {
|
||||
cancelUsage.Memory = addMem
|
||||
}
|
||||
|
||||
lockman.LockClass(ctx, guest.GetModelManager(), guest.ProjectId)
|
||||
defer lockman.ReleaseClass(ctx, guest.GetModelManager(), guest.ProjectId)
|
||||
|
||||
err = models.QuotaManager.CancelPendingUsage(ctx, self.UserCred, guest.ProjectId, &pendingUsage, &cancelUsage)
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("CancelPendingUsage fail %s", err))
|
||||
return
|
||||
}
|
||||
err = self.SetPendingUsage(&pendingUsage)
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("SetPendingUsage fail %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
self.OnGuestChangeCpuMemSpecFinish(ctx, guest)
|
||||
}
|
||||
|
||||
func (self *GuestChangeConfigTask) OnGuestChangeCpuMemSpecFinish(ctx context.Context, guest *models.SGuest) {
|
||||
self.SetStage("on_sync_config_complete", nil)
|
||||
err := guest.StartSyncTask(ctx, self.UserCred, false, self.GetTaskId())
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("StartSyncstatus fail %s", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (self *GuestChangeConfigTask) OnSyncConfigComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
guest := obj.(*models.SGuest)
|
||||
|
||||
self.SetStage("on_sync_status_complete", nil)
|
||||
err = guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId())
|
||||
err := guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId())
|
||||
if err != nil {
|
||||
self.markStageFailed(ctx, guest, fmt.Sprintf("StartSyncstatus fail %s", err))
|
||||
return
|
||||
|
||||
@@ -71,22 +71,30 @@ func optionsStructRvToParams(rv reflect.Value) (*jsonutils.JSONDict, error) {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
rv64 := f.Convert(gotypes.Int64Type)
|
||||
i64 := rv64.Interface().(int64)
|
||||
p.Set(name, jsonutils.NewInt(i64))
|
||||
if i64 != 0 || !jsonInfo.OmitZero {
|
||||
p.Set(name, jsonutils.NewInt(i64))
|
||||
}
|
||||
case reflect.Bool:
|
||||
b := f.Interface().(bool)
|
||||
p.Set(name, jsonutils.NewBool(b))
|
||||
if b || !jsonInfo.OmitFalse {
|
||||
p.Set(name, jsonutils.NewBool(b))
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
// NOTE uint64 converted to int64
|
||||
rv64 := f.Convert(gotypes.Uint64Type)
|
||||
i64 := rv64.Interface().(uint64)
|
||||
p.Set(name, jsonutils.NewInt(int64(i64)))
|
||||
if i64 != 0 || !jsonInfo.OmitZero {
|
||||
p.Set(name, jsonutils.NewInt(int64(i64)))
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
rv64 := f.Convert(gotypes.Float64Type)
|
||||
f64 := rv64.Interface().(float64)
|
||||
p.Set(name, jsonutils.NewFloat(f64))
|
||||
if f64 != 0 || !jsonInfo.OmitZero {
|
||||
p.Set(name, jsonutils.NewFloat(f64))
|
||||
}
|
||||
case reflect.String:
|
||||
s := f.Interface().(string)
|
||||
if len(s) > 0 {
|
||||
if len(s) > 0 || !jsonInfo.OmitEmpty {
|
||||
p.Set(name, jsonutils.NewString(s))
|
||||
}
|
||||
case reflect.Struct:
|
||||
|
||||
@@ -129,13 +129,13 @@ type ServerCreateOptions struct {
|
||||
|
||||
Duration string `help:"valid duration of the server, e.g. 1H, 1D, 1W, 1M, 1Y, ADMIN ONLY option"`
|
||||
|
||||
AutoPrepaidRecycle bool `help:"automatically enable prepaid recycling after server is created successfully" json:",omitfalse"`
|
||||
AutoPrepaidRecycle bool `help:"automatically enable prepaid recycling after server is created successfully" json:"auto_prepaid_recycle,omitfalse"`
|
||||
|
||||
GenerateName bool `help:"name is generated by pattern" json:"-"`
|
||||
|
||||
EipBw int `help:"allocate EIP with bandwidth in MB when server is created"`
|
||||
EipChargeType string `help:"newly allocated EIP charge type, either traffic or bandwidth" choices:"traffic|bandwidth"`
|
||||
Eip string `help:"associate with an existing EIP when server is created"`
|
||||
EipBw int `help:"allocate EIP with bandwidth in MB when server is created" json:"eip_bw,omitzero"`
|
||||
EipChargeType string `help:"newly allocated EIP charge type, either traffic or bandwidth" choices:"traffic|bandwidth" json:"eip_charge_type,omitempty"`
|
||||
Eip string `help:"associate with an existing EIP when server is created" json:"eip,omitempty"`
|
||||
}
|
||||
|
||||
func (opts *ServerCreateOptions) Params() (*jsonutils.JSONDict, error) {
|
||||
@@ -311,7 +311,7 @@ type ServerChangeConfigOptions struct {
|
||||
ID string `help:"Server to rebuild root" json:"-"`
|
||||
Ncpu *int `help:"New number of Virtual CPU cores" json:"vcpu_count"`
|
||||
Vmem string `help:"New memory size" json:"vmem_size"`
|
||||
Disk []string `help:"Data disk description, from the 1st data disk to the last one, empty string if no change for this data disk"`
|
||||
Disk []string `help:"Data disk description, from the 1st data disk to the last one, empty string if no change for this data disk" json:"-"`
|
||||
|
||||
InstanceType string `help:"Instance Type, e.g. S2.SMALL2 for qcloud"`
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ func ParseJSONResponse(resp *http.Response, err error, debug bool) (http.Header,
|
||||
}
|
||||
rbody, err := ioutil.ReadAll(resp.Body)
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(rbody))
|
||||
fmt.Fprintf(os.Stderr, "Response body: %s\n", string(rbody))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Fail to read body: %s", err)
|
||||
@@ -229,12 +229,16 @@ func ParseJSONResponse(resp *http.Response, err error, debug bool) (http.Header,
|
||||
ce.Class = "redirect"
|
||||
return nil, nil, &ce
|
||||
} else {
|
||||
ce := JSONClientError{
|
||||
Code: resp.StatusCode,
|
||||
Details: resp.Status,
|
||||
}
|
||||
ce := JSONClientError{}
|
||||
|
||||
if jrbody == nil {
|
||||
ce.Code = resp.StatusCode
|
||||
ce.Details = resp.Status
|
||||
return nil, nil, &ce
|
||||
}
|
||||
|
||||
err = jrbody.Unmarshal(&ce)
|
||||
if len(ce.Class) > 0 && ce.Code >= 400 && len(ce.Details) > 0 {
|
||||
return nil, nil, &ce
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user