Skip to content

Commit

Permalink
feat(xo-server/xo-web): ability to block migration
Browse files Browse the repository at this point in the history
  • Loading branch information
stephane-m-dev committed Nov 12, 2024
1 parent 804af1d commit a000106
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/xo-web/src/common/intl/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,7 @@ const messages = {
vmWarmMigrationProcessInfo:
'Warm migration process will first create a copy of the VM on the destination while the source VM is still running, then shutdown the source VM and send the changes that happened during the migration to the destination to minimize downtime.',
backupLabel: 'Backup',
vmAllowMigration: 'Allow migration',

// ----- SR general tab -----
baseCopyTooltip: '{n, number} base cop{n, plural, one {y} other {ies}} ({usage})',
Expand Down
56 changes: 55 additions & 1 deletion packages/xo-web/src/common/xo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,15 @@ connect()

const _signIn = new Promise(resolve => xo.once('authenticated', resolve))

// eslint-disable-next-line n/no-unsupported-features/node-builtins
const _call = new URLSearchParams(window.location.search.slice(1)).has('debug')
? async (method, params) => {
await _signIn
const now = Date.now()
return tap.call(
xo.call(method, params),
result => {
// eslint-disable-next-line no-console
// eslint-disable-next-line no-console, n/no-unsupported-features/node-builtins
console.debug('API call (%d ms)', Date.now() - now, method, params, result)
},
error => {
Expand Down Expand Up @@ -2441,6 +2442,59 @@ export const vmWarmMigration = async vm => {
})
}

export const vmAllowMigration = async vm => {
/*
_call('vm.allowMigration', {
vm: resolveId(vm),
})
*/

const reason = 'VM migration is blocked during backup'
const { pool_migrate, migrate_send } = vm.blockedOperations

// block migration during the backup on the VM itself, not the latest snapshot
async function block() {
// TODO : VM.set({vmId, blocked_operations :{pool_migrate: null, send_migrate, null})
await _call('vm.set', { id: resolveId(vm), blockedOperations: { pool_migrate: reason, migrate_send: reason } })

// _call('vm.set', { id: resolveId(vm), uefiMode: mode }):: tap(() => subscribeSecurebootReadiness.forceRefresh(vm))

// await vm.update_blocked_operations({ pool_migrate: reason, migrate_send: reason })
}

async function unBlock() {
// unblock operations
await _call('vm.set', {
id: resolveId(vm),
blockedOperations: {
migrate_send: migrate_send === undefined || migrate_send === reason ? null : migrate_send,
pool_migrate: pool_migrate === undefined || pool_migrate === reason ? null : pool_migrate,
},
})

// delete the entries if they did not exist previously or if they were
// equal to reason (which happen if a previous backup was interrupted
// before resetting them)
// await vm.update_blocked_operations({
// migrate_send: migrate_send === undefined || migrate_send === reason ? null : migrate_send,
// pool_migrate: pool_migrate === undefined || pool_migrate === reason ? null : pool_migrate,
// })

// 2024-08-19 - Work-around a XAPI bug where allowed_operations are not properly computed when blocked_operations is updated
//
// this is a problem because some clients (e.g. XenCenter) use this field to allow operations.
//
// internal source: https://team.vates.fr/vates/pl/mjmxnce9qfdx587r3qpe4z91ho
// await vm.$call('update_allowed_operations')
}

if (migrate_send === undefined && pool_migrate === undefined) {
await block()
} else {
await unBlock()
}
}

// DISK ---------------------------------------------------------------

export const createDisk = (name, size, sr, { vm, bootable, mode, position }) =>
Expand Down
1 change: 1 addition & 0 deletions packages/xo-web/src/xo-app/jobs/new/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ export default class Jobs extends Component {
'host.stop',
'job.runSequence',
'vm.attachDisk',
'vm.allowMigration',
'vm.clone',
'vm.convertToTemplate',
'vm.copy',
Expand Down
11 changes: 11 additions & 0 deletions packages/xo-web/src/xo-app/vm/tab-advanced.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
vmDetachPcis,
vmSetUefiMode,
vmWarmMigration,
vmAllowMigration,
XEN_DEFAULT_CPU_CAP,
XEN_DEFAULT_CPU_WEIGHT,
XEN_VIDEORAM_VALUES,
Expand Down Expand Up @@ -721,6 +722,7 @@ export default class TabAdvanced extends Component {
vusbs,
} = this.props
const isWarmMigrationAvailable = getXoaPlan().value >= PREMIUM.value
const isMigrationAllowed = vm.blockedOperations?.migrate_send === null
const addVtpmTooltip = this._getDisabledAddVtpmReason()
const deleteVtpmTooltip = this._getDisabledDeleteVtpmReason()
const host = this.props.vmHosts[vm.$container]
Expand Down Expand Up @@ -780,6 +782,15 @@ export default class TabAdvanced extends Component {
labelId='vmWarmMigration'
tooltip={isWarmMigrationAvailable ? undefined : _('availableXoaPremium')}
/>
<TabButton
btnStyle='warning'
disabled={false /* !isMigrationAllowed */}
handler={vmAllowMigration}
handlerParam={vm}
icon='vm-allow-migration'
labelId='vmAllowMigration'
tooltip={isMigrationAllowed ? 'allowed' : 'disallowed'}
/>
</span>
)}
{vm.power_state === 'Halted' && (
Expand Down

0 comments on commit a000106

Please sign in to comment.