fix(region,host): migrate use source desc file. (#15623)

This commit is contained in:
wanyaoqi
2022-12-27 16:50:47 +08:00
committed by GitHub
parent 0386ea3453
commit e1d3635b0a
21 changed files with 539 additions and 179 deletions
+1
View File
@@ -43,6 +43,7 @@ const (
VM_RENEW_FAILED = "renew_failed"
VM_ATTACH_DISK = "attach_disk"
VM_DETACH_DISK = "detach_disk"
VM_UNSYNC = "unsync"
VM_BACKUP_STARTING = "backup_starting"
VM_BACKUP_STOPING = "backup_stopping"
+1 -7
View File
@@ -59,7 +59,6 @@ import (
"yunion.io/x/onecloud/pkg/compute/baremetal"
"yunion.io/x/onecloud/pkg/hostman/guestfs"
"yunion.io/x/onecloud/pkg/hostman/guestfs/sshpart"
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -2913,12 +2912,7 @@ func (s *SBaremetalServer) deployFs(tool *disktool.SSHPartitionTool, term *ssh.C
if strings.ToLower(rootfs.GetOs()) == "windows" {
return nil, fmt.Errorf("Unsupported OS: %s", rootfs.GetOs())
}
guestDesc := new(desc.SGuestDesc)
err = s.desc.Unmarshal(guestDesc)
if err != nil {
return nil, errors.Wrap(err, "Failed unmarsh guest desc")
}
deployDesc := deployapi.GuestDescToDeployDesc(guestDesc)
deployDesc, err := deployapi.GuestJsonDescToDeployDesc(s.desc)
if err != nil {
return nil, errors.Wrap(err, "To deploy desc fail")
}
+21 -14
View File
@@ -54,6 +54,14 @@ func init() {
taskman.RegisterTask(ManagedGuestLiveMigrateTask{})
}
func (self *GuestMigrateTask) isLiveMigrate() bool {
guestStatus, _ := self.Params.GetString("guest_status")
if !self.isRescueMode() && (guestStatus == api.VM_RUNNING || guestStatus == api.VM_SUSPEND) {
return true
}
return false
}
func (self *GuestMigrateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
StartScheduleObjects(ctx, self, []db.IStandaloneModel{obj})
}
@@ -66,8 +74,7 @@ func (self *GuestMigrateTask) GetSchedParams() (*schedapi.ScheduleInput, error)
preferHostId, _ := self.Params.GetString("prefer_host_id")
input.PreferHostId = preferHostId
}
guestStatus, _ := self.Params.GetString("guest_status")
if !self.isRescueMode() && (guestStatus == api.VM_RUNNING || guestStatus == api.VM_SUSPEND) {
if self.isLiveMigrate() {
input.LiveMigrate = true
skipCpuCheck := jsonutils.QueryBoolean(self.Params, "skip_cpu_check", false)
skipKernelCheck := jsonutils.QueryBoolean(self.Params, "skip_kernel_check", false)
@@ -189,8 +196,7 @@ func (self *GuestMigrateTask) OnCachedImageComplete(ctx context.Context, guest *
func (self *GuestMigrateTask) OnCachedCdromComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
header := self.GetTaskRequestHeader()
body := jsonutils.NewDict()
guestStatus, _ := self.Params.GetString("guest_status")
if !self.isRescueMode() && (guestStatus == api.VM_RUNNING || guestStatus == api.VM_SUSPEND) {
if self.isLiveMigrate() {
body.Set("live_migrate", jsonutils.JSONTrue)
body.Set("enable_tls", jsonutils.NewBool(jsonutils.QueryBoolean(self.GetParams(), "enable_tls", false)))
}
@@ -232,6 +238,15 @@ func (self *GuestMigrateTask) OnSrcPrepareComplete(ctx context.Context, guest *m
} else {
body, err = self.sharedStorageMigrateConf(ctx, guest, targetHost)
}
if self.isLiveMigrate() {
srcDesc, err := data.Get("src_desc")
if err != nil {
self.TaskFailed(ctx, guest, jsonutils.NewString(errors.Wrap(err, "get src_desc from data").Error()))
return
}
body.Set("src_desc", srcDesc)
body.Set("live_migrate", jsonutils.JSONTrue)
}
if jsonutils.QueryBoolean(self.GetParams(), "enable_tls", false) {
body.Set("enable_tls", jsonutils.JSONTrue)
certsObj, err := data.Get("migrate_certs")
@@ -245,15 +260,10 @@ func (self *GuestMigrateTask) OnSrcPrepareComplete(ctx context.Context, guest *m
self.TaskFailed(ctx, guest, jsonutils.NewString(err.Error()))
return
}
guestStatus, _ := self.Params.GetString("guest_status")
if !self.isRescueMode() && (guestStatus == api.VM_RUNNING || guestStatus == api.VM_SUSPEND) {
body.Set("live_migrate", jsonutils.JSONTrue)
}
headers := self.GetTaskRequestHeader()
url := fmt.Sprintf("%s/servers/%s/dest-prepare-migrate", targetHost.ManagerUri, guest.Id)
self.SetStage("OnMigrateConfAndDiskComplete", body)
self.SetStage("OnMigrateConfAndDiskComplete", nil)
_, _, err = httputils.JSONRequest(httputils.GetDefaultClient(),
ctx, "POST", url, headers, body, false)
if err != nil {
@@ -288,8 +298,7 @@ func (self *GuestMigrateTask) OnMigrateConfAndDiskComplete(ctx context.Context,
msData, _ := data.Get("dest_prepared_memory_snapshots")
self.Params.Set("dest_prepared_memory_snapshots", msData)
}
guestStatus, _ := self.Params.GetString("guest_status")
if !self.isRescueMode() && (guestStatus == api.VM_RUNNING || guestStatus == api.VM_SUSPEND) {
if self.isLiveMigrate() {
// Live migrate
self.SetStage("OnStartDestComplete", nil)
} else {
@@ -388,7 +397,6 @@ func (self *GuestMigrateTask) sharedStorageMigrateConf(ctx context.Context, gues
body := jsonutils.NewDict()
body.Set("is_local_storage", jsonutils.JSONFalse)
body.Set("qemu_version", jsonutils.NewString(guest.GetQemuVersion(self.UserCred)))
body.Set("qemu_cmdline", jsonutils.NewString(guest.GetQemuCmdline(self.UserCred)))
targetDesc := guest.GetJsonDescAtHypervisor(ctx, targetHost)
body.Set("desc", jsonutils.Marshal(targetDesc))
@@ -426,7 +434,6 @@ func (self *GuestMigrateTask) localStorageMigrateConf(ctx context.Context,
body.Set("disks_uri", jsonutils.NewString(disksUri))
body.Set("server_url", jsonutils.NewString(serverUrl))
body.Set("qemu_version", jsonutils.NewString(guest.GetQemuVersion(self.UserCred)))
body.Set("qemu_cmdline", jsonutils.NewString(guest.GetQemuCmdline(self.UserCred)))
if err := self.setBodyMemorySnapshotParams(guest, sourceHost, body); err != nil {
return nil, errors.Wrap(err, "setBodyMemorySnapshotParams")
+1 -1
View File
@@ -22,7 +22,7 @@ const (
)
type Arch interface {
GenerateCpuDesc(cpus uint, s KVMGuestInstance) (*desc.SGuestCpu, error)
GenerateCpuDesc(cpus uint, cpuMax uint, s KVMGuestInstance) (*desc.SGuestCpu, error)
GenerateMemDesc() *desc.SGuestMem
GenerateMachineDesc(accel string) *desc.SGuestMachine
GenerateCdromDesc(osName string, cdrom *desc.SGuestCdrom)
+1 -6
View File
@@ -66,12 +66,7 @@ func (*ARM) GenerateMemDesc() *desc.SGuestMem {
}
}
func (*ARM) GenerateCpuDesc(cpus uint, s KVMGuestInstance) (*desc.SGuestCpu, error) {
cpuMax, err := s.CpuMax()
if err != nil {
return nil, err
}
func (*ARM) GenerateCpuDesc(cpus uint, cpuMax uint, s KVMGuestInstance) (*desc.SGuestCpu, error) {
var hostCPUPassthrough = options.HostOptions.HostCpuPassthrough
var accel, cpuType string
if s.IsKvmSupport() {
+1 -5
View File
@@ -127,11 +127,7 @@ func (*X86) enableHypervFeatures(features map[string]bool) {
}
}
func (x86 *X86) GenerateCpuDesc(cpus uint, s KVMGuestInstance) (*desc.SGuestCpu, error) {
cpuMax, err := s.CpuMax()
if err != nil {
return nil, err
}
func (x86 *X86) GenerateCpuDesc(cpus uint, cpuMax uint, s KVMGuestInstance) (*desc.SGuestCpu, error) {
var hideKVM = true
if s.IsNestedVirt() {
hideKVM = false
+2 -1
View File
@@ -95,7 +95,6 @@ type SGuestHardwareDesc struct {
Floppys []*SGuestFloppy `json:",omitempty"`
Disks []*SGuestDisk `json:",omitempty"`
Nics []*SGuestNetwork `json:",omitempty"`
NicsStandby []*SGuestNetwork `json:",omitempty"`
IsolatedDevices []*SGuestIsolatedDevice `json:",omitempty"`
// Random Number Generator Device
@@ -295,6 +294,8 @@ type SGuestVirtioSerial struct {
type SGuestVirtioScsi struct {
*PCIDevice
NumQueues *uint8 `json:"num_queues"`
}
type SGuestPvScsi struct {
@@ -327,25 +327,30 @@ func guestDestPrepareMigrateInternal(ctx context.Context, userCred mcclient.Toke
return httperrors.NewBadRequestError("Failed unmarshal guest desc %s", err)
}
var params = &guestman.SDestPrepareMigrate{}
qemuVersion, err := body.GetString("qemu_version")
if err != nil {
return httperrors.NewMissingParameterError("qemu_version")
}
liveMigrate := jsonutils.QueryBoolean(body, "live_migrate", false)
if liveMigrate {
var sourceDesc = new(desc.SGuestDesc)
err := body.Unmarshal(sourceDesc, "src_desc")
if err != nil {
return httperrors.NewBadRequestError("Failed unmarshal guest source desc %s", err)
}
params.SrcDesc = sourceDesc
}
isLocal, err := body.Bool("is_local_storage")
if err != nil {
return httperrors.NewMissingParameterError("is_local_storage")
}
qemuCmdline, err := body.GetString("qemu_cmdline")
if err != nil {
return httperrors.NewMissingParameterError("qemu_cmdline")
}
var params = &guestman.SDestPrepareMigrate{}
params.Sid = sid
params.Desc = guestDesc
params.QemuVersion = qemuVersion
params.LiveMigrate = liveMigrate
params.SourceQemuCmdline = qemuCmdline
params.EnableTLS = jsonutils.QueryBoolean(body, "enable_tls", false)
if params.EnableTLS {
certsObj, err := body.Get("migrate_certs")
@@ -400,7 +405,6 @@ func guestDestPrepareMigrateInternal(ctx context.Context, userCred mcclient.Toke
return httperrors.NewMissingParameterError("target_storage_id")
}
targetStorageIds = append(targetStorageIds, targetStorageId)
// params.TargetStorageId = targetStorageId
params.TargetStorageIds = targetStorageIds
}
+8 -8
View File
@@ -44,20 +44,20 @@ type SSrcPrepareMigrate struct {
}
type SDestPrepareMigrate struct {
Sid string
ServerUrl string
QemuVersion string
SourceQemuCmdline string
MigrateCerts map[string]string
EnableTLS bool
SnapshotsUri string
DisksUri string
Sid string
ServerUrl string
QemuVersion string
MigrateCerts map[string]string
EnableTLS bool
SnapshotsUri string
DisksUri string
// TargetStorageId string
TargetStorageIds []string
LiveMigrate bool
RebaseDisks bool
Desc *desc.SGuestDesc
SrcDesc *desc.SGuestDesc
DisksBackingFile jsonutils.JSONObject
SrcSnapshots jsonutils.JSONObject
+17 -8
View File
@@ -740,7 +740,14 @@ func (m *SGuestManager) StatusWithBlockJobsCount(ctx context.Context, params int
sid := params.(string)
status := m.getStatus(sid)
guest, _ := m.GetServer(sid)
if status == GUEST_RUNNING {
body := jsonutils.NewDict()
if guest != nil {
body.Set("power_status", jsonutils.NewString(guest.GetPowerStates()))
}
if status == GUEST_RUNNING && guest.pciUninitialized {
status = compute.VM_UNSYNC
} else if status == GUEST_RUNNING {
var runCb = func() {
body := jsonutils.NewDict()
if guest.IsMaster() {
@@ -757,21 +764,20 @@ func (m *SGuestManager) StatusWithBlockJobsCount(ctx context.Context, params int
blockJobsCount := guest.BlockJobsCount()
body.Set("block_jobs_count", jsonutils.NewInt(int64(blockJobsCount)))
}
body.Set("status", jsonutils.NewString(status))
hostutils.TaskComplete(ctx, body)
}
if guest.Monitor == nil && !guest.IsStopping() {
guest.StartMonitor(context.Background(), runCb)
if err := guest.StartMonitor(context.Background(), runCb); err != nil {
log.Errorf("guest %s failed start monitor %s", guest.GetName(), err)
body.Set("status", jsonutils.NewString(status))
hostutils.TaskComplete(ctx, body)
}
} else {
runCb()
}
return nil, nil
}
body := jsonutils.NewDict()
if guest != nil {
body.Set("power_status", jsonutils.NewString(guest.GetPowerStates()))
}
body.Set("status", jsonutils.NewString(status))
hostutils.TaskComplete(ctx, body)
return nil, nil
@@ -910,6 +916,9 @@ func (m *SGuestManager) SrcPrepareMigrate(ctx context.Context, params interface{
}
ret.Set("migrate_certs", jsonutils.Marshal(certs))
}
if migParams.LiveMigrate {
ret.Set("src_desc", jsonutils.Marshal(guest.Desc))
}
return ret, nil
}
@@ -970,8 +979,8 @@ func (m *SGuestManager) DestPrepareMigrate(ctx context.Context, params interface
startParams := jsonutils.NewDict()
startParams.Set("qemu_version", jsonutils.NewString(migParams.QemuVersion))
startParams.Set("need_migrate", jsonutils.JSONTrue)
startParams.Set("source_qemu_cmdline", jsonutils.NewString(migParams.SourceQemuCmdline))
startParams.Set("live_migrate_use_tls", jsonutils.NewBool(migParams.EnableTLS))
startParams.Set("src_desc", jsonutils.Marshal(migParams.SrcDesc))
if len(migParams.MigrateCerts) > 0 {
if err := guest.WriteMigrateCerts(migParams.MigrateCerts); err != nil {
return nil, errors.Wrap(err, "write migrate certs")
+99 -44
View File
@@ -50,7 +50,7 @@ func (s *SKVMGuestInstance) pciControllerFind(cont desc.PCI_CONTROLLER_TYPE) *de
}
func (s *SKVMGuestInstance) initGuestDesc() error {
err := s.initCpuDesc()
err := s.initCpuDesc(0)
if err != nil {
return err
}
@@ -62,10 +62,19 @@ func (s *SKVMGuestInstance) initGuestDesc() error {
if err != nil {
return errors.Wrap(err, "init guest pci addresses")
}
if err := s.initMachineDefaultDevices(); err != nil {
return errors.Wrap(err, "init machine default devices")
err = s.initGuestDevicesDesc(pciRoot, pciBridge)
if err != nil {
return err
}
if err := s.initMachineDefaultAddresses(); err != nil {
return errors.Wrap(err, "init machine default devices")
}
return s.ensurePciAddresses()
}
func (s *SKVMGuestInstance) initGuestDevicesDesc(pciRoot, pciBridge *desc.PCIController) error {
// vdi device for spice
s.Desc.VdiDevice = new(desc.SGuestVdi)
if s.IsVdiSpice() {
@@ -77,7 +86,7 @@ func (s *SKVMGuestInstance) initGuestDesc() error {
s.initCdromDesc()
s.initFloppyDesc()
s.initGuestDisks(pciRoot, pciBridge)
if err = s.initGuestNetworks(pciRoot, pciBridge); err != nil {
if err := s.initGuestNetworks(pciRoot, pciBridge); err != nil {
return errors.Wrap(err, "init guest networks")
}
@@ -87,8 +96,7 @@ func (s *SKVMGuestInstance) initGuestDesc() error {
s.initQgaDesc()
s.initPvpanicDesc()
s.initIsaSerialDesc()
return s.ensurePciAddresses()
return nil
}
func (s *SKVMGuestInstance) loadGuestPciAddresses() error {
@@ -96,7 +104,7 @@ func (s *SKVMGuestInstance) loadGuestPciAddresses() error {
if err != nil {
return errors.Wrap(err, "init guest pci addresses")
}
if err := s.initMachineDefaultDevices(); err != nil {
if err := s.initMachineDefaultAddresses(); err != nil {
return errors.Wrap(err, "init machine default devices")
}
err = s.ensurePciAddresses()
@@ -106,7 +114,7 @@ func (s *SKVMGuestInstance) loadGuestPciAddresses() error {
return nil
}
func (s *SKVMGuestInstance) initMachineDefaultDevices() error {
func (s *SKVMGuestInstance) initMachineDefaultAddresses() error {
switch s.Desc.Machine {
case "pc":
I440FXSlot1 := &desc.PCIDevice{
@@ -172,6 +180,28 @@ func (s *SKVMGuestInstance) initMachineDefaultDevices() error {
return nil
}
func (s *SKVMGuestInstance) isMachineDefaultAddress(pciAddr *desc.PCIAddr) bool {
switch s.Desc.Machine {
case "pc":
if pciAddr.Bus == 0 && pciAddr.Slot == 1 && pciAddr.Function < 4 {
return true
}
case "q35":
if pciAddr.Bus == 0 && pciAddr.Slot == 29 {
switch pciAddr.Function {
case 0, 1, 2, 7:
return true
}
} else if pciAddr.Bus == 0 && pciAddr.Slot == 31 {
switch pciAddr.Function {
case 0, 2, 3:
return true
}
}
}
return false
}
func (s *SKVMGuestInstance) initGuestPciControllers() (*desc.PCIController, *desc.PCIController) {
var isPcie = s.isPcie()
var pciRoot, pciBridge *desc.PCIController
@@ -238,12 +268,6 @@ func (s *SKVMGuestInstance) initUsbController(pciRoot *desc.PCIController) {
s.Desc.Usb = &desc.UsbController{
PCIDevice: desc.NewPCIDevice(pciRoot.CType, contType, "usb"),
}
if contType == "qemu-xhci" {
s.Desc.Usb.Options = map[string]string{
"p2": "8", // usb2 port count
"p3": "8", // usb3 port count
}
}
}
func (s *SKVMGuestInstance) initGuestNetworks(pciRoot, pciBridge *desc.PCIController) error {
@@ -674,19 +698,20 @@ func (s *SKVMGuestInstance) ensurePciAddresses() error {
// guests description no pci description before host-agent assign pci device address info
// in this case wo need query pci address info by `query-pci` command. Also memory devices.
func (s *SKVMGuestInstance) initGuestDescFromExistingGuest(
pciInfoList []monitor.PCIInfo, memoryDevicesInfoList []monitor.MemoryDeviceInfo,
cpuList []monitor.HotpluggableCPU, pciInfoList []monitor.PCIInfo,
memoryDevicesInfoList []monitor.MemoryDeviceInfo, memDevs []monitor.Memdev,
scsiNumQueues int64,
) error {
if len(pciInfoList) > 1 {
return errors.Errorf("unsupported pci info list with multi bus")
}
unknownDevices := make([]monitor.PCIDeviceInfo, 0)
err := s.initCpuDesc()
err := s.initCpuDesc(uint(len(cpuList)))
if err != nil {
return err
}
err = s.initMemDescFromMemoryInfo(memoryDevicesInfoList)
err = s.initMemDescFromMemoryInfo(memoryDevicesInfoList, memDevs)
if err != nil {
return errors.Wrap(err, "init guest memory devices")
}
@@ -698,27 +723,11 @@ func (s *SKVMGuestInstance) initGuestDescFromExistingGuest(
return errors.Wrap(err, "init guest pci addresses")
}
// vdi device for spice
s.Desc.VdiDevice = new(desc.SGuestVdi)
if s.IsVdiSpice() {
s.initSpiceDevices(pciRoot)
err = s.initGuestDevicesDesc(pciRoot, nil)
if err != nil {
return err
}
s.initVirtioSerial(pciRoot)
s.initGuestVga(pciRoot)
s.initCdromDesc()
s.initGuestDisks(pciRoot, nil)
if err = s.initGuestNetworks(pciRoot, nil); err != nil {
return errors.Wrap(err, "init guest networks")
}
s.initIsolatedDevices(pciRoot, nil)
s.initUsbController(pciRoot)
s.initRandomDevice(pciRoot, options.HostOptions.EnableVirtioRngDevice)
s.initQgaDesc()
s.initPvpanicDesc()
s.initIsaSerialDesc()
for i := 0; i < len(pciInfoList[0].Devices); i++ {
pciAddr := &desc.PCIAddr{
Bus: uint(pciInfoList[0].Devices[i].Bus),
@@ -733,6 +742,10 @@ func (s *SKVMGuestInstance) initGuestDescFromExistingGuest(
if err != nil {
return errors.Wrap(err, "ensure virtio scsi pci address")
}
if scsiNumQueues > 1 {
numQueues := uint8(scsiNumQueues)
s.Desc.VirtioScsi.NumQueues = &numQueues
}
} else if s.Desc.PvScsi != nil {
s.Desc.PvScsi.PCIAddr = pciAddr
err = s.ensureDevicePciAddress(s.Desc.PvScsi.PCIDevice, -1, nil)
@@ -772,7 +785,7 @@ func (s *SKVMGuestInstance) initGuestDescFromExistingGuest(
if err != nil {
return errors.Wrap(err, "ensure vdi hda pci address")
}
case "virtio-serial0":
case "vdagent-serial0":
if s.Desc.VdiDevice.Spice == nil {
s.Desc.Vdi = "spice"
s.initSpiceDevices(pciRoot)
@@ -782,6 +795,12 @@ func (s *SKVMGuestInstance) initGuestDescFromExistingGuest(
if err != nil {
return errors.Wrap(err, "ensure vdagent serial pci address")
}
case "virtio-serial0":
s.Desc.VirtioSerial.PCIAddr = pciAddr
err = s.ensureDevicePciAddress(s.Desc.VirtioSerial.PCIDevice, -1, nil)
if err != nil {
return errors.Wrap(err, "ensure virtio serial address")
}
case "usbspice":
if s.Desc.VdiDevice.Spice == nil {
s.Desc.Vdi = "spice"
@@ -845,18 +864,48 @@ func (s *SKVMGuestInstance) initGuestDescFromExistingGuest(
}
}
default:
unknownDevices = append(unknownDevices, pciInfoList[0].Devices[i])
class := pciInfoList[0].Devices[i].ClassInfo.Class
vendor := pciInfoList[0].Devices[i].ID.Vendor
device := pciInfoList[0].Devices[i].ID.Device
switch { // qemu: docs/specs/pci-ids.txt
case class == 3075 && vendor == 6966 && device == 13: // { 0x0c03, "USB controller", "usb"}, 1b36:000d PCI xhci usb host adapter
s.Desc.Usb.PCIAddr = pciAddr
err = s.ensureDevicePciAddress(s.Desc.Usb.PCIDevice, -1, nil)
if err != nil {
return errors.Wrap(err, "ensure usb controller pci address")
}
case class == 255 && vendor == 6900 && device == 4101: // 0x00ff, 1af4:1005 entropy generator device (legacy)
if s.Desc.Rng == nil {
// in case rng device disable by host options
s.initRandomDevice(pciRoot, true)
}
s.Desc.Rng.PCIAddr = pciAddr
err = s.ensureDevicePciAddress(s.Desc.Rng.PCIDevice, -1, nil)
if err != nil {
return errors.Wrap(err, "ensure random device pci address")
}
case class == 1920 && vendor == 6900 && device == 4099: // 0x0780, 1af4:1003 console device (legacy)
s.Desc.VirtioSerial.PCIAddr = pciAddr
err = s.ensureDevicePciAddress(s.Desc.VirtioSerial.PCIDevice, -1, nil)
if err != nil {
return errors.Wrap(err, "ensure virtio serial address")
}
case class == 768 && vendor == 4660 && device == 4369: // { 0x0300, "VGA controller", "display", 0x00ff}, PCI ID: 1234:1111
s.Desc.VgaDevice.PCIAddr = pciAddr
err = s.ensureDevicePciAddress(s.Desc.VgaDevice.PCIDevice, -1, nil)
if err != nil {
return errors.Wrap(err, "ensure vga pci address")
}
default:
unknownDevices = append(unknownDevices, pciInfoList[0].Devices[i])
}
}
}
}
if len(unknownDevices) > 0 {
s.Desc.AnonymousPCIDevs = make([]*desc.PCIDevice, len(unknownDevices))
}
for i := 0; i < len(unknownDevices); i++ {
if unknownDevices[i].Bus == 0 && unknownDevices[i].Slot == 0 {
// host bridge
continue
continue // host bridge
}
pciDev := desc.NewPCIDevice(pciRoot.CType, "", unknownDevices[i].QdevID)
pciDev.PCIAddr = &desc.PCIAddr{
@@ -868,6 +917,12 @@ func (s *SKVMGuestInstance) initGuestDescFromExistingGuest(
if err != nil {
return errors.Wrap(err, "ensure anonymous pci dev address")
}
if s.isMachineDefaultAddress(pciDev.PCIAddr) {
continue
}
if s.Desc.AnonymousPCIDevs == nil {
s.Desc.AnonymousPCIDevs = make([]*desc.PCIDevice, 0)
}
s.Desc.AnonymousPCIDevs = append(s.Desc.AnonymousPCIDevs, pciDev)
}
return nil
+1 -1
View File
@@ -163,7 +163,7 @@ func TestSKVMGuestInstance_initGuestDesc(t *testing.T) {
if err != nil {
t.Error(err)
}
if err := s.initMachineDefaultDevices(); err != nil {
if err := s.initMachineDefaultAddresses(); err != nil {
t.Error(err)
}
+153 -55
View File
@@ -157,6 +157,27 @@ func (s *SKVMGuestInstance) updateGuestDesc() error {
return s.SaveLiveDesc(s.Desc)
}
func (s *SKVMGuestInstance) initLiveDescFromSourceGuest(srcDesc *desc.SGuestDesc) error {
srcDesc.SGuestProjectDesc = s.SourceDesc.SGuestProjectDesc
srcDesc.SGuestRegionDesc = s.SourceDesc.SGuestRegionDesc
srcDesc.SGuestControlDesc = s.SourceDesc.SGuestControlDesc
srcDesc.SGuestMetaDesc = s.SourceDesc.SGuestMetaDesc
for i := 0; i < len(s.SourceDesc.Cdroms); i++ {
srcDesc.Cdroms[i].Path = s.SourceDesc.Cdroms[i].Path
}
for i := 0; i < len(s.SourceDesc.Disks); i++ {
srcDesc.Disks[i].GuestdiskJsonDesc = s.SourceDesc.Disks[i].GuestdiskJsonDesc
}
for i := 0; i < len(s.SourceDesc.Nics); i++ {
if err := s.generateNicScripts(s.SourceDesc.Nics[i]); err != nil {
return errors.Wrapf(err, "generateNicScripts for nic: %v", s.SourceDesc.Nics[i])
}
srcDesc.Nics[i].UpscriptPath = s.getNicUpScriptPath(s.SourceDesc.Nics[i])
srcDesc.Nics[i].DownscriptPath = s.getNicDownScriptPath(s.SourceDesc.Nics[i])
}
return s.SaveLiveDesc(srcDesc)
}
func (s *SKVMGuestInstance) IsStopping() bool {
return s.stopping
}
@@ -459,9 +480,18 @@ func (s *SKVMGuestInstance) asyncScriptStart(ctx context.Context, params interfa
return nil, errors.Wrap(err, "fuse mount")
}
err = s.updateGuestDesc()
if jsonutils.QueryBoolean(data, "need_migrate", false) {
var sourceDesc = new(desc.SGuestDesc)
err = data.Unmarshal(sourceDesc, "src_desc")
if err != nil {
return nil, errors.Wrap(err, "unmarshal src desc")
}
err = s.initLiveDescFromSourceGuest(sourceDesc)
} else {
err = s.updateGuestDesc()
}
if err != nil {
return nil, errors.Wrap(err, "generate desc")
return nil, errors.Wrap(err, "asyncScriptStart init desc")
}
hostbridge.CleanDeletedPorts(options.HostOptions.BridgeDriver)
@@ -535,23 +565,6 @@ func (s *SKVMGuestInstance) saveScripts(data *jsonutils.JSONDict) error {
if err != nil {
return err
}
// diff qemu command options when migrating
if jsonutils.QueryBoolean(data, "need_migrate", false) {
srcCmdline, err := data.GetString("source_qemu_cmdline")
if err != nil {
return errors.Wrap(err, "Get source_qemu_cmdline")
}
currentCmd, err := s.getQemuCmdlineFromContent(startScript)
if err != nil {
return errors.Wrapf(err, "Get qemu cmdline from %q", startScript)
}
unifyCmd, err := s.unifyMigrateQemuCmdline(currentCmd, srcCmdline)
if err != nil {
return errors.Wrap(err, "Unify migrate qemu cmdline")
}
// reinject cmd
startScript = strings.ReplaceAll(startScript, currentCmd, unifyCmd)
}
if err = fileutils2.FilePutContents(s.GetStartScriptPath(), startScript, false); err != nil {
return err
@@ -717,23 +730,25 @@ func (s *SKVMGuestInstance) StartMonitorWithImportGuestSocketFile(ctx context.Co
func (s *SKVMGuestInstance) StartMonitor(ctx context.Context, cb func()) error {
if s.GetQmpMonitorPort(-1) > 0 {
var mon monitor.Monitor
var onMonitorTimeout = func(err error) { s.onMonitorTimeout(ctx, err) }
var onMonitorConnected = func() {
s.Monitor = mon
s.onMonitorConnected(ctx)
if cb != nil {
cb()
}
}
mon = monitor.NewQmpMonitor(
s.GetName(), s.Id,
s.onMonitorDisConnect, // on monitor disconnect
func(err error) { s.onMonitorTimeout(ctx, err) }, // on monitor timeout
func() {
s.Monitor = mon
s.onMonitorConnected(ctx)
if cb != nil {
cb()
}
}, // on monitor connected
s.onReceiveQMPEvent, // on receive qmp event
s.onMonitorDisConnect, // on monitor disconnect
onMonitorTimeout, // on monitor timeout
onMonitorConnected, // on monitor connected
s.onReceiveQMPEvent, // on receive qmp event
)
err := mon.Connect("127.0.0.1", s.GetQmpMonitorPort(-1))
if err != nil {
mon = nil
log.Errorf("Guest %s hmp monitor connect failed %s, something wrong", s.GetName(), err)
log.Errorf("Guest %s qmp monitor connect failed %s, something wrong", s.GetName(), err)
return errors.Errorf("connect qmp monitor: %s", err)
}
return nil
@@ -962,44 +977,127 @@ func (s *SKVMGuestInstance) onGetQemuVersion(ctx context.Context, version string
s.QemuVersion = version
log.Infof("Guest(%s) qemu version %s", s.Id, s.QemuVersion)
if s.pciUninitialized {
s.getPciDevices(ctx)
} else {
s.guestRun(ctx)
if err := s.collectGuestDescription(); err != nil {
log.Errorf("failed init desc from existing guest: %s", err)
s.syncStatusUnsync(fmt.Sprintf("failed init desc from existing guest: %s", err))
return
}
s.pciUninitialized = false
}
s.guestRun(ctx)
}
func (s *SKVMGuestInstance) syncStatusUnsync(reason string) {
statusInput := &apis.PerformStatusInput{
Status: api.VM_UNSYNC,
Reason: reason,
PowerStates: s.GetPowerStates(),
}
if _, err := hostutils.UpdateServerStatus(context.Background(), s.Id, statusInput); err != nil {
log.Errorf("failed update guest status %s", err)
}
}
func (s *SKVMGuestInstance) getPciDevices(ctx context.Context) {
cb := func(pciInfoList []monitor.PCIInfo, err string) {
if err != "" && pciInfoList == nil {
log.Errorf("failed query pci %s", err)
s.guestRun(ctx)
func (s *SKVMGuestInstance) collectGuestDescription() error {
cpuList, err := s.getHotpluggableCPUList()
if err != nil {
return errors.Wrap(err, "get hotpluggable cpus")
}
pciInfoList, err := s.getPciDevices()
if err != nil {
return errors.Wrap(err, "get pci devices")
}
memoryDevicesInfoList, err := s.getMemoryDevices()
if err != nil {
return errors.Wrap(err, "get memory devices")
}
memDevs, err := s.getMemoryDevs()
if err != nil {
return errors.Wrap(err, "query mem devs")
}
scsiNumQueues := s.getScsiNumQueues()
err = s.initGuestDescFromExistingGuest(cpuList, pciInfoList, memoryDevicesInfoList, memDevs, scsiNumQueues)
if err != nil {
return errors.Wrap(err, "failed init guest devices")
}
if err := s.SaveLiveDesc(s.Desc); err != nil {
return errors.Wrap(err, "failed save live desc")
}
return nil
}
func (s *SKVMGuestInstance) getHotpluggableCPUList() ([]monitor.HotpluggableCPU, error) {
var res []monitor.HotpluggableCPU
var errChan = make(chan error)
cb := func(cpuList []monitor.HotpluggableCPU, err string) {
if err != "" {
errChan <- errors.Errorf(err)
} else {
s.getMemoryDevices(ctx, pciInfoList)
res = cpuList
errChan <- nil
}
}
s.Monitor.GetHotPluggableCpus(cb)
err := <-errChan
return res, err
}
func (s *SKVMGuestInstance) getScsiNumQueues() int64 {
var numQueueChan = make(chan int64)
cb := func(numQueues int64) {
numQueueChan <- numQueues
}
s.Monitor.GetScsiNumQueues(cb)
return <-numQueueChan
}
func (s *SKVMGuestInstance) getPciDevices() ([]monitor.PCIInfo, error) {
var res []monitor.PCIInfo
var errChan = make(chan error)
cb := func(pciInfoList []monitor.PCIInfo, err string) {
if err != "" {
errChan <- errors.Errorf(err)
} else {
res = pciInfoList
errChan <- nil
}
}
s.Monitor.QueryPci(cb)
err := <-errChan
return res, err
}
func (s *SKVMGuestInstance) getMemoryDevices(ctx context.Context, pciInfoList []monitor.PCIInfo) {
cb := func(memoryDevicesInfoList []monitor.MemoryDeviceInfo, err string) {
if err != "" && memoryDevicesInfoList == nil {
log.Errorf("failed query memory device info: %s", err)
func (s *SKVMGuestInstance) getMemoryDevs() ([]monitor.Memdev, error) {
var res []monitor.Memdev
var errChan = make(chan error)
cb := func(memDevs []monitor.Memdev, err string) {
if err != "" {
errChan <- errors.Errorf(err)
} else {
if err := s.initGuestDescFromExistingGuest(pciInfoList, memoryDevicesInfoList); err != nil {
log.Errorf("failed init guest devices: %s", err)
} else {
s.pciUninitialized = false
s.SaveLiveDesc(s.Desc)
vncPort := s.GetVncPort()
data := jsonutils.NewDict()
data.Set("vnc_port", jsonutils.NewInt(int64(vncPort)))
data.Set("sync_qemu_cmdline", jsonutils.JSONTrue)
s.saveScripts(data)
}
res = memDevs
errChan <- nil
}
}
s.Monitor.GetMemdevList(cb)
err := <-errChan
return res, err
}
func (s *SKVMGuestInstance) getMemoryDevices() ([]monitor.MemoryDeviceInfo, error) {
var res []monitor.MemoryDeviceInfo
var errChan = make(chan error)
cb := func(memoryDevicesInfoList []monitor.MemoryDeviceInfo, err string) {
if err != "" {
errChan <- errors.Errorf(err)
} else {
res = memoryDevicesInfoList
errChan <- nil
}
s.guestRun(ctx)
}
s.Monitor.GetMemoryDevicesInfo(cb)
err := <-errChan
return res, err
}
func (s *SKVMGuestInstance) guestRun(ctx context.Context) {
+40 -15
View File
@@ -804,9 +804,16 @@ func (s *SKVMGuestInstance) gpusHasVga() bool {
return false
}
func (s *SKVMGuestInstance) initCpuDesc() error {
func (s *SKVMGuestInstance) initCpuDesc(cpuMax uint) error {
var err error
if cpuMax == 0 {
cpuMax, err = s.CpuMax()
if err != nil {
return err
}
}
s.fixGuestMachineType()
cpuDesc, err := s.archMan.GenerateCpuDesc(uint(s.Desc.Cpu), s)
cpuDesc, err := s.archMan.GenerateCpuDesc(uint(s.Desc.Cpu), cpuMax, s)
if err != nil {
return err
}
@@ -817,37 +824,51 @@ func (s *SKVMGuestInstance) initCpuDesc() error {
func (s *SKVMGuestInstance) initMemDesc(memSizeMB int64) {
s.Desc.MemDesc = s.archMan.GenerateMemDesc()
s.Desc.MemDesc.SizeMB = memSizeMB
s.initDefaultMemObject(memSizeMB)
}
func (s *SKVMGuestInstance) memObjectType() string {
if s.manager.host.IsHugepagesEnabled() {
return "memory-backend-file"
} else if s.isMemcleanEnabled() {
return "memory-backend-memfd"
} else {
return "memory-backend-ram"
}
}
func (s *SKVMGuestInstance) initDefaultMemObject(memSizeMB int64) {
s.Desc.MemDesc.Mem = desc.NewObject(s.memObjectType(), "mem")
if s.manager.host.IsHugepagesEnabled() {
s.Desc.MemDesc.Mem = desc.NewObject("memory-backend-file", "mem")
s.Desc.MemDesc.Mem.Options = map[string]string{
"mem-path": fmt.Sprintf("/dev/hugepages/%s", s.Desc.Uuid),
"size": fmt.Sprintf("%dM", memSizeMB),
"share": "on", "prealloc": "on",
}
} else if s.isMemcleanEnabled() {
s.Desc.MemDesc.Mem = desc.NewObject("memory-backend-memfd", "mem")
s.Desc.MemDesc.Mem.Options = map[string]string{
"size": fmt.Sprintf("%dM", memSizeMB),
"share": "on", "prealloc": "on",
}
} else {
s.Desc.MemDesc.Mem = desc.NewObject("memory-backend-ram", "mem")
s.Desc.MemDesc.Mem.Options = map[string]string{
"size": fmt.Sprintf("%dM", memSizeMB),
}
}
}
func (s *SKVMGuestInstance) initMemDescFromMemoryInfo(memoryDevicesInfoList []monitor.MemoryDeviceInfo) error {
var objType string
if s.manager.host.IsHugepagesEnabled() {
objType = "memory-backend-file"
} else if s.isMemcleanEnabled() {
objType = "memory-backend-memfd"
} else {
objType = "memory-backend-ram"
func (s *SKVMGuestInstance) defaultMemNodeHasObject(memDevs []monitor.Memdev) bool {
for _, dev := range memDevs {
if dev.ID != nil && *dev.ID == "mem" {
return true
}
}
return false
}
func (s *SKVMGuestInstance) initMemDescFromMemoryInfo(
memoryDevicesInfoList []monitor.MemoryDeviceInfo, memDevs []monitor.Memdev,
) error {
memSize := s.Desc.Mem
memSlots := make([]*desc.SMemSlot, 0)
for i := 0; i < len(memoryDevicesInfoList); i++ {
@@ -857,7 +878,7 @@ func (s *SKVMGuestInstance) initMemDescFromMemoryInfo(memoryDevicesInfoList []mo
memSize -= (memoryDevicesInfoList[i].Data.Size / 1024 / 1024)
memSlots = append(memSlots, &desc.SMemSlot{
SizeMB: memoryDevicesInfoList[i].Data.Size / 1024 / 1024,
MemObj: desc.NewObject(objType, path.Base(memoryDevicesInfoList[i].Data.Memdev)),
MemObj: desc.NewObject(s.memObjectType(), path.Base(memoryDevicesInfoList[i].Data.Memdev)),
MemDev: &desc.SMemDevice{
Type: "pc-dimm", Id: *memoryDevicesInfoList[i].Data.ID,
},
@@ -866,7 +887,11 @@ func (s *SKVMGuestInstance) initMemDescFromMemoryInfo(memoryDevicesInfoList []mo
if memSize <= 0 {
return errors.Errorf("wrong memsize %d", s.Desc.Mem)
}
s.initMemDesc(memSize)
s.Desc.MemDesc = s.archMan.GenerateMemDesc()
s.Desc.MemDesc.SizeMB = memSize
if s.defaultMemNodeHasObject(memDevs) {
s.initDefaultMemObject(memSize)
}
s.Desc.MemDesc.MemSlots = memSlots
return nil
}
+13 -3
View File
@@ -145,8 +145,10 @@ func generateMemoryOption(memDesc *desc.SGuestMem) string {
"-m %dM,slots=%d,maxmem=%dM",
memDesc.SizeMB, memDesc.Slots, memDesc.MaxMem,
))
cmds = append(cmds, generateObjectOption(memDesc.Mem))
cmds = append(cmds, generateNumaOption(memDesc.Mem.Id))
if memDesc.Mem != nil {
cmds = append(cmds, generateObjectOption(memDesc.Mem))
cmds = append(cmds, generateNumaOption(memDesc.Mem.Id))
}
for i := 0; i < len(memDesc.MemSlots); i++ {
memDev := memDesc.MemSlots[i].MemDev
memObj := memDesc.MemSlots[i].MemObj
@@ -202,6 +204,14 @@ func getMonitorOptions(drvOpt QemuOptions, input *Monitor) []string {
return opts
}
func generateScsiOptions(scsi *desc.SGuestVirtioScsi) string {
opt := generatePCIDeviceOption(scsi.PCIDevice)
if scsi.NumQueues != nil && *scsi.NumQueues > 0 {
opt += fmt.Sprintf(",num_queues=%d,vectors=%d", *scsi.NumQueues, *scsi.NumQueues+1)
}
return opt
}
func generateDisksOptions(drvOpt QemuOptions, disks []*desc.SGuestDisk, isEncrypt, isSlave, isMaster bool) []string {
opts := make([]string, 0)
for _, disk := range disks {
@@ -712,7 +722,7 @@ func GenerateStartOptions(
opts = append(opts, generatePciControllerOptions(input.GuestDesc.PCIControllers)...)
if input.GuestDesc.VirtioScsi != nil {
opts = append(opts, generatePCIDeviceOption(input.GuestDesc.VirtioScsi.PCIDevice))
opts = append(opts, generateScsiOptions(input.GuestDesc.VirtioScsi))
} else if input.GuestDesc.PvScsi != nil {
opts = append(opts, generatePCIDeviceOption(input.GuestDesc.PvScsi.PCIDevice))
}
+10 -2
View File
@@ -19,6 +19,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
@@ -167,7 +168,15 @@ func GuestnetworksDescToDeployDesc(guestnetworks []*desc.SGuestNetwork) []*Nic {
return nics
}
func GuestDescToDeployDesc(guestDesc *desc.SGuestDesc) *GuestDesc {
func GuestJsonDescToDeployDesc(guestDesc *jsonutils.JSONDict) (*GuestDesc, error) {
ret := new(GuestDesc)
if err := guestDesc.Unmarshal(ret); err != nil {
return nil, errors.Wrap(err, "GuestJsonDescToDeployDesc unmarshal")
}
return ret, nil
}
func GuestStructDescToDeployDesc(guestDesc *desc.SGuestDesc) *GuestDesc {
ret := new(GuestDesc)
ret.Name = guestDesc.Name
@@ -176,7 +185,6 @@ func GuestDescToDeployDesc(guestDesc *desc.SGuestDesc) *GuestDesc {
ret.Hostname = guestDesc.Hostname
ret.Nics = GuestnetworksDescToDeployDesc(guestDesc.Nics)
ret.Disks = GuestdisksDescToDeployDesc(guestDesc.Disks)
ret.NicsStandby = GuestnetworksDescToDeployDesc(guestDesc.NicsStandby)
return ret
}
+41 -1
View File
@@ -20,6 +20,7 @@ import (
"fmt"
"io"
"regexp"
"strconv"
"strings"
"time"
@@ -489,7 +490,11 @@ func (m *HmpMonitor) GeMemtSlotIndex(callback func(index int)) {
}
func (m *HmpMonitor) GetMemoryDevicesInfo(cb QueryMemoryDevicesCallback) {
go cb(nil, "not supported")
go cb(nil, "hmp unsupport get memory devices info")
}
func (m *HmpMonitor) GetMemdevList(callback MemdevListCallback) {
go callback(nil, "hmp unsupport get memdev list")
}
func (m *HmpMonitor) ObjectAdd(objectType string, params map[string]string, callback StringCallback) {
@@ -544,3 +549,38 @@ func (m *HmpMonitor) QueryMachines(callback QueryMachinesCallback) {
func (m *HmpMonitor) Quit(cb StringCallback) {
m.Query("quit", cb)
}
func getScsiNumQueues(output string) int64 {
var lines = strings.Split(strings.TrimSuffix(output, "\r\n"), "\r\n")
for i, line := range lines {
line := strings.TrimSpace(line)
if strings.HasPrefix(line, "dev: virtio-scsi-device") {
if len(lines) <= i+1 {
log.Errorf("failed parse num queues")
return -1
}
line = strings.TrimSpace(lines[i+1])
segs := strings.Split(line, " ")
numQueue, err := strconv.ParseInt(segs[2], 10, 0)
if err != nil {
log.Errorf("failed parse num queue %s", err)
return -1
} else {
return numQueue
}
}
}
return -1
}
func (m *HmpMonitor) GetScsiNumQueues(callback func(int64)) {
cb := func(output string) {
numQueues := getScsiNumQueues(output)
callback(numQueues)
}
m.Query("info qtree", cb)
}
func (m *HmpMonitor) GetHotPluggableCpus(callback HotpluggableCPUListCallback) {
go callback(nil, "unsupported get hotpluggable cpu list for hmp")
}
+3
View File
@@ -200,11 +200,14 @@ type Monitor interface {
GetBlockJobCounts(func(jobs int))
GetBlockJobs(func([]BlockJob))
QueryPci(callback QueryPciCallback)
GetScsiNumQueues(callback func(int64))
GetCpuCount(func(count int))
AddCpu(cpuIndex int, callback StringCallback)
GetHotPluggableCpus(HotpluggableCPUListCallback)
GeMemtSlotIndex(func(index int))
GetMemoryDevicesInfo(QueryMemoryDevicesCallback)
GetMemdevList(MemdevListCallback)
GetBlocks(callback func([]QemuBlock))
EjectCdrom(dev string, callback StringCallback)
+37
View File
@@ -123,3 +123,40 @@ type MachineInfo struct {
}
type QueryMachinesCallback func(machineInfoList []MachineInfo, err string)
// Memdev -> Memdev (struct)
// Memdev implements the "Memdev" QMP API type.
type Memdev struct {
ID *string `json:"id,omitempty"`
Size uint64 `json:"size"`
Merge bool `json:"merge"`
Dump bool `json:"dump"`
Prealloc bool `json:"prealloc"`
HostNodes []uint16 `json:"host-nodes"`
Policy string `json:"policy"`
}
type MemdevListCallback func(res []Memdev, err string)
// CpuInstanceProperties -> CPUInstanceProperties (struct)
// CPUInstanceProperties implements the "CpuInstanceProperties" QMP API type.
type CPUInstanceProperties struct {
NodeID *int64 `json:"node-id,omitempty"`
SocketID *int64 `json:"socket-id,omitempty"`
CoreID *int64 `json:"core-id,omitempty"`
ThreadID *int64 `json:"thread-id,omitempty"`
}
// HotpluggableCPU -> HotpluggableCPU (struct)
// HotpluggableCPU implements the "HotpluggableCPU" QMP API type.
type HotpluggableCPU struct {
Type string `json:"type"`
VcpusCount int64 `json:"vcpus-count"`
Props CPUInstanceProperties `json:"props"`
QomPath *string `json:"qom-path,omitempty"`
}
type HotpluggableCPUListCallback func(res []HotpluggableCPU, err string)
+77
View File
@@ -21,6 +21,7 @@ import (
"io"
"regexp"
"runtime/debug"
"strconv"
"strings"
"time"
@@ -1046,6 +1047,29 @@ func (m *QmpMonitor) GetMemoryDevicesInfo(callback QueryMemoryDevicesCallback) {
m.Query(cmd, cb)
}
func (m *QmpMonitor) GetMemdevList(callback MemdevListCallback) {
var (
cb = func(res *Response) {
if res.ErrorVal != nil {
callback(nil, res.ErrorVal.Error())
} else {
memdevList := make([]Memdev, 0)
err := json.Unmarshal(res.Return, &memdevList)
if err != nil {
callback(nil, err.Error())
} else {
callback(memdevList, "")
}
}
}
cmd = &Command{
Execute: "query-memdev",
}
)
m.Query(cmd, cb)
}
func (m *QmpMonitor) BlockIoThrottle(driveName string, bps, iops int64, callback StringCallback) {
cmd := fmt.Sprintf("block_set_io_throttle %s %d 0 0 %d 0 0", driveName, bps, iops)
m.HumanMonitorCommand(cmd, callback)
@@ -1178,3 +1202,56 @@ func (m *QmpMonitor) Quit(callback StringCallback) {
)
m.Query(cmd, cb)
}
func getScsiNumQueuesQmp(output string) int64 {
var lines = strings.Split(strings.TrimSuffix(output, "\r\n"), "\\r\\n")
for i, line := range lines {
line := strings.TrimSpace(line)
if strings.HasPrefix(line, "dev: virtio-scsi-device") {
if len(lines) <= i+1 {
log.Errorf("failed parse num queues")
return -1
}
line = strings.TrimSpace(lines[i+1])
segs := strings.Split(line, " ")
numQueue, err := strconv.ParseInt(segs[2], 10, 0)
if err != nil {
log.Errorf("failed parse num queue %s", err)
return -1
} else {
return numQueue
}
}
}
return -1
}
func (m *QmpMonitor) GetScsiNumQueues(callback func(int64)) {
cb := func(output string) {
numQueues := getScsiNumQueuesQmp(output)
callback(numQueues)
}
m.HumanMonitorCommand("info qtree", cb)
}
func (m *QmpMonitor) GetHotPluggableCpus(callback HotpluggableCPUListCallback) {
var (
cb = func(res *Response) {
if res.ErrorVal != nil {
callback(nil, res.ErrorVal.Error())
} else {
cpuList := make([]HotpluggableCPU, 0)
err := json.Unmarshal(res.Return, &cpuList)
if err != nil {
callback(nil, err.Error())
} else {
callback(cpuList, "")
}
}
}
cmd = &Command{
Execute: "query-hotpluggable-cpus",
}
)
m.Query(cmd, cb)
}
+1 -1
View File
@@ -137,7 +137,7 @@ func (d *SBaseDisk) GetZoneId() string {
func (d *SBaseDisk) DeployGuestFs(diskInfo *deployapi.DiskInfo, guestDesc *desc.SGuestDesc,
deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error) {
deployGuestDesc := deployapi.GuestDescToDeployDesc(guestDesc)
deployGuestDesc := deployapi.GuestStructDescToDeployDesc(guestDesc)
ret, err := deployclient.GetDeployClient().DeployGuestFs(
context.Background(), &deployapi.DeployParams{
DiskInfo: diskInfo,