diff --git a/gulpfile.js b/gulpfile.js index 10296d3ef..feec71a8d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -42,6 +42,10 @@ gulp.task(function buildCoffee () { .pipe(coffee({ bare: true })) + + // Necessary to correctly compile generators. + .pipe(babel()) + .pipe(sourceMaps.write('.')) .pipe(gulp.dest(DIST_DIR)) }) diff --git a/package.json b/package.json index db6e058e2..879ae0c43 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "debug": "^2.1.3", "event-to-promise": "^0.3.2", "exec-promise": "^0.5.1", - "fibers": "~1.0.5", "fs-promise": "^0.3.1", "got": "^3.2.0", "graceful-fs": "^3.0.6", diff --git a/src/api/disk.js b/src/api/disk.js index c64897e77..26cea6cd0 100644 --- a/src/api/disk.js +++ b/src/api/disk.js @@ -1,12 +1,11 @@ -import {coroutine, wait} from '../fibers-utils' import {parseSize} from '../utils' // =================================================================== -export const create = coroutine(function ({name, size, sr}) { +export async function create ({name, size, sr}) { const xapi = this.getXAPI(sr) - const ref = wait(xapi.call('VDI.create', { + const ref = await xapi.call('VDI.create', { name_label: name, other_config: {}, read_only: false, @@ -14,10 +13,10 @@ export const create = coroutine(function ({name, size, sr}) { SR: sr.ref, type: 'user', virtual_size: String(parseSize(size)) - })) + }) - return wait(xapi.call('VDI.get_record', ref)).uuid -}) + return (await xapi.call('VDI.get_record', ref)).uuid +} create.description = 'create a new disk on a SR' diff --git a/src/api/host.coffee b/src/api/host.coffee index 76c9d3c86..8e260602a 100644 --- a/src/api/host.coffee +++ b/src/api/host.coffee @@ -1,12 +1,12 @@ -{$coroutine, $wait} = require '../fibers-utils' $debug = (require 'debug') 'xo:api:vm' -$request = require('bluebird').promisify(require('request')) -{parseXml} = require '../utils' -$forEach = require 'lodash.foreach' $find = require 'lodash.find' $findIndex = require 'lodash.findindex' -startsWith = require 'lodash.startswith' +$forEach = require 'lodash.foreach' +$request = require('bluebird').promisify(require('request')) endsWith = require 'lodash.endswith' +startsWith = require 'lodash.startswith' +{coroutine: $coroutine} = require 'bluebird' +{parseXml} = require '../utils' #===================================================================== @@ -21,7 +21,7 @@ set = $coroutine (params) -> } continue unless param of params - $wait xapi.call "host.set_#{field}", host.ref, params[param] + yield xapi.call "host.set_#{field}", host.ref, params[param] return true @@ -48,8 +48,8 @@ exports.set = set restart = $coroutine ({host}) -> xapi = @getXAPI host - $wait xapi.call 'host.disable', host.ref - $wait xapi.call 'host.reboot', host.ref + yield xapi.call 'host.disable', host.ref + yield xapi.call 'host.reboot', host.ref return true @@ -68,7 +68,7 @@ exports.restart = restart restartAgent = $coroutine ({host}) -> xapi = @getXAPI host - $wait xapi.call 'host.restart_agent', host.ref + yield xapi.call 'host.restart_agent', host.ref return true @@ -88,7 +88,7 @@ exports.restart_agent = restartAgent start = $coroutine ({host}) -> xapi = @getXAPI host - $wait xapi.call 'host.power_on', host.ref + yield xapi.call 'host.power_on', host.ref return true @@ -107,8 +107,8 @@ exports.start = start stop = $coroutine ({host}) -> xapi = @getXAPI host - $wait xapi.call 'host.disable', host.ref - $wait xapi.call 'host.shutdown', host.ref + yield xapi.call 'host.disable', host.ref + yield xapi.call 'host.shutdown', host.ref return true @@ -127,7 +127,7 @@ exports.stop = stop detach = $coroutine ({host}) -> xapi = @getXAPI host - $wait xapi.call 'pool.eject', host.ref + yield xapi.call 'pool.eject', host.ref return true @@ -146,7 +146,7 @@ exports.detach = detach enable = $coroutine ({host}) -> xapi = @getXAPI host - $wait xapi.call 'host.enable', host.ref + yield xapi.call 'host.enable', host.ref return true @@ -165,7 +165,7 @@ exports.enable = enable disable = $coroutine ({host}) -> xapi = @getXAPI host - $wait xapi.call 'host.disable', host.ref + yield xapi.call 'host.disable', host.ref return true @@ -186,7 +186,7 @@ createNetwork = $coroutine ({host, name, description, pif, mtu, vlan}) -> description = description ? 'Created with Xen Orchestra' - network_ref = $wait xapi.call 'network.create', { + network_ref = yield xapi.call 'network.create', { name_label: name, name_description: description, MTU: mtu ? '1500' @@ -196,7 +196,7 @@ createNetwork = $coroutine ({host, name, description, pif, mtu, vlan}) -> if pif? vlan = vlan ? '0' pif = @getObject pif, 'PIF' - $wait xapi.call 'pool.create_VLAN_from_PIF', pif.ref, network_ref, vlan + yield xapi.call 'pool.create_VLAN_from_PIF', pif.ref, network_ref, vlan return true @@ -256,7 +256,7 @@ stats = $coroutine ({host}) -> xapi = @getXAPI host - [response, body] = $wait $request { + [response, body] = yield $request { method: 'get' rejectUnauthorized: false url: 'https://'+host.address+'/host_rrd?session_id='+xapi.sessionId diff --git a/src/api/message.coffee b/src/api/message.coffee deleted file mode 100644 index af9f6dfe1..000000000 --- a/src/api/message.coffee +++ /dev/null @@ -1,20 +0,0 @@ -{$coroutine, $wait} = require '../fibers-utils' - -#===================================================================== - -delete_ = $coroutine ({message}) -> - xapi = @getXAPI message - - $wait xapi.call 'message.destroy', message.ref - - return true - -delete_.params = { - id: { type: 'string' }, -} - -delete_.resolve = { - message: ['id', 'message', 'administrate'] -} - -exports.delete = delete_ diff --git a/src/api/message.js b/src/api/message.js new file mode 100644 index 000000000..9f1391dcc --- /dev/null +++ b/src/api/message.js @@ -0,0 +1,12 @@ +async function delete_ ({message}) { + await this.getXAPI(message).call('message.destroy', message.ref) +} +export {delete_ as delete} + +delete_.params = { + id: { type: 'string' } +} + +delete_.resolve = { + message: ['id', 'message', 'administrate'] +} diff --git a/src/api/pbd.coffee b/src/api/pbd.coffee deleted file mode 100644 index df267da4e..000000000 --- a/src/api/pbd.coffee +++ /dev/null @@ -1,54 +0,0 @@ -# FIXME: too low level, should be removed. - -{$coroutine, $wait} = require '../fibers-utils' - -#===================================================================== -# Delete - -exports.delete = $coroutine ({PBD}) -> - xapi = @getXAPI PBD - - # TODO: check if PBD is attached before - $wait xapi.call 'PBD.destroy', PBD.ref - - return true -exports.delete.params = { - id: { type: 'string' } -} -exports.delete.resolve = { - PBD: ['id', 'PBD', 'administrate'] -} - -#===================================================================== -# Disconnect - -exports.disconnect = $coroutine ({PBD}) -> - xapi = @getXAPI PBD - - # TODO: check if PBD is attached before - $wait xapi.call 'PBD.unplug', PBD.ref - - return true -exports.disconnect.params = { - id: { type: 'string' } -} -exports.disconnect.resolve = { - PBD: ['id', 'PBD', 'administrate'] -} - -#===================================================================== -# Connect - -exports.connect = $coroutine ({PBD}) -> - xapi = @getXAPI PBD - - # TODO: check if PBD is attached before - $wait xapi.call 'PBD.plug', PBD.ref - - return true -exports.connect.params = { - id: { type: 'string' } -} -exports.connect.resolve = { - PBD: ['id', 'PBD', 'administrate'] -} diff --git a/src/api/pbd.js b/src/api/pbd.js new file mode 100644 index 000000000..a05b3d214 --- /dev/null +++ b/src/api/pbd.js @@ -0,0 +1,50 @@ +// FIXME: too low level, should be removed. + +// =================================================================== +// Delete + +async function delete_ ({PBD}) { + // TODO: check if PBD is attached before + await this.getXAPI(PBD).call('PBD.destroy', PBD.ref) +} +export {delete_ as delete} + +delete_.params = { + id: { type: 'string' } +} + +delete_.resolve = { + PBD: ['id', 'PBD', 'administrate'] +} + +// =================================================================== +// Disconnect + +export async function disconnect ({PBD}) { + // TODO: check if PBD is attached before + await this.getXAPI(PBD).call('PBD.unplug', PBD.ref) +} + +disconnect.params = { + id: { type: 'string' } +} + +disconnect.resolve = { + PBD: ['id', 'PBD', 'administrate'] +} + +// =================================================================== +// Connect + +export async function connect ({PBD}) { + // TODO: check if PBD is attached before + await this.getXAPI(PBD).call('PBD.plug', PBD.ref) +} + +connect.params = { + id: { type: 'string' } +} + +connect.resolve = { + PBD: ['id', 'PBD', 'administrate'] +} diff --git a/src/api/pif.coffee b/src/api/pif.coffee deleted file mode 100644 index 409d88a4f..000000000 --- a/src/api/pif.coffee +++ /dev/null @@ -1,51 +0,0 @@ -{$coroutine, $wait} = require '../fibers-utils' - -#===================================================================== -# Delete - -exports.delete = $coroutine ({PIF}) -> - xapi = @getXAPI PIF - - # TODO: check if PIF is attached before - $wait xapi.call 'PIF.destroy', PIF.ref - - return true -exports.delete.params = { - id: { type: 'string' } -} -exports.delete.resolve = { - PIF: ['id', 'PIF', 'administrate'] -} - -#===================================================================== -# Disconnect - -exports.disconnect = $coroutine ({PIF}) -> - xapi = @getXAPI PIF - - # TODO: check if PIF is attached before - $wait xapi.call 'PIF.unplug', PIF.ref - - return true -exports.disconnect.params = { - id: { type: 'string' } -} -exports.disconnect.resolve = { - PIF: ['id', 'PIF', 'administrate'] -} -#===================================================================== -# Connect - -exports.connect = $coroutine ({PIF}) -> - xapi = @getXAPI PIF - - # TODO: check if PIF is attached before - $wait xapi.call 'PIF.plug', PIF.ref - - return true -exports.connect.params = { - id: { type: 'string' } -} -exports.connect.resolve = { - PIF: ['id', 'PIF', 'administrate'] -} diff --git a/src/api/pif.js b/src/api/pif.js new file mode 100644 index 000000000..ca2e29c84 --- /dev/null +++ b/src/api/pif.js @@ -0,0 +1,47 @@ +// =================================================================== +// Delete + +async function delete_ ({PIF}) { + // TODO: check if PIF is attached before + await this.getXAPI(PIF).call('PIF.destroy', PIF.ref) +} +export {delete_ as delete} + +delete_.params = { + id: { type: 'string' } +} + +delete_.resolve = { + PIF: ['id', 'PIF', 'administrate'] +} + +// =================================================================== +// Disconnect + +export async function disconnect ({PIF}) { + // TODO: check if PIF is attached before + await this.getXAPI(PIF).call('PIF.unplug', PIF.ref) +} + +disconnect.params = { + id: { type: 'string' } +} + +disconnect.resolve = { + PIF: ['id', 'PIF', 'administrate'] +} +// =================================================================== +// Connect + +export async function connect ({PIF}) { + // TODO: check if PIF is attached before + await this.getXAPI(PIF).call('PIF.plug', PIF.ref) +} + +connect.params = { + id: { type: 'string' } +} + +connect.resolve = { + PIF: ['id', 'PIF', 'administrate'] +} diff --git a/src/api/session.js b/src/api/session.js index 371f86dbe..6bd799e08 100644 --- a/src/api/session.js +++ b/src/api/session.js @@ -2,23 +2,21 @@ import {deprecate} from 'util' import {InvalidCredential, AlreadyAuthenticated} from '../api-errors' -import {coroutine, wait} from '../fibers-utils' - // =================================================================== -export const signIn = coroutine(function (credentials) { +export async function signIn (credentials) { if (this.session.has('user_id')) { throw new AlreadyAuthenticated() } - const user = wait(this.authenticateUser(credentials)) + const user = await this.authenticateUser(credentials) if (!user) { throw new InvalidCredential() } this.session.set('user_id', user.get('id')) return this.getUserPublicProperties(user) -}) +} signIn.description = 'sign in' @@ -52,12 +50,12 @@ signOut.permission = '' // ------------------------------------------------------------------- -export const getUser = coroutine(function () { +export async function getUser () { const userId = this.session.get('user_id') return userId === undefined ? null : - this.getUserPublicProperties(wait(this.getUser(userId))) -}) + this.getUserPublicProperties(await this.getUser(userId)) +} getUser.description = 'return the currently connected user' diff --git a/src/api/sr.js b/src/api/sr.js index 9a122f7ff..2dd4f4fdc 100644 --- a/src/api/sr.js +++ b/src/api/sr.js @@ -1,5 +1,4 @@ import forEach from 'lodash.foreach' -import {coroutine, wait} from '../fibers-utils' import {ensureArray, parseXml} from '../utils' // =================================================================== @@ -25,13 +24,9 @@ set.resolve = { // ------------------------------------------------------------------- -export const scan = coroutine(function ({SR}) { - const xapi = this.getXAPI(SR) - - wait(xapi.call('SR.scan', SR.ref)) - - return true -}) +export async function scan ({SR}) { + await this.getXAPI(SR).call('SR.scan', SR.ref) +} scan.params = { id: { type: 'string' } @@ -44,13 +39,9 @@ scan.resolve = { // ------------------------------------------------------------------- // TODO: find a way to call this "delete" and not destroy -export const destroy = coroutine(function ({SR}) { - const xapi = this.getXAPI(SR) - - wait(xapi.call('SR.destroy', SR.ref)) - - return true -}) +export async function destroy ({SR}) { + await this.getXAPI(SR).call('SR.destroy', SR.ref) +} destroy.params = { id: { type: 'string' } @@ -62,13 +53,9 @@ destroy.resolve = { // ------------------------------------------------------------------- -export const forget = coroutine(function ({SR}) { - const xapi = this.getXAPI(SR) - - wait(xapi.call('SR.forget', SR.ref)) - - return true -}) +export async function forget ({SR}) { + await this.getXAPI(SR).call('SR.forget', SR.ref) +} forget.params = { id: { type: 'string' } @@ -80,7 +67,7 @@ forget.resolve = { // ------------------------------------------------------------------- -export const createIso = coroutine(function ({ +export async function createIso ({ host, nameLabel, nameDescription, @@ -95,7 +82,7 @@ export const createIso = coroutine(function ({ // TODO: legacy will be removed in XAPI soon by FileSR deviceConfig.legacy_mode = 'true' } - const srRef = wait(xapi.call( + const srRef = await xapi.call( 'SR.create', host.ref, deviceConfig, @@ -106,11 +93,11 @@ export const createIso = coroutine(function ({ 'iso', // SR content type ISO true, {} - )) + ) - const sr = wait(xapi.call('SR.get_record', srRef)) + const sr = await xapi.call('SR.get_record', srRef) return sr.uuid -}) +} createIso.params = { host: { type: 'string' }, @@ -128,7 +115,7 @@ createIso.resolve = { // This functions creates a NFS SR -export const createNfs = coroutine(function ({ +export async function createNfs ({ host, nameLabel, nameDescription, @@ -148,7 +135,7 @@ export const createNfs = coroutine(function ({ deviceConfig.nfsversion = nfsVersion } - const srRef = wait(xapi.call( + const srRef = await xapi.call( 'SR.create', host.ref, deviceConfig, @@ -159,11 +146,11 @@ export const createNfs = coroutine(function ({ 'user', // recommended by Citrix true, {} - )) + ) - const sr = wait(xapi.call('SR.get_record', srRef)) + const sr = await xapi.call('SR.get_record', srRef) return sr.uuid -}) +} createNfs.params = { host: { type: 'string' }, @@ -183,7 +170,7 @@ createNfs.resolve = { // This functions creates a local LVM SR -export const createLvm = coroutine(function ({ +export async function createLvm ({ host, nameLabel, nameDescription, @@ -195,7 +182,7 @@ export const createLvm = coroutine(function ({ device } - const srRef = wait(xapi.call( + const srRef = await xapi.call( 'SR.create', host.ref, deviceConfig, @@ -206,11 +193,11 @@ export const createLvm = coroutine(function ({ 'user', // recommended by Citrix false, {} - )) + ) - const sr = wait(xapi.call('SR.get_record', srRef)) + const sr = await xapi.call('SR.get_record', srRef) return sr.uuid -}) +} createLvm.params = { host: { type: 'string' }, @@ -227,7 +214,7 @@ createLvm.resolve = { // This function helps to detect all NFS shares (exports) on a NFS server // Return a table of exports with their paths and ACLs -export const probeNfs = coroutine(function ({ +export async function probeNfs ({ host, server }) { @@ -240,13 +227,13 @@ export const probeNfs = coroutine(function ({ let xml try { - wait(xapi.call( + await xapi.call( 'SR.probe', host.ref, deviceConfig, 'nfs', {} - )) + ) throw new Error('the call above should have thrown an error') } catch (error) { @@ -266,7 +253,7 @@ export const probeNfs = coroutine(function ({ }) return nfsExports -}) +} probeNfs.params = { host: { type: 'string' }, @@ -282,7 +269,7 @@ probeNfs.resolve = { // This functions creates a iSCSI SR -export const createIscsi = coroutine(function ({ +export async function createIscsi ({ host, nameLabel, nameDescription, @@ -313,7 +300,7 @@ export const createIscsi = coroutine(function ({ deviceConfig.port = port } - const srRef = wait(xapi.call( + const srRef = await xapi.call( 'SR.create', host.ref, deviceConfig, @@ -324,11 +311,11 @@ export const createIscsi = coroutine(function ({ 'user', // recommended by Citrix true, {} - )) + ) - const sr = wait(xapi.call('SR.get_record', srRef)) + const sr = await xapi.call('SR.get_record', srRef) return sr.uuid -}) +} createIscsi.params = { host: { type: 'string' }, @@ -350,7 +337,7 @@ createIscsi.resolve = { // This function helps to detect all iSCSI IQN on a Target (iSCSI "server") // Return a table of IQN or empty table if no iSCSI connection to the target -export const probeIscsiIqns = coroutine(function ({ +export async function probeIscsiIqns ({ host, target: targetIp, port, @@ -377,13 +364,13 @@ export const probeIscsiIqns = coroutine(function ({ let xml try { - wait(xapi.call( + await xapi.call( 'SR.probe', host.ref, deviceConfig, 'lvmoiscsi', {} - )) + ) throw new Error('the call above should have thrown an error') } catch (error) { @@ -409,7 +396,7 @@ export const probeIscsiIqns = coroutine(function ({ }) return targets -}) +} probeIscsiIqns.params = { host: { type: 'string' }, @@ -426,7 +413,7 @@ probeIscsiIqns.resolve = { // This function helps to detect all iSCSI ID and LUNs on a Target // It will return a LUN table -export const probeIscsiLuns = coroutine(function ({ +export async function probeIscsiLuns ({ host, target: targetIp, port, @@ -455,13 +442,13 @@ export const probeIscsiLuns = coroutine(function ({ let xml try { - wait(xapi.call( + await xapi.call( 'SR.probe', host.ref, deviceConfig, 'lvmoiscsi', {} - )) + ) throw new Error('the call above should have thrown an error') } catch (error) { @@ -484,7 +471,7 @@ export const probeIscsiLuns = coroutine(function ({ }) return luns -}) +} probeIscsiLuns.params = { host: { type: 'string' }, @@ -503,7 +490,7 @@ probeIscsiLuns.resolve = { // This function helps to detect if this target already exists in XAPI // It returns a table of SR UUID, empty if no existing connections -export const probeIscsiExists = coroutine(function ({ +export async function probeIscsiExists ({ host, target: targetIp, port, @@ -531,7 +518,7 @@ export const probeIscsiExists = coroutine(function ({ deviceConfig.port = port } - const xml = parseXml(wait(xapi.call('SR.probe', host.ref, deviceConfig, 'lvmoiscsi', {}))) + const xml = parseXml(await xapi.call('SR.probe', host.ref, deviceConfig, 'lvmoiscsi', {})) const srs = [] forEach(ensureArray(xml['SRlist'].SR), sr => { @@ -540,7 +527,7 @@ export const probeIscsiExists = coroutine(function ({ }) return srs -}) +} probeIscsiExists.params = { host: { type: 'string' }, @@ -560,7 +547,7 @@ probeIscsiExists.resolve = { // This function helps to detect if this NFS SR already exists in XAPI // It returns a table of SR UUID, empty if no existing connections -export const probeNfsExists = coroutine(function ({ +export async function probeNfsExists ({ host, server, serverPath, @@ -572,7 +559,7 @@ export const probeNfsExists = coroutine(function ({ serverpath: serverPath } - const xml = parseXml(wait(xapi.call('SR.probe', host.ref, deviceConfig, 'nfs', {}))) + const xml = parseXml(await xapi.call('SR.probe', host.ref, deviceConfig, 'nfs', {})) const srs = [] @@ -582,7 +569,7 @@ export const probeNfsExists = coroutine(function ({ }) return srs -}) +} probeNfsExists.params = { host: { type: 'string' }, @@ -597,7 +584,7 @@ probeNfsExists.resolve = { // ------------------------------------------------------------------- // This function helps to reattach a forgotten NFS/iSCSI SR -export const reattach = coroutine(function ({ +export async function reattach ({ host, uuid, nameLabel, @@ -610,7 +597,7 @@ export const reattach = coroutine(function ({ type = 'lvmoiscsi' // the internal XAPI name } - const srRef = wait(xapi.call( + const srRef = await xapi.call( 'SR.introduce', uuid, nameLabel, @@ -619,11 +606,11 @@ export const reattach = coroutine(function ({ 'user', true, {} - )) + ) - const sr = wait(xapi.call('SR.get_record', srRef)) + const sr = await xapi.call('SR.get_record', srRef) return sr.uuid -}) +} reattach.params = { host: { type: 'string' }, @@ -640,7 +627,7 @@ reattach.resolve = { // ------------------------------------------------------------------- // This function helps to reattach a forgotten ISO SR -export const reattachIso = coroutine(function ({ +export async function reattachIso ({ host, uuid, nameLabel, @@ -653,7 +640,7 @@ export const reattachIso = coroutine(function ({ type = 'lvmoiscsi' // the internal XAPI name } - const srRef = wait(xapi.call( + const srRef = await xapi.call( 'SR.introduce', uuid, nameLabel, @@ -662,11 +649,11 @@ export const reattachIso = coroutine(function ({ 'iso', true, {} - )) + ) - const sr = wait(xapi.call('SR.get_record', srRef)) + const sr = await xapi.call('SR.get_record', srRef) return sr.uuid -}) +} reattachIso.params = { host: { type: 'string' }, diff --git a/src/api/task.coffee b/src/api/task.coffee deleted file mode 100644 index 9ba366014..000000000 --- a/src/api/task.coffee +++ /dev/null @@ -1,38 +0,0 @@ -{$coroutine, $wait} = require '../fibers-utils' - -#===================================================================== - -cancel = $coroutine ({task}) -> - xapi = @getXAPI task - - $wait xapi.call 'task.cancel', task.ref - - return true - -cancel.params = { - id: { type: 'string' }, -} - -cancel.resolve = { - task: ['id', 'task', 'administrate'], -} - -exports.cancel = cancel - -#--------------------------------------------------------------------- -destroy = $coroutine ({task}) -> - xapi = @getXAPI task - - $wait xapi.call 'task.destroy', task.ref - - return true - -destroy.params = { - id: { type: 'string' }, -} - -destroy.resolve = { - task: ['id', 'task', 'administrate'], -} - -exports.destroy = destroy diff --git a/src/api/task.js b/src/api/task.js new file mode 100644 index 000000000..586285fde --- /dev/null +++ b/src/api/task.js @@ -0,0 +1,25 @@ +export async function cancel ({task}) { + await this.getXAPI(task).call('task.cancel', task.ref) +} + +cancel.params = { + id: { type: 'string' } +} + +cancel.resolve = { + task: ['id', 'task', 'administrate'] +} + +// ------------------------------------------------------------------- + +export async function destroy ({task}) { + await this.getXAPI(task).call('task.destroy', task.ref) +} + +destroy.params = { + id: { type: 'string' } +} + +destroy.resolve = { + task: ['id', 'task', 'administrate'] +} diff --git a/src/api/vbd.coffee b/src/api/vbd.coffee index 65189b7e7..ae412a386 100644 --- a/src/api/vbd.coffee +++ b/src/api/vbd.coffee @@ -1,6 +1,6 @@ # FIXME: too low level, should be removed. -{$coroutine, $wait} = require '../fibers-utils' +{coroutine: $coroutine} = require 'bluebird' #===================================================================== @@ -8,7 +8,7 @@ delete_ = $coroutine ({vbd}) -> xapi = @getXAPI vbd # TODO: check if VBD is attached before - $wait xapi.call 'VBD.destroy', vbd.ref + yield xapi.call 'VBD.destroy', vbd.ref return true @@ -28,7 +28,7 @@ disconnect = $coroutine ({vbd}) -> xapi = @getXAPI vbd # TODO: check if VBD is attached before - $wait xapi.call 'VBD.unplug_force', vbd.ref + yield xapi.call 'VBD.unplug_force', vbd.ref return true @@ -48,7 +48,7 @@ connect = $coroutine ({vbd}) -> xapi = @getXAPI vbd # TODO: check if VBD is attached before - $wait xapi.call 'VBD.plug', vbd.ref + yield xapi.call 'VBD.plug', vbd.ref return true @@ -72,7 +72,7 @@ set = $coroutine (params) -> # VBD position if 'position' of params - $wait xapi.call 'VBD.set_userdevice', ref, params.position + yield xapi.call 'VBD.set_userdevice', ref, params.position set.params = { # Identifier of the VBD to update. diff --git a/src/api/vdi.coffee b/src/api/vdi.coffee index 14f2384aa..fded37742 100644 --- a/src/api/vdi.coffee +++ b/src/api/vdi.coffee @@ -4,7 +4,7 @@ $isArray = require 'lodash.isarray' #--------------------------------------------------------------------- -{$coroutine, $wait} = require '../fibers-utils' +{coroutine: $coroutine} = require 'bluebird' #===================================================================== @@ -12,7 +12,7 @@ delete_ = $coroutine ({vdi}) -> xapi = @getXAPI vdi # TODO: check if VDI is attached before - $wait xapi.call 'VDI.destroy', vdi.ref + yield xapi.call 'VDI.destroy', vdi.ref return true @@ -45,7 +45,7 @@ set = $coroutine (params) -> "cannot set new size below the current size (#{vdi.size})" ) - $wait xapi.call 'VDI.resize_online', ref, "#{size}" + yield xapi.call 'VDI.resize_online', ref, "#{size}" # Other fields. for param, fields of { @@ -55,7 +55,7 @@ set = $coroutine (params) -> continue unless param of params for field in (if $isArray fields then fields else [fields]) - $wait xapi.call "VDI.set_#{field}", ref, "#{params[param]}" + yield xapi.call "VDI.set_#{field}", ref, "#{params[param]}" return true @@ -83,7 +83,7 @@ migrate = $coroutine ({vdi, sr}) -> xapi = @getXAPI vdi # TODO: check if VDI is attached before - $wait xapi.call 'VDI.pool_migrate', vdi.ref, sr.ref, {} + yield xapi.call 'VDI.pool_migrate', vdi.ref, sr.ref, {} return true diff --git a/src/api/vif.coffee b/src/api/vif.coffee deleted file mode 100644 index ea49b3ef3..000000000 --- a/src/api/vif.coffee +++ /dev/null @@ -1,61 +0,0 @@ -{$coroutine, $wait} = require '../fibers-utils' - -#===================================================================== - -delete_ = $coroutine ({vif}) -> - xapi = @getXAPI vif - - # TODO: check if VIF is attached before - $wait xapi.call 'VIF.destroy', vif.ref - - return true - -delete_.params = { - id: { type: 'string' } -} - -delete_.resolve = { - vif: ['id', 'VIF', 'administrate'] -} - -exports.delete = delete_ - -#--------------------------------------------------------------------- - -disconnect = $coroutine ({vif}) -> - xapi = @getXAPI vif - - # TODO: check if VIF is attached before - $wait xapi.call 'VIF.unplug_force', vif.ref - - return true - -disconnect.params = { - id: { type: 'string' } -} - -disconnect.resolve = { - vif: ['id', 'VIF', 'operate'] -} - -exports.disconnect = disconnect - -#--------------------------------------------------------------------- - -connect = $coroutine ({vif}) -> - xapi = @getXAPI vif - - # TODO: check if VIF is attached before - $wait xapi.call 'VIF.plug', vif.ref - - return true - -connect.params = { - id: { type: 'string' } -} - -connect.resolve = { - vif: ['id', 'VIF', 'operate'] -} - -exports.connect = connect diff --git a/src/api/vif.js b/src/api/vif.js new file mode 100644 index 000000000..a3deb1bee --- /dev/null +++ b/src/api/vif.js @@ -0,0 +1,43 @@ +async function delete_ ({vif}) { + // TODO: check if VIF is attached before + await this.getXAPI(vif).call('VIF.destroy', vif.ref) +} +export {delete_ as delete} + +delete_.params = { + id: { type: 'string' } +} + +delete_.resolve = { + vif: ['id', 'VIF', 'administrate'] +} + +// ------------------------------------------------------------------- + +export async function disconnect ({vif}) { + // TODO: check if VIF is attached before + await this.getXAPI(vif).call('VIF.unplug_force', vif.ref) +} + +disconnect.params = { + id: { type: 'string' } +} + +disconnect.resolve = { + vif: ['id', 'VIF', 'operate'] +} + +// ------------------------------------------------------------------- + +export async function connect ({vif}) { + // TODO: check if VIF is attached before + await this.getXAPI(vif).call('VIF.plug', vif.ref) +} + +connect.params = { + id: { type: 'string' } +} + +connect.resolve = { + vif: ['id', 'VIF', 'operate'] +} diff --git a/src/api/vm.coffee b/src/api/vm.coffee index 37d1d029a..9ba6284ca 100644 --- a/src/api/vm.coffee +++ b/src/api/vm.coffee @@ -1,14 +1,14 @@ $debug = (require 'debug') 'xo:api:vm' +$findIndex = require 'lodash.findindex' $findWhere = require 'lodash.find' -$result = require 'lodash.result' $forEach = require 'lodash.foreach' $isArray = require 'lodash.isarray' -$findIndex = require 'lodash.findindex' -startsWith = require 'lodash.startswith' -endsWith = require 'lodash.endswith' $request = require('bluebird').promisify(require('request')) +$result = require 'lodash.result' +endsWith = require 'lodash.endswith' +startsWith = require 'lodash.startswith' +{coroutine: $coroutine} = require 'bluebird' -{$coroutine, $wait} = require '../fibers-utils' { formatXml: $js2xml, parseXml, @@ -38,7 +38,7 @@ create = $coroutine ({ xapi = @getXAPI template # Clones the VM from the template. - ref = $wait xapi.call 'VM.clone', template.ref, name_label + ref = yield xapi.call 'VM.clone', template.ref, name_label # TODO: if there is an error from now, removes this VM. @@ -51,7 +51,7 @@ create = $coroutine ({ $forEach VIFs, (VIF) => network = @getObject VIF.network, 'network' - $wait xapi.call 'VIF.create', { + yield xapi.call 'VIF.create', { device: String(deviceId++) MAC: VIF.MAC ? '' @@ -65,11 +65,11 @@ create = $coroutine ({ return - # TODO: ? $wait xapi.call 'VM.set_PV_args', ref, 'noninteractive' + # TODO: ? yield xapi.call 'VM.set_PV_args', ref, 'noninteractive' # Updates the number of existing vCPUs. if CPUs? - $wait xapi.call 'VM.set_VCPUs_at_startup', ref, CPUs + yield xapi.call 'VM.set_VCPUs_at_startup', ref, CPUs # TODO: remove existing VDIs (o make sure we have only those we # asked. @@ -96,10 +96,10 @@ create = $coroutine ({ } # Replace the existing entry in the VM object. - try $wait xapi.call 'VM.remove_from_other_config', ref, 'disks' - $wait xapi.call 'VM.add_to_other_config', ref, 'disks', VDIs + try yield xapi.call 'VM.remove_from_other_config', ref, 'disks' + yield xapi.call 'VM.add_to_other_config', ref, 'disks', VDIs - try $wait xapi.call( + try yield xapi.call( 'VM.remove_from_other_config' ref 'install-repository' @@ -107,12 +107,12 @@ create = $coroutine ({ if installation switch installation.method when 'cdrom' - $wait xapi.call( + yield xapi.call( 'VM.add_to_other_config', ref 'install-repository', 'cdrom' ) when 'ftp', 'http', 'nfs' - $wait xapi.call( + yield xapi.call( 'VM.add_to_other_config', ref 'install-repository', installation.repository ) @@ -124,10 +124,10 @@ create = $coroutine ({ # Creates the VDIs and executes the initial steps of the # installation. - $wait xapi.call 'VM.provision', ref + yield xapi.call 'VM.provision', ref # Gets the VM record. - VM = $wait xapi.call 'VM.get_record', ref + VM = yield xapi.call 'VM.get_record', ref if installation.method is 'cdrom' # Gets the VDI containing the ISO to mount. @@ -140,7 +140,7 @@ create = $coroutine ({ # CD. CD_drive = null $forEach VM.VBDs, (ref) -> - VBD = $wait xapi.call 'VBD.get_record', ref + VBD = yield xapi.call 'VBD.get_record', ref # TODO: Checks it has been correctly retrieved. if VBD.type is 'CD' CD_drive = VBD.ref @@ -150,7 +150,7 @@ create = $coroutine ({ # No CD drives have been found, creates one. unless CD_drive # See: https://github.com/xenserver/xenadmin/blob/da00b13bb94603b369b873b0a555d44f15fa0ca5/XenModel/Actions/VM/CreateVMAction.cs#L370 - CD_drive = $wait xapi.call 'VBD.create', { + CD_drive = yield xapi.call 'VBD.create', { bootable: true device: '' empty: true @@ -160,7 +160,7 @@ create = $coroutine ({ qos_algorithm_type: '' type: 'CD' unpluggable: true - userdevice: ($wait xapi.call 'VM.get_allowed_VBD_devices', ref)[0] + userdevice: (yield xapi.call 'VM.get_allowed_VBD_devices', ref)[0] VDI: 'OpaqueRef:NULL' VM: ref } @@ -169,10 +169,10 @@ create = $coroutine ({ @throw 'NO_SUCH_OBJECT' unless CD_drive # Mounts the VDI into the VBD. - $wait xapi.call 'VBD.insert', CD_drive, VDIref + yield xapi.call 'VBD.insert', CD_drive, VDIref else - $wait xapi.call 'VM.provision', ref - VM = $wait xapi.call 'VM.get_record', ref + yield xapi.call 'VM.provision', ref + VM = yield xapi.call 'VM.get_record', ref # The VM should be properly created. return VM.uuid @@ -272,7 +272,7 @@ ejectCd = $coroutine ({vm}) -> return if cdDriveRef - $wait xapi.call 'VBD.eject', cdDriveRef + yield xapi.call 'VBD.eject', cdDriveRef # Silently attempts to destroy the VBD. xapi.call('VBD.destroy', cdDriveRef).catch(->) @@ -306,9 +306,9 @@ insertCd = $coroutine ({vm, vdi, force}) -> if cdDrive.VDI @throw 'INVALID_PARAMS' unless force - $wait xapi.call 'VBD.eject', cdDriveRef + yield xapi.call 'VBD.eject', cdDriveRef else - cdDriveRef = $wait xapi.call 'VBD.create', { + cdDriveRef = yield xapi.call 'VBD.create', { bootable: true device: '' empty: true @@ -318,12 +318,12 @@ insertCd = $coroutine ({vm, vdi, force}) -> qos_algorithm_type: '' type: 'CD' unpluggable: true - userdevice: ($wait xapi.call 'VM.get_allowed_VBD_devices', vm.ref)[0] + userdevice: (yield xapi.call 'VM.get_allowed_VBD_devices', vm.ref)[0] VDI: 'OpaqueRef:NULL' VM: vm.ref } - $wait xapi.call 'VBD.insert', cdDriveRef, vdi.ref + yield xapi.call 'VBD.insert', cdDriveRef, vdi.ref return true @@ -347,7 +347,7 @@ migrate = $coroutine ({vm, host}) -> xapi = @getXAPI vm - $wait xapi.call 'VM.pool_migrate', vm.ref, host.ref, {'force': 'true'} + yield xapi.call 'VM.pool_migrate', vm.ref, host.ref, {'force': 'true'} return true @@ -411,14 +411,14 @@ migratePool = $coroutine ({ VIF = @getObject vifId, 'VIF' vifMap[VIF.ref] = network.ref - token = $wait (@getXAPI host).call( + token = yield (@getXAPI host).call( 'host.migrate_receive' host.ref migrationNetwork.ref {} # Other parameters ) - $wait (@getXAPI VM).call( + yield (@getXAPI VM).call( 'VM.migrate_send' VM.ref token @@ -486,10 +486,10 @@ set = $coroutine (params) -> ) if memory < VM.memory.dynamic[0] - $wait xapi.call 'VM.set_memory_dynamic_min', ref, "#{memory}" + yield xapi.call 'VM.set_memory_dynamic_min', ref, "#{memory}" else if memory > VM.memory.static[1] - $wait xapi.call 'VM.set_memory_static_max', ref, "#{memory}" - $wait xapi.call 'VM.set_memory_dynamic_max', ref, "#{memory}" + yield xapi.call 'VM.set_memory_static_max', ref, "#{memory}" + yield xapi.call 'VM.set_memory_dynamic_max', ref, "#{memory}" # Number of CPUs. if 'CPUs' of params @@ -502,11 +502,11 @@ set = $coroutine (params) -> "cannot set CPUs above the static maximum (#{VM.CPUs.max}) "+ "for a running VM" ) - $wait xapi.call 'VM.set_VCPUs_number_live', ref, "#{CPUs}" + yield xapi.call 'VM.set_VCPUs_number_live', ref, "#{CPUs}" else if CPUs > VM.CPUs.max - $wait xapi.call 'VM.set_VCPUs_max', ref, "#{CPUs}" - $wait xapi.call 'VM.set_VCPUs_at_startup', ref, "#{CPUs}" + yield xapi.call 'VM.set_VCPUs_max', ref, "#{CPUs}" + yield xapi.call 'VM.set_VCPUs_at_startup', ref, "#{CPUs}" # HA policy # TODO: also handle "best-effort" case @@ -514,17 +514,17 @@ set = $coroutine (params) -> {high_availability} = params if high_availability - $wait xapi.call 'VM.set_ha_restart_priority', ref, "restart" + yield xapi.call 'VM.set_ha_restart_priority', ref, "restart" else - $wait xapi.call 'VM.set_ha_restart_priority', ref, "" + yield xapi.call 'VM.set_ha_restart_priority', ref, "" if 'auto_poweron' of params {auto_poweron} = params if auto_poweron - $wait xapi.call 'VM.add_to_other_config', ref, 'auto_poweron', 'true' + yield xapi.call 'VM.add_to_other_config', ref, 'auto_poweron', 'true' else - $wait xapi.call 'VM.remove_from_other_config', ref, 'auto_poweron' + yield xapi.call 'VM.remove_from_other_config', ref, 'auto_poweron' # Other fields. for param, fields of { @@ -534,7 +534,7 @@ set = $coroutine (params) -> continue unless param of params for field in (if $isArray fields then fields else [fields]) - $wait xapi.call "VM.set_#{field}", ref, "#{params[param]}" + yield xapi.call "VM.set_#{field}", ref, "#{params[param]}" return true @@ -573,9 +573,9 @@ restart = $coroutine ({vm, force}) -> xapi = @getXAPI(vm) if force - $wait xapi.call 'VM.hard_reboot', vm.ref + yield xapi.call 'VM.hard_reboot', vm.ref else - $wait xapi.call 'VM.clean_reboot', vm.ref + yield xapi.call 'VM.clean_reboot', vm.ref return true @@ -595,9 +595,9 @@ exports.restart = restart clone = $coroutine ({vm, name, full_copy}) -> xapi = @getXAPI vm if full_copy - $wait xapi.call 'VM.copy', vm.ref, name, '' + yield xapi.call 'VM.copy', vm.ref, name, '' else - $wait xapi.call 'VM.clone', vm.ref, name + yield xapi.call 'VM.clone', vm.ref, name return true @@ -621,7 +621,7 @@ exports.clone = clone # TODO: rename convertToTemplate() convert = $coroutine ({vm}) -> - $wait @getXAPI(vm).call 'VM.set_is_a_template', vm.ref, true + yield @getXAPI(vm).call 'VM.set_is_a_template', vm.ref, true return true @@ -638,7 +638,7 @@ exports.convert = convert #--------------------------------------------------------------------- snapshot = $coroutine ({vm, name}) -> - snapshot = $wait @getXAPI(vm).snapshotVm(vm.ref, name) + snapshot = yield @getXAPI(vm).snapshotVm(vm.ref, name) return snapshot.$id snapshot.params = { @@ -655,7 +655,7 @@ exports.snapshot = snapshot #--------------------------------------------------------------------- start = $coroutine ({vm}) -> - $wait @getXAPI(vm).call( + yield @getXAPI(vm).call( 'VM.start', vm.ref false # Start paused? false # Skips the pre-boot checks? @@ -684,12 +684,12 @@ stop = $coroutine ({vm, force}) -> # Hard shutdown if force - $wait xapi.call 'VM.hard_shutdown', vm.ref + yield xapi.call 'VM.hard_shutdown', vm.ref return true # Clean shutdown try - $wait xapi.call 'VM.clean_shutdown', vm.ref + yield xapi.call 'VM.clean_shutdown', vm.ref catch error if error.code is 'VM_MISSING_PV_DRIVERS' # TODO: Improve reporting: this message is unclear. @@ -713,7 +713,7 @@ exports.stop = stop #--------------------------------------------------------------------- suspend = $coroutine ({vm}) -> - $wait @getXAPI(vm).call 'VM.suspend', vm.ref + yield @getXAPI(vm).call 'VM.suspend', vm.ref return true @@ -733,7 +733,7 @@ resume = $coroutine ({vm, force}) -> if not force force = true - $wait @getXAPI(vm).call 'VM.resume', vm.ref, false, force + yield @getXAPI(vm).call 'VM.resume', vm.ref, false, force return true @@ -752,7 +752,7 @@ exports.resume = resume # revert a snapshot to its parent VM revert = $coroutine ({snapshot}) -> # Attempts a revert from this snapshot to its parent VM - $wait @getXAPI(snapshot).call 'VM.revert', snapshot.ref + yield @getXAPI(snapshot).call 'VM.revert', snapshot.ref return true @@ -778,12 +778,12 @@ handleExport = (req, res, {stream, response: upstream}) -> # TODO: integrate in xapi.js export_ = $coroutine ({vm, compress}) -> - stream = $wait @getXAPI(vm).exportVm(vm.id, compress ? true) + stream = yield @getXAPI(vm).exportVm(vm.id, compress ? true) return { - $getFrom: $wait @registerHttpRequest(handleExport, { + $getFrom: yield @registerHttpRequest(handleExport, { stream, - response: $wait stream.response + response: yield stream.response }) } @@ -805,7 +805,7 @@ import_ = $coroutine ({host}) -> {sessionId} = @getXAPI(host) - url = $wait @registerProxyRequest { + url = yield @registerProxyRequest { # Receive a POST but send a PUT. method: 'put' proxyMethod: 'post' @@ -834,7 +834,7 @@ exports.import = import_ # FIXME: if position is used, all other disks after this position # should be shifted. attachDisk = $coroutine ({vm, vdi, position, mode, bootable}) -> - $wait @getXAPI(vm).attachVdiToVm(vdi.id, vm.id, {bootable, mode, position}) + yield @getXAPI(vm).attachVdiToVm(vdi.id, vm.id, {bootable, mode, position}) return attachDisk.params = { @@ -859,7 +859,7 @@ exports.attachDisk = attachDisk # FIXME: position should be optional and default to last. createInterface = $coroutine ({vm, network, position, mtu, mac}) -> - vif = $wait @getXAPI(vm).createVirtualInterface(vm.id, network.id, { + vif = yield @getXAPI(vm).createVirtualInterface(vm.id, network.id, { mac, mtu, position @@ -886,7 +886,7 @@ exports.createInterface = createInterface attachPci = $coroutine ({vm, pciId}) -> xapi = @getXAPI vm - $wait xapi.call 'VM.add_to_other_config', vm.ref, 'pci', pciId + yield xapi.call 'VM.add_to_other_config', vm.ref, 'pci', pciId return true @@ -906,7 +906,7 @@ exports.attachPci = attachPci detachPci = $coroutine ({vm}) -> xapi = @getXAPI vm - $wait xapi.call 'VM.remove_from_other_config', vm.ref, 'pci' + yield xapi.call 'VM.remove_from_other_config', vm.ref, 'pci' return true @@ -933,7 +933,7 @@ stats = $coroutine ({vm}) -> else unless type is 'host' throw new Error "unexpected type: got #{type} instead of host" - [response, body] = $wait $request { + [response, body] = yield $request { method: 'get' rejectUnauthorized: false url: 'https://'+host.address+'/vm_rrd?session_id='+xapi.sessionId+'&uuid='+vm.id @@ -1031,7 +1031,7 @@ bootOrder = $coroutine ({vm, order}) -> order = {order: order} - $wait xapi.call 'VM.set_HVM_boot_params', vm.ref, order + yield xapi.call 'VM.set_HVM_boot_params', vm.ref, order return true diff --git a/src/fibers-utils.js b/src/fibers-utils.js deleted file mode 100644 index 96f93406b..000000000 --- a/src/fibers-utils.js +++ /dev/null @@ -1,115 +0,0 @@ -import Bluebird from 'bluebird' -import Fiber from 'fibers' -import forEach from 'lodash.foreach' -import isArray from 'lodash.isarray' -import isFunction from 'lodash.isfunction' -import isObject from 'lodash.isobject' - -// =================================================================== - -export const isPromise = (obj) => obj && isFunction(obj.then) - -// The value is guarantee to resolve asynchronously. -const runAsync = (value, resolve, reject) => { - if (isPromise(value)) { - return value.then(resolve, reject) - } - - if (isFunction(value)) { // Continuable - throw new Error('continuable are no longer supported') - } - - if (!isObject(value)) { - return process.nextTick(() => { - resolve(value) - }) - } - - let left = 0 - let results = isArray(value) ? - new Array(value.length) : - Object.create(null) - - forEach(value, (value, index) => { - ++left - runAsync( - value, - (result) => { - // Returns if already rejected. - if (!results) { - return - } - - results[index] = result - if (!--left) { - resolve(results) - } - }, - (error) => { - // Returns if already rejected. - if (!results) { - return - } - - // Frees the reference ASAP. - results = null - - reject(error) - } - ) - }) - - if (!left) { - process.nextTick(() => { - resolve(value) - }) - } -} - -// =================================================================== - -// Makes a function run in its own fiber and returns a promise. -export function coroutine (fn) { - return function (...args) { - return new Bluebird((resolve, reject) => { - new Fiber(() => { - try { - resolve(fn.apply(this, args)) - } catch (error) { - reject(error) - } - }).run() - }) - } -} - -// Waits for a promise or a continuable to end. -// -// If value is composed (array or map), every asynchronous value is -// resolved before returning (parallelization). -export const wait = (value) => { - const fiber = Fiber.current - if (!fiber) { - throw new Error('not running in a fiber') - } - - runAsync( - value, - (value) => { - fiber.run(value) - }, - (error) => { - fiber.throwInto(error) - } - ) - - return Fiber.yield() -} - -// =================================================================== - -// Compatibility. -export { - coroutine as $coroutine, - wait as $wait -} diff --git a/src/fibers-utils.spec.js b/src/fibers-utils.spec.js deleted file mode 100644 index d814a66ef..000000000 --- a/src/fibers-utils.spec.js +++ /dev/null @@ -1,151 +0,0 @@ -/* eslint-env mocha */ - -import {expect} from 'chai' - -// ------------------------------------------------------------------- - -import Bluebird from 'bluebird' - -// ------------------------------------------------------------------- - -import {$coroutine, $wait} from './fibers-utils' - -// Enable source maps support for traces. -import sourceMapSupport from 'source-map-support' -sourceMapSupport.install() - -// =================================================================== - -describe('$coroutine', function () { - it('creates a function which returns promises', function () { - const fn = $coroutine(function () {}) - expect(fn().then).to.be.a('function') - }) - - it('creates a function which runs in a new fiber', function () { - const previous = require('fibers').current - - const fn = $coroutine(function () { - const current = require('fibers').current - - expect(current).to.exists - expect(current).to.not.equal(previous) - }) - - return fn() - }) - - it('forwards all arguments (even this)', function () { - const self = {} - const arg1 = {} - const arg2 = {} - - return $coroutine(function (arg1_, arg2_) { - expect(this).to.equal(self) - expect(arg1_).to.equal(arg1) - expect(arg2_).to.equal(arg2) - }).call(self, arg1, arg2) - }) -}) - -// ------------------------------------------------------------------- - -describe('$wait', function () { - it('waits for a promise', function () { - return $coroutine(function () { - const value = {} - const promise = Bluebird.resolve(value) - - expect($wait(promise)).to.equal(value) - })() - }) - - it('handles promise rejection', function () { - return $coroutine(function () { - const promise = Bluebird.reject('an exception') - - expect(function () { - $wait(promise) - }).to.throw('an exception') - })() - }) - - it('forwards scalar values', function () { - return $coroutine(function () { - let value = 'a scalar value' - expect($wait(value)).to.equal(value) - - value = [ - 'foo', - 'bar', - 'baz' - ] - expect($wait(value)).to.deep.equal(value) - - value = [] - expect($wait(value)).to.deep.equal(value) - - value = { - foo: 'foo', - bar: 'bar', - baz: 'baz' - } - expect($wait(value)).to.deep.equal(value) - - value = {} - expect($wait(value)).to.deep.equal(value) - })() - }) - - it('handles arrays of promises', function () { - return $coroutine(function () { - const value1 = {} - const value2 = {} - - const promise1 = Bluebird.resolve(value1) - const promise2 = Bluebird.resolve(value2) - - const results = $wait([promise1, promise2]) - expect(results[0]).to.equal(value1) - expect(results[1]).to.equal(value2) - })() - }) - - it('handles maps of promises', function () { - return $coroutine(function () { - const value1 = {} - const value2 = {} - - const promise1 = Bluebird.resolve(value1) - const promise2 = Bluebird.resolve(value2) - - const results = $wait({ - foo: promise1, - bar: promise2 - }) - expect(results.foo).to.equal(value1) - expect(results.bar).to.equal(value2) - })() - }) - - it('handles nested arrays/maps', function () { - const promise1 = Bluebird.resolve('promise 1') - const promise2 = Bluebird.resolve('promise 2') - - return $coroutine(function () { - expect($wait({ - foo: promise1, - bar: [ - promise2, - 'a scalar' - ] - })).to.deep.equal({ - foo: 'promise 1', - bar: [ - 'promise 2', - 'a scalar' - ] - }) - })() - }) -})