Skip to content

Commit b52dfef

Browse files
authored
Merge pull request #1775 from stgraber/main
Handle live migration between QEMU versions
2 parents bb7316b + 2a9a0fd commit b52dfef

File tree

6 files changed

+76
-3
lines changed

6 files changed

+76
-3
lines changed

doc/config_options.txt

+6
Original file line numberDiff line numberDiff line change
@@ -1458,6 +1458,12 @@ The instance generation UUID changes whenever the instance's place in time moves
14581458
It is globally unique across all servers and projects.
14591459
```
14601460

1461+
```{config:option} volatile.vm.definition instance-volatile
1462+
:shortdesc: "QEMU VM definition name (used for migration between versions)"
1463+
:type: "string"
1464+
1465+
```
1466+
14611467
```{config:option} volatile.vsock_id instance-volatile
14621468
:shortdesc: "Instance `vsock ID` used as of last start"
14631469
:type: "string"

internal/instance/config.go

+7
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,13 @@ var InstanceConfigKeysVM = map[string]func(value string) error{
10891089
// shortdesc: Whether to regenerate VM NVRAM the next time the instance starts
10901090
"volatile.apply_nvram": validate.Optional(validate.IsBool),
10911091

1092+
// gendoc:generate(entity=instance, group=volatile, key=volatile.vm.definition)
1093+
//
1094+
// ---
1095+
// type: string
1096+
// shortdesc: QEMU VM definition name (used for migration between versions)
1097+
"volatile.vm.definition": validate.Optional(validate.IsAny),
1098+
10921099
// gendoc:generate(entity=instance, group=volatile, key=volatile.vsock_id)
10931100
//
10941101
// ---

internal/server/instance/drivers/driver_qemu.go

+26-3
Original file line numberDiff line numberDiff line change
@@ -1572,8 +1572,14 @@ func (d *qemu) start(stateful bool, op *operationlock.InstanceOperation) error {
15721572
cpuType += "," + strings.Join(cpuExtensions, ",")
15731573
}
15741574

1575+
// Provide machine definition when restoring state.
1576+
var machineDefinition string
1577+
if stateful {
1578+
machineDefinition = d.localConfig["volatile.vm.definition"]
1579+
}
1580+
15751581
// Generate the QEMU configuration.
1576-
monHooks, err := d.generateQemuConfig(cpuInfo, mountInfo, qemuBus, vsockFD, devConfs, &fdFiles)
1582+
monHooks, err := d.generateQemuConfig(machineDefinition, cpuInfo, mountInfo, qemuBus, vsockFD, devConfs, &fdFiles)
15771583
if err != nil {
15781584
op.Done(err)
15791585
return err
@@ -1824,6 +1830,23 @@ func (d *qemu) start(stateful bool, op *operationlock.InstanceOperation) error {
18241830
return err
18251831
}
18261832

1833+
// Record the QEMU machine definition.
1834+
if !stateful {
1835+
definition, err := monitor.MachineDefinition()
1836+
if err != nil {
1837+
op.Done(err)
1838+
return err
1839+
}
1840+
1841+
err = d.VolatileSet(map[string]string{
1842+
"volatile.vm.definition": definition,
1843+
})
1844+
if err != nil {
1845+
op.Done(err)
1846+
return err
1847+
}
1848+
}
1849+
18271850
// Don't allow the monitor to trigger a disconnection shutdown event until cleanly started so that the
18281851
// onStop hook isn't triggered prematurely (as this function's reverter will clean up on failure to start).
18291852
monitor.SetOnDisconnectEvent(false)
@@ -3351,11 +3374,11 @@ func (d *qemu) isWindows() bool {
33513374
}
33523375

33533376
// generateQemuConfig generates the QEMU configuration.
3354-
func (d *qemu) generateQemuConfig(cpuInfo *cpuTopology, mountInfo *storagePools.MountInfo, busName string, vsockFD int, devConfs []*deviceConfig.RunConfig, fdFiles *[]*os.File) ([]monitorHook, error) {
3377+
func (d *qemu) generateQemuConfig(machineDefinition string, cpuInfo *cpuTopology, mountInfo *storagePools.MountInfo, busName string, vsockFD int, devConfs []*deviceConfig.RunConfig, fdFiles *[]*os.File) ([]monitorHook, error) {
33553378
var monHooks []monitorHook
33563379

33573380
isWindows := d.isWindows()
3358-
conf := qemuBase(&qemuBaseOpts{d.Architecture(), util.IsTrue(d.expandedConfig["security.iommu"])})
3381+
conf := qemuBase(&qemuBaseOpts{d.Architecture(), util.IsTrue(d.expandedConfig["security.iommu"]), machineDefinition})
33593382

33603383
err := d.addCPUMemoryConfig(&conf, cpuInfo)
33613384
if err != nil {

internal/server/instance/drivers/driver_qemu_templates.go

+5
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ func qemuMachineType(architecture int) string {
5252
type qemuBaseOpts struct {
5353
architecture int
5454
iommu bool
55+
definition string
5556
}
5657

5758
func qemuBase(opts *qemuBaseOpts) []cfg.Section {
@@ -66,6 +67,10 @@ func qemuBase(opts *qemuBaseOpts) []cfg.Section {
6667
capLargeDecr = "off"
6768
}
6869

70+
if opts.definition != "" {
71+
machineType = opts.definition
72+
}
73+
6974
sections := []cfg.Section{{
7075
Name: "machine",
7176
Comment: "Machine",

internal/server/instance/drivers/qmp/commands.go

+25
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,31 @@ func (m *Monitor) Status() (string, error) {
144144
return resp.Return.Status, nil
145145
}
146146

147+
// MachineDefinition returns the current QEMU machine definition name.
148+
func (m *Monitor) MachineDefinition() (string, error) {
149+
// Prepare the request.
150+
var req struct {
151+
Path string `json:"path"`
152+
Property string `json:"property"`
153+
}
154+
155+
req.Path = "/machine"
156+
req.Property = "type"
157+
158+
// Prepare the response.
159+
var resp struct {
160+
Return string `json:"return"`
161+
}
162+
163+
// Query the machine.
164+
err := m.Run("qom-get", req, &resp)
165+
if err != nil {
166+
return "", err
167+
}
168+
169+
return strings.TrimSuffix(resp.Return, "-machine"), nil
170+
}
171+
147172
// SendFile adds a new file descriptor to the QMP fd table associated to name.
148173
func (m *Monitor) SendFile(name string, file *os.File) error {
149174
// Check if disconnected.

internal/server/metadata/configuration.json

+7
Original file line numberDiff line numberDiff line change
@@ -1589,6 +1589,13 @@
15891589
"type": "string"
15901590
}
15911591
},
1592+
{
1593+
"volatile.vm.definition": {
1594+
"longdesc": "",
1595+
"shortdesc": "QEMU VM definition name (used for migration between versions)",
1596+
"type": "string"
1597+
}
1598+
},
15921599
{
15931600
"volatile.vsock_id": {
15941601
"longdesc": "",

0 commit comments

Comments
 (0)