Merge branch 'master' of https://github.com/joyent/node-triton
This commit is contained in:
commit
be74f307e0
12
CHANGES.md
12
CHANGES.md
@ -6,6 +6,18 @@ Known issues:
|
|||||||
|
|
||||||
## not yet released
|
## not yet released
|
||||||
|
|
||||||
|
## 5.8.0
|
||||||
|
|
||||||
|
- [TRITON-124] add node-triton support for bhyve. This adds a `triton instance
|
||||||
|
create --brand=bhyve ...` option that can be used for zvol images that support
|
||||||
|
it. Note that bhyve support is alpha in TritonDC -- most datacenters won't yet
|
||||||
|
support this option.
|
||||||
|
|
||||||
|
## 5.7.0
|
||||||
|
|
||||||
|
- [TRITON-116] node-triton image sharing. Adds `triton image share` and
|
||||||
|
`triton image unshare` commands.
|
||||||
|
|
||||||
## 5.6.1
|
## 5.6.1
|
||||||
|
|
||||||
- [PUBAPI-1470] volume objects should expose their creation timestamp in a
|
- [PUBAPI-1470] volume objects should expose their creation timestamp in a
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2017 Joyent, Inc.
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
*
|
*
|
||||||
* Client library for the SmartDataCenter Cloud API (cloudapi).
|
* Client library for the SmartDataCenter Cloud API (cloudapi).
|
||||||
* http://apidocs.joyent.com/cloudapi/
|
* http://apidocs.joyent.com/cloudapi/
|
||||||
@ -767,6 +767,33 @@ CloudApi.prototype.exportImage = function exportImage(opts, cb) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an image.
|
||||||
|
* <http://apidocs.joyent.com/cloudapi/#UpdateImage>
|
||||||
|
*
|
||||||
|
* @param {Object} opts
|
||||||
|
* - {UUID} id Required. The id of the image to update.
|
||||||
|
* - {Object} fields Required. The fields to update in the image.
|
||||||
|
* @param {Function} cb of the form `function (err, body, res)`
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.updateImage = function shareImage(opts, cb) {
|
||||||
|
assert.uuid(opts.id, 'id');
|
||||||
|
assert.object(opts.fields, 'fields');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'POST',
|
||||||
|
path: format('/%s/images/%s?action=update', this.account, opts.id),
|
||||||
|
data: opts.fields
|
||||||
|
}, function (err, req, res, body) {
|
||||||
|
if (err) {
|
||||||
|
cb(err, null, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cb(null, body, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for an image to go one of a set of specfic states.
|
* Wait for an image to go one of a set of specfic states.
|
||||||
*
|
*
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Joyent, Inc.
|
* Copyright 2018 Joyent, Inc.
|
||||||
*
|
*
|
||||||
* `triton fwrule instances ...`
|
* `triton fwrule instances ...`
|
||||||
*/
|
*/
|
||||||
@ -111,6 +111,7 @@ function do_instances(subcmd, opts, args, cb) {
|
|||||||
common.uuidToShortId(inst.image);
|
common.uuidToShortId(inst.image);
|
||||||
inst.shortid = inst.id.split('-', 1)[0];
|
inst.shortid = inst.id.split('-', 1)[0];
|
||||||
var flags = [];
|
var flags = [];
|
||||||
|
if (inst.brand === 'bhyve') flags.push('B');
|
||||||
if (inst.docker) flags.push('D');
|
if (inst.docker) flags.push('D');
|
||||||
if (inst.firewall_enabled) flags.push('F');
|
if (inst.firewall_enabled) flags.push('F');
|
||||||
if (inst.brand === 'kvm') flags.push('K');
|
if (inst.brand === 'kvm') flags.push('K');
|
||||||
@ -159,6 +160,7 @@ do_instances.help = [
|
|||||||
'for convenience):',
|
'for convenience):',
|
||||||
' shortid* A short ID prefix.',
|
' shortid* A short ID prefix.',
|
||||||
' flags* Single letter flags summarizing some fields:',
|
' flags* Single letter flags summarizing some fields:',
|
||||||
|
' "B" the brand is "bhyve"',
|
||||||
' "D" docker instance',
|
' "D" docker instance',
|
||||||
' "F" firewall is enabled',
|
' "F" firewall is enabled',
|
||||||
' "K" the brand is "kvm"',
|
' "K" the brand is "kvm"',
|
||||||
|
115
lib/do_image/do_share.js
Normal file
115
lib/do_image/do_share.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton image share ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var format = require('util').format;
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
// ---- the command
|
||||||
|
|
||||||
|
function do_share(subcmd, opts, args, cb) {
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
} else if (args.length !== 2) {
|
||||||
|
cb(new errors.UsageError(
|
||||||
|
'incorrect number of args: expect 2, got ' + args.length));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var log = this.top.log;
|
||||||
|
var tritonapi = this.top.tritonapi;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: {cli: this.top}, funcs: [
|
||||||
|
common.cliSetupTritonApi,
|
||||||
|
function shareImage(ctx, next) {
|
||||||
|
log.trace({dryRun: opts.dry_run, account: ctx.account},
|
||||||
|
'image share account');
|
||||||
|
|
||||||
|
if (opts.dry_run) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tritonapi.shareImage({
|
||||||
|
image: args[0],
|
||||||
|
account: args[1]
|
||||||
|
}, function (err, img) {
|
||||||
|
if (err) {
|
||||||
|
next(new errors.TritonError(err, 'error sharing image'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.trace({img: img}, 'image share result');
|
||||||
|
|
||||||
|
if (opts.json) {
|
||||||
|
console.log(JSON.stringify(img));
|
||||||
|
} else {
|
||||||
|
console.log('Shared image %s with account %s',
|
||||||
|
args[0], args[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
do_share.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: 'Other options'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['dry-run'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Go through the motions without actually sharing.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['json', 'j'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'JSON stream output.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
do_share.synopses = [
|
||||||
|
'{{name}} {{cmd}} [OPTIONS] IMAGE ACCOUNT'
|
||||||
|
];
|
||||||
|
|
||||||
|
do_share.help = [
|
||||||
|
/* BEGIN JSSTYLED */
|
||||||
|
'Share an image with another account.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Where "IMAGE" is an image id (a full UUID), an image name (selects the',
|
||||||
|
'latest, by "published_at", image with that name), an image "name@version"',
|
||||||
|
'(selects latest match by "published_at"), or an image short ID (ID prefix).',
|
||||||
|
'',
|
||||||
|
'Where "ACCOUNT" is the full account UUID.',
|
||||||
|
'',
|
||||||
|
'Note: Only images that are owned by the account can be shared.'
|
||||||
|
/* END JSSTYLED */
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_share.completionArgtypes = ['tritonimage', 'none'];
|
||||||
|
|
||||||
|
module.exports = do_share;
|
115
lib/do_image/do_unshare.js
Normal file
115
lib/do_image/do_unshare.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton image unshare ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var format = require('util').format;
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
// ---- the command
|
||||||
|
|
||||||
|
function do_unshare(subcmd, opts, args, cb) {
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
} else if (args.length !== 2) {
|
||||||
|
cb(new errors.UsageError(
|
||||||
|
'incorrect number of args: expect 2, got ' + args.length));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var log = this.top.log;
|
||||||
|
var tritonapi = this.top.tritonapi;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: {cli: this.top}, funcs: [
|
||||||
|
common.cliSetupTritonApi,
|
||||||
|
function unshareImage(ctx, next) {
|
||||||
|
log.trace({dryRun: opts.dry_run, account: ctx.account},
|
||||||
|
'image unshare account');
|
||||||
|
|
||||||
|
if (opts.dry_run) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tritonapi.unshareImage({
|
||||||
|
image: args[0],
|
||||||
|
account: args[1]
|
||||||
|
}, function (err, img) {
|
||||||
|
if (err) {
|
||||||
|
next(new errors.TritonError(err, 'error unsharing image'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.trace({img: img}, 'image unshare result');
|
||||||
|
|
||||||
|
if (opts.json) {
|
||||||
|
console.log(JSON.stringify(img));
|
||||||
|
} else {
|
||||||
|
console.log('Unshared image %s with account %s',
|
||||||
|
args[0], args[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
do_unshare.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: 'Other options'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['dry-run'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Go through the motions without actually sharing.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['json', 'j'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'JSON stream output.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
do_unshare.synopses = [
|
||||||
|
'{{name}} {{cmd}} [OPTIONS] IMAGE ACCOUNT'
|
||||||
|
];
|
||||||
|
|
||||||
|
do_unshare.help = [
|
||||||
|
/* BEGIN JSSTYLED */
|
||||||
|
'Unshare an image with another account.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Where "IMAGE" is an image id (a full UUID), an image name (selects the',
|
||||||
|
'latest, by "published_at", image with that name), an image "name@version"',
|
||||||
|
'(selects latest match by "published_at"), or an image short ID (ID prefix).',
|
||||||
|
'',
|
||||||
|
'Where "ACCOUNT" is the full account UUID.',
|
||||||
|
'',
|
||||||
|
'Note: Only images that are owned by the account can be unshared.'
|
||||||
|
/* END JSSTYLED */
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_unshare.completionArgtypes = ['tritonimage', 'none'];
|
||||||
|
|
||||||
|
module.exports = do_unshare;
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2017 Joyent, Inc.
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
*
|
*
|
||||||
* `triton image ...`
|
* `triton image ...`
|
||||||
*/
|
*/
|
||||||
@ -36,6 +36,8 @@ function ImageCLI(top) {
|
|||||||
'create',
|
'create',
|
||||||
'delete',
|
'delete',
|
||||||
'export',
|
'export',
|
||||||
|
'share',
|
||||||
|
'unshare',
|
||||||
'wait'
|
'wait'
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -52,6 +54,8 @@ ImageCLI.prototype.do_get = require('./do_get');
|
|||||||
ImageCLI.prototype.do_create = require('./do_create');
|
ImageCLI.prototype.do_create = require('./do_create');
|
||||||
ImageCLI.prototype.do_delete = require('./do_delete');
|
ImageCLI.prototype.do_delete = require('./do_delete');
|
||||||
ImageCLI.prototype.do_export = require('./do_export');
|
ImageCLI.prototype.do_export = require('./do_export');
|
||||||
|
ImageCLI.prototype.do_share = require('./do_share');
|
||||||
|
ImageCLI.prototype.do_unshare = require('./do_unshare');
|
||||||
ImageCLI.prototype.do_wait = require('./do_wait');
|
ImageCLI.prototype.do_wait = require('./do_wait');
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2017 Joyent, Inc.
|
* Copyright 2018 Joyent, Inc.
|
||||||
*
|
*
|
||||||
* `triton instance create ...`
|
* `triton instance create ...`
|
||||||
*/
|
*/
|
||||||
@ -376,6 +376,9 @@ function do_create(subcmd, opts, args, cb) {
|
|||||||
function (net) { return net.id; })
|
function (net) { return net.id; })
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (opts.brand) {
|
||||||
|
createOpts.brand = opts.brand;
|
||||||
|
}
|
||||||
if (ctx.volMounts) {
|
if (ctx.volMounts) {
|
||||||
createOpts.volumes = ctx.volMounts;
|
createOpts.volumes = ctx.volMounts;
|
||||||
}
|
}
|
||||||
@ -492,6 +495,13 @@ do_create.options = [
|
|||||||
{
|
{
|
||||||
group: 'Create options'
|
group: 'Create options'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
names: ['brand'],
|
||||||
|
helpArg: 'BRAND',
|
||||||
|
type: 'string',
|
||||||
|
help: 'Override the default brand for this instance. Most users will ' +
|
||||||
|
'not need this option.'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
names: ['name', 'n'],
|
names: ['name', 'n'],
|
||||||
helpArg: 'NAME',
|
helpArg: 'NAME',
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, Joyent, Inc.
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
*
|
*
|
||||||
* `triton instance list ...`
|
* `triton instance list ...`
|
||||||
*/
|
*/
|
||||||
@ -150,6 +150,7 @@ function do_list(subcmd, opts, args, callback) {
|
|||||||
common.uuidToShortId(inst.image);
|
common.uuidToShortId(inst.image);
|
||||||
inst.shortid = inst.id.split('-', 1)[0];
|
inst.shortid = inst.id.split('-', 1)[0];
|
||||||
var flags = [];
|
var flags = [];
|
||||||
|
if (inst.brand === 'bhyve') flags.push('B');
|
||||||
if (inst.docker) flags.push('D');
|
if (inst.docker) flags.push('D');
|
||||||
if (inst.firewall_enabled) flags.push('F');
|
if (inst.firewall_enabled) flags.push('F');
|
||||||
if (inst.brand === 'kvm') flags.push('K');
|
if (inst.brand === 'kvm') flags.push('K');
|
||||||
@ -208,6 +209,7 @@ do_list.help = [
|
|||||||
'for convenience):',
|
'for convenience):',
|
||||||
' shortid* A short ID prefix.',
|
' shortid* A short ID prefix.',
|
||||||
' flags* Single letter flags summarizing some fields:',
|
' flags* Single letter flags summarizing some fields:',
|
||||||
|
' "B" the brand is "bhyve"',
|
||||||
' "D" docker instance',
|
' "D" docker instance',
|
||||||
' "F" firewall is enabled',
|
' "F" firewall is enabled',
|
||||||
' "K" the brand is "kvm"',
|
' "K" the brand is "kvm"',
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Joyent, Inc.
|
* Copyright 2018 Joyent, Inc.
|
||||||
*
|
*
|
||||||
* `triton snapshot create ...`
|
* `triton snapshot create ...`
|
||||||
*/
|
*/
|
||||||
@ -133,7 +133,7 @@ do_create.help = [
|
|||||||
'{{usage}}',
|
'{{usage}}',
|
||||||
'',
|
'',
|
||||||
'{{options}}',
|
'{{options}}',
|
||||||
'Snapshot do not work for instances of type "kvm".'
|
'Snapshots do not work for instances of type "bhyve" or "kvm".'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
do_create.completionArgtypes = ['tritoninstance', 'none'];
|
do_create.completionArgtypes = ['tritoninstance', 'none'];
|
||||||
|
109
lib/tritonapi.js
109
lib/tritonapi.js
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2017 Joyent, Inc.
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* BEGIN JSSTYLED */
|
/* BEGIN JSSTYLED */
|
||||||
@ -233,10 +233,10 @@ function _stepPkgId(arg, next) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A function appropriate for `vasync.pipeline` funcs that takes a `arg.image`
|
* A function appropriate for `vasync.pipeline` funcs that takes a `arg.image`
|
||||||
* image name, shortid, or uuid, and determines the image id (setting it
|
* image name, shortid, or uuid, and determines the image object (setting it
|
||||||
* as arg.imgId).
|
* as arg.img).
|
||||||
*/
|
*/
|
||||||
function _stepImgId(arg, next) {
|
function _stepImg(arg, next) {
|
||||||
assert.object(arg.client, 'arg.client');
|
assert.object(arg.client, 'arg.client');
|
||||||
assert.string(arg.image, 'arg.image');
|
assert.string(arg.image, 'arg.image');
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ function _stepImgId(arg, next) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
next(err);
|
next(err);
|
||||||
} else {
|
} else {
|
||||||
arg.imgId = img.id;
|
arg.img = img;
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -745,10 +745,10 @@ TritonApi.prototype.exportImage = function exportImage(opts, cb)
|
|||||||
};
|
};
|
||||||
|
|
||||||
vasync.pipeline({arg: arg, funcs: [
|
vasync.pipeline({arg: arg, funcs: [
|
||||||
_stepImgId,
|
_stepImg,
|
||||||
function cloudApiExportImage(ctx, next) {
|
function cloudApiExportImage(ctx, next) {
|
||||||
self.cloudapi.exportImage({
|
self.cloudapi.exportImage({
|
||||||
id: ctx.imgId, manta_path: opts.manta_path },
|
id: ctx.img.id, manta_path: opts.manta_path },
|
||||||
function (err, exportInfo_, res_) {
|
function (err, exportInfo_, res_) {
|
||||||
if (err) {
|
if (err) {
|
||||||
next(err);
|
next(err);
|
||||||
@ -769,6 +769,101 @@ TritonApi.prototype.exportImage = function exportImage(opts, cb)
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Share an image with another account.
|
||||||
|
*
|
||||||
|
* @param {Object} opts
|
||||||
|
* - {String} image The image UUID, name, or short ID. Required.
|
||||||
|
* - {String} account The account UUID. Required.
|
||||||
|
* @param {Function} cb `function (err, img)`
|
||||||
|
* On failure `err` is an error instance, else it is null.
|
||||||
|
* On success: `img` is an image object.
|
||||||
|
*/
|
||||||
|
TritonApi.prototype.shareImage = function shareImage(opts, cb)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.string(opts.image, 'opts.image');
|
||||||
|
assert.string(opts.account, 'opts.account');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var arg = {
|
||||||
|
image: opts.image,
|
||||||
|
client: self
|
||||||
|
};
|
||||||
|
var res;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: arg, funcs: [
|
||||||
|
_stepImg,
|
||||||
|
function validateAcl(ctx, next) {
|
||||||
|
ctx.acl = ctx.img.acl && ctx.img.acl.slice() || [];
|
||||||
|
if (ctx.acl.indexOf(opts.account) === -1) {
|
||||||
|
ctx.acl.push(opts.account);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
function cloudApiShareImage(ctx, next) {
|
||||||
|
self.cloudapi.updateImage({id: ctx.img.id, fields: {acl: ctx.acl}},
|
||||||
|
function _updateImageCb(err, img) {
|
||||||
|
res = img;
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unshare an image with another account.
|
||||||
|
*
|
||||||
|
* @param {Object} opts
|
||||||
|
* - {String} image The image UUID, name, or short ID. Required.
|
||||||
|
* - {String} account The account UUID. Required.
|
||||||
|
* @param {Function} cb `function (err, img)`
|
||||||
|
* On failure `err` is an error instance, else it is null.
|
||||||
|
* On success: `img` is an image object.
|
||||||
|
*/
|
||||||
|
TritonApi.prototype.unshareImage = function unshareImage(opts, cb)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.string(opts.image, 'opts.image');
|
||||||
|
assert.string(opts.account, 'opts.account');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var arg = {
|
||||||
|
image: opts.image,
|
||||||
|
client: self
|
||||||
|
};
|
||||||
|
var res;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: arg, funcs: [
|
||||||
|
_stepImg,
|
||||||
|
function validateAcl(ctx, next) {
|
||||||
|
assert.object(ctx.img, 'img');
|
||||||
|
ctx.acl = ctx.img.acl && ctx.img.acl.slice() || [];
|
||||||
|
var aclIdx = ctx.acl.indexOf(opts.account);
|
||||||
|
if (aclIdx === -1) {
|
||||||
|
cb(new errors.TritonError(format('image is not shared with %s',
|
||||||
|
opts.account)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.acl.splice(aclIdx, 1);
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
function cloudApiUnshareImage(ctx, next) {
|
||||||
|
self.cloudapi.updateImage({id: ctx.img.id, fields: {acl: ctx.acl}},
|
||||||
|
function _updateImageCb(err, img) {
|
||||||
|
res = img;
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an active package by ID, exact name, or short ID, in that order.
|
* Get an active package by ID, exact name, or short ID, in that order.
|
||||||
*
|
*
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "spearhead",
|
"name": "spearhead",
|
||||||
"description": "Spearhead Cloud CLI and client (https://spearhead.cloud)",
|
"description": "Spearhead Cloud CLI and client (https://spearhead.cloud)",
|
||||||
"version": "5.6.4",
|
"version": "5.8.0",
|
||||||
"author": "Spearhead Systems (spearhead.systems)",
|
"author": "Spearhead Systems (spearhead.systems)",
|
||||||
"homepage": "https://code.spearhead.cloud/Spearhead/node-spearhead",
|
"homepage": "https://code.spearhead.cloud/Spearhead/node-spearhead",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -33,7 +33,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"tape": "4.2.0",
|
"tape": "4.2.0",
|
||||||
"tap-summary": "3.0.2"
|
"tap-summary": "3.0.2",
|
||||||
|
"uuid": "3.2.1"
|
||||||
},
|
},
|
||||||
"main": "./lib",
|
"main": "./lib",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -26,6 +26,11 @@
|
|||||||
// to true.
|
// to true.
|
||||||
"skipAffinityTests": false,
|
"skipAffinityTests": false,
|
||||||
|
|
||||||
|
// Optional. Set to 'true' to skip testing of bhyve things. Some DCs might
|
||||||
|
// not support bhyve (no packages or images available, and/or no CNs with
|
||||||
|
// bhyve compatible hardware).
|
||||||
|
"skipBhyveTests": false,
|
||||||
|
|
||||||
// Optional. Set to 'true' to skip testing of KVM things. Some DCs might
|
// Optional. Set to 'true' to skip testing of KVM things. Some DCs might
|
||||||
// not support KVM (no KVM packages or images available).
|
// not support KVM (no KVM packages or images available).
|
||||||
"skipKvmTests": false,
|
"skipKvmTests": false,
|
||||||
@ -36,6 +41,12 @@
|
|||||||
"resizePackage": "<package name>",
|
"resizePackage": "<package name>",
|
||||||
"image": "<image uuid, name or name@version>"
|
"image": "<image uuid, name or name@version>"
|
||||||
|
|
||||||
|
// The params used for test *bhyve* provisions. By default the tests use:
|
||||||
|
// the smallest RAM package with "kvm" in the name, the latest
|
||||||
|
// ubuntu-certified image.
|
||||||
|
"bhyvePackage": "<package name or uuid>",
|
||||||
|
"bhyveImage": "<image uuid, name or name@version>",
|
||||||
|
|
||||||
// The params used for test *KVM* provisions. By default the tests use:
|
// The params used for test *KVM* provisions. By default the tests use:
|
||||||
// the smallest RAM package with "kvm" in the name, the latest
|
// the smallest RAM package with "kvm" in the name, the latest
|
||||||
// ubuntu-certified image.
|
// ubuntu-certified image.
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2016, Joyent, Inc.
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -15,6 +15,7 @@
|
|||||||
var format = require('util').format;
|
var format = require('util').format;
|
||||||
var os = require('os');
|
var os = require('os');
|
||||||
var test = require('tape');
|
var test = require('tape');
|
||||||
|
var uuid = require('uuid');
|
||||||
var vasync = require('vasync');
|
var vasync = require('vasync');
|
||||||
|
|
||||||
var common = require('../../lib/common');
|
var common = require('../../lib/common');
|
||||||
@ -37,7 +38,7 @@ var testOpts = {
|
|||||||
|
|
||||||
// --- Tests
|
// --- Tests
|
||||||
|
|
||||||
test('triton image ...', testOpts, function (tt) {
|
test('spearhead image ...', testOpts, function (tt) {
|
||||||
var imgNameVer = IMAGE_DATA.name + '@' + IMAGE_DATA.version;
|
var imgNameVer = IMAGE_DATA.name + '@' + IMAGE_DATA.version;
|
||||||
var originInst;
|
var originInst;
|
||||||
var img;
|
var img;
|
||||||
@ -48,7 +49,7 @@ test('triton image ...', testOpts, function (tt) {
|
|||||||
tt.comment(format('- %s: %j', key, value));
|
tt.comment(format('- %s: %j', key, value));
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: `triton rm -f` would be helpful for this
|
// TODO: `spearhead rm -f` would be helpful for this
|
||||||
tt.test(' setup: rm existing origin inst ' + ORIGIN_ALIAS, function (t) {
|
tt.test(' setup: rm existing origin inst ' + ORIGIN_ALIAS, function (t) {
|
||||||
h.triton(['inst', 'get', '-j', ORIGIN_ALIAS],
|
h.triton(['inst', 'get', '-j', ORIGIN_ALIAS],
|
||||||
function (err, stdout, stderr) {
|
function (err, stdout, stderr) {
|
||||||
@ -199,6 +200,62 @@ test('triton image ...', testOpts, function (tt) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tt.test(' triton image share ...', function (t) {
|
||||||
|
var dummyUuid = uuid.v4();
|
||||||
|
var argv = ['image', 'share', img.id, dummyUuid];
|
||||||
|
h.safeTriton(t, argv, function (err) {
|
||||||
|
if (err) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
argv = ['image', 'get', '-j', img.id];
|
||||||
|
h.safeTriton(t, argv, function (err2, stdout2) {
|
||||||
|
t.ifErr(err2, 'image get response');
|
||||||
|
if (err2) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var result = JSON.parse(stdout2);
|
||||||
|
t.ok(result, 'image share result');
|
||||||
|
t.ok(result.acl, 'image share result.acl');
|
||||||
|
if (result.acl && Array.isArray(result.acl)) {
|
||||||
|
t.notEqual(result.acl.indexOf(dummyUuid), -1,
|
||||||
|
'image share result.acl contains uuid');
|
||||||
|
} else {
|
||||||
|
t.fail('image share result does not contain acl array');
|
||||||
|
}
|
||||||
|
unshareImage();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function unshareImage() {
|
||||||
|
argv = ['image', 'unshare', img.id, dummyUuid];
|
||||||
|
h.safeTriton(t, argv, function (err) {
|
||||||
|
if (err) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
argv = ['image', 'get', '-j', img.id];
|
||||||
|
h.safeTriton(t, argv, function (err2, stdout2) {
|
||||||
|
t.ifErr(err2, 'image get response');
|
||||||
|
if (err2) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var result = JSON.parse(stdout2);
|
||||||
|
t.ok(result, 'image unshare result');
|
||||||
|
if (result.acl && Array.isArray(result.acl)) {
|
||||||
|
t.equal(result.acl.indexOf(dummyUuid), -1,
|
||||||
|
'image unshare result.acl should not contain uuid');
|
||||||
|
} else {
|
||||||
|
t.equal(result.acl, undefined, 'image has no acl');
|
||||||
|
}
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: Once have `triton ssh ...` working in test suite without hangs,
|
// TODO: Once have `triton ssh ...` working in test suite without hangs,
|
||||||
// then want to check that the created VM has the markerFile.
|
// then want to check that the created VM has the markerFile.
|
||||||
|
|
||||||
|
92
test/integration/cli-instance-create-bhyve.test.js
Normal file
92
test/integration/cli-instance-create-bhyve.test.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2018, Joyent, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test creating a bhyve VM.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var os = require('os');
|
||||||
|
|
||||||
|
var format = require('util').format;
|
||||||
|
var test = require('tape');
|
||||||
|
|
||||||
|
var h = require('./helpers');
|
||||||
|
|
||||||
|
|
||||||
|
// --- globals
|
||||||
|
|
||||||
|
var INST_ALIAS = 'nodetritontest-instance-create-bhyve-' +
|
||||||
|
os.hostname();
|
||||||
|
|
||||||
|
var testOpts = {
|
||||||
|
skip: !h.CONFIG.allowWriteActions || h.CONFIG.skipBhyveTests
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// --- Tests
|
||||||
|
|
||||||
|
test('triton image ...', testOpts, function (tt) {
|
||||||
|
var imgId;
|
||||||
|
var inst;
|
||||||
|
var pkgId;
|
||||||
|
|
||||||
|
tt.comment('Test config:');
|
||||||
|
Object.keys(h.CONFIG).forEach(function (key) {
|
||||||
|
var value = h.CONFIG[key];
|
||||||
|
tt.comment(format('- %s: %j', key, value));
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: `triton rm -f` would be helpful for this
|
||||||
|
tt.test(' setup: rm existing inst ' + INST_ALIAS, function (t) {
|
||||||
|
h.deleteTestInst(t, INST_ALIAS, function onDel() {
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' setup: find image', function (t) {
|
||||||
|
h.getTestBhyveImg(t, function (err, _imgId) {
|
||||||
|
t.ifError(err, 'getTestImg' + (err ? ': ' + err : ''));
|
||||||
|
imgId = _imgId;
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' setup: find test package', function (t) {
|
||||||
|
h.getTestBhyvePkg(t, function (err, _pkgId) {
|
||||||
|
t.ifError(err, 'getTestPkg' + (err ? ': ' + err : ''));
|
||||||
|
pkgId = _pkgId;
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' setup: triton create ... -n ' + INST_ALIAS, function (t) {
|
||||||
|
var argv = ['create', '-wj', '--brand=bhyve', '-n', INST_ALIAS,
|
||||||
|
imgId, pkgId];
|
||||||
|
h.safeTriton(t, argv, function (err, stdout) {
|
||||||
|
var lines = h.jsonStreamParse(stdout);
|
||||||
|
inst = lines[1];
|
||||||
|
t.ok(inst.id, 'inst.id: ' + inst.id);
|
||||||
|
t.equal(lines[1].state, 'running', 'inst is running');
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Once have `triton ssh ...` working in test suite without hangs,
|
||||||
|
// then want to check that the created VM works.
|
||||||
|
|
||||||
|
// Remove instance. Add a test timeout, because '-w' on delete doesn't
|
||||||
|
// have a way to know if the attempt failed or if it is just taking a
|
||||||
|
// really long time.
|
||||||
|
tt.test(' cleanup: spearhead rm', {timeout: 10 * 60 * 1000}, function (t) {
|
||||||
|
h.safeTriton(t, ['rm', '-w', inst.id], function () {
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2017 Joyent, Inc.
|
* Copyright 2018 Joyent, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -26,8 +26,8 @@ var testcommon = require('../lib/testcommon');
|
|||||||
|
|
||||||
|
|
||||||
var CONFIG;
|
var CONFIG;
|
||||||
var configPath = process.env.TRITON_TEST_CONFIG
|
var configPath = process.env.TSC_TEST_CONFIG
|
||||||
? path.resolve(process.cwd(), process.env.TRITON_TEST_CONFIG)
|
? path.resolve(process.cwd(), process.env.SC_TEST_CONFIG)
|
||||||
: path.resolve(__dirname, '..', 'config.json');
|
: path.resolve(__dirname, '..', 'config.json');
|
||||||
try {
|
try {
|
||||||
CONFIG = require(configPath);
|
CONFIG = require(configPath);
|
||||||
@ -44,7 +44,7 @@ try {
|
|||||||
'CONFIG.profile.insecure');
|
'CONFIG.profile.insecure');
|
||||||
} else if (CONFIG.profileName) {
|
} else if (CONFIG.profileName) {
|
||||||
CONFIG.profile = mod_triton.loadProfile({
|
CONFIG.profile = mod_triton.loadProfile({
|
||||||
configDir: path.join(process.env.HOME, '.triton'),
|
configDir: path.join(process.env.HOME, '.spearhead'),
|
||||||
name: CONFIG.profileName
|
name: CONFIG.profileName
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -55,11 +55,11 @@ try {
|
|||||||
'test/config.json#allowWriteActions');
|
'test/config.json#allowWriteActions');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error('* * *');
|
error('* * *');
|
||||||
error('node-triton integration tests require a config file. By default');
|
error('node-spearhead integration tests require a config file. By default');
|
||||||
error('it looks for "test/config.json". Or you can set the');
|
error('it looks for "test/config.json". Or you can set the');
|
||||||
error('TRITON_TEST_CONFIG envvar. E.g.:');
|
error('SC_TEST_CONFIG envvar. E.g.:');
|
||||||
error('');
|
error('');
|
||||||
error(' TRITON_TEST_CONFIG=test/coal.json make test');
|
error(' SC_TEST_CONFIG=test/coal.json make test');
|
||||||
error('');
|
error('');
|
||||||
error('See "test/config.json.sample" for a starting point for a config.');
|
error('See "test/config.json.sample" for a starting point for a config.');
|
||||||
error('');
|
error('');
|
||||||
@ -75,7 +75,7 @@ if (CONFIG.profile.insecure === undefined)
|
|||||||
if (CONFIG.allowWriteActions === undefined)
|
if (CONFIG.allowWriteActions === undefined)
|
||||||
CONFIG.allowWriteActions = false;
|
CONFIG.allowWriteActions = false;
|
||||||
|
|
||||||
var TRITON = [process.execPath, path.resolve(__dirname, '../../bin/triton')];
|
var TRITON = [process.execPath, path.resolve(__dirname, '../../bin/spearhead')];
|
||||||
var UA = 'node-triton-test';
|
var UA = 'node-triton-test';
|
||||||
|
|
||||||
var LOG = require('../lib/log');
|
var LOG = require('../lib/log');
|
||||||
@ -83,10 +83,10 @@ var LOG = require('../lib/log');
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call the `triton` CLI with the given args.
|
* Call the `spearhead` CLI with the given args.
|
||||||
*
|
*
|
||||||
* @param args {String|Array} Required. CLI arguments to `triton ...` (without
|
* @param args {String|Array} Required. CLI arguments to `spearhead ...` (without
|
||||||
* the "triton"). This can be an array of args, or a string.
|
* the "spearhead"). This can be an array of args, or a string.
|
||||||
* @param opts {Object} Optional.
|
* @param opts {Object} Optional.
|
||||||
* - opts.cwd {String} cwd option to exec.
|
* - opts.cwd {String} cwd option to exec.
|
||||||
* @param cb {Function}
|
* @param cb {Function}
|
||||||
@ -111,11 +111,11 @@ function triton(args, opts, cb) {
|
|||||||
PATH: process.env.PATH,
|
PATH: process.env.PATH,
|
||||||
HOME: process.env.HOME,
|
HOME: process.env.HOME,
|
||||||
SSH_AUTH_SOCK: process.env.SSH_AUTH_SOCK,
|
SSH_AUTH_SOCK: process.env.SSH_AUTH_SOCK,
|
||||||
TRITON_PROFILE: 'env',
|
SC_PROFILE: 'env',
|
||||||
TRITON_URL: CONFIG.profile.url,
|
SC_URL: CONFIG.profile.url,
|
||||||
TRITON_ACCOUNT: CONFIG.profile.account,
|
SC_ACCOUNT: CONFIG.profile.account,
|
||||||
TRITON_KEY_ID: CONFIG.profile.keyId,
|
SC_KEY_ID: CONFIG.profile.keyId,
|
||||||
TRITON_TLS_INSECURE: CONFIG.profile.insecure
|
SC_TLS_INSECURE: CONFIG.profile.insecure
|
||||||
},
|
},
|
||||||
cwd: opts.cwd
|
cwd: opts.cwd
|
||||||
},
|
},
|
||||||
@ -126,12 +126,12 @@ function triton(args, opts, cb) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* `triton ...` wrapper that:
|
* `spearhead ...` wrapper that:
|
||||||
* - tests non-error exit
|
* - tests non-error exit
|
||||||
* - tests stderr is empty
|
* - tests stderr is empty
|
||||||
*
|
*
|
||||||
* @param {Tape} t - tape test object
|
* @param {Tape} t - tape test object
|
||||||
* @param {Object|Array} opts - options object, or just the `triton` args
|
* @param {Object|Array} opts - options object, or just the `spearhead` args
|
||||||
* @param {Function} cb - `function (err, stdout)`
|
* @param {Function} cb - `function (err, stdout)`
|
||||||
* Note that `err` will already have been tested to be falsey via
|
* Note that `err` will already have been tested to be falsey via
|
||||||
* `t.error(err, ...)`, so it may be fine for the calling test case
|
* `t.error(err, ...)`, so it may be fine for the calling test case
|
||||||
@ -149,7 +149,7 @@ function safeTriton(t, opts, cb) {
|
|||||||
|
|
||||||
// t.comment(f('running: triton %s', opts.args.join(' ')));
|
// t.comment(f('running: triton %s', opts.args.join(' ')));
|
||||||
triton(opts.args, function (err, stdout, stderr) {
|
triton(opts.args, function (err, stdout, stderr) {
|
||||||
t.error(err, f('ran "triton %s", err=%s', opts.args.join(' '), err));
|
t.error(err, f('ran "spearhead %s", err=%s', opts.args.join(' '), err));
|
||||||
t.equal(stderr, '', 'empty stderr');
|
t.equal(stderr, '', 'empty stderr');
|
||||||
if (opts.json) {
|
if (opts.json) {
|
||||||
try {
|
try {
|
||||||
@ -211,6 +211,46 @@ function getTestImg(t, cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find and return an image that can be used for test *bhyve* provisions.
|
||||||
|
*
|
||||||
|
* @param {Tape} t - tape test object
|
||||||
|
* @param {Function} cb - `function (err, imgId)`
|
||||||
|
* where `imgId` is an image identifier (an image name, shortid, or id).
|
||||||
|
*/
|
||||||
|
function getTestBhyveImg(t, cb) {
|
||||||
|
if (CONFIG.bhyveImage) {
|
||||||
|
assert.string(CONFIG.bhyvePackage, 'CONFIG.bhyvePackage');
|
||||||
|
t.ok(CONFIG.bhyveImage, 'bhyveImage from config: ' + CONFIG.bhyveImage);
|
||||||
|
cb(null, CONFIG.bhyveImage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var candidateImageNames = {
|
||||||
|
'ubuntu-certified-16.04': true
|
||||||
|
};
|
||||||
|
safeTriton(t, ['img', 'ls', '-j'], function (err, stdout) {
|
||||||
|
var imgId;
|
||||||
|
var imgs = jsonStreamParse(stdout);
|
||||||
|
// Newest images first.
|
||||||
|
tabula.sortArrayOfObjects(imgs, ['-published_at']);
|
||||||
|
var imgRepr;
|
||||||
|
for (var i = 0; i < imgs.length; i++) {
|
||||||
|
var img = imgs[i];
|
||||||
|
if (candidateImageNames[img.name]) {
|
||||||
|
imgId = img.id;
|
||||||
|
imgRepr = f('%s@%s', img.name, img.version);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ok(imgId,
|
||||||
|
f('latest bhyve image (using subset of supported names): %s (%s)',
|
||||||
|
imgId, imgRepr));
|
||||||
|
cb(err, imgId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find and return an image that can be used for test *KVM* provisions.
|
* Find and return an image that can be used for test *KVM* provisions.
|
||||||
*
|
*
|
||||||
@ -281,6 +321,38 @@ function getTestPkg(t, cb) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find and return an package that can be used for *bhyve* test provisions.
|
||||||
|
*
|
||||||
|
* @param {Tape} t - tape test object
|
||||||
|
* @param {Function} cb - `function (err, pkgId)`
|
||||||
|
* where `pkgId` is an package identifier (a name, shortid, or id).
|
||||||
|
*/
|
||||||
|
function getTestBhyvePkg(t, cb) {
|
||||||
|
if (CONFIG.bhyvePackage) {
|
||||||
|
assert.string(CONFIG.bhyvePackage, 'CONFIG.bhyvePackage');
|
||||||
|
t.ok(CONFIG.bhyvePackage, 'bhyvePackage from config: ' +
|
||||||
|
CONFIG.bhyvePackage);
|
||||||
|
cb(null, CONFIG.bhyvePackage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bhyve uses the same packages as kvm
|
||||||
|
safeTriton(t, ['pkg', 'ls', '-j'], function (err, stdout) {
|
||||||
|
var pkgs = jsonStreamParse(stdout);
|
||||||
|
// Filter on those with 'kvm' in the name.
|
||||||
|
pkgs = pkgs.filter(function (pkg) {
|
||||||
|
return pkg.name.indexOf('kvm') !== -1;
|
||||||
|
});
|
||||||
|
// Smallest RAM first.
|
||||||
|
tabula.sortArrayOfObjects(pkgs, ['memory']);
|
||||||
|
var pkgId = pkgs[0].id;
|
||||||
|
t.ok(pkgId, f('smallest (RAM) available kvm package: %s (%s)',
|
||||||
|
pkgId, pkgs[0].name));
|
||||||
|
cb(null, pkgId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find and return an package that can be used for *KVM* test provisions.
|
* Find and return an package that can be used for *KVM* test provisions.
|
||||||
*
|
*
|
||||||
@ -361,7 +433,7 @@ function createClient(cb) {
|
|||||||
mod_triton.createClient({
|
mod_triton.createClient({
|
||||||
log: LOG,
|
log: LOG,
|
||||||
profile: CONFIG.profile,
|
profile: CONFIG.profile,
|
||||||
configDir: '~/.triton' // piggy-back on Triton CLI config dir
|
configDir: '~/.spearhead' // piggy-back on Spearhead CLI config dir
|
||||||
}, cb);
|
}, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,8 +583,10 @@ module.exports = {
|
|||||||
deleteTestImg: deleteTestImg,
|
deleteTestImg: deleteTestImg,
|
||||||
|
|
||||||
getTestImg: getTestImg,
|
getTestImg: getTestImg,
|
||||||
|
getTestBhyveImg: getTestBhyveImg,
|
||||||
getTestKvmImg: getTestKvmImg,
|
getTestKvmImg: getTestKvmImg,
|
||||||
getTestPkg: getTestPkg,
|
getTestPkg: getTestPkg,
|
||||||
|
getTestBhyvePkg: getTestBhyvePkg,
|
||||||
getTestKvmPkg: getTestKvmPkg,
|
getTestKvmPkg: getTestKvmPkg,
|
||||||
getResizeTestPkg: getResizeTestPkg,
|
getResizeTestPkg: getResizeTestPkg,
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user