joyent/node-triton#54 a start at 'triton rbac info', add 'triton rbac instance-role-tags'
This commit is contained in:
parent
74b8f3e42e
commit
4e45e4061f
@ -18,6 +18,10 @@
|
|||||||
- `triton rbac policy ...` to show, create, edit and delete policies.
|
- `triton rbac policy ...` to show, create, edit and delete policies.
|
||||||
- `triton rbac keys` to list all RBAC user SSH keys.
|
- `triton rbac keys` to list all RBAC user SSH keys.
|
||||||
- `triton rbac key ...` to show, create, edit and delete user keys.
|
- `triton rbac key ...` to show, create, edit and delete user keys.
|
||||||
|
- `triton rbac info` will dump a summary of the full current RBAC
|
||||||
|
configuration. This command is still in development.
|
||||||
|
- `triton rbac instance-role-tags ...` to list and manage role tags
|
||||||
|
on an instance.
|
||||||
|
|
||||||
|
|
||||||
## 2.1.4
|
## 2.1.4
|
||||||
|
@ -224,7 +224,7 @@ CloudApi.prototype._request = function _request(options, callback) {
|
|||||||
assert.optionalObject(options.data, 'options.data');
|
assert.optionalObject(options.data, 'options.data');
|
||||||
|
|
||||||
var method = (options.method || 'GET').toLowerCase();
|
var method = (options.method || 'GET').toLowerCase();
|
||||||
assert.ok(['get', 'post', 'delete', 'head'].indexOf(method) >= 0,
|
assert.ok(['get', 'post', 'put', 'delete', 'head'].indexOf(method) >= 0,
|
||||||
'invalid method given');
|
'invalid method given');
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case 'delete':
|
case 'delete':
|
||||||
@ -1170,6 +1170,69 @@ CloudApi.prototype.deletePolicy = function deletePolicy(opts, cb) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <http://apidocs.joyent.com/cloudapi/#SetRoleTags>
|
||||||
|
* Set RBAC role-tags on a resource.
|
||||||
|
*
|
||||||
|
* @param {Object} opts (object):
|
||||||
|
* - {String} resource (required) The resource URL. E.g.
|
||||||
|
* '/:account/machines/:uuid' to tag a particular machine instance.
|
||||||
|
* - {Array} roleTags (required) the array of role tags to set. Each
|
||||||
|
* role tag string is the name of a RBAC role. See `ListRoles`.
|
||||||
|
* @param {Function} cb of the form `function (err, body, res)`
|
||||||
|
* Where `body` is of the form `{name: <resource url>,
|
||||||
|
* 'role-tag': <array of added role tags>}`.
|
||||||
|
* @throws {AssertionError, TypeError} on invalid inputs
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.setRoleTags = function setRoleTags(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.string(opts.resource, 'opts.resource');
|
||||||
|
assert.arrayOfString(opts.roleTags, 'opts.roleTags');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
// Validate `resource`.
|
||||||
|
// XXX Do we need to massage '/my' to '/:account' as old cloudapi.js does?
|
||||||
|
var resourceRe = new RegExp('^/[^/]{2,}/[^/]+');
|
||||||
|
if (! resourceRe.test(opts.resource)) {
|
||||||
|
throw new TypeError(format('invalid resource "%s": must match ' +
|
||||||
|
'"/:account/:type..."', opts.resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
var validResources = [
|
||||||
|
'machines',
|
||||||
|
'packages',
|
||||||
|
'images',
|
||||||
|
'fwrules',
|
||||||
|
'networks',
|
||||||
|
// TODO: validate/test role tags on these rbac resources
|
||||||
|
'users',
|
||||||
|
'roles',
|
||||||
|
'policies',
|
||||||
|
// TODO: validate, test
|
||||||
|
'keys',
|
||||||
|
'datacenters',
|
||||||
|
'analytics',
|
||||||
|
'instrumentations'
|
||||||
|
];
|
||||||
|
var parts = opts.resource.split('/');
|
||||||
|
if (validResources.indexOf(parts[2]) === -1) {
|
||||||
|
throw new TypeError(format('invalid resource "%s": resource type ' +
|
||||||
|
'must be one of: %s', opts.resource, validResources.join(', ')));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'PUT',
|
||||||
|
path: opts.resource,
|
||||||
|
data: {
|
||||||
|
'role-tag': opts.roleTags
|
||||||
|
}
|
||||||
|
}, function (err, req, res, body) {
|
||||||
|
cb(err, body, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// --- Exports
|
// --- Exports
|
||||||
|
|
||||||
module.exports.createClient = function (options) {
|
module.exports.createClient = function (options) {
|
||||||
|
272
lib/do_rbac/do_info.js
Normal file
272
lib/do_rbac/do_info.js
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* 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 rbac info ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* BEGIN JSSTYLED */
|
||||||
|
/*
|
||||||
|
|
||||||
|
Sample output for development/discussion:
|
||||||
|
|
||||||
|
```
|
||||||
|
users ($numUsers):
|
||||||
|
bob ($fullname, **no ssh keys**): roles web*
|
||||||
|
carl (Carl Fogel): roles eng, operator*, cibot*, monbot*
|
||||||
|
...
|
||||||
|
roles ($numRoles):
|
||||||
|
eng: policies write, read # include users here?
|
||||||
|
ops: policies delete, read, write
|
||||||
|
support: policies read
|
||||||
|
policies ($numPolicies):
|
||||||
|
delete ($desc):
|
||||||
|
can deletemachine
|
||||||
|
read (cloudapi read-only actions):
|
||||||
|
can listmachines, getmachine and listimages
|
||||||
|
write (cloudapi write (non-delete) actions):
|
||||||
|
can createmachine, updatemachine, stopmachine and startmachine
|
||||||
|
resources: # or call this 'resources'? role-tags?
|
||||||
|
# some dump of all resources (perhaps not default to *all*) and their
|
||||||
|
# role-tags
|
||||||
|
instance foo0 ($uuid): role-tags eng
|
||||||
|
image bar@1.2.3 ($uuid): role-tags ops
|
||||||
|
```
|
||||||
|
|
||||||
|
Ideas:
|
||||||
|
- red warning about users with no keys
|
||||||
|
- `triton rbac info -u bob` Show everything from bob's p.o.v.
|
||||||
|
- `triton rbac info -r readonly` Show everything from this role's p.o.v.
|
||||||
|
`... --instance foo0`, etc.
|
||||||
|
- `-t|--role-tags` to include the role tag info. Perhaps with arg for which?
|
||||||
|
E.g. do we traverse all machines, images, networks? That could too much...
|
||||||
|
Might need cloudapi support for returning those optionally.
|
||||||
|
ListImages?fields=*,role_tags # perhaps don't support '*'
|
||||||
|
*/
|
||||||
|
/* END JSSTYLED */
|
||||||
|
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
var format = require('util').format;
|
||||||
|
var tabula = require('tabula');
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
var ansiStylize = common.ansiStylize;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gather RBAC users, policies, roles and add those to the given `ctx` object.
|
||||||
|
*/
|
||||||
|
function gatherRbacBasicInfo(ctx, cb) {
|
||||||
|
assert.object(ctx.cloudapi, 'ctx.cloudapi');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
vasync.parallel({funcs: [
|
||||||
|
function listUsers(next) {
|
||||||
|
ctx.cloudapi.listUsers(function (err, users) {
|
||||||
|
ctx.users = users;
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function listPolicies(next) {
|
||||||
|
ctx.cloudapi.listPolicies(function (err, policies) {
|
||||||
|
ctx.policies = policies;
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function listRoles(next) {
|
||||||
|
ctx.cloudapi.listRoles(function (err, roles) {
|
||||||
|
ctx.roles = roles;
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function do_info(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;
|
||||||
|
}
|
||||||
|
var log = this.log;
|
||||||
|
|
||||||
|
var context = {
|
||||||
|
tritonapi: this.top.tritonapi,
|
||||||
|
cloudapi: this.top.tritonapi.cloudapi
|
||||||
|
};
|
||||||
|
vasync.pipeline({arg: context, funcs: [
|
||||||
|
gatherRbacBasicInfo,
|
||||||
|
function gatherUserKeys(ctx, next) {
|
||||||
|
if (!opts.all) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// XXX Q! or concurrency forEachParallel
|
||||||
|
vasync.forEachParallel({
|
||||||
|
inputs: ctx.users,
|
||||||
|
func: function oneUser(user, nextUser) {
|
||||||
|
ctx.cloudapi.listUserKeys({userId: user.id},
|
||||||
|
function (err, userKeys) {
|
||||||
|
user.keys = userKeys;
|
||||||
|
nextUser(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
function fillInUserRoles(ctx, next) {
|
||||||
|
var i;
|
||||||
|
var userFromLogin = {};
|
||||||
|
for (i = 0; i < ctx.users.length; i++) {
|
||||||
|
var user = ctx.users[i];
|
||||||
|
user.default_roles = [];
|
||||||
|
user.roles = [];
|
||||||
|
userFromLogin[user.login] = user;
|
||||||
|
}
|
||||||
|
for (i = 0; i < ctx.roles.length; i++) {
|
||||||
|
var role = ctx.roles[i];
|
||||||
|
role.default_members.forEach(function (login) {
|
||||||
|
userFromLogin[login].default_roles.push(role.name);
|
||||||
|
});
|
||||||
|
role.members.forEach(function (login) {
|
||||||
|
userFromLogin[login].roles.push(role.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
function printInfo(ctx, next) {
|
||||||
|
var i;
|
||||||
|
log.trace({
|
||||||
|
users: ctx.users,
|
||||||
|
policies: ctx.policies,
|
||||||
|
roles: ctx.roles
|
||||||
|
}, 'rbac info data');
|
||||||
|
|
||||||
|
console.log('users (%d):', ctx.users.length);
|
||||||
|
tabula.sortArrayOfObjects(ctx.users, ['name']);
|
||||||
|
for (i = 0; i < ctx.users.length; i++) {
|
||||||
|
var user = ctx.users[i];
|
||||||
|
|
||||||
|
var userExtra = [];
|
||||||
|
if (user.firstName || user.lastName) {
|
||||||
|
userExtra.push(((user.firstName || '') + ' ' +
|
||||||
|
(user.lastName || '')).trim());
|
||||||
|
}
|
||||||
|
if (user.keys && user.keys.length === 0) {
|
||||||
|
userExtra.push(ansiStylize('no ssh keys', 'red'));
|
||||||
|
}
|
||||||
|
if (userExtra.length > 0) {
|
||||||
|
userExtra = format(' (%s)', userExtra.join(', '));
|
||||||
|
} else {
|
||||||
|
userExtra = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
var roleInfo = [];
|
||||||
|
user.default_roles.sort();
|
||||||
|
user.roles.sort();
|
||||||
|
var roleSeen = {};
|
||||||
|
user.default_roles.forEach(function (r) {
|
||||||
|
roleSeen[r] = true;
|
||||||
|
roleInfo.push(r);
|
||||||
|
});
|
||||||
|
user.roles.forEach(function (r) {
|
||||||
|
if (!roleSeen[r]) {
|
||||||
|
roleInfo.push(r + '*'); // marker for non-default role
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (roleInfo.length === 1) {
|
||||||
|
roleInfo = 'role ' + roleInfo.join(', ');
|
||||||
|
} else if (roleInfo.length > 0) {
|
||||||
|
roleInfo = 'roles ' + roleInfo.join(', ');
|
||||||
|
} else {
|
||||||
|
roleInfo = ansiStylize('no roles', 'red');
|
||||||
|
}
|
||||||
|
console.log(' %s%s: %s', ansiStylize(user.login, 'bold'),
|
||||||
|
userExtra, roleInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('roles (%d):', ctx.roles.length);
|
||||||
|
tabula.sortArrayOfObjects(ctx.roles, ['name']);
|
||||||
|
for (i = 0; i < ctx.roles.length; i++) {
|
||||||
|
var role = ctx.roles[i];
|
||||||
|
|
||||||
|
var policyInfo;
|
||||||
|
if (role.policies.length === 1) {
|
||||||
|
policyInfo = 'policy ' + role.policies.join(', ');
|
||||||
|
} else if (role.policies.length > 0) {
|
||||||
|
policyInfo = 'policies ' + role.policies.join(', ');
|
||||||
|
} else {
|
||||||
|
policyInfo = ansiStylize('no policies', 'red');
|
||||||
|
}
|
||||||
|
console.log(' %s: %s', ansiStylize(role.name, 'bold'),
|
||||||
|
policyInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('policies (%d):', ctx.policies.length);
|
||||||
|
tabula.sortArrayOfObjects(ctx.policies, ['name']);
|
||||||
|
for (i = 0; i < ctx.policies.length; i++) {
|
||||||
|
var policy = ctx.policies[i];
|
||||||
|
var noRules = '';
|
||||||
|
if (policy.rules.length === 0) {
|
||||||
|
noRules = ' ' + ansiStylize('no rules', 'red');
|
||||||
|
}
|
||||||
|
if (policy.description) {
|
||||||
|
console.log(' %s (%s) rules:%s',
|
||||||
|
ansiStylize(policy.name, 'bold'),
|
||||||
|
policy.description, noRules);
|
||||||
|
} else {
|
||||||
|
console.log(' %s rules:%s',
|
||||||
|
ansiStylize(policy.name, 'bold'), noRules);
|
||||||
|
}
|
||||||
|
policy.rules.forEach(function (r) {
|
||||||
|
console.log(' %s', r);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
do_info.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['all', 'a'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Include all info for a more full report. This requires more ' +
|
||||||
|
'work to gather all info.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
do_info.help = (
|
||||||
|
/* BEGIN JSSTYLED */
|
||||||
|
'Print an account RBAC summary.\n' +
|
||||||
|
'\n' +
|
||||||
|
'Usage:\n' +
|
||||||
|
' {{name}} info [<options>]\n' +
|
||||||
|
'\n' +
|
||||||
|
'{{options}}'
|
||||||
|
/* END JSSTYLED */
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = do_info;
|
582
lib/do_rbac/do_role_tags.js
Normal file
582
lib/do_rbac/do_role_tags.js
Normal file
@ -0,0 +1,582 @@
|
|||||||
|
/*
|
||||||
|
* 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 rbac role-tags ...` # hidden lower-level command
|
||||||
|
* `triton rbac instance-role-tags ...`
|
||||||
|
* `triton rbac image-role-tags ...`
|
||||||
|
* `triton rbac package-role-tags ...`
|
||||||
|
* `triton rbac network-role-tags ...`
|
||||||
|
* etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
var format = require('util').format;
|
||||||
|
var fs = require('fs');
|
||||||
|
var strsplit = require('strsplit');
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
|
||||||
|
// ---- internal support stuff
|
||||||
|
|
||||||
|
function _listRoleTags(opts, cb) {
|
||||||
|
assert.object(opts.cli, 'opts.cli');
|
||||||
|
assert.string(opts.resourceId, 'opts.resourceId');
|
||||||
|
assert.optionalBool(opts.json, 'opts.json');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
var cli = opts.cli;
|
||||||
|
|
||||||
|
cli.tritonapi.getInstanceRoleTags(opts.resourceId,
|
||||||
|
function (err, roleTags) {
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.json) {
|
||||||
|
console.log(JSON.stringify(roleTags));
|
||||||
|
} else {
|
||||||
|
roleTags.forEach(function (r) {
|
||||||
|
console.log(r);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function _addRoleTags(opts, cb) {
|
||||||
|
assert.object(opts.cli, 'opts.cli');
|
||||||
|
assert.string(opts.resourceId, 'opts.resourceId');
|
||||||
|
assert.arrayOfString(opts.roleTags, 'opts.roleTags');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
var cli = opts.cli;
|
||||||
|
var log = cli.log;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: {}, funcs: [
|
||||||
|
function getCurrRoleTags(ctx, next) {
|
||||||
|
cli.tritonapi.getInstanceRoleTags(opts.resourceId,
|
||||||
|
function (err, roleTags, inst) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.roleTags = roleTags;
|
||||||
|
ctx.inst = inst;
|
||||||
|
log.trace({inst: inst, roleTags: roleTags}, 'curr role tags');
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function addRoleTags(ctx, next) {
|
||||||
|
var adding = [];
|
||||||
|
for (var i = 0; i < opts.roleTags.length; i++) {
|
||||||
|
var r = opts.roleTags[i];
|
||||||
|
if (ctx.roleTags.indexOf(r) === -1) {
|
||||||
|
ctx.roleTags.push(r);
|
||||||
|
adding.push(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (adding.length === 0) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
console.log('Adding %d role tag%s (%s) to instance "%s"',
|
||||||
|
adding.length, adding.length === 1 ? '' : 's',
|
||||||
|
adding.join(', '), ctx.inst.name);
|
||||||
|
}
|
||||||
|
cli.tritonapi.cloudapi.setRoleTags({
|
||||||
|
resource: _resourceUrlFromId(
|
||||||
|
cli.tritonapi.profile.account, ctx.inst.id),
|
||||||
|
roleTags: ctx.roleTags
|
||||||
|
}, next);
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: resource URL should be in tritonapi.js,
|
||||||
|
// E.g. perhaps `TritonApi.setInstanceRoleTags`?
|
||||||
|
function _resourceUrlFromId(account, id) {
|
||||||
|
return format('/%s/machines/%s', account, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _reprFromRoleTags(roleTags) {
|
||||||
|
assert.arrayOfString(roleTags, 'roleTags');
|
||||||
|
|
||||||
|
if (roleTags.length === 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make this somewhat canonical by sorting.
|
||||||
|
roleTags.sort();
|
||||||
|
return roleTags.join('\n') + '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _roleTagsFromRepr(repr) {
|
||||||
|
assert.string(repr, 'repr');
|
||||||
|
|
||||||
|
var roleTags = [];
|
||||||
|
var lines = repr.split(/\n/g);
|
||||||
|
lines.forEach(function (line) {
|
||||||
|
var commentIdx = line.indexOf('#');
|
||||||
|
if (commentIdx !== -1) {
|
||||||
|
line = line.slice(0, commentIdx);
|
||||||
|
}
|
||||||
|
line = line.trim();
|
||||||
|
if (!line) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
roleTags.push(line);
|
||||||
|
});
|
||||||
|
|
||||||
|
roleTags.sort();
|
||||||
|
return roleTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _editRoleTags(opts, cb) {
|
||||||
|
assert.object(opts.cli, 'opts.cli');
|
||||||
|
assert.string(opts.resourceId, 'opts.resourceId');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
var cli = opts.cli;
|
||||||
|
|
||||||
|
var account = cli.tritonapi.profile.account;
|
||||||
|
var id;
|
||||||
|
var roleTags;
|
||||||
|
var filename;
|
||||||
|
var origText;
|
||||||
|
|
||||||
|
function offerRetry(afterText) {
|
||||||
|
common.promptEnter(
|
||||||
|
'Press <Enter> to re-edit, Ctrl+C to abort.',
|
||||||
|
function (aborted) {
|
||||||
|
if (aborted) {
|
||||||
|
console.log('\nAborting. No change made.');
|
||||||
|
cb();
|
||||||
|
} else {
|
||||||
|
editAttempt(afterText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function editAttempt(text) {
|
||||||
|
common.editInEditor({
|
||||||
|
text: text,
|
||||||
|
filename: filename
|
||||||
|
}, function (err, afterText, changed) {
|
||||||
|
if (err) {
|
||||||
|
return cb(new errors.TritonError(err));
|
||||||
|
}
|
||||||
|
// We don't use this `changed` in case it is a second attempt.
|
||||||
|
|
||||||
|
try {
|
||||||
|
var edited = _roleTagsFromRepr(afterText);
|
||||||
|
|
||||||
|
if (_reprFromRoleTags(edited) === origText) {
|
||||||
|
// This repr is the closest to a canonical form we have.
|
||||||
|
console.log('No change');
|
||||||
|
cb();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (textErr) {
|
||||||
|
console.error('Error with your changes: %s', textErr);
|
||||||
|
offerRetry(afterText);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save changes.
|
||||||
|
cli.tritonapi.cloudapi.setRoleTags({
|
||||||
|
resource: _resourceUrlFromId(account, id),
|
||||||
|
roleTags: edited
|
||||||
|
}, function (setErr) {
|
||||||
|
if (setErr) {
|
||||||
|
console.error('Error updating role tags with ' +
|
||||||
|
'your changes: %s', setErr);
|
||||||
|
offerRetry(afterText);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('Edited role tags on instance "%s"',
|
||||||
|
opts.resourceId);
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cli.tritonapi.getInstanceRoleTags(opts.resourceId,
|
||||||
|
function (err, roleTags_, inst) {
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = inst.id;
|
||||||
|
roleTags = roleTags_;
|
||||||
|
filename = format('%s-inst-%s-roleTags.txt',
|
||||||
|
cli.tritonapi.profile.account,
|
||||||
|
opts.resourceId);
|
||||||
|
origText = _reprFromRoleTags(roleTags);
|
||||||
|
editAttempt(origText);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _setRoleTags(opts, cb) {
|
||||||
|
assert.object(opts.cli, 'opts.cli');
|
||||||
|
assert.string(opts.resourceId, 'opts.resourceId');
|
||||||
|
assert.arrayOfString(opts.roleTags, 'opts.roleTags');
|
||||||
|
assert.optionalBool(opts.yes, 'opts.yes');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
var cli = opts.cli;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: {}, funcs: [
|
||||||
|
// TODO: consider shorter path if the instance UUID is given
|
||||||
|
// (but what if the instance has a UUID for an *alias*)?
|
||||||
|
function getResource(ctx, next) {
|
||||||
|
cli.tritonapi.getInstance(opts.resourceId, function (err, inst) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.inst = inst;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function confirm(ctx, next) {
|
||||||
|
if (opts.yes) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
var msg = format('Set role tags on instance "%s"? [y/n] ',
|
||||||
|
ctx.inst.name);
|
||||||
|
common.promptYesNo({msg: msg}, function (answer) {
|
||||||
|
if (answer !== 'y') {
|
||||||
|
console.error('Aborting');
|
||||||
|
next(true); // early abort signal
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function setThem(ctx, next) {
|
||||||
|
console.log('Setting role tags on instance "%s"', ctx.inst.name);
|
||||||
|
cli.tritonapi.cloudapi.setRoleTags({
|
||||||
|
resource: _resourceUrlFromId(
|
||||||
|
cli.tritonapi.profile.account, ctx.inst.id),
|
||||||
|
roleTags: opts.roleTags
|
||||||
|
}, next);
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function _deleteRoleTags(opts, cb) {
|
||||||
|
assert.object(opts.cli, 'opts.cli');
|
||||||
|
assert.string(opts.resourceId, 'opts.resourceId');
|
||||||
|
assert.arrayOfString(opts.roleTags, 'opts.roleTags');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
var cli = opts.cli;
|
||||||
|
var log = cli.log;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: {}, funcs: [
|
||||||
|
function getCurrRoleTags(ctx, next) {
|
||||||
|
cli.tritonapi.getInstanceRoleTags(opts.resourceId,
|
||||||
|
function (err, roleTags, inst) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.roleTags = roleTags;
|
||||||
|
ctx.inst = inst;
|
||||||
|
log.trace({inst: inst, roleTags: roleTags}, 'curr role tags');
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function determineToDelete(ctx, next) {
|
||||||
|
ctx.toDelete = [];
|
||||||
|
ctx.roleTagsToKeep = [];
|
||||||
|
for (var i = 0; i < ctx.roleTags.length; i++) {
|
||||||
|
var r = ctx.roleTags[i];
|
||||||
|
if (opts.roleTags.indexOf(r) !== -1) {
|
||||||
|
ctx.toDelete.push(r);
|
||||||
|
} else {
|
||||||
|
ctx.roleTagsToKeep.push(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
|
||||||
|
function confirm(ctx, next) {
|
||||||
|
if (ctx.toDelete.length === 0 || opts.yes) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
var msg = format(
|
||||||
|
'Delete %d role tag%s (%s) from instance "%s"? [y/n] ',
|
||||||
|
ctx.toDelete.length, ctx.toDelete.length === 1 ? '' : 's',
|
||||||
|
ctx.toDelete.join(', '), ctx.inst.name);
|
||||||
|
common.promptYesNo({msg: msg}, function (answer) {
|
||||||
|
if (answer !== 'y') {
|
||||||
|
console.error('Aborting');
|
||||||
|
next(true); // early abort signal
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function deleteRoleTags(ctx, next) {
|
||||||
|
if (ctx.toDelete.length === 0) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('Deleting %d role tag%s (%s) from instance "%s"',
|
||||||
|
ctx.toDelete.length, ctx.toDelete.length === 1 ? '' : 's',
|
||||||
|
ctx.toDelete.join(', '), ctx.inst.name);
|
||||||
|
cli.tritonapi.cloudapi.setRoleTags({
|
||||||
|
resource: _resourceUrlFromId(
|
||||||
|
cli.tritonapi.profile.account, ctx.inst.id),
|
||||||
|
roleTags: ctx.roleTagsToKeep
|
||||||
|
}, next);
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _deleteAllRoleTags(opts, cb) {
|
||||||
|
assert.object(opts.cli, 'opts.cli');
|
||||||
|
assert.string(opts.resourceId, 'opts.resourceId');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
var cli = opts.cli;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: {}, funcs: [
|
||||||
|
// TODO: consider shorter path if the instance UUID is given
|
||||||
|
// (but what if the instance has a UUID for an *alias*)?
|
||||||
|
function getResource(ctx, next) {
|
||||||
|
cli.tritonapi.getInstance(opts.resourceId, function (err, inst) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.inst = inst;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function confirm(ctx, next) {
|
||||||
|
if (opts.yes) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
var msg = format('Delete all role tags from instance "%s"? [y/n] ',
|
||||||
|
ctx.inst.name);
|
||||||
|
common.promptYesNo({msg: msg}, function (answer) {
|
||||||
|
if (answer !== 'y') {
|
||||||
|
console.error('Aborting');
|
||||||
|
next(true); // early abort signal
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function deleteAllRoleTags(ctx, next) {
|
||||||
|
console.log('Deleting all role tags from instance "%s"',
|
||||||
|
ctx.inst.name);
|
||||||
|
cli.tritonapi.cloudapi.setRoleTags({
|
||||||
|
resource: _resourceUrlFromId(
|
||||||
|
cli.tritonapi.profile.account, ctx.inst.id),
|
||||||
|
roleTags: []
|
||||||
|
}, next);
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _roleTagsFromArrayOfString(arr) {
|
||||||
|
assert.arrayOfString(arr, arr);
|
||||||
|
var allRoleTags = [];
|
||||||
|
for (var i = 0; i < arr.length; i++) {
|
||||||
|
var roleTags = arr[i]
|
||||||
|
/* JSSTYLED */
|
||||||
|
.split(/\s*,\s*/)
|
||||||
|
.filter(function (r) { return r.trim(); });
|
||||||
|
allRoleTags = allRoleTags.concat(roleTags);
|
||||||
|
}
|
||||||
|
return allRoleTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---- `triton rbac instance-role-tags`
|
||||||
|
|
||||||
|
function do_instance_role_tags(subcmd, opts, args, cb) {
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Which action?
|
||||||
|
var actions = [];
|
||||||
|
if (opts.add) { actions.push('add'); }
|
||||||
|
if (opts.edit) { actions.push('edit'); }
|
||||||
|
if (opts.set) { actions.push('set'); }
|
||||||
|
if (opts['delete']) { actions.push('delete'); }
|
||||||
|
if (opts.delete_all) { actions.push('deleteAll'); }
|
||||||
|
var action;
|
||||||
|
if (actions.length === 0) {
|
||||||
|
action = 'list';
|
||||||
|
} else if (actions.length > 1) {
|
||||||
|
return cb(new errors.UsageError(
|
||||||
|
'only one action option may be used at once'));
|
||||||
|
} else {
|
||||||
|
action = actions[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arg count validation.
|
||||||
|
if (args.length === 0) {
|
||||||
|
return cb(new errors.UsageError('INST argument is required'));
|
||||||
|
} else if (args.length > 1) {
|
||||||
|
return cb(new errors.UsageError('too many arguments'));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 'list':
|
||||||
|
_listRoleTags({
|
||||||
|
cli: this.top,
|
||||||
|
resourceId: args[0],
|
||||||
|
json: opts.json
|
||||||
|
}, cb);
|
||||||
|
break;
|
||||||
|
case 'add':
|
||||||
|
_addRoleTags({
|
||||||
|
cli: this.top,
|
||||||
|
resourceId: args[0],
|
||||||
|
roleTags: _roleTagsFromArrayOfString(opts.add)
|
||||||
|
}, cb);
|
||||||
|
break;
|
||||||
|
case 'edit':
|
||||||
|
_editRoleTags({
|
||||||
|
cli: this.top,
|
||||||
|
resourceId: args[0]
|
||||||
|
}, cb);
|
||||||
|
break;
|
||||||
|
case 'set':
|
||||||
|
_setRoleTags({
|
||||||
|
cli: this.top,
|
||||||
|
resourceId: args[0],
|
||||||
|
roleTags: _roleTagsFromArrayOfString(opts.set),
|
||||||
|
yes: opts.yes
|
||||||
|
}, cb);
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
_deleteRoleTags({
|
||||||
|
cli: this.top,
|
||||||
|
resourceId: args[0],
|
||||||
|
roleTags: _roleTagsFromArrayOfString(opts['delete']),
|
||||||
|
yes: opts.yes
|
||||||
|
}, cb);
|
||||||
|
break;
|
||||||
|
case 'deleteAll':
|
||||||
|
_deleteAllRoleTags({
|
||||||
|
cli: this.top,
|
||||||
|
resourceId: args[0],
|
||||||
|
yes: opts.yes
|
||||||
|
}, cb);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return cb(new errors.InternalError('unknown action: ' + action));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_instance_role_tags.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 confirmations, e.g. confirmation of deletion.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: 'Action Options'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['add', 'a'],
|
||||||
|
type: 'arrayOfString',
|
||||||
|
helpArg: 'ROLE[,ROLE...]',
|
||||||
|
help: 'Add the given role tags. Can be specified multiple times.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['set', 's'],
|
||||||
|
type: 'arrayOfString',
|
||||||
|
helpArg: 'ROLE[,ROLE...]',
|
||||||
|
help: 'Set role tags to the given value(s). Can be specified ' +
|
||||||
|
'multiple times.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['edit', 'e'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Edit role tags in your $EDITOR.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['delete', 'd'],
|
||||||
|
type: 'arrayOfString',
|
||||||
|
helpArg: 'ROLE[,ROLE...]',
|
||||||
|
help: 'Delete the given role tags. Can be specified multiple times.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['delete-all', 'D'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Delete all role tags from the given resource.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
do_instance_role_tags.help = [
|
||||||
|
/* BEGIN JSSTYLED */
|
||||||
|
'List and manage role tags for the given instance.',
|
||||||
|
'',
|
||||||
|
'Usage:',
|
||||||
|
' {{name}} instance-role-tags INST # list role tags',
|
||||||
|
' {{name}} instance-role-tags -a ROLE[,ROLE...] INST # add',
|
||||||
|
' {{name}} instance-role-tags -s ROLE[,ROLE...] INST # set/replace',
|
||||||
|
' {{name}} instance-role-tags -e INST # edit in $EDITOR',
|
||||||
|
' {{name}} instance-role-tags -d ROLE[,ROLE...] INST # delete',
|
||||||
|
' {{name}} instance-role-tags -D INST # delete all',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Where "ROLE" is a role tag name (see `triton rbac roles`) and INST is',
|
||||||
|
'an instance "id", "name" or short id.'
|
||||||
|
/* END JSSTYLED */
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
//do_role_tags: do_role_tags,
|
||||||
|
do_instance_role_tags: do_instance_role_tags
|
||||||
|
};
|
@ -28,7 +28,22 @@ function RbacCLI(top) {
|
|||||||
/* END JSSTYLED */
|
/* END JSSTYLED */
|
||||||
helpOpts: {
|
helpOpts: {
|
||||||
minHelpCol: 24 /* line up with option help */
|
minHelpCol: 24 /* line up with option help */
|
||||||
}
|
},
|
||||||
|
helpSubcmds: [
|
||||||
|
'help',
|
||||||
|
'info',
|
||||||
|
{ group: 'RBAC Resources' },
|
||||||
|
'users',
|
||||||
|
'user',
|
||||||
|
'keys',
|
||||||
|
'key',
|
||||||
|
'policies',
|
||||||
|
'policy',
|
||||||
|
'roles',
|
||||||
|
'role',
|
||||||
|
{ group: 'Role Tags' },
|
||||||
|
'instance-role-tags'
|
||||||
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
util.inherits(RbacCLI, Cmdln);
|
util.inherits(RbacCLI, Cmdln);
|
||||||
@ -40,17 +55,19 @@ RbacCLI.prototype.init = function init(opts, args, cb) {
|
|||||||
Cmdln.prototype.init.apply(this, arguments);
|
Cmdln.prototype.init.apply(this, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
RbacCLI.prototype.do_info = require('./do_info');
|
||||||
|
|
||||||
RbacCLI.prototype.do_users = require('./do_users');
|
RbacCLI.prototype.do_users = require('./do_users');
|
||||||
RbacCLI.prototype.do_user = require('./do_user');
|
RbacCLI.prototype.do_user = require('./do_user');
|
||||||
|
RbacCLI.prototype.do_keys = require('./do_keys');
|
||||||
|
RbacCLI.prototype.do_key = require('./do_key');
|
||||||
|
RbacCLI.prototype.do_policies = require('./do_policies');
|
||||||
|
RbacCLI.prototype.do_policy = require('./do_policy');
|
||||||
RbacCLI.prototype.do_roles = require('./do_roles');
|
RbacCLI.prototype.do_roles = require('./do_roles');
|
||||||
RbacCLI.prototype.do_role = require('./do_role');
|
RbacCLI.prototype.do_role = require('./do_role');
|
||||||
|
|
||||||
RbacCLI.prototype.do_policies = require('./do_policies');
|
var doRoleTags = require('./do_role_tags');
|
||||||
RbacCLI.prototype.do_policy = require('./do_policy');
|
//RbacCLI.prototype.do_role_tags = doRoleTags.do_role_tags;
|
||||||
|
RbacCLI.prototype.do_instance_role_tags = doRoleTags.do_instance_role_tags;
|
||||||
RbacCLI.prototype.do_keys = require('./do_keys');
|
|
||||||
RbacCLI.prototype.do_key = require('./do_key');
|
|
||||||
|
|
||||||
module.exports = RbacCLI;
|
module.exports = RbacCLI;
|
||||||
|
@ -487,13 +487,16 @@ TritonApi.prototype.getNetwork = function getNetwork(name, cb) {
|
|||||||
* Get an instance by ID, exact name, or short ID, in that order.
|
* Get an instance by ID, exact name, or short ID, in that order.
|
||||||
*
|
*
|
||||||
* @param {String} name
|
* @param {String} name
|
||||||
* @param {Function} callback `function (err, inst)`
|
* @param {Function} callback `function (err, inst, res)`
|
||||||
|
* Where, on success, `res` is the response object from a `GetMachine` call
|
||||||
|
* if one was made.
|
||||||
*/
|
*/
|
||||||
TritonApi.prototype.getInstance = function getInstance(name, cb) {
|
TritonApi.prototype.getInstance = function getInstance(name, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
assert.string(name, 'name');
|
assert.string(name, 'name');
|
||||||
assert.func(cb, 'cb');
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var res;
|
||||||
var shortId;
|
var shortId;
|
||||||
var inst;
|
var inst;
|
||||||
|
|
||||||
@ -511,7 +514,8 @@ TritonApi.prototype.getInstance = function getInstance(name, cb) {
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.cloudapi.getMachine(uuid, function (err, inst_) {
|
self.cloudapi.getMachine(uuid, function (err, inst_, res_) {
|
||||||
|
res = res_;
|
||||||
inst = inst_;
|
inst = inst_;
|
||||||
if (err && err.restCode === 'ResourceNotFound') {
|
if (err && err.restCode === 'ResourceNotFound') {
|
||||||
// The CloudApi 404 error message sucks: "VM not found".
|
// The CloudApi 404 error message sucks: "VM not found".
|
||||||
@ -579,7 +583,7 @@ TritonApi.prototype.getInstance = function getInstance(name, cb) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
cb(err);
|
cb(err);
|
||||||
} else if (inst) {
|
} else if (inst) {
|
||||||
cb(null, inst);
|
cb(null, inst, res);
|
||||||
} else {
|
} else {
|
||||||
cb(new errors.ResourceNotFoundError(format(
|
cb(new errors.ResourceNotFoundError(format(
|
||||||
'no instance with name or short id "%s" was found', name)));
|
'no instance with name or short id "%s" was found', name)));
|
||||||
@ -588,6 +592,62 @@ TritonApi.prototype.getInstance = function getInstance(name, cb) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get instance role tags.
|
||||||
|
*
|
||||||
|
* @param {String} name The instance id, name, or short id.
|
||||||
|
* @param {Function} callback `function (err, roleTags, inst)`
|
||||||
|
*/
|
||||||
|
TritonApi.prototype.getInstanceRoleTags =
|
||||||
|
function getInstanceRoleTags(name, cb) {
|
||||||
|
var self = this;
|
||||||
|
assert.string(name, 'name');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var roleTags;
|
||||||
|
var inst;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: {}, funcs: [
|
||||||
|
function getInst(ctx, next) {
|
||||||
|
self.getInstance(name, function (err, inst_, res) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inst = inst_;
|
||||||
|
ctx.res = res;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function getMachineIfNecessary(ctx, next) {
|
||||||
|
// Sometimes `getInstance` returns a CloudAPI `GetMachine` res on
|
||||||
|
// which there is a 'role-tag' header that we want. Sometimes not.
|
||||||
|
if (ctx.res) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cloudapi.getMachine(inst.id, function (err, inst_, res) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.res = res;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function getRolesFromRes(ctx, next) {
|
||||||
|
roleTags = (ctx.res.headers['role-tag'] || '')
|
||||||
|
/* JSSTYLED */
|
||||||
|
.split(/\s*,\s*/)
|
||||||
|
.filter(function (r) { return r.trim(); });
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err, roleTags, inst);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an RBAC user by ID, login, or short ID, in that order.
|
* Get an RBAC user by ID, login, or short ID, in that order.
|
||||||
@ -715,7 +775,8 @@ TritonApi.prototype.getUser = function getUser(opts, cb) {
|
|||||||
next();
|
next();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.cloudapi.listUserKeys({id: ctx.user.id}, function (err, keys) {
|
self.cloudapi.listUserKeys({userId: ctx.user.id},
|
||||||
|
function (err, keys) {
|
||||||
if (err) {
|
if (err) {
|
||||||
next(err);
|
next(err);
|
||||||
return;
|
return;
|
||||||
|
Reference in New Issue
Block a user