mirror of
https://github.com/vatesfr/xen-orchestra.git
synced 2026-09-10 22:14:48 -05:00
chore(backups): use set_memory_limits instead of convoluted code (#10286)
This commit is contained in:
@@ -16,42 +16,15 @@ import { toQcow2Stream } from '@xen-orchestra/qcow2'
|
||||
|
||||
const ensureArray = value => (value === undefined ? [] : Array.isArray(value) ? value : [value])
|
||||
|
||||
const orderedMemoryLimits = ['memory_static_min', 'memory_dynamic_min', 'memory_dynamic_max', 'memory_static_max']
|
||||
|
||||
// The dynamic memory range MUST respect this inequality at any moment: static_min <= dynamic_min <= dynamic_max <= static_max.
|
||||
// We must update these properties in the right order to avoid XAPI error.
|
||||
// The order depends on the values. It can be an increase, a decrease or a mix of both, so any order could be required.
|
||||
// VM.set_memory_limits sets all four fields atomically, so there is no intermediate state for XAPI to reject
|
||||
export async function updateMemoryFields(xapi, targetVm, vmRecord) {
|
||||
const memoryValues = {}
|
||||
for (const key of orderedMemoryLimits) {
|
||||
memoryValues[key] = {
|
||||
currentValue: targetVm[key],
|
||||
newValue: vmRecord[key] ?? targetVm[key],
|
||||
}
|
||||
}
|
||||
const staticMin = vmRecord.memory_static_min ?? targetVm.memory_static_min
|
||||
const staticMax = vmRecord.memory_static_max ?? targetVm.memory_static_max
|
||||
const dynamicMin = vmRecord.memory_dynamic_min ?? targetVm.memory_dynamic_min
|
||||
const dynamicMax = vmRecord.memory_dynamic_max ?? targetVm.memory_dynamic_max
|
||||
|
||||
while (await updateNextMemoryField(xapi, memoryValues, targetVm.$ref)) {
|
||||
/* execute until all memory fields are updated */
|
||||
}
|
||||
}
|
||||
|
||||
// Update one more memory field if needed, then return a boolean describing if a field was updated or if all fields are up to date
|
||||
async function updateNextMemoryField(xapi, memoryValues, vmRef) {
|
||||
for (let i = 0; i < orderedMemoryLimits.length; i++) {
|
||||
const currentField = memoryValues[orderedMemoryLimits[i]]
|
||||
const nextField = i === orderedMemoryLimits.length - 1 ? undefined : memoryValues[orderedMemoryLimits[i + 1]]
|
||||
if (
|
||||
currentField.newValue !== currentField.currentValue &&
|
||||
(nextField === undefined || currentField.newValue <= nextField.currentValue)
|
||||
) {
|
||||
// no need to check that previousField.currentValue <= currentField.newValue, as we can deduce it
|
||||
await xapi.setField('VM', vmRef, orderedMemoryLimits[i], currentField.newValue)
|
||||
await xapi.barrier()
|
||||
currentField.currentValue = currentField.newValue
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
await xapi.call('VM.set_memory_limits', targetVm.$ref, staticMin, staticMax, dynamicMin, dynamicMax)
|
||||
}
|
||||
|
||||
export async function exportIncrementalVm(
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
import { describe, it } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
|
||||
import { updateMemoryFields } from './_incrementalVm.mjs'
|
||||
|
||||
const MOCK_REF = 'mockRef'
|
||||
|
||||
function mockXapiVm(initialMemoryValues) {
|
||||
const res = {
|
||||
...initialMemoryValues,
|
||||
updates: [],
|
||||
barrier: () => {},
|
||||
setField: (type, ref, field, value) => {
|
||||
assert(type === 'VM')
|
||||
assert(ref === MOCK_REF)
|
||||
res.updates.push({ field, value })
|
||||
res[field] = value
|
||||
assert(res.memory_static_min <= res.memory_dynamic_min)
|
||||
assert(res.memory_dynamic_min <= res.memory_dynamic_max)
|
||||
assert(res.memory_dynamic_max <= res.memory_static_max)
|
||||
},
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
const tests = [
|
||||
{
|
||||
label: 'handles a memory increase',
|
||||
targetVm: {
|
||||
memory_static_min: 2,
|
||||
memory_dynamic_min: 4,
|
||||
memory_dynamic_max: 4,
|
||||
memory_static_max: 8,
|
||||
},
|
||||
vmRecord: {
|
||||
memory_static_min: 16,
|
||||
memory_dynamic_min: 16,
|
||||
memory_dynamic_max: 16,
|
||||
memory_static_max: 16,
|
||||
},
|
||||
expectedUpdates: [
|
||||
{ field: 'memory_static_max', value: 16 },
|
||||
{ field: 'memory_dynamic_max', value: 16 },
|
||||
{ field: 'memory_dynamic_min', value: 16 },
|
||||
{ field: 'memory_static_min', value: 16 },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'handles a memory decrease',
|
||||
targetVm: {
|
||||
memory_static_min: 4,
|
||||
memory_dynamic_min: 8,
|
||||
memory_dynamic_max: 16,
|
||||
memory_static_max: 16,
|
||||
},
|
||||
vmRecord: {
|
||||
memory_static_min: 2,
|
||||
memory_dynamic_min: 2,
|
||||
memory_dynamic_max: 2,
|
||||
memory_static_max: 2,
|
||||
},
|
||||
expectedUpdates: [
|
||||
{ field: 'memory_static_min', value: 2 },
|
||||
{ field: 'memory_dynamic_min', value: 2 },
|
||||
{ field: 'memory_dynamic_max', value: 2 },
|
||||
{ field: 'memory_static_max', value: 2 },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'handles a more complex case',
|
||||
targetVm: {
|
||||
memory_static_min: 1,
|
||||
memory_dynamic_min: 2,
|
||||
memory_dynamic_max: 8,
|
||||
memory_static_max: 16,
|
||||
},
|
||||
vmRecord: {
|
||||
memory_static_min: 4,
|
||||
memory_dynamic_min: 4,
|
||||
memory_dynamic_max: 4,
|
||||
memory_static_max: 4,
|
||||
},
|
||||
expectedUpdates: [
|
||||
{ field: 'memory_dynamic_min', value: 4 },
|
||||
{ field: 'memory_static_min', value: 4 },
|
||||
{ field: 'memory_dynamic_max', value: 4 },
|
||||
{ field: 'memory_static_max', value: 4 },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'avoids updating identical value',
|
||||
targetVm: {
|
||||
memory_static_min: 1,
|
||||
memory_dynamic_min: 2,
|
||||
memory_dynamic_max: 4,
|
||||
memory_static_max: 8,
|
||||
},
|
||||
vmRecord: {
|
||||
memory_static_min: 1,
|
||||
memory_dynamic_min: 2,
|
||||
memory_dynamic_max: 4,
|
||||
memory_static_max: 8,
|
||||
},
|
||||
expectedUpdates: [],
|
||||
},
|
||||
]
|
||||
|
||||
describe('updateMemoryFields() should update in the right order', () => {
|
||||
for (const test of tests) {
|
||||
it(test.label, async () => {
|
||||
const mock = mockXapiVm(test.targetVm)
|
||||
test.targetVm.$ref = MOCK_REF
|
||||
await updateMemoryFields(mock, test.targetVm, test.vmRecord)
|
||||
|
||||
assert.equal(mock.updates.length, test.expectedUpdates.length)
|
||||
for (let i = 0; i < mock.updates.length; i++) {
|
||||
assert.equal(mock.updates[i].value, test.expectedUpdates[i].value)
|
||||
assert.equal(mock.updates[i].field, test.expectedUpdates[i].field)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -59,6 +59,7 @@
|
||||
- @vates/types patch
|
||||
- @xen-orchestra/acl minor
|
||||
- @xen-orchestra/async-map patch
|
||||
- @xen-orchestra/backups patch
|
||||
- @xen-orchestra/proxy-cli patch
|
||||
- @xen-orchestra/rest-api minor
|
||||
- @xen-orchestra/upload-ova patch
|
||||
|
||||
Reference in New Issue
Block a user