fix(xen-api): correct $type for records from event

XenApi event system returns lowercased types which things difficult, for
instance, `Record#set_name_label` methods did not work for some VM
because the lib called `vm.set_name_label` instead of
`VM.set_name_label`.

To work-around this problem, a map of types from lowercased is
constructed at connection.
This commit is contained in:
Julien Fontanet 2019-02-24 14:40:30 +01:00
parent 685355c6fb
commit 12a7000e36

View File

@ -7,7 +7,6 @@ import { BaseError } from 'make-error'
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import { fibonacci } from 'iterable-backoff' import { fibonacci } from 'iterable-backoff'
import { import {
filter,
forEach, forEach,
isArray, isArray,
isInteger, isInteger,
@ -403,42 +402,55 @@ export class Xapi extends EventEmitter {
) )
} }
connect() { async connect() {
const { status } = this const { status } = this
if (status === CONNECTED) { if (status === CONNECTED) {
return Promise.reject(new Error('already connected')) throw new Error('already connected')
} }
if (status === CONNECTING) { if (status === CONNECTING) {
return Promise.reject(new Error('already connecting')) throw new Error('already connecting')
} }
const auth = this._auth const auth = this._auth
if (auth === undefined) { if (auth === undefined) {
return Promise.reject(new Error('missing credentials')) throw new Error('missing credentials')
} }
this._sessionId = CONNECTING this._sessionId = CONNECTING
return this._transportCall('session.login_with_password', [ try {
const [methods, sessionId] = await Promise.all([
this._transportCall('system.listMethods'),
this._transportCall('session.login_with_password', [
auth.user, auth.user,
auth.password, auth.password,
]).then( ]),
async sessionId => { ])
// Uses introspection to list available types.
const types = (this._types = methods
.filter(isGetAllRecordsMethod)
.map(method => method.slice(0, method.indexOf('.'))))
this._lcToTypes = { __proto__: null }
types.forEach(type => {
const lcType = type.toLowerCase()
if (lcType !== type) {
this._lcToTypes[lcType] = type
}
})
this._sessionId = sessionId this._sessionId = sessionId
this._pool = (await this.getAllRecords('pool'))[0] this._pool = (await this.getAllRecords('pool'))[0]
debug('%s: connected', this._humanId) debug('%s: connected', this._humanId)
this.emit(CONNECTED) this.emit(CONNECTED)
}, } catch (error) {
error => {
this._sessionId = null this._sessionId = null
throw error throw error
} }
)
} }
disconnect() { disconnect() {
@ -911,7 +923,12 @@ export class Xapi extends EventEmitter {
_processEvents(events) { _processEvents(events) {
forEach(events, event => { forEach(events, event => {
const { class: type, ref } = event let type = event.class
const lcToTypes = this._lcToTypes
if (type in lcToTypes) {
type = lcToTypes[type]
}
const { ref } = event
if (event.operation === 'del') { if (event.operation === 'del') {
this._removeObject(type, ref) this._removeObject(type, ref)
} else { } else {
@ -996,17 +1013,11 @@ export class Xapi extends EventEmitter {
// //
// It also has to manually get all objects first. // It also has to manually get all objects first.
_watchEventsLegacy() { _watchEventsLegacy() {
const getAllObjects = () => { const getAllObjects = async () => {
return this._sessionCall('system.listMethods').then(methods => {
// Uses introspection to determine the methods to use to get
// all objects.
const getAllRecordsMethods = filter(methods, isGetAllRecordsMethod)
return Promise.all( return Promise.all(
map(getAllRecordsMethods, method => this._types.map(type =>
this._sessionCall(method).then( this._sessionCall(`${type}.get_all_records`).then(
objects => { objects => {
const type = method.slice(0, method.indexOf('.')).toLowerCase()
forEach(objects, (object, ref) => { forEach(objects, (object, ref) => {
this._addObject(type, ref, object) this._addObject(type, ref, object)
}) })
@ -1019,7 +1030,6 @@ export class Xapi extends EventEmitter {
) )
) )
) )
})
} }
const watchEvents = () => const watchEvents = () =>