2015-09-25 00:48:26 +03:00
|
|
|
/*
|
|
|
|
* 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) 2015, Joyent, Inc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Test create/start/stop/delete/etc. work flows
|
|
|
|
*/
|
|
|
|
|
|
|
|
var f = require('util').format;
|
2015-10-07 09:09:52 +03:00
|
|
|
var os = require('os');
|
|
|
|
var test = require('tape');
|
2015-09-25 00:48:26 +03:00
|
|
|
var vasync = require('vasync');
|
|
|
|
|
2015-10-07 09:09:52 +03:00
|
|
|
var common = require('../../lib/common');
|
2015-09-25 00:48:26 +03:00
|
|
|
var h = require('./helpers');
|
|
|
|
|
|
|
|
|
2015-10-07 09:09:52 +03:00
|
|
|
// --- globals
|
|
|
|
|
2016-02-09 22:23:55 +02:00
|
|
|
var INST_ALIAS = f('nodetritontest-managewf-%s', os.hostname());
|
2016-12-21 04:30:24 +02:00
|
|
|
var INST_ALIAS_NEWNAME = INST_ALIAS + '-renamed';
|
2015-09-25 00:48:26 +03:00
|
|
|
|
2015-09-25 20:45:16 +03:00
|
|
|
var opts = {
|
2015-10-07 22:19:26 +03:00
|
|
|
skip: !h.CONFIG.allowWriteActions
|
2015-09-25 20:45:16 +03:00
|
|
|
};
|
2015-09-25 00:48:26 +03:00
|
|
|
|
|
|
|
// global variable to hold vm instance JSON
|
|
|
|
var instance;
|
|
|
|
|
2015-09-25 22:24:37 +03:00
|
|
|
|
2015-09-25 00:48:26 +03:00
|
|
|
// --- Tests
|
|
|
|
|
2015-09-25 20:45:16 +03:00
|
|
|
if (opts.skip) {
|
2015-10-07 22:19:26 +03:00
|
|
|
console.error('** skipping %s tests', __filename);
|
|
|
|
console.error('** set "allowWriteActions" in test config to enable');
|
2015-09-25 20:45:16 +03:00
|
|
|
}
|
2015-09-25 22:24:37 +03:00
|
|
|
test('triton manage workflow', opts, function (tt) {
|
2016-02-04 15:39:50 +02:00
|
|
|
h.printConfig(tt);
|
2015-10-07 09:09:52 +03:00
|
|
|
|
|
|
|
tt.test(' cleanup existing inst with alias ' + INST_ALIAS, function (t) {
|
2016-02-04 15:39:50 +02:00
|
|
|
h.deleteTestInst(t, INST_ALIAS, function (err) {
|
|
|
|
t.ifErr(err);
|
|
|
|
t.end();
|
2015-10-07 09:09:52 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
var imgId;
|
2016-02-09 22:23:55 +02:00
|
|
|
tt.test(' setup: find test image', function (t) {
|
|
|
|
h.getTestImg(t, function (err, imgId_) {
|
|
|
|
t.ifError(err, 'getTestImg' + (err ? ': ' + err : ''));
|
|
|
|
imgId = imgId_;
|
2015-10-07 09:09:52 +03:00
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
var pkgId;
|
2016-02-09 22:23:55 +02:00
|
|
|
tt.test(' setup: find test package', function (t) {
|
|
|
|
h.getTestPkg(t, function (err, pkgId_) {
|
|
|
|
t.ifError(err, 'getTestPkg' + (err ? ': ' + err : ''));
|
|
|
|
pkgId = pkgId_;
|
2015-10-07 09:09:52 +03:00
|
|
|
t.end();
|
|
|
|
});
|
2015-09-29 21:45:34 +03:00
|
|
|
});
|
2015-09-25 22:24:37 +03:00
|
|
|
|
2017-02-17 03:00:32 +02:00
|
|
|
var resizePkgName;
|
|
|
|
tt.test(' setup: find resize test package', function (t) {
|
|
|
|
h.getResizeTestPkg(t, function (err, pkgName_) {
|
|
|
|
t.ifError(err, 'getResizeTestPkg' + (err ? ': ' + err : ''));
|
|
|
|
resizePkgName = pkgName_;
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-09-25 20:45:16 +03:00
|
|
|
// create a test machine (blocking) and output JSON
|
2016-02-09 22:23:55 +02:00
|
|
|
tt.test(' setup: triton create', function (t) {
|
2015-12-07 21:28:59 +02:00
|
|
|
var argv = [
|
|
|
|
'create',
|
|
|
|
'-wj',
|
|
|
|
'-m', 'foo=bar',
|
|
|
|
'--script', __dirname + '/script-log-boot.sh',
|
2015-12-31 02:11:54 +02:00
|
|
|
'--tag', 'blah=bling',
|
2015-12-07 21:28:59 +02:00
|
|
|
'-n', INST_ALIAS,
|
|
|
|
imgId, pkgId
|
|
|
|
];
|
|
|
|
|
2016-02-09 22:23:55 +02:00
|
|
|
h.safeTriton(t, argv, function (err, stdout) {
|
|
|
|
var lines = h.jsonStreamParse(stdout);
|
2015-09-25 20:45:16 +03:00
|
|
|
instance = lines[1];
|
|
|
|
t.equal(lines[0].id, lines[1].id, 'correct UUID given');
|
2015-12-07 21:28:59 +02:00
|
|
|
t.equal(lines[0].metadata.foo, 'bar', 'foo metadata set');
|
|
|
|
t.ok(lines[0].metadata['user-script'], 'user-script set');
|
2015-12-31 02:11:54 +02:00
|
|
|
t.equal(lines[0].tags.blah, 'bling', 'blah tag set');
|
2015-09-25 20:45:16 +03:00
|
|
|
t.equal(lines[1].state, 'running', 'correct machine state');
|
2015-09-25 00:48:26 +03:00
|
|
|
|
2015-09-25 20:45:16 +03:00
|
|
|
t.end();
|
|
|
|
});
|
2015-09-25 00:48:26 +03:00
|
|
|
});
|
|
|
|
|
2015-09-25 20:45:16 +03:00
|
|
|
// test `triton instance -j` with the UUID, the alias, and the short ID
|
2016-01-04 20:45:13 +02:00
|
|
|
tt.test(' triton instance get', function (t) {
|
2015-09-25 20:45:16 +03:00
|
|
|
var uuid = instance.id;
|
|
|
|
var shortId = common.uuidToShortId(uuid);
|
|
|
|
vasync.parallel({
|
|
|
|
funcs: [
|
|
|
|
function (cb) {
|
2016-02-09 22:23:55 +02:00
|
|
|
h.safeTriton(t, ['instance', 'get', '-j', INST_ALIAS], cb);
|
2015-09-25 20:45:16 +03:00
|
|
|
},
|
|
|
|
function (cb) {
|
2016-02-09 22:23:55 +02:00
|
|
|
h.safeTriton(t, ['instance', 'get', '-j', uuid], cb);
|
2015-09-25 20:45:16 +03:00
|
|
|
},
|
|
|
|
function (cb) {
|
2016-02-09 22:23:55 +02:00
|
|
|
h.safeTriton(t, ['instance', 'get', '-j', shortId], cb);
|
2015-09-25 22:24:37 +03:00
|
|
|
}
|
|
|
|
]
|
2015-09-25 20:45:16 +03:00
|
|
|
}, function (err, results) {
|
|
|
|
if (h.ifErr(t, err, 'no error'))
|
|
|
|
return t.end();
|
|
|
|
|
|
|
|
var output;
|
|
|
|
try {
|
|
|
|
output = results.operations.map(function (op) {
|
|
|
|
return JSON.parse(op.result);
|
2015-09-25 00:48:26 +03:00
|
|
|
});
|
2015-09-25 20:45:16 +03:00
|
|
|
} catch (e) {
|
|
|
|
t.fail('failed to parse JSON');
|
|
|
|
t.end();
|
|
|
|
}
|
|
|
|
|
2015-12-07 21:28:59 +02:00
|
|
|
t.equal(output[0].metadata.foo, 'bar', 'foo metadata set');
|
2015-09-25 20:45:16 +03:00
|
|
|
output.forEach(function (res) {
|
|
|
|
t.deepEqual(output[0], res, 'same data');
|
2015-09-25 00:48:26 +03:00
|
|
|
});
|
|
|
|
|
2015-09-25 20:45:16 +03:00
|
|
|
t.end();
|
2015-09-25 00:48:26 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-01-19 22:30:46 +02:00
|
|
|
// 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(' triton delete', {timeout: 10 * 60 * 1000}, function (t) {
|
2016-02-09 22:23:55 +02:00
|
|
|
h.safeTriton(t, ['delete', '-w', instance.id], function () {
|
2015-09-25 20:45:16 +03:00
|
|
|
t.end();
|
|
|
|
});
|
2015-09-25 00:48:26 +03:00
|
|
|
});
|
2015-09-25 22:24:37 +03:00
|
|
|
|
2016-03-02 10:05:06 +02:00
|
|
|
// Test the '410 Gone' handling from CloudAPI GetMachine.
|
|
|
|
tt.test(' triton inst get (deleted)', function (t) {
|
|
|
|
h.triton(['inst', 'get', instance.id], function (err, stdout, stderr) {
|
|
|
|
t.ok(err, 'got err: ' + err);
|
|
|
|
t.equal(err.code, 3, 'exit status of 3');
|
|
|
|
var errCodeRe = /InstanceDeleted/;
|
|
|
|
t.ok(errCodeRe.exec(stderr),
|
|
|
|
f('stderr matched %s: %j', errCodeRe, stderr));
|
|
|
|
t.ok(stdout, 'still got stdout');
|
|
|
|
var inst = JSON.parse(stdout);
|
|
|
|
t.equal(inst.state, 'deleted', 'instance state is "deleted"');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-12-07 21:28:59 +02:00
|
|
|
// TODO: would be nice to have a `triton ssh cat /var/log/boot.log` to
|
|
|
|
// verify the user-script worked.
|
|
|
|
|
2015-09-29 19:53:34 +03:00
|
|
|
// create a test machine (non-blocking)
|
2015-10-07 09:09:52 +03:00
|
|
|
tt.test(' triton create', function (t) {
|
|
|
|
h.safeTriton(t, ['create', '-jn', INST_ALIAS, imgId, pkgId],
|
2016-02-09 22:23:55 +02:00
|
|
|
function (err, stdout) {
|
2015-09-29 19:53:34 +03:00
|
|
|
|
|
|
|
// parse JSON response
|
|
|
|
var lines = stdout.trim().split('\n');
|
|
|
|
t.equal(lines.length, 1, 'correct number of JSON lines');
|
|
|
|
var d;
|
|
|
|
try {
|
|
|
|
d = JSON.parse(lines[0]);
|
|
|
|
} catch (e) {
|
|
|
|
t.fail('failed to parse JSON');
|
|
|
|
t.end();
|
|
|
|
}
|
|
|
|
instance = d;
|
|
|
|
|
|
|
|
t.equal(d.state, 'provisioning', 'correct machine state');
|
|
|
|
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// wait for the machine to start
|
2016-01-04 23:08:16 +02:00
|
|
|
tt.test(' triton inst wait', function (t) {
|
|
|
|
h.safeTriton(t, ['inst', 'wait', instance.id],
|
2016-02-09 22:23:55 +02:00
|
|
|
function (err, stdout) {
|
2015-09-29 19:53:34 +03:00
|
|
|
|
|
|
|
// parse JSON response
|
|
|
|
var lines = stdout.trim().split('\n');
|
|
|
|
t.equal(lines.length, 2, 'correct number of stdout lines');
|
|
|
|
|
|
|
|
t.ok(lines[0].match(/\(states: running, failed\)$/),
|
|
|
|
'first line correct');
|
|
|
|
t.ok(lines[1].match(/moved to state running$/),
|
|
|
|
'second line correct');
|
|
|
|
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// stop the machine
|
2015-10-07 09:09:52 +03:00
|
|
|
tt.test(' triton stop', function (t) {
|
2016-02-09 22:23:55 +02:00
|
|
|
h.safeTriton(t, ['stop', '-w', INST_ALIAS], function (err, stdout) {
|
2015-09-29 19:53:34 +03:00
|
|
|
t.ok(stdout.match(/^Stop instance/, 'correct stdout'));
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// wait for the machine to stop
|
2015-10-07 09:09:52 +03:00
|
|
|
tt.test(' triton confirm stopped', function (t) {
|
2016-01-04 20:45:13 +02:00
|
|
|
h.safeTriton(t, {json: true, args: ['inst', 'get', '-j', INST_ALIAS]},
|
2016-02-09 22:23:55 +02:00
|
|
|
function (err, d) {
|
2015-09-29 19:53:34 +03:00
|
|
|
instance = d;
|
|
|
|
t.equal(d.state, 'stopped', 'machine stopped');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// start the machine
|
2015-10-07 09:09:52 +03:00
|
|
|
tt.test(' triton start', function (t) {
|
|
|
|
h.safeTriton(t, ['start', '-w', INST_ALIAS],
|
2016-02-09 22:23:55 +02:00
|
|
|
function (err, stdout) {
|
2015-09-29 19:53:34 +03:00
|
|
|
t.ok(stdout.match(/^Start instance/, 'correct stdout'));
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
2017-02-09 02:49:00 +02:00
|
|
|
tt.test(' confirm running', function (t) {
|
|
|
|
h.safeTriton(t, {json: true, args: ['inst', 'get', '-j', INST_ALIAS]},
|
|
|
|
function (err, d) {
|
|
|
|
instance = d;
|
|
|
|
t.equal(d.state, 'running', 'machine running');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
2015-09-29 19:53:34 +03:00
|
|
|
|
2017-02-09 02:49:00 +02:00
|
|
|
// reboot the machine
|
|
|
|
tt.test(' triton reboot', function (t) {
|
|
|
|
h.safeTriton(t, ['reboot', '-w', INST_ALIAS],
|
|
|
|
function (err, stdout) {
|
|
|
|
t.ok(stdout.match(/^Rebooting instance/),
|
|
|
|
'"Rebooting ..." in stdout');
|
|
|
|
t.ok(stdout.match(/^Rebooted instance/m),
|
|
|
|
'"Rebooted ..." in stdout');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
2015-10-07 09:09:52 +03:00
|
|
|
tt.test(' confirm running', function (t) {
|
2016-01-04 20:45:13 +02:00
|
|
|
h.safeTriton(t, {json: true, args: ['inst', 'get', '-j', INST_ALIAS]},
|
2016-02-09 22:23:55 +02:00
|
|
|
function (err, d) {
|
2015-09-29 19:53:34 +03:00
|
|
|
instance = d;
|
|
|
|
t.equal(d.state, 'running', 'machine running');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-02-17 03:00:32 +02:00
|
|
|
// resize the instance
|
|
|
|
tt.test(' triton inst resize', function (t) {
|
|
|
|
var args = ['inst', 'resize', '-w', instance.id, resizePkgName];
|
|
|
|
h.safeTriton(t, args, function (err, stdout) {
|
|
|
|
t.ok(stdout.match(/^Resizing instance/m),
|
|
|
|
'"Resizing instance" in stdout');
|
|
|
|
t.ok(stdout.match(/^Resized instance/m),
|
|
|
|
'"Resized instance" in stdout');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
tt.test(' confirm resized', function (t) {
|
|
|
|
h.safeTriton(t, {json: true, args: ['inst', 'get', '-j',
|
|
|
|
INST_ALIAS]},
|
|
|
|
function (err, inst) {
|
|
|
|
t.equal(inst.package, resizePkgName, 'instance was resized');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-12-21 04:30:24 +02:00
|
|
|
// rename the instance
|
|
|
|
tt.test(' triton inst rename', function (t) {
|
|
|
|
var args = ['inst', 'rename', '-w', instance.id, INST_ALIAS_NEWNAME];
|
|
|
|
h.safeTriton(t, args, function (err, stdout) {
|
|
|
|
t.ok(stdout.match(/^Renaming instance/m),
|
|
|
|
'"Renaming instance" in stdout');
|
|
|
|
t.ok(stdout.match(/^Renamed instance/m),
|
|
|
|
'"Renamed instance" in stdout');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
tt.test(' confirm renamed', function (t) {
|
|
|
|
h.safeTriton(t, {json: true, args: ['inst', 'get', '-j',
|
|
|
|
INST_ALIAS_NEWNAME]},
|
|
|
|
function (err, inst) {
|
|
|
|
t.equal(inst.name, INST_ALIAS_NEWNAME, 'instance was renamed');
|
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-09-29 19:53:34 +03:00
|
|
|
// remove test instance
|
2015-10-07 09:09:52 +03:00
|
|
|
tt.test(' cleanup (triton delete)', function (t) {
|
2016-02-09 22:23:55 +02:00
|
|
|
h.safeTriton(t, ['delete', '-w', instance.id], function () {
|
2015-09-29 19:53:34 +03:00
|
|
|
t.end();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-09-25 00:48:26 +03:00
|
|
|
});
|