mirror of
https://github.com/vatesfr/xen-orchestra.git
synced 2026-11-09 17:06:13 -06:00
This branch is a reliability overhaul of the ESXi/vSphere source side of V2V, plus a scope reduction of the package. The SOAP plumbing is rewritten:
VimClient wraps @vates/node-vsphere-soap in a promise API with one emitter per call (no more cross-talk between concurrent calls, no listener leak) and a pTimeout;
vim25 faults are now parsed (_parseFault.mjs) so callers get a real fault type instead of task execution failed;
the library no longer throws from async callbacks (which killed xo-server) and its beforeExit logout hook is per-client instead of removeAllListeners.
Request specs are built in explicit schema order (soap/specs.mjs) with xsi:type, and property values are normalized (soap/normalize.mjs) so search() and the new #retrieveProperty share one shape.
search() now paginates, cancels the retrieval and destroys the container view.
Datastore HTTP downloads get session-cookie reuse, retry with jittered backoff, a headers-only timeout, and range-honouring validation.
Task waiting polls with backoff and per-operation timeouts (6 h for snapshot consolidation).
nbdkit servers are memoized by a key that includes the export options, the readiness wait races the process death instead of sleeping 2 s
the password file is 0600 and unlinked
the thumbprint is read over TLS in-process instead of two openssl spawns.
The old VHD-over-datastore readers (VhdEsxi*, Datastore*, openDeltaVmdkAsVhd) are deleted, hence the majo, rleaving the vddk/NBD path with a COWD grain-directory parser as data-map fallback.
~1.7k lines of unit tests are added.
90 lines
2.8 KiB
JavaScript
90 lines
2.8 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { describe, it } from 'node:test'
|
|
|
|
import {
|
|
moRef,
|
|
objectSpec,
|
|
orderedChildren,
|
|
propertyFilterSpec,
|
|
propertySpec,
|
|
retrieveOptions,
|
|
traversalSpec,
|
|
} from './specs.mjs'
|
|
|
|
describe('moRef', function () {
|
|
it('carries the type of the object', function () {
|
|
assert.deepEqual(moRef('VirtualMachine', 'vm-42'), { attributes: { type: 'VirtualMachine' }, $value: 'vm-42' })
|
|
})
|
|
})
|
|
|
|
describe('orderedChildren', function () {
|
|
const ORDER = Object.freeze(['first', 'second', 'third'])
|
|
|
|
it('emits the keys in schema order, whatever the order they are given in', function () {
|
|
const node = orderedChildren(ORDER, 'SomeType', { third: 3, first: 1 })
|
|
|
|
// the insertion order of the keys is what the library turns into element order
|
|
assert.deepEqual(Object.keys(node), ['attributes', 'first', 'third'])
|
|
assert.deepEqual(node, { attributes: { 'xsi:type': 'SomeType' }, first: 1, third: 3 })
|
|
})
|
|
|
|
it('skips the values which are not set', function () {
|
|
assert.deepEqual(orderedChildren(ORDER, undefined, { first: undefined, second: null, third: 0 }), { third: 0 })
|
|
})
|
|
|
|
it('refuses an unknown element', function () {
|
|
assert.throws(() => orderedChildren(ORDER, 'SomeType', { frist: 1 }), {
|
|
code: 'BAD_VIM25_SPEC',
|
|
message: 'unknown element(s) for this type: frist',
|
|
})
|
|
})
|
|
|
|
it('ignores an unknown element which is not set', function () {
|
|
assert.deepEqual(orderedChildren(ORDER, undefined, { frist: undefined }), {})
|
|
})
|
|
|
|
it('omits the type when there is none to declare', function () {
|
|
assert.deepEqual(Object.keys(orderedChildren(ORDER, undefined, { first: 1 })), ['first'])
|
|
})
|
|
})
|
|
|
|
describe('property collector specs', function () {
|
|
it('builds a PropertySpec', function () {
|
|
assert.deepEqual(propertySpec({ pathSet: ['config'], type: 'VirtualMachine' }), {
|
|
attributes: { 'xsi:type': 'PropertySpec' },
|
|
type: 'VirtualMachine',
|
|
pathSet: ['config'],
|
|
})
|
|
})
|
|
|
|
it('builds an ObjectSpec', function () {
|
|
const spec = objectSpec({ skip: false, obj: moRef('Task', 'task-1') })
|
|
|
|
assert.deepEqual(Object.keys(spec), ['attributes', 'obj', 'skip'])
|
|
assert.equal(spec.skip, false)
|
|
})
|
|
|
|
it('builds a TraversalSpec', function () {
|
|
assert.deepEqual(Object.keys(traversalSpec({ path: 'view', name: 'traverseEntities', type: 'ContainerView' })), [
|
|
'attributes',
|
|
'name',
|
|
'type',
|
|
'path',
|
|
])
|
|
})
|
|
|
|
it('builds a PropertyFilterSpec', function () {
|
|
assert.deepEqual(
|
|
Object.keys(propertyFilterSpec({ objectSet: [objectSpec({ obj: moRef('Task', 'task-1') })], propSet: [] })),
|
|
['attributes', 'propSet', 'objectSet']
|
|
)
|
|
})
|
|
|
|
it('builds RetrieveOptions', function () {
|
|
assert.deepEqual(retrieveOptions({ maxObjects: 100 }), {
|
|
attributes: { 'xsi:type': 'RetrieveOptions' },
|
|
maxObjects: 100,
|
|
})
|
|
})
|
|
})
|