mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 02:37:24 +08:00
fix(region,host): migrate use source desc file. (#15623)
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user