Skip to content

Commit

Permalink
implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
julien-f committed Sep 23, 2022
1 parent 6d91a44 commit ab8e65b
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 0 deletions.
File renamed without changes.
4 changes: 4 additions & 0 deletions @xen-orchestra/xapi/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ class Xapi extends Base {
constructor({
callRetryWhenTooManyPendingTasks = { delay: 5e3, tries: 10 },
maxUncoalescedVdis,
syncHookSecret,
syncHookTimeout,
vdiDestroyRetryWhenInUse = { delay: 5e3, tries: 10 },
...opts
}) {
Expand All @@ -112,6 +114,8 @@ class Xapi extends Base {
when: { code: 'TOO_MANY_PENDING_TASKS' },
}
this._maxUncoalescedVdis = maxUncoalescedVdis
this._syncHookSecret = syncHookSecret
this._syncHookTimeout = syncHookTimeout
this._vdiDestroyRetryWhenInUse = {
...vdiDestroyRetryWhenInUse,
onRetry,
Expand Down
1 change: 1 addition & 0 deletions @xen-orchestra/xapi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@xen-orchestra/log": "^0.3.0",
"d3-time-format": "^3.0.0",
"golike-defer": "^0.5.1",
"http-request-plus": "^0.14.0",
"json-rpc-protocol": "^0.13.2",
"lodash": "^4.17.15",
"promise-toolbox": "^0.21.0",
Expand Down
79 changes: 79 additions & 0 deletions @xen-orchestra/xapi/vm.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const CancelToken = require('promise-toolbox/CancelToken')
const groupBy = require('lodash/groupBy.js')
const hrp = require('http-request-plus')
const ignoreErrors = require('promise-toolbox/ignoreErrors')
const pickBy = require('lodash/pickBy.js')
const omit = require('lodash/omit.js')
Expand Down Expand Up @@ -46,6 +47,37 @@ const cleanBiosStrings = biosStrings => {
}
}

// See: https://github.com/xapi-project/xen-api/blob/324bc6ee6664dd915c0bbe57185f1d6243d9ed7e/ocaml/xapi/xapi_guest_agent.ml#L59-L81
//
// Returns <min(n)>/ip || <min(n)>/ipv4/<min(m)> || <min(n)>/ipv6/<min(m)> || undefined
// where n corresponds to the network interface and m to its IP
const IPV4_KEY_RE = /^\d+\/ip(?:v4\/\d+)?$/
const IPV6_KEY_RE = /^\d+\/ipv6\/\d+$/
function getVmAddress(networks) {
if (networks !== undefined) {
let ipv6
for (const key of Object.keys(networks).sort()) {
if (IPV4_KEY_RE.test(key)) {
return networks[key]
}

if (ipv6 === undefined && IPV6_KEY_RE.test(key)) {
ipv6 = networks[key]
}
}
if (ipv6 !== undefined) {
return ipv6
}
}
throw new Error('no VM address found')
}

function stripPrefix(string, prefix) {
if (string.startsWith(prefix)) {
return string.slice(prefix.length)
}
}

async function listNobakVbds(xapi, vbdRefs) {
const vbds = []
await asyncMap(vbdRefs, async vbdRef => {
Expand Down Expand Up @@ -132,6 +164,43 @@ class Vm {
}
}

async _httpHook({ guest_metrics, tags, uuid }, pathname) {
let url
let i = tags.length
do {
if (i === 0) {
return
}
const tag = tags[--i]
if (tag === 'xo:notify-on-snapshot') {
const { networks } = await this.getRecord('VM_guest_metrics', guest_metrics)
url = Object.assign(new URL('https://locahost'), {
hostname: getVmAddress(networks),
port: 1727,
})
} else {
url = new URL(stripPrefix(tag, 'xo:notify-on-snapshot='))
}
} while (url === undefined)

url.pathname = pathname

const headers = {}
const secret = this._asyncHookSecret
if (secret !== undefined) {
headers.authorization = 'Bearer ' + Buffer.from(secret).toString('base64')
}

try {
await hrp.get(url, {
headers,
timeout: this._syncHookTimeout ?? 60e3,
})
} catch (error) {
warn('HTTP hook failed', { error, url, vm: uuid })
}
}

async assertHealthyVdiChains(vmRef, tolerance = this._maxUncoalescedVdis) {
const vdiRefs = {}
;(await this.getRecords('VBD', await this.getField('VM', vmRef, 'VBDs'))).forEach(({ VDI: ref }) => {
Expand All @@ -148,6 +217,8 @@ class Vm {
async checkpoint($defer, vmRef, { cancelToken = CancelToken.none, ignoreNobakVdis = false, name_label } = {}) {
const vm = await this.getRecord('VM', vmRef)

await this._httpHook(vm, '/sync')

let destroyNobakVdis = false

if (ignoreNobakVdis) {
Expand All @@ -168,6 +239,9 @@ class Vm {
try {
const ref = await this.callAsync(cancelToken, 'VM.checkpoint', vmRef, name_label).then(extractOpaqueRef)

// detached async
this._httpHook(vm, '/post-sync').catch(noop)

// VM checkpoints are marked as templates, unfortunately it does not play well with XVA export/import
// which will import them as templates and not VM checkpoints or plain VMs
await pCatch.call(
Expand Down Expand Up @@ -544,6 +618,8 @@ class Vm {
) {
const vm = await this.getRecord('VM', vmRef)

await this._httpHook(vm, '/sync')

const isHalted = vm.power_state === 'Halted'

// requires the VM to be halted because it's not possible to re-plug VUSB on a live VM
Expand Down Expand Up @@ -646,6 +722,9 @@ class Vm {
ref = await this.callAsync(cancelToken, 'VM.snapshot', vmRef, name_label).then(extractOpaqueRef)
} while (false)

// detached async
this._httpHook(vm, '/post-sync').catch(noop)

// VM snapshots are marked as templates, unfortunately it does not play well with XVA export/import
// which will import them as templates and not VM snapshots or plain VMs
await pCatch.call(
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [Backup/Restore file] Implement File level restore for s3 and encrypted backups (PR [#6409](https://github.com/vatesfr/xen-orchestra/pull/6409))
- [Backup] Improve listing speed by updating caches instead of regenerating them on backup creation/deletion (PR [#6411](https://github.com/vatesfr/xen-orchestra/pull/6411))
- [Backup] Add `mergeBlockConcurrency` and `writeBlockConcurrency` to allow tuning of backup resources consumptions (PR [#6416](https://github.com/vatesfr/xen-orchestra/pull/6416))
- [Sync hook] VM can now be notified before being snapshot, please [see the documentation](https://github.com/vatesfr/xen-orchestra/blob/master/@xen-orchestra/xapi/docs/vm-sync-hook.md) (PR [#6423](https://github.com/vatesfr/xen-orchestra/pull/6423))

### Bug fixes

Expand Down Expand Up @@ -40,6 +41,7 @@

- @vates/fuse-vhd major
- @xen-orchestra/backups minor
- @xen-orchestra/xapi minor
- vhd-lib minor
- xo-server-auth-saml patch
- xo-server minor
Expand Down

0 comments on commit ab8e65b

Please sign in to comment.