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 {
auth.user, const [methods, sessionId] = await Promise.all([
auth.password, this._transportCall('system.listMethods'),
]).then( this._transportCall('session.login_with_password', [
async sessionId => { auth.user,
this._sessionId = sessionId auth.password,
this._pool = (await this.getAllRecords('pool'))[0] ]),
])
debug('%s: connected', this._humanId) // 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.emit(CONNECTED) this._sessionId = sessionId
}, this._pool = (await this.getAllRecords('pool'))[0]
error => {
this._sessionId = null
throw error debug('%s: connected', this._humanId)
} this.emit(CONNECTED)
) } catch (error) {
this._sessionId = null
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,30 +1013,23 @@ 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 => { return Promise.all(
// Uses introspection to determine the methods to use to get this._types.map(type =>
// all objects. this._sessionCall(`${type}.get_all_records`).then(
const getAllRecordsMethods = filter(methods, isGetAllRecordsMethod) objects => {
forEach(objects, (object, ref) => {
return Promise.all( this._addObject(type, ref, object)
map(getAllRecordsMethods, method => })
this._sessionCall(method).then( },
objects => { error => {
const type = method.slice(0, method.indexOf('.')).toLowerCase() if (error.code !== 'MESSAGE_REMOVED') {
forEach(objects, (object, ref) => { throw error
this._addObject(type, ref, object)
})
},
error => {
if (error.code !== 'MESSAGE_REMOVED') {
throw error
}
} }
) }
) )
) )
}) )
} }
const watchEvents = () => const watchEvents = () =>