clistyle: add support for account keys, expand subcommand tests,
some trivial bug fixes.
This commit is contained in:
parent
f4246b5faf
commit
96216c6e61
@ -212,7 +212,7 @@ function CLI() {
|
||||
{ group: 'Other Commands' },
|
||||
'info',
|
||||
'account',
|
||||
'keys',
|
||||
'key',
|
||||
'services',
|
||||
'datacenters'
|
||||
],
|
||||
@ -337,6 +337,9 @@ CLI.prototype.do_account = require('./do_account');
|
||||
CLI.prototype.do_services = require('./do_services');
|
||||
CLI.prototype.do_datacenters = require('./do_datacenters');
|
||||
CLI.prototype.do_info = require('./do_info');
|
||||
|
||||
// Account keys
|
||||
CLI.prototype.do_key = require('./do_key');
|
||||
CLI.prototype.do_keys = require('./do_keys');
|
||||
|
||||
// Images
|
||||
|
@ -351,14 +351,103 @@ CloudApi.prototype.getAccount = function getAccount(opts, cb) {
|
||||
this._passThrough(endpoint, opts, cb);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* List account's SSH keys.
|
||||
*
|
||||
* @param {Object} opts (object)
|
||||
* @param {Function} callback of the form `function (err, keys, res)`
|
||||
*/
|
||||
CloudApi.prototype.listKeys = function listKeys(opts, cb) {
|
||||
assert.object(opts, 'opts');
|
||||
assert.func(cb, 'cb');
|
||||
|
||||
var endpoint = format('/%s/keys', this.account);
|
||||
this._passThrough(endpoint, opts, cb);
|
||||
this._passThrough(endpoint, {}, cb);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get an account's SSH key.
|
||||
*
|
||||
* @param {Object} opts (object)
|
||||
* - {String} fingerprint (required*) The SSH key fingerprint. One of
|
||||
* 'fingerprint' or 'name' is required.
|
||||
* - {String} name (required*) The SSH key name. One of 'fingerprint'
|
||||
* or 'name' is required.
|
||||
* @param {Function} callback of the form `function (err, res)`
|
||||
*/
|
||||
CloudApi.prototype.getKey = function getKey(opts, cb) {
|
||||
assert.object(opts, 'opts');
|
||||
assert.optionalString(opts.fingerprint, 'opts.fingerprint');
|
||||
assert.optionalString(opts.name, 'opts.name');
|
||||
assert.func(cb, 'cb');
|
||||
|
||||
var identifier = opts.fingerprint || opts.name;
|
||||
assert.ok(identifier, 'one of "fingerprint" or "name" is require');
|
||||
|
||||
var endpoint = format('/%s/keys/%s', this.account,
|
||||
encodeURIComponent(identifier));
|
||||
this._passThrough(endpoint, {}, cb);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create/upload a new account SSH public key.
|
||||
*
|
||||
* @param {Object} opts (object)
|
||||
* - {String} key (required) The SSH public key content.
|
||||
* - {String} name (optional) A name for the key. If not given, the
|
||||
* key fingerprint will be used.
|
||||
* @param {Function} callback of the form `function (err, res)`
|
||||
*/
|
||||
CloudApi.prototype.createKey = function createKey(opts, cb) {
|
||||
assert.object(opts, 'opts');
|
||||
assert.string(opts.key, 'opts.key');
|
||||
assert.optionalString(opts.name, 'opts.name');
|
||||
assert.func(cb, 'cb');
|
||||
|
||||
var data = {
|
||||
name: opts.name,
|
||||
key: opts.key
|
||||
};
|
||||
|
||||
this._request({
|
||||
method: 'POST',
|
||||
path: format('/%s/keys', this.account),
|
||||
data: data
|
||||
}, function (err, req, res, body) {
|
||||
cb(err, body, res);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Delete an account's SSH key.
|
||||
*
|
||||
* @param {Object} opts (object)
|
||||
* - {String} fingerprint (required*) The SSH key fingerprint. One of
|
||||
* 'fingerprint' or 'name' is required.
|
||||
* - {String} name (required*) The SSH key name. One of 'fingerprint'
|
||||
* or 'name' is required.
|
||||
* @param {Function} callback of the form `function (err, res)`
|
||||
*/
|
||||
CloudApi.prototype.deleteKey = function deleteKey(opts, cb) {
|
||||
assert.object(opts, 'opts');
|
||||
assert.optionalString(opts.fingerprint, 'opts.fingerprint');
|
||||
assert.optionalString(opts.name, 'opts.name');
|
||||
assert.func(cb, 'cb');
|
||||
|
||||
var identifier = opts.fingerprint || opts.name;
|
||||
assert.ok(identifier, 'one of "fingerprint" or "name" is require');
|
||||
|
||||
this._request({
|
||||
method: 'DELETE',
|
||||
path: format('/%s/keys/%s', this.account,
|
||||
encodeURIComponent(identifier))
|
||||
}, function (err, req, res) {
|
||||
cb(err, res);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
140
lib/do_key/do_add.js
Normal file
140
lib/do_key/do_add.js
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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 2015 Joyent, Inc.
|
||||
*
|
||||
* `triton key add ...`
|
||||
*/
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var format = require('util').format;
|
||||
var fs = require('fs');
|
||||
var sshpk = require('sshpk');
|
||||
var vasync = require('vasync');
|
||||
|
||||
var common = require('../common');
|
||||
var errors = require('../errors');
|
||||
|
||||
|
||||
function do_add(subcmd, opts, args, cb) {
|
||||
assert.optionalString(opts.name, 'opts.name');
|
||||
assert.func(cb, 'cb');
|
||||
|
||||
if (opts.help) {
|
||||
this.do_help('help', {}, [subcmd], cb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length === 0) {
|
||||
cb(new errors.UsageError('missing FILE argument'));
|
||||
return;
|
||||
} else if (args.length > 1) {
|
||||
cb(new errors.UsageError('incorrect number of arguments'));
|
||||
return;
|
||||
}
|
||||
|
||||
var filePath = args[0];
|
||||
var cli = this.top;
|
||||
|
||||
vasync.pipeline({arg: {}, funcs: [
|
||||
function gatherDataStdin(ctx, next) {
|
||||
if (filePath !== '-') {
|
||||
return next();
|
||||
}
|
||||
|
||||
var stdin = '';
|
||||
process.stdin.resume();
|
||||
process.stdin.on('data', function (chunk) {
|
||||
stdin += chunk;
|
||||
});
|
||||
|
||||
process.stdin.on('end', function () {
|
||||
ctx.data = stdin;
|
||||
ctx.from = '<stdin>';
|
||||
next();
|
||||
});
|
||||
},
|
||||
function gatherDataFile(ctx, next) {
|
||||
if (!filePath || filePath === '-') {
|
||||
return next();
|
||||
}
|
||||
|
||||
ctx.data = fs.readFileSync(filePath);
|
||||
ctx.from = filePath;
|
||||
next();
|
||||
},
|
||||
function validateData(ctx, next) {
|
||||
try {
|
||||
sshpk.parseKey(ctx.data, 'ssh', ctx.from);
|
||||
} catch (keyErr) {
|
||||
next(keyErr);
|
||||
return;
|
||||
}
|
||||
|
||||
next();
|
||||
},
|
||||
function createIt(ctx, next) {
|
||||
var createOpts = {
|
||||
userId: opts.userId,
|
||||
key: ctx.data.toString('utf8')
|
||||
};
|
||||
|
||||
if (opts.name) {
|
||||
createOpts.name = opts.name;
|
||||
}
|
||||
|
||||
cli.tritonapi.cloudapi.createKey(createOpts, function (err, key) {
|
||||
if (err) {
|
||||
next(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (key.name) {
|
||||
console.log('Added key "%s" (%s)',
|
||||
key.name, key.fingerprint);
|
||||
} else {
|
||||
console.log('Added key %s', key.fingerprint);
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
}
|
||||
]}, cb);
|
||||
}
|
||||
|
||||
|
||||
do_add.options = [
|
||||
{
|
||||
names: ['help', 'h'],
|
||||
type: 'bool',
|
||||
help: 'Show this help.'
|
||||
},
|
||||
{
|
||||
names: ['json', 'j'],
|
||||
type: 'bool',
|
||||
help: 'JSON stream output.'
|
||||
},
|
||||
{
|
||||
names: ['name', 'n'],
|
||||
type: 'string',
|
||||
helpArg: 'NAME',
|
||||
help: 'An optional name for an added key.'
|
||||
}
|
||||
];
|
||||
do_add.help = [
|
||||
'Add an SSH key to an account.',
|
||||
'',
|
||||
'Usage:',
|
||||
' {{name}} key add FILE [<options>]',
|
||||
'',
|
||||
'{{options}}',
|
||||
'',
|
||||
'Where "FILE" must be a file path to an SSH public key, ',
|
||||
'or "-" to pass the public key in on stdin.'
|
||||
].join('\n');
|
||||
|
||||
module.exports = do_add;
|
120
lib/do_key/do_delete.js
Normal file
120
lib/do_key/do_delete.js
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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 2015 Joyent, Inc.
|
||||
*
|
||||
* `triton key delete ...`
|
||||
*/
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var format = require('util').format;
|
||||
var fs = require('fs');
|
||||
var sshpk = require('sshpk');
|
||||
var vasync = require('vasync');
|
||||
|
||||
var common = require('../common');
|
||||
var errors = require('../errors');
|
||||
|
||||
|
||||
function do_delete(subcmd, opts, args, cb) {
|
||||
assert.func(cb, 'cb');
|
||||
|
||||
if (opts.help) {
|
||||
this.do_help('help', {}, [subcmd], cb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length === 0) {
|
||||
cb(new errors.UsageError('missing KEY argument(s)'));
|
||||
return;
|
||||
}
|
||||
|
||||
var cli = this.top;
|
||||
|
||||
vasync.pipeline({funcs: [
|
||||
function confirm(_, next) {
|
||||
if (opts.yes) {
|
||||
return next();
|
||||
}
|
||||
|
||||
var msg;
|
||||
if (args.length === 1) {
|
||||
msg = 'Delete key "' + args[0] + '"? [y/n] ';
|
||||
} else {
|
||||
msg = format('Delete %d keys (%s)? [y/n] ',
|
||||
args.length, args.join(', '));
|
||||
}
|
||||
|
||||
common.promptYesNo({msg: msg}, function (answer) {
|
||||
if (answer !== 'y') {
|
||||
console.error('Aborting');
|
||||
next(true); // early abort signal
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
},
|
||||
function deleteThem(_, next) {
|
||||
vasync.forEachPipeline({
|
||||
inputs: args,
|
||||
func: function deleteOne(id, nextId) {
|
||||
var delOpts = {
|
||||
fingerprint: id
|
||||
};
|
||||
|
||||
cli.tritonapi.cloudapi.deleteKey(delOpts, function (err) {
|
||||
if (err) {
|
||||
nextId(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Deleted key "%s"', id);
|
||||
nextId();
|
||||
});
|
||||
}
|
||||
}, next);
|
||||
}
|
||||
]}, function (err) {
|
||||
if (err === true) {
|
||||
err = null;
|
||||
}
|
||||
cb(err);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
do_delete.options = [
|
||||
{
|
||||
names: ['help', 'h'],
|
||||
type: 'bool',
|
||||
help: 'Show this help.'
|
||||
},
|
||||
{
|
||||
names: ['json', 'j'],
|
||||
type: 'bool',
|
||||
help: 'JSON stream output.'
|
||||
},
|
||||
{
|
||||
names: ['yes', 'y'],
|
||||
type: 'bool',
|
||||
help: 'Answer yes to confirmation to delete.'
|
||||
}
|
||||
];
|
||||
do_delete.help = [
|
||||
'Remove an SSH key from an account.',
|
||||
'',
|
||||
'Usage:',
|
||||
' {{name}} key delete FILE [<options>]',
|
||||
'',
|
||||
'{{options}}',
|
||||
'',
|
||||
'Where "KEY" is an SSH key "name" or "fingerprint".'
|
||||
].join('\n');
|
||||
|
||||
do_delete.aliases = ['rm'];
|
||||
|
||||
module.exports = do_delete;
|
80
lib/do_key/do_get.js
Normal file
80
lib/do_key/do_get.js
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 2015 Joyent, Inc.
|
||||
*
|
||||
* `triton key get ...`
|
||||
*/
|
||||
|
||||
var assert = require('assert-plus');
|
||||
|
||||
var common = require('../common');
|
||||
var errors = require('../errors');
|
||||
|
||||
|
||||
function do_get(subcmd, opts, args, cb) {
|
||||
assert.func(cb, 'cb');
|
||||
|
||||
if (opts.help) {
|
||||
this.do_help('help', {}, [subcmd], cb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length === 0) {
|
||||
cb(new errors.UsageError('missing KEY argument'));
|
||||
return;
|
||||
} else if (args.length > 1) {
|
||||
cb(new errors.UsageError('incorrect number of arguments'));
|
||||
return;
|
||||
}
|
||||
|
||||
var id = args[0];
|
||||
var cli = this.top;
|
||||
|
||||
cli.tritonapi.cloudapi.getKey({
|
||||
// Currently `cloudapi.getUserKey` isn't picky about the `name` being
|
||||
// passed in as the `opts.fingerprint` arg.
|
||||
fingerprint: id
|
||||
}, function onKey(err, key) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (opts.json) {
|
||||
console.log(JSON.stringify(key));
|
||||
} else {
|
||||
console.log(common.chomp(key.key));
|
||||
}
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
do_get.options = [
|
||||
{
|
||||
names: ['help', 'h'],
|
||||
type: 'bool',
|
||||
help: 'Show this help.'
|
||||
},
|
||||
{
|
||||
names: ['json', 'j'],
|
||||
type: 'bool',
|
||||
help: 'JSON stream output.'
|
||||
}
|
||||
];
|
||||
do_get.help = [
|
||||
'Show a specific SSH key in an account.',
|
||||
'',
|
||||
'Usage:',
|
||||
' {{name}} key get KEY # show account\'s KEY',
|
||||
'',
|
||||
'{{options}}',
|
||||
'Where "KEY" is an SSH key "name" or "fingerprint".'
|
||||
].join('\n');
|
||||
|
||||
module.exports = do_get;
|
79
lib/do_key/do_list.js
Normal file
79
lib/do_key/do_list.js
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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 2015 Joyent, Inc.
|
||||
*
|
||||
* `triton key list ...`
|
||||
*/
|
||||
|
||||
var assert = require('assert-plus');
|
||||
|
||||
var common = require('../common');
|
||||
var errors = require('../errors');
|
||||
|
||||
|
||||
function do_list(subcmd, opts, args, cb) {
|
||||
assert.func(cb, 'cb');
|
||||
|
||||
if (opts.help) {
|
||||
this.do_help('help', {}, [subcmd], cb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length > 0) {
|
||||
cb(new errors.UsageError('incorrect number of arguments'));
|
||||
return;
|
||||
}
|
||||
|
||||
var cli = this.top;
|
||||
|
||||
cli.tritonapi.cloudapi.listKeys({}, function onKeys(err, keys) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (opts.json) {
|
||||
console.log(JSON.stringify(keys));
|
||||
} else {
|
||||
keys.forEach(function (key) {
|
||||
console.log(common.chomp(key.key));
|
||||
});
|
||||
}
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
do_list.options = [
|
||||
{
|
||||
names: ['help', 'h'],
|
||||
type: 'bool',
|
||||
help: 'Show this help.'
|
||||
},
|
||||
{
|
||||
names: ['json', 'j'],
|
||||
type: 'bool',
|
||||
help: 'JSON stream output.'
|
||||
}
|
||||
];
|
||||
do_list.help = [
|
||||
'Show all of an account\'s SSH keys.',
|
||||
'',
|
||||
'Usage:',
|
||||
' {{name}} key list [<options>]',
|
||||
'',
|
||||
'{{options}}',
|
||||
'',
|
||||
'By default this lists just the key content for each key -- in other',
|
||||
'words, content appropriate for a "~/.ssh/authorized_keys" file.',
|
||||
'Use `triton keys -j` to see all fields.'
|
||||
].join('\n');
|
||||
|
||||
do_list.aliases = ['ls'];
|
||||
|
||||
module.exports = do_list;
|
48
lib/do_key/index.js
Normal file
48
lib/do_key/index.js
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 2015 Joyent, Inc.
|
||||
*
|
||||
* `triton key ...`
|
||||
*/
|
||||
|
||||
var Cmdln = require('cmdln').Cmdln;
|
||||
var util = require('util');
|
||||
|
||||
|
||||
|
||||
// ---- CLI class
|
||||
|
||||
function KeyCLI(top) {
|
||||
this.top = top;
|
||||
|
||||
Cmdln.call(this, {
|
||||
name: top.name + ' key',
|
||||
desc: 'Account SSH key commands.',
|
||||
helpSubcmds: [
|
||||
'help',
|
||||
{ group: 'Key Resources' },
|
||||
'add',
|
||||
'list',
|
||||
'get',
|
||||
'delete'
|
||||
]
|
||||
});
|
||||
}
|
||||
util.inherits(KeyCLI, Cmdln);
|
||||
|
||||
KeyCLI.prototype.init = function init(opts, args, cb) {
|
||||
this.log = this.top.log;
|
||||
Cmdln.prototype.init.apply(this, arguments);
|
||||
};
|
||||
|
||||
KeyCLI.prototype.do_add = require('./do_add');
|
||||
KeyCLI.prototype.do_get = require('./do_get');
|
||||
KeyCLI.prototype.do_list = require('./do_list');
|
||||
KeyCLI.prototype.do_delete = require('./do_delete');
|
||||
|
||||
module.exports = KeyCLI;
|
@ -7,62 +7,21 @@
|
||||
/*
|
||||
* Copyright 2015 Joyent, Inc.
|
||||
*
|
||||
* `triton keys ...`
|
||||
* `triton keys ...` bwcompat shortcut for `triton keys list ...`.
|
||||
*/
|
||||
|
||||
var common = require('./common');
|
||||
var errors = require('./errors');
|
||||
|
||||
|
||||
function do_keys(subcmd, opts, args, cb) {
|
||||
if (opts.help) {
|
||||
this.do_help('help', {}, [subcmd], cb);
|
||||
return;
|
||||
} else if (args.length !== 0) {
|
||||
cb(new errors.UsageError('invalid args: ' + args));
|
||||
return;
|
||||
}
|
||||
|
||||
this.tritonapi.cloudapi.listKeys(function (err, keys) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (opts.json) {
|
||||
common.jsonStream(keys);
|
||||
} else {
|
||||
keys.forEach(function (key) {
|
||||
console.log(common.chomp(key.key));
|
||||
});
|
||||
}
|
||||
cb();
|
||||
});
|
||||
function do_keys(subcmd, opts, args, callback) {
|
||||
var subcmdArgv = ['node', 'triton', 'key', 'list'].concat(args);
|
||||
this.dispatch('key', subcmdArgv, callback);
|
||||
}
|
||||
|
||||
do_keys.options = [
|
||||
{
|
||||
names: ['help', 'h'],
|
||||
type: 'bool',
|
||||
help: 'Show this help.'
|
||||
},
|
||||
{
|
||||
names: ['json', 'j'],
|
||||
type: 'bool',
|
||||
help: 'JSON output.'
|
||||
}
|
||||
];
|
||||
do_keys.help = (
|
||||
'Show account SSH keys.\n'
|
||||
+ '\n'
|
||||
+ 'Usage:\n'
|
||||
+ ' {{name}} keys [<options>]\n'
|
||||
+ '\n'
|
||||
+ '{{options}}'
|
||||
+ '\n'
|
||||
+ 'By default this lists just the key content for each key -- in other\n'
|
||||
+ 'words, content appropriate for a "~/.ssh/authorized_keys" file.\n'
|
||||
+ 'Use `triton keys -j` to see all fields.\n'
|
||||
);
|
||||
do_keys.help = [
|
||||
'A shortcut for "triton key list".',
|
||||
'',
|
||||
'Usage:',
|
||||
' {{name}} key ...'
|
||||
].join('\n');
|
||||
|
||||
do_keys.hidden = true;
|
||||
|
||||
module.exports = do_keys;
|
||||
|
@ -156,7 +156,7 @@ do_list.options = [
|
||||
|
||||
do_list.help = [
|
||||
/* BEGIN JSSTYLED */
|
||||
'List packgaes.',
|
||||
'List packages.',
|
||||
'',
|
||||
'Usage:',
|
||||
' {{name}} package list [<filters>]',
|
||||
|
@ -22,8 +22,6 @@ do_profiles.help = [
|
||||
' {{name}} profiles ...'
|
||||
].join('\n');
|
||||
|
||||
do_profiles.aliases = ['imgs'];
|
||||
|
||||
do_profiles.hidden = true;
|
||||
|
||||
module.exports = do_profiles;
|
||||
|
95
test/integration/cli-keys.test.js
Normal file
95
test/integration/cli-keys.test.js
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Integration tests for `triton key ...`
|
||||
*/
|
||||
|
||||
var h = require('./helpers');
|
||||
var test = require('tape');
|
||||
var backoff = require('backoff');
|
||||
|
||||
|
||||
|
||||
// --- Globals
|
||||
|
||||
var KEY_PATH = 'data/id_rsa.pub';
|
||||
var KEY_SIG = '66:ca:1c:09:75:99:35:69:be:91:08:25:03:c0:17:c0';
|
||||
var KEY_EMAIL = 'test@localhost.local';
|
||||
var MAX_CHECK_KEY_TRIES = 10;
|
||||
|
||||
// --- Tests
|
||||
|
||||
test('triton key', function (tt) {
|
||||
tt.test(' triton key add', function (t) {
|
||||
h.triton('key add ' + KEY_PATH, function (err, stdout, stderr) {
|
||||
if (h.ifErr(t, err, 'triton key add'))
|
||||
return t.end();
|
||||
|
||||
t.ok(stdout.match('Added key "' + KEY_SIG + '"'));
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
tt.test(' triton key get', function (t) {
|
||||
h.triton('key get ' + KEY_SIG, function (err, stdout, stderr) {
|
||||
if (h.ifErr(t, err, 'triton key get'))
|
||||
return t.end();
|
||||
|
||||
t.ok(stdout.match(KEY_EMAIL));
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
tt.test(' triton key list', function (t) {
|
||||
h.triton('key list', function (err, stdout, stderr) {
|
||||
if (h.ifErr(t, err, 'triton key list'))
|
||||
return t.end();
|
||||
|
||||
// there should always be at least two keys -- the original
|
||||
// account's key, and the test key these tests added
|
||||
var keys = stdout.split('\n');
|
||||
t.ok(keys.length > 2, 'triton key list expected key num');
|
||||
|
||||
var testKeys = keys.filter(function (key) {
|
||||
return key.match(KEY_EMAIL);
|
||||
});
|
||||
|
||||
// this test is a tad dodgy, since it's plausible that there might
|
||||
// be other test keys with different signatures lying around
|
||||
t.equal(testKeys.length, 1, 'triton key list test key found');
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
tt.test(' triton key delete', function (t) {
|
||||
var cmd = 'key delete ' + KEY_SIG + ' --yes';
|
||||
h.triton(cmd, function (err, stdout, stderr) {
|
||||
if (h.ifErr(t, err, 'triton key delete'))
|
||||
return t.end();
|
||||
|
||||
t.ok(stdout.match('Deleted key "' + KEY_SIG + '"'));
|
||||
|
||||
// verify key is gone, which sometimes takes a while
|
||||
var call = backoff.call(function checkKey(next) {
|
||||
h.triton('key get ' + KEY_SIG, function (err2) {
|
||||
next(!err2);
|
||||
});
|
||||
}, function (err3) {
|
||||
h.ifErr(t, err3, 'triton key delete did not remove key');
|
||||
t.end();
|
||||
});
|
||||
|
||||
call.failAfter(MAX_CHECK_KEY_TRIES);
|
||||
call.start();
|
||||
});
|
||||
});
|
||||
});
|
@ -22,9 +22,13 @@ var common = require('../../lib/common');
|
||||
var subs = [
|
||||
['info'],
|
||||
['profile'],
|
||||
['profiles'],
|
||||
['profile list', 'profile ls', 'profiles'],
|
||||
['profile get'],
|
||||
['profile set-current'],
|
||||
['profile create'],
|
||||
['profile edit'],
|
||||
['profile delete', 'profile rm'],
|
||||
['account', 'whoami'],
|
||||
['keys'],
|
||||
['services'],
|
||||
['datacenters'],
|
||||
['create-instance', 'create'],
|
||||
@ -37,12 +41,35 @@ var subs = [
|
||||
['delete-instance', 'delete'],
|
||||
['wait-instance', 'wait'],
|
||||
['ssh'],
|
||||
['images', 'imgs'],
|
||||
['image', 'img'],
|
||||
['packages', 'pkgs'],
|
||||
['package', 'pkg'],
|
||||
['networks'],
|
||||
['network']
|
||||
['network'],
|
||||
['key'],
|
||||
['key add'],
|
||||
['key list', 'key ls', 'keys'],
|
||||
['key get'],
|
||||
['key delete', 'key rm'],
|
||||
['image', 'img'],
|
||||
['image get'],
|
||||
['image list', 'images', 'imgs'],
|
||||
['package', 'pkg'],
|
||||
['package get'],
|
||||
['package list', 'packages', 'pkgs'],
|
||||
['rbac'],
|
||||
['rbac info'],
|
||||
['rbac apply'],
|
||||
['rbac users'],
|
||||
['rbac user'],
|
||||
['rbac keys'],
|
||||
['rbac key'],
|
||||
['rbac policies'],
|
||||
['rbac policy'],
|
||||
['rbac roles'],
|
||||
['rbac role'],
|
||||
['rbac instance-role-tags'],
|
||||
['rbac image-role-tags'],
|
||||
['rbac network-role-tags'],
|
||||
['rbac package-role-tags'],
|
||||
['rbac role-tags']
|
||||
];
|
||||
|
||||
// --- Tests
|
||||
@ -58,8 +85,11 @@ test('triton subcommands', function (ttt) {
|
||||
// triton help <subcmd>
|
||||
// triton <subcmd> -h
|
||||
subcmds.forEach(function (subcmd) {
|
||||
tt.test(f(' triton help %s', subcmd), function (t) {
|
||||
h.triton(['help', subcmd], function (err, stdout, stderr) {
|
||||
var helpArgs = subcmd.split(' ');
|
||||
helpArgs.splice(helpArgs.length - 1, 0, 'help');
|
||||
|
||||
tt.test(f(' triton %s', helpArgs.join(' ')), function (t) {
|
||||
h.triton(helpArgs, function (err, stdout, stderr) {
|
||||
if (h.ifErr(t, err, 'no error'))
|
||||
return t.end();
|
||||
t.equal(stderr, '', 'stderr produced');
|
||||
@ -69,8 +99,10 @@ test('triton subcommands', function (ttt) {
|
||||
});
|
||||
});
|
||||
|
||||
tt.test(f(' triton %s -h', subcmd), function (t) {
|
||||
h.triton([subcmd, '-h'], function (err, stdout, stderr) {
|
||||
var flagArgs = subcmd.split(' ').concat('-h');
|
||||
|
||||
tt.test(f(' triton %s', flagArgs.join(' ')), function (t) {
|
||||
h.triton(flagArgs, function (err, stdout, stderr) {
|
||||
if (h.ifErr(t, err, 'no error'))
|
||||
return t.end();
|
||||
t.equal(stderr, '', 'stderr produced');
|
||||
|
1
test/integration/data/id_rsa.pub
Normal file
1
test/integration/data/id_rsa.pub
Normal file
@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNr4q9zMKtylAZGr17fjtUfH2gS+6Gx4m3TJ1H5QwC97JCmtTgke/PBRSEacbXjsYlBjJ9DifNpIbrZrP9hOGhknPDyC3EaRUe/TCUCVGRiHFspurxZAiHvfENCQcvDaVcu9/tO3QyGjDSoYSaQ6NNvl8+yPZ6+mGtXeMnXlCWEvhy/fe3yNVp0isvSIinB2paI+pQqmytJ8omCGShdLqq4/Lvw/zbROe6gEb78+mvwqS+fqYDuPjGc5DXZATqM8rjOSKSPllzNILh9MbR3cHDBfhVi77jL9P8FfQv1U1SZBTbZj78xFcBRnGxrxWE0H7FcXldK5vJvafqWgxZZpgb test@localhost.local
|
Reference in New Issue
Block a user