Compare commits
179 Commits
xen-api-v0
...
xen-api-v0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07945ef8a6 | ||
|
|
35d7fa4a85 | ||
|
|
fbb6870310 | ||
|
|
81efe25fbc | ||
|
|
63d440677b | ||
|
|
2e0df47581 | ||
|
|
a84ced70a6 | ||
|
|
4a9498e25e | ||
|
|
1978e218f4 | ||
|
|
2ab912c4f4 | ||
|
|
ca329fa2ff | ||
|
|
db122ed8c5 | ||
|
|
28d7f106b2 | ||
|
|
d6e46adfde | ||
|
|
93109fe9b8 | ||
|
|
439992d96f | ||
|
|
f94fe0b325 | ||
|
|
cc543ae33a | ||
|
|
5df1e62d53 | ||
|
|
1dff6f81fc | ||
|
|
ecf2d95318 | ||
|
|
a1af272180 | ||
|
|
72f0793aeb | ||
|
|
e150be6a3e | ||
|
|
d71b13f2a2 | ||
|
|
66c88b37a4 | ||
|
|
a7198d2e83 | ||
|
|
d3584b5820 | ||
|
|
e2e6267dd7 | ||
|
|
aa5baecdc3 | ||
|
|
601b2aa6bb | ||
|
|
d09ba38dbd | ||
|
|
b847c2b7b5 | ||
|
|
30e44cb533 | ||
|
|
d43b83081b | ||
|
|
699363c548 | ||
|
|
6ea3eb4ba6 | ||
|
|
4aa20b6f6a | ||
|
|
9c8ea27238 | ||
|
|
22c515b0e7 | ||
|
|
7e2bd52f25 | ||
|
|
e65dd15edc | ||
|
|
781ffa5574 | ||
|
|
8fe3b1a368 | ||
|
|
69c48e2770 | ||
|
|
aa934ad725 | ||
|
|
8596ca607d | ||
|
|
643ea9e523 | ||
|
|
26f630d9d6 | ||
|
|
7481874ba2 | ||
|
|
a348585e76 | ||
|
|
8d135bc1fc | ||
|
|
2c00f0ffab | ||
|
|
5e1d627834 | ||
|
|
37b23bdc47 | ||
|
|
47f3788f55 | ||
|
|
63be8afd35 | ||
|
|
1166db7834 | ||
|
|
3d96765b1f | ||
|
|
4c52fe11d3 | ||
|
|
6c4178e107 | ||
|
|
02d1fb436d | ||
|
|
1c97bf9019 | ||
|
|
bfc4bb1f4c | ||
|
|
ccdce32562 | ||
|
|
87fdcf14e5 | ||
|
|
c0c63f49b1 | ||
|
|
4e1bef9537 | ||
|
|
8b78727d20 | ||
|
|
4cd7025be4 | ||
|
|
015ce2690d | ||
|
|
3e7f552a63 | ||
|
|
22882b1ff2 | ||
|
|
c7e6e72ce8 | ||
|
|
27e0621ad8 | ||
|
|
1987a8c68a | ||
|
|
1642798aa6 | ||
|
|
36b589c2db | ||
|
|
1f710b9b78 | ||
|
|
9b9f0e5607 | ||
|
|
590f6cb7b3 | ||
|
|
2c35ee11b3 | ||
|
|
bd0c747d98 | ||
|
|
b12fd45df1 | ||
|
|
c21fef7c72 | ||
|
|
b7f34b9da6 | ||
|
|
f82a6efda1 | ||
|
|
556ca71c3a | ||
|
|
42be2d5031 | ||
|
|
876e22b092 | ||
|
|
f9f9c16cb0 | ||
|
|
a881090e65 | ||
|
|
3d9fce02a4 | ||
|
|
ab6b1e2c32 | ||
|
|
59d9b3c6b4 | ||
|
|
8851a661c0 | ||
|
|
2d327961da | ||
|
|
3a41efbea8 | ||
|
|
45b8fd0100 | ||
|
|
155f2fc36c | ||
|
|
c3dc136de4 | ||
|
|
4cbc5c4e2f | ||
|
|
68820aaf59 | ||
|
|
cd65bc7683 | ||
|
|
6e0956f09f | ||
|
|
1191f0ba93 | ||
|
|
6534ffea26 | ||
|
|
f9173c41d1 | ||
|
|
a2faedcacb | ||
|
|
cb56b3b9d0 | ||
|
|
a61b50548c | ||
|
|
75ad588e0b | ||
|
|
6564edcc32 | ||
|
|
c46c0018ea | ||
|
|
35e8dcc3be | ||
|
|
d1600fd058 | ||
|
|
1416fb0c71 | ||
|
|
2975db247d | ||
|
|
03eaa652ce | ||
|
|
eac29993d3 | ||
|
|
af2a9225b8 | ||
|
|
a24de7fe3f | ||
|
|
16a9f44d4d | ||
|
|
6fcc148105 | ||
|
|
3485cb4ec4 | ||
|
|
b2a51bd658 | ||
|
|
e5ab1dc154 | ||
|
|
6274969635 | ||
|
|
069c430346 | ||
|
|
cbcc4dd21d | ||
|
|
b4cdf4d277 | ||
|
|
716d7bfcf6 | ||
|
|
b45a169a2f | ||
|
|
720b9ef999 | ||
|
|
9b9e4dddfc | ||
|
|
7434e0352f | ||
|
|
26d61af902 | ||
|
|
5bd12c5f9e | ||
|
|
e07fae4290 | ||
|
|
e304395179 | ||
|
|
6b83130853 | ||
|
|
9565718699 | ||
|
|
ac11885379 | ||
|
|
277669a13c | ||
|
|
fcbc476462 | ||
|
|
4944b415c7 | ||
|
|
5da7312d2d | ||
|
|
954d19fe50 | ||
|
|
addd86f5d2 | ||
|
|
1b90223210 | ||
|
|
95989ff63b | ||
|
|
799f758dce | ||
|
|
e075f1c08b | ||
|
|
7e0aa719b4 | ||
|
|
4ee352fdb2 | ||
|
|
96ea3ded4a | ||
|
|
8bbc6e9ff5 | ||
|
|
af7029812c | ||
|
|
c517b59138 | ||
|
|
5485e8a322 | ||
|
|
2540ac34b3 | ||
|
|
76e5d41a34 | ||
|
|
2c32a4e912 | ||
|
|
c66f7235b6 | ||
|
|
5444381f7d | ||
|
|
dc44679031 | ||
|
|
2cbd17b745 | ||
|
|
9ef13696d8 | ||
|
|
c3f635fd12 | ||
|
|
e3d1380435 | ||
|
|
f83737b538 | ||
|
|
bb1ea4e4d0 | ||
|
|
9cb4de2ea8 | ||
|
|
048cbf60ec | ||
|
|
36f40b4188 | ||
|
|
a3bba92063 | ||
|
|
ebcc6c9341 | ||
|
|
95f765055e | ||
|
|
49aa5ffccc |
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"comments": false,
|
||||
"compact": true,
|
||||
"optional": [
|
||||
// Experimental features.
|
||||
// "minification.constantFolding",
|
||||
// "minification.deadCodeElimination",
|
||||
|
||||
"es7.asyncFunctions",
|
||||
"es7.decorators",
|
||||
"es7.functionBind",
|
||||
"runtime"
|
||||
]
|
||||
}
|
||||
10
packages/xen-api/.gitignore
vendored
10
packages/xen-api/.gitignore
vendored
@@ -1,8 +1,12 @@
|
||||
/bower_components/
|
||||
/coverage/
|
||||
/dist/
|
||||
/examples/node_modules/
|
||||
/node_modules/
|
||||
|
||||
npm-debug.log
|
||||
npm-debug.log.*
|
||||
pnpm-debug.log
|
||||
pnpm-debug.log.*
|
||||
yarn-error.log*
|
||||
|
||||
!node_modules/*
|
||||
node_modules/*/
|
||||
/plot.dat
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
try { require('clarify') } catch (_) {}
|
||||
try { require('trace') } catch (_) {}
|
||||
try { require('source-map-support/register') } catch (_) {}
|
||||
@@ -1 +0,0 @@
|
||||
--require ./.mocha.js
|
||||
@@ -1,9 +1,24 @@
|
||||
/benchmark/
|
||||
/benchmarks/
|
||||
*.bench.js
|
||||
*.bench.js.map
|
||||
|
||||
/examples/
|
||||
example.js
|
||||
example.js.map
|
||||
*.example.js
|
||||
*.example.js.map
|
||||
|
||||
/fixture/
|
||||
/fixtures/
|
||||
*.fixture.js
|
||||
*.fixture.js.map
|
||||
*.fixtures.js
|
||||
*.fixtures.js.map
|
||||
|
||||
/test/
|
||||
/tests/
|
||||
*.spec.js
|
||||
*.spec.js.map
|
||||
|
||||
__snapshots__/
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 'iojs-v2'
|
||||
- 'iojs-v1'
|
||||
- '0.12'
|
||||
- '0.10'
|
||||
- stable
|
||||
- 6
|
||||
- 4
|
||||
|
||||
# Use containers.
|
||||
# http://docs.travis-ci.com/user/workers/container-based-infrastructure/
|
||||
sudo: false
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
# xen-api [](https://travis-ci.org/julien-f/js-xen-api)
|
||||
# xen-api [](https://travis-ci.org/vatesfr/xen-api)
|
||||
|
||||
> Connector to the Xen API
|
||||
|
||||
Tested with:
|
||||
|
||||
- XenServer 7.1
|
||||
- XenServer 7
|
||||
- XenServer 6.5
|
||||
- XenServer 6.2
|
||||
- XenServer 5.6
|
||||
|
||||
## Install
|
||||
|
||||
Installation of the [npm package](https://npmjs.org/package/xen-api):
|
||||
@@ -22,9 +30,18 @@ var xapi = createClient({
|
||||
auth: {
|
||||
user: 'root',
|
||||
password: 'important secret password'
|
||||
}
|
||||
},
|
||||
readOnly: false
|
||||
})
|
||||
```
|
||||
|
||||
Options:
|
||||
|
||||
- `url`: address of a host in the pool we are trying to connect to
|
||||
- `auth`: credentials used to sign in
|
||||
- `readOnly = false`: if true, no methods with side-effects can be called
|
||||
|
||||
```js
|
||||
// Force connection.
|
||||
xapi.connect().catch(error => {
|
||||
console.error(error)
|
||||
@@ -36,7 +53,9 @@ xapi.objects.on('add', function (objects) {
|
||||
})
|
||||
```
|
||||
|
||||
Custom fields on objects (hidden and read-only):
|
||||
> Note: all objects are frozen and cannot be altered!
|
||||
|
||||
Custom fields on objects (hidden − ie. non enumerable):
|
||||
- `$type`: the type of the object (`VM`, `task`, …);
|
||||
- `$ref`: the (opaque) reference of the object;
|
||||
- `$id`: the identifier of this object (its UUID if any, otherwise its reference);
|
||||
@@ -65,26 +84,30 @@ root@xen1.company.net> xapi.pool.$master.name_label
|
||||
'xen1'
|
||||
```
|
||||
|
||||
To ease searches, `find()` and `findAll()` functions are available:
|
||||
|
||||
```
|
||||
root@xen1.company.net> findAll({ $type: 'vm' }).length
|
||||
183
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Installing dependencies
|
||||
|
||||
```
|
||||
# Install dependencies
|
||||
> npm install
|
||||
```
|
||||
|
||||
### Compilation
|
||||
# Run the tests
|
||||
> npm test
|
||||
|
||||
The sources files are watched and automatically recompiled on changes.
|
||||
|
||||
```
|
||||
# Continuously compile
|
||||
> npm run dev
|
||||
```
|
||||
|
||||
### Tests
|
||||
# Continuously run the tests
|
||||
> npm run dev-test
|
||||
|
||||
```
|
||||
> npm run test-dev
|
||||
# Build for production (automatically called by npm install)
|
||||
> npm run build
|
||||
```
|
||||
|
||||
## Contributions
|
||||
@@ -94,7 +117,7 @@ the code.
|
||||
|
||||
You may:
|
||||
|
||||
- report any [issue](https://github.com/julien-f/js-xen-api/issues)
|
||||
- report any [issue](https://github.com/pbdxen-api/issues)
|
||||
you've encountered;
|
||||
- fork and create a pull request.
|
||||
|
||||
|
||||
50
packages/xen-api/examples/export-vdi
Executable file
50
packages/xen-api/examples/export-vdi
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
process.env.DEBUG = '*'
|
||||
|
||||
const defer = require('golike-defer').default
|
||||
const pump = require('pump')
|
||||
const { fromCallback } = require('promise-toolbox')
|
||||
|
||||
const { createClient } = require('../')
|
||||
|
||||
const { createOutputStream, resolveRef } = require('./utils')
|
||||
|
||||
defer(async ($defer, args) => {
|
||||
let raw = false
|
||||
if (args[0] === '--raw') {
|
||||
raw = true
|
||||
args.shift()
|
||||
}
|
||||
|
||||
if (args.length < 2) {
|
||||
return console.log('Usage: export-vdi [--raw] <XS URL> <VDI identifier> [<VHD file>]')
|
||||
}
|
||||
|
||||
const xapi = createClient({
|
||||
allowUnauthorized: true,
|
||||
url: args[0],
|
||||
watchEvents: false
|
||||
})
|
||||
|
||||
await xapi.connect()
|
||||
$defer(() => xapi.disconnect())
|
||||
|
||||
// https://xapi-project.github.io/xen-api/snapshots.html#downloading-a-disk-or-snapshot
|
||||
const exportStream = await xapi.getResource('/export_raw_vdi/', {
|
||||
query: {
|
||||
format: raw ? 'raw' : 'vhd',
|
||||
vdi: await resolveRef(xapi, 'VDI', args[1])
|
||||
}
|
||||
})
|
||||
|
||||
console.warn('Export task:', exportStream.headers['task-id'])
|
||||
|
||||
await fromCallback(cb => pump(
|
||||
exportStream,
|
||||
createOutputStream(args[2]),
|
||||
cb
|
||||
))
|
||||
})(process.argv.slice(2)).catch(
|
||||
console.error.bind(console, 'error')
|
||||
)
|
||||
44
packages/xen-api/examples/export-vm
Executable file
44
packages/xen-api/examples/export-vm
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
process.env.DEBUG = '*'
|
||||
|
||||
const defer = require('golike-defer').default
|
||||
const pump = require('pump')
|
||||
const { fromCallback } = require('promise-toolbox')
|
||||
|
||||
const { createClient } = require('../')
|
||||
|
||||
const { createOutputStream, resolveRef } = require('./utils')
|
||||
|
||||
defer(async ($defer, args) => {
|
||||
if (args.length < 2) {
|
||||
return console.log('Usage: export-vm <XS URL> <VM identifier> [<XVA file>]')
|
||||
}
|
||||
|
||||
const xapi = createClient({
|
||||
allowUnauthorized: true,
|
||||
url: args[0],
|
||||
watchEvents: false
|
||||
})
|
||||
|
||||
await xapi.connect()
|
||||
$defer(() => xapi.disconnect())
|
||||
|
||||
// https://xapi-project.github.io/xen-api/importexport.html
|
||||
const exportStream = await xapi.getResource('/export/', {
|
||||
query: {
|
||||
ref: await resolveRef(xapi, 'VM', args[1]),
|
||||
use_compression: 'true'
|
||||
}
|
||||
})
|
||||
|
||||
console.warn('Export task:', exportStream.headers['task-id'])
|
||||
|
||||
await fromCallback(cb => pump(
|
||||
exportStream,
|
||||
createOutputStream(args[2]),
|
||||
cb
|
||||
))
|
||||
})(process.argv.slice(2)).catch(
|
||||
console.error.bind(console, 'error')
|
||||
)
|
||||
40
packages/xen-api/examples/import-vdi
Executable file
40
packages/xen-api/examples/import-vdi
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
process.env.DEBUG = '*'
|
||||
|
||||
const defer = require('golike-defer').default
|
||||
|
||||
const { createClient } = require('../')
|
||||
|
||||
const { createInputStream, resolveRef } = require('./utils')
|
||||
|
||||
defer(async ($defer, args) => {
|
||||
let raw = false
|
||||
if (args[0] === '--raw') {
|
||||
raw = true
|
||||
args.shift()
|
||||
}
|
||||
|
||||
if (args.length < 2) {
|
||||
return console.log('Usage: import-vdi [--raw] <XS URL> <VDI identifier> [<VHD file>]')
|
||||
}
|
||||
|
||||
const xapi = createClient({
|
||||
allowUnauthorized: true,
|
||||
url: args[0],
|
||||
watchEvents: false
|
||||
})
|
||||
|
||||
await xapi.connect()
|
||||
$defer(() => xapi.disconnect())
|
||||
|
||||
// https://xapi-project.github.io/xen-api/snapshots.html#uploading-a-disk-or-snapshot
|
||||
await xapi.putResource(createInputStream(args[2]), '/import_raw_vdi/', {
|
||||
query: {
|
||||
format: raw ? 'raw' : 'vhd',
|
||||
vdi: await resolveRef(xapi, 'VDI', args[1])
|
||||
}
|
||||
})
|
||||
})(process.argv.slice(2)).catch(
|
||||
console.error.bind(console, 'error')
|
||||
)
|
||||
31
packages/xen-api/examples/import-vm
Executable file
31
packages/xen-api/examples/import-vm
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
process.env.DEBUG = '*'
|
||||
|
||||
const defer = require('golike-defer').default
|
||||
|
||||
const { createClient } = require('../')
|
||||
|
||||
const { createInputStream, resolveRef } = require('./utils')
|
||||
|
||||
defer(async ($defer, args) => {
|
||||
if (args.length < 1) {
|
||||
return console.log('Usage: import-vm <XS URL> [<XVA file>] [<SR identifier>]')
|
||||
}
|
||||
|
||||
const xapi = createClient({
|
||||
allowUnauthorized: true,
|
||||
url: args[0],
|
||||
watchEvents: false
|
||||
})
|
||||
|
||||
await xapi.connect()
|
||||
$defer(() => xapi.disconnect())
|
||||
|
||||
// https://xapi-project.github.io/xen-api/importexport.html
|
||||
await xapi.putResource(createInputStream(args[1]), '/import/', {
|
||||
query: args[2] && { sr_id: await resolveRef(xapi, 'SR', args[2]) }
|
||||
})
|
||||
})(process.argv.slice(2)).catch(
|
||||
console.error.bind(console, 'error')
|
||||
)
|
||||
30
packages/xen-api/src/example.js → packages/xen-api/examples/log-events
Normal file → Executable file
30
packages/xen-api/src/example.js → packages/xen-api/examples/log-events
Normal file → Executable file
@@ -1,33 +1,37 @@
|
||||
import forEach from 'lodash.foreach'
|
||||
import size from 'lodash.size'
|
||||
import {createClient} from './'
|
||||
#!/usr/bin/env node
|
||||
|
||||
import sourceMapSupport from 'source-map-support'
|
||||
sourceMapSupport.install()
|
||||
require('source-map-support').install()
|
||||
|
||||
const { forEach, size } = require('lodash')
|
||||
|
||||
const { createClient } = require('../')
|
||||
|
||||
// ===================================================================
|
||||
|
||||
if (process.argv.length < 3) {
|
||||
return console.log('Usage: log-events <XS URL>')
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Creation
|
||||
|
||||
const xapi = createClient({
|
||||
url: 'https://192.168.1.1',
|
||||
auth: {
|
||||
user: 'root',
|
||||
password: 'qwerty'
|
||||
}
|
||||
allowUnauthorized: true,
|
||||
url: process.argv[2]
|
||||
})
|
||||
|
||||
// ===================================================================
|
||||
// Method call
|
||||
|
||||
const getAllVms = xapi.call('VM.get_all_records')
|
||||
|
||||
getAllVms()
|
||||
xapi.connect().then(() => {
|
||||
xapi.call('VM.get_all_records')
|
||||
.then(function (vms) {
|
||||
console.log('%s VMs fetched', size(vms))
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error)
|
||||
})
|
||||
})
|
||||
|
||||
// ===================================================================
|
||||
// Objects
|
||||
6
packages/xen-api/examples/package.json
Normal file
6
packages/xen-api/examples/package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"golike-defer": "^0.1.0",
|
||||
"pump": "^1.0.2"
|
||||
}
|
||||
}
|
||||
41
packages/xen-api/examples/utils.js
Normal file
41
packages/xen-api/examples/utils.js
Normal file
@@ -0,0 +1,41 @@
|
||||
const { createReadStream, createWriteStream, statSync } = require('fs')
|
||||
const { PassThrough } = require('stream')
|
||||
|
||||
const { isOpaqueRef } = require('../')
|
||||
|
||||
exports.createInputStream = path => {
|
||||
if (path === undefined || path === '-') {
|
||||
return process.stdin
|
||||
}
|
||||
|
||||
const { size } = statSync(path)
|
||||
|
||||
const stream = createReadStream(path)
|
||||
stream.length = size
|
||||
return stream
|
||||
}
|
||||
|
||||
exports.createOutputStream = path => {
|
||||
if (path !== undefined && path !== '-') {
|
||||
return createWriteStream(path)
|
||||
}
|
||||
|
||||
// introduce a through stream because stdout is not a normal stream!
|
||||
const stream = new PassThrough()
|
||||
stream.pipe(process.stdout)
|
||||
return stream
|
||||
}
|
||||
|
||||
exports.resolveRef = (xapi, type, refOrUuidOrNameLabel) =>
|
||||
isOpaqueRef(refOrUuidOrNameLabel)
|
||||
? refOrUuidOrNameLabel
|
||||
: xapi.call(`${type}.get_by_uuid`, refOrUuidOrNameLabel).catch(
|
||||
() => xapi.call(`${type}.get_by_name_label`, refOrUuidOrNameLabel).then(
|
||||
refs => {
|
||||
if (refs.length === 1) {
|
||||
return refs[0]
|
||||
}
|
||||
throw new Error(`no single match for ${type} with name label ${refOrUuidOrNameLabel}`)
|
||||
}
|
||||
)
|
||||
)
|
||||
30
packages/xen-api/examples/yarn.lock
Normal file
30
packages/xen-api/examples/yarn.lock
Normal file
@@ -0,0 +1,30 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
end-of-stream@^1.1.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206"
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
golike-defer@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/golike-defer/-/golike-defer-0.1.0.tgz#70a3d8991cdfe41845956bfb578f69bc3e49f525"
|
||||
|
||||
once@^1.3.1, once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
pump@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.2.tgz#3b3ee6512f94f0e575538c17995f9f16990a5d51"
|
||||
dependencies:
|
||||
end-of-stream "^1.1.0"
|
||||
once "^1.3.1"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
4
packages/xen-api/memory-test.gnu
Normal file
4
packages/xen-api/memory-test.gnu
Normal file
@@ -0,0 +1,4 @@
|
||||
set yrange [ 0 : ]
|
||||
set grid
|
||||
|
||||
plot for [i=2:4] "plot.dat" using 1:i with lines
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xen-api",
|
||||
"version": "0.5.6",
|
||||
"version": "0.13.5",
|
||||
"license": "ISC",
|
||||
"description": "Connector to the Xen API",
|
||||
"keywords": [
|
||||
@@ -10,11 +10,11 @@
|
||||
"xenapi",
|
||||
"xapi"
|
||||
],
|
||||
"homepage": "https://github.com/julien-f/js-xen-api",
|
||||
"bugs": "https://github.com/julien-f/js-xen-api/issues",
|
||||
"homepage": "https://github.com/vatesfr/xen-api",
|
||||
"bugs": "https://github.com/vatesfr/xen-api/issues",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/julien-f/js-xen-api.git"
|
||||
"url": "https://github.com/vatesfr/xen-api.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Julien Fontanet",
|
||||
@@ -28,49 +28,79 @@
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-runtime": "^5",
|
||||
"blocked": "^1.1.0",
|
||||
"bluebird": "^2.9.21",
|
||||
"debug": "^2.1.3",
|
||||
"event-to-promise": "^0.3.2",
|
||||
"exec-promise": "^0.5.1",
|
||||
"lodash.find": "^3.2.0",
|
||||
"lodash.findkey": "^3.0.1",
|
||||
"lodash.foreach": "^3.0.2",
|
||||
"lodash.isarray": "^3.0.2",
|
||||
"lodash.isobject": "^3.0.1",
|
||||
"lodash.map": "^3.1.2",
|
||||
"lodash.size": "^3.0.0",
|
||||
"lodash.startswith": "^3.0.1",
|
||||
"make-error": "^1.0.2",
|
||||
"minimist": "^1.1.1",
|
||||
"babel-polyfill": "^6.23.0",
|
||||
"blocked": "^1.2.1",
|
||||
"debug": "^2.6.8",
|
||||
"event-to-promise": "^0.8.0",
|
||||
"exec-promise": "^0.7.0",
|
||||
"http-request-plus": "^0.4.0",
|
||||
"json-rpc-protocol": "^0.11.2",
|
||||
"kindof": "^2.0.0",
|
||||
"lodash": "^4.17.4",
|
||||
"make-error": "^1.3.0",
|
||||
"minimist": "^1.2.0",
|
||||
"ms": "^2.0.0",
|
||||
"promise-toolbox": "^0.9.5",
|
||||
"pw": "0.0.4",
|
||||
"source-map-support": "^0.2.10",
|
||||
"xmlrpc": "^1.3.0",
|
||||
"xo-collection": "^0.3.0"
|
||||
"xmlrpc": "^1.3.2",
|
||||
"xo-collection": "^0.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel": "^5.5.8",
|
||||
"babel-eslint": "^3.1.16",
|
||||
"clarify": "^1.0.5",
|
||||
"mocha": "^2.2.5",
|
||||
"must": "^0.12.0",
|
||||
"source-map-support": "^0.3.1",
|
||||
"standard": "^4.3.0",
|
||||
"trace": "^1.2.0"
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-eslint": "^7.2.3",
|
||||
"babel-plugin-lodash": "^3.2.11",
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
"babel-preset-env": "^1.5.2",
|
||||
"babel-preset-stage-0": "^6.24.1",
|
||||
"cross-env": "^5.0.1",
|
||||
"dependency-check": "^2.9.1",
|
||||
"husky": "^0.14.1",
|
||||
"jest": "^20.0.4",
|
||||
"rimraf": "^2.6.1",
|
||||
"standard": "^10.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "babel --source-maps --out-dir=dist/ src/",
|
||||
"dev": "babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"lint": "standard",
|
||||
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"commitmsg": "npm test",
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"dev-test": "jest --bail --watch",
|
||||
"plot": "gnuplot -p memory-test.gnu",
|
||||
"posttest": "standard && dependency-check ./package.json",
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "npm run prebuild",
|
||||
"prepublish": "npm run build",
|
||||
"test": "mocha --opts .mocha.opts \"dist/**/*.spec.js\"",
|
||||
"test-dev": "mocha --opts .mocha.opts --watch --reporter=min \"dist/**/*.spec.js\""
|
||||
"test": "jest"
|
||||
},
|
||||
"babel": {
|
||||
"plugins": [
|
||||
"lodash",
|
||||
"transform-decorators-legacy"
|
||||
],
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"targets": {
|
||||
"node": 4
|
||||
}
|
||||
}
|
||||
],
|
||||
"stage-0"
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"roots": [
|
||||
"<rootDir>/src"
|
||||
],
|
||||
"testRegex": "\\.spec\\.js$"
|
||||
},
|
||||
"standard": {
|
||||
"ignore": [
|
||||
"dist/**"
|
||||
"dist"
|
||||
],
|
||||
"parser": "babel-eslint"
|
||||
}
|
||||
|
||||
@@ -1,34 +1,48 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import 'babel-polyfill'
|
||||
|
||||
import blocked from 'blocked'
|
||||
import Bluebird, {coroutine} from 'bluebird'
|
||||
import createDebug from 'debug'
|
||||
import eventToPromise from 'event-to-promise'
|
||||
import execPromise from 'exec-promise'
|
||||
import minimist from 'minimist'
|
||||
import pw from 'pw'
|
||||
import {start as createRepl} from 'repl'
|
||||
import { asCallback, fromCallback } from 'promise-toolbox'
|
||||
import { filter, find, isArray } from 'lodash'
|
||||
import { start as createRepl } from 'repl'
|
||||
|
||||
import {createClient} from './'
|
||||
import { createClient } from './'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
Bluebird.longStackTraces()
|
||||
function askPassword (prompt = 'Password: ') {
|
||||
if (prompt) {
|
||||
process.stdout.write(prompt)
|
||||
}
|
||||
|
||||
import createDebug from 'debug'
|
||||
return new Promise(resolve => {
|
||||
pw(resolve)
|
||||
})
|
||||
}
|
||||
|
||||
import sourceMapSupport from 'source-map-support'
|
||||
sourceMapSupport.install()
|
||||
function required (name) {
|
||||
throw new Error(`missing required argument ${name}`)
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const usage = `Usage: xen-api <url> <user>`
|
||||
const usage = 'Usage: xen-api <url> <user> [<password>]'
|
||||
|
||||
const main = coroutine(function * (args) {
|
||||
const main = async args => {
|
||||
const opts = minimist(args, {
|
||||
boolean: ['help', 'verbose'],
|
||||
boolean: ['allow-unauthorized', 'help', 'read-only', 'verbose'],
|
||||
|
||||
alias: {
|
||||
'allow-unauthorized': 'au',
|
||||
debounce: 'd',
|
||||
help: 'h',
|
||||
'read-only': 'ro',
|
||||
verbose: 'v'
|
||||
}
|
||||
})
|
||||
@@ -44,15 +58,11 @@ const main = coroutine(function * (args) {
|
||||
createDebug.enable('xen-api,xen-api:*')
|
||||
}
|
||||
|
||||
const [url, user] = opts._
|
||||
if (!url || !user) {
|
||||
throw new Error('missing arguments')
|
||||
}
|
||||
|
||||
process.stdout.write('Password: ')
|
||||
const password = yield new Bluebird(resolve => {
|
||||
pw(resolve)
|
||||
})
|
||||
const [
|
||||
url = required('url'),
|
||||
user = required('user'),
|
||||
password = await askPassword()
|
||||
] = opts._
|
||||
|
||||
{
|
||||
const debug = createDebug('xen-api:perf')
|
||||
@@ -61,31 +71,38 @@ const main = coroutine(function * (args) {
|
||||
})
|
||||
}
|
||||
|
||||
const xapi = createClient({url, auth: {user, password}})
|
||||
yield xapi.connect()
|
||||
const xapi = createClient({
|
||||
url,
|
||||
allowUnauthorized: opts.au,
|
||||
auth: { user, password },
|
||||
debounce: opts.debounce != null ? +opts.debounce : null,
|
||||
readOnly: opts.ro
|
||||
})
|
||||
await xapi.connect()
|
||||
|
||||
const repl = createRepl({
|
||||
prompt: `${xapi._humanId}> `
|
||||
})
|
||||
repl.context.xapi = xapi
|
||||
|
||||
// Make the REPL waits for promise completion.
|
||||
{
|
||||
const evaluate = Bluebird.promisify(repl.eval)
|
||||
repl.eval = (cmd, context, filename, cb) => {
|
||||
evaluate(cmd, context, filename)
|
||||
// See https://github.com/petkaantonov/bluebird/issues/594
|
||||
.then(result => result)
|
||||
.nodeify(cb)
|
||||
}
|
||||
}
|
||||
repl.context.find = predicate => find(xapi.objects.all, predicate)
|
||||
repl.context.findAll = predicate => filter(xapi.objects.all, predicate)
|
||||
|
||||
yield eventToPromise(repl, 'exit')
|
||||
// Make the REPL waits for promise completion.
|
||||
repl.eval = (evaluate => (cmd, context, filename, cb) => {
|
||||
fromCallback(cb => {
|
||||
evaluate.call(repl, cmd, context, filename, cb)
|
||||
}).then(value =>
|
||||
isArray(value) ? Promise.all(value) : value
|
||||
)::asCallback(cb)
|
||||
})(repl.eval)
|
||||
|
||||
await eventToPromise(repl, 'exit')
|
||||
|
||||
try {
|
||||
yield xapi.disconnect()
|
||||
await xapi.disconnect()
|
||||
} catch (error) {}
|
||||
})
|
||||
}
|
||||
export default main
|
||||
|
||||
if (!module.parent) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import {createClient, Xapi} from './'
|
||||
|
||||
import expect from 'must'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
describe('createClient()', function () {
|
||||
it('is a function', function () {
|
||||
expect(createClient).to.be.a.function()
|
||||
})
|
||||
|
||||
it.skip('returns an instance of Xapi', function () {
|
||||
expect(createClient('example.org')).to.be.a(Xapi)
|
||||
})
|
||||
})
|
||||
29
packages/xen-api/src/inject-events.js
Executable file
29
packages/xen-api/src/inject-events.js
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { delay as pDelay } from 'promise-toolbox'
|
||||
|
||||
import { createClient } from './'
|
||||
|
||||
const xapi = (() => {
|
||||
const [ , , url, user, password ] = process.argv
|
||||
|
||||
return createClient({
|
||||
auth: { user, password },
|
||||
url,
|
||||
watchEvents: false
|
||||
})
|
||||
})()
|
||||
|
||||
xapi.connect()
|
||||
|
||||
// Get the pool record's ref.
|
||||
.then(() => xapi.call('pool.get_all'))
|
||||
|
||||
// Injects lots of events.
|
||||
.then(([ poolRef ]) => {
|
||||
const loop = () => xapi.call('event.inject', 'pool', poolRef)
|
||||
::pDelay(10) // A small delay is required to avoid overloading the Xen API.
|
||||
.then(loop)
|
||||
|
||||
return loop()
|
||||
})
|
||||
22
packages/xen-api/src/memory-test.js
Executable file
22
packages/xen-api/src/memory-test.js
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { createClient } from './'
|
||||
|
||||
let i = 0
|
||||
setInterval(() => {
|
||||
const usage = process.memoryUsage()
|
||||
console.log(
|
||||
'%s %s %s %s',
|
||||
i++,
|
||||
Math.round(usage.rss / 1e6),
|
||||
Math.round(usage.heapTotal / 1e6),
|
||||
Math.round(usage.heapUsed / 1e6)
|
||||
)
|
||||
}, 1e2)
|
||||
|
||||
const [ , , url, user, password ] = process.argv
|
||||
createClient({
|
||||
auth: { user, password },
|
||||
readOnly: true,
|
||||
url
|
||||
}).connect()
|
||||
3
packages/xen-api/src/transports/_utils.js
Normal file
3
packages/xen-api/src/transports/_utils.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import makeError from 'make-error'
|
||||
|
||||
export const UnsupportedTransport = makeError('UnsupportedTransport')
|
||||
36
packages/xen-api/src/transports/auto.js
Normal file
36
packages/xen-api/src/transports/auto.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import jsonRpc from './json-rpc'
|
||||
import xmlRpc from './xml-rpc'
|
||||
import xmlRpcJson from './xml-rpc-json'
|
||||
import { UnsupportedTransport } from './_utils'
|
||||
|
||||
const factories = [ jsonRpc, xmlRpcJson, xmlRpc ]
|
||||
const { length } = factories
|
||||
|
||||
export default opts => {
|
||||
let i = 0
|
||||
|
||||
let call
|
||||
function create () {
|
||||
const current = factories[i++](opts)
|
||||
if (i < length) {
|
||||
const currentI = i
|
||||
call = (method, args) => current(method, args).catch(
|
||||
error => {
|
||||
if (error instanceof UnsupportedTransport) {
|
||||
if (currentI === i) { // not changed yet
|
||||
create()
|
||||
}
|
||||
return call(method, args)
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
)
|
||||
} else {
|
||||
call = current
|
||||
}
|
||||
}
|
||||
create()
|
||||
|
||||
return (method, args) => call(method, args)
|
||||
}
|
||||
38
packages/xen-api/src/transports/json-rpc.js
Normal file
38
packages/xen-api/src/transports/json-rpc.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import httpRequestPlus from 'http-request-plus'
|
||||
import { format, parse } from 'json-rpc-protocol'
|
||||
|
||||
import { UnsupportedTransport } from './_utils'
|
||||
|
||||
export default ({ allowUnauthorized, url }) => {
|
||||
return (method, args) => httpRequestPlus.post(url, {
|
||||
rejectUnauthorized: !allowUnauthorized,
|
||||
body: format.request(0, method, args),
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
path: '/jsonrpc'
|
||||
}).readAll('utf8').then(
|
||||
text => {
|
||||
let response
|
||||
try {
|
||||
response = parse(text)
|
||||
} catch (error) {
|
||||
throw new UnsupportedTransport()
|
||||
}
|
||||
|
||||
if (response.type === 'response') {
|
||||
return response.result
|
||||
}
|
||||
|
||||
throw response.error
|
||||
},
|
||||
error => {
|
||||
if (error.response !== undefined) { // HTTP error
|
||||
throw new UnsupportedTransport()
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
)
|
||||
}
|
||||
97
packages/xen-api/src/transports/xml-rpc-json.js
Normal file
97
packages/xen-api/src/transports/xml-rpc-json.js
Normal file
@@ -0,0 +1,97 @@
|
||||
import { createClient, createSecureClient } from 'xmlrpc'
|
||||
import { promisify } from 'promise-toolbox'
|
||||
|
||||
import { UnsupportedTransport } from './_utils'
|
||||
|
||||
const logError = error => {
|
||||
if (error.res) {
|
||||
console.error(
|
||||
'XML-RPC Error: %s (response status %s)',
|
||||
error.message,
|
||||
error.res.statusCode
|
||||
)
|
||||
console.error('%s', error.body)
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
|
||||
const SPECIAL_CHARS = {
|
||||
'\r': '\\r',
|
||||
'\t': '\\t'
|
||||
}
|
||||
const SPECIAL_CHARS_RE = new RegExp(
|
||||
Object.keys(SPECIAL_CHARS).join('|'),
|
||||
'g'
|
||||
)
|
||||
|
||||
const parseResult = result => {
|
||||
const status = result.Status
|
||||
|
||||
// Return the plain result if it does not have a valid XAPI
|
||||
// format.
|
||||
if (status === undefined) {
|
||||
return result
|
||||
}
|
||||
|
||||
if (status !== 'Success') {
|
||||
throw result.ErrorDescription
|
||||
}
|
||||
|
||||
const value = result.Value
|
||||
|
||||
// XAPI returns an empty string (invalid JSON) for an empty
|
||||
// result.
|
||||
if (value === '') {
|
||||
return ''
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(value)
|
||||
} catch (error) {
|
||||
// XAPI JSON sometimes contains invalid characters.
|
||||
if (!(error instanceof SyntaxError)) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
let replaced = false
|
||||
const fixedValue = value.replace(SPECIAL_CHARS_RE, match => {
|
||||
replaced = true
|
||||
return SPECIAL_CHARS[match]
|
||||
})
|
||||
|
||||
if (replaced) {
|
||||
try {
|
||||
return JSON.parse(fixedValue)
|
||||
} catch (error) {
|
||||
if (!(error instanceof SyntaxError)) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new UnsupportedTransport()
|
||||
}
|
||||
|
||||
export default ({
|
||||
allowUnauthorized,
|
||||
url: { hostname, path, port, protocol }
|
||||
}) => {
|
||||
const client = (
|
||||
protocol === 'https:'
|
||||
? createSecureClient
|
||||
: createClient
|
||||
)({
|
||||
host: hostname,
|
||||
path: '/json',
|
||||
port,
|
||||
rejectUnauthorized: !allowUnauthorized
|
||||
})
|
||||
const call = promisify(client.methodCall, client)
|
||||
|
||||
return (method, args) => call(method, args).then(
|
||||
parseResult,
|
||||
logError
|
||||
)
|
||||
}
|
||||
52
packages/xen-api/src/transports/xml-rpc.js
Normal file
52
packages/xen-api/src/transports/xml-rpc.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import { createClient, createSecureClient } from 'xmlrpc'
|
||||
import { promisify } from 'promise-toolbox'
|
||||
|
||||
const logError = error => {
|
||||
if (error.res) {
|
||||
console.error(
|
||||
'XML-RPC Error: %s (response status %s)',
|
||||
error.message,
|
||||
error.res.statusCode
|
||||
)
|
||||
console.error('%s', error.body)
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
|
||||
const parseResult = result => {
|
||||
const status = result.Status
|
||||
|
||||
// Return the plain result if it does not have a valid XAPI
|
||||
// format.
|
||||
if (status === undefined) {
|
||||
return result
|
||||
}
|
||||
|
||||
if (status !== 'Success') {
|
||||
throw result.ErrorDescription
|
||||
}
|
||||
|
||||
return result.Value
|
||||
}
|
||||
|
||||
export default ({
|
||||
allowUnauthorized,
|
||||
url: { hostname, path, port, protocol }
|
||||
}) => {
|
||||
const client = (
|
||||
protocol === 'https:'
|
||||
? createSecureClient
|
||||
: createClient
|
||||
)({
|
||||
host: hostname,
|
||||
port,
|
||||
rejectUnauthorized: !allowUnauthorized
|
||||
})
|
||||
const call = promisify(client.methodCall, client)
|
||||
|
||||
return (method, args) => call(method, args).then(
|
||||
parseResult,
|
||||
logError
|
||||
)
|
||||
}
|
||||
3780
packages/xen-api/yarn.lock
Normal file
3780
packages/xen-api/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user