@yawetse/pkgcloud
Version:
An infrastructure-as-a-service agnostic cloud library for node.js
292 lines (255 loc) • 9.24 kB
JavaScript
/*
* users.js: Client methods for working with users on database within instances from Openstack Trove.
*
* (C) 2014 Hewlett-Packard Development Company, L.P.
*
*/
var pkgcloud = require('../../../../../lib/pkgcloud'),
Database = pkgcloud.providers.rackspace.database.Database,
Instance = pkgcloud.providers.rackspace.database.Instance,
User = pkgcloud.providers.rackspace.database.User,
errs = require('errs'),
qs = require('querystring');
// Create a User(s) for a Database.
// Need an Instance and a Database name.
// ### @options {Object|Array} Set of options can be one user object or an
// ### array of user objects.
// #### options['username'] {string} Name of user to create (required)
// #### options['password'] {string} The password for the user to create (required)
// #### options['databases'] {string | array} Name or instances of databases that the user can access (required)
// #### options['instance'] {string | Object} The instance could be the ID for the instance or a instance of Instance class (required)
exports.createUser = function createUser(options, callback) {
var self = this,
users = [],
regex = /^\s|^\?|^@|^#| \w* \d* |'|"|`|;|,|\\|\/| \s$/,
instanceId,
count = 0;
function assessOptions(opts) {
var databases = [],
calledBack = false;
// Check for required options.
['username', 'password', 'database', 'instance'].forEach(function (required) {
// API allows for individual or multiple databases
if (!opts[required] && ( required === 'database' && !opts['databases'])) {
if (calledBack) { return; }
errs.handle(errs.create({
message: 'Options. ' + required + ' is a required argument'
}), callback);
calledBack = true;
}
});
if (calledBack) {
return;
}
// Check for invalid characters in username and password
if (regex.test(opts['username'])) {
return errs.handle(errs.create({
message: 'Invalid characters in username ' + opts['username']
}), callback);
}
if (regex.test(opts['password'])) {
return errs.handle(errs.create({
message: 'Invalid characters in password ' + opts['password']
}), callback);
}
// Check username character limit
if (opts['username'].length > 16) {
return errs.handle(errs.create({
message: 'Username character limit is 16'
}), callback);
}
// If 'databases' is an array so we push each name in databases list
if (opts && opts['databases'] &&
opts['databases'] instanceof Array &&
opts['databases'].length > 0) {
opts['databases'].forEach(function (item) {
if (typeof item === 'string') {
databases.push({'name' : item});
} else if (item instanceof Database) {
databases.push({'name' : item.name});
}
});
}
if (opts && opts['database'] && typeof opts['database'] === 'string') {
databases.push({ 'name' : opts['database']});
}
if (opts && opts['database'] && opts['database'] instanceof Database) {
databases.push({ 'name' : opts['database'].name});
}
if (opts && opts['databases'] && typeof opts['databases'] === 'string') {
databases.push({ 'name' : opts['databases']});
}
if (opts && opts['databases'] && opts['databases'] instanceof Database) {
databases.push({ 'name' : opts['databases'].name});
}
// Check for invalid characters and permitted length of database
databases.forEach(function (db) {
if (regex.test(db)) {
return errs.handle(errs.create({
message: 'Invalid characters in database ' + db
}), callback);
}
if (db.length > 64) {
return errs.handle(errs.create({
message: 'Database character limit is 64'
}), callback);
}
});
instanceId = opts['instance'] instanceof Instance ? opts['instance'].id : opts['instance'];
users.push({
name: opts['username'],
password: opts['password'],
databases: databases
});
// Only make request once all users are added.
if (options instanceof Array) {
++count;
if (count === options.length) {
makeRequest();
}
} else {
makeRequest();
}
}
// Check for options
if (!options || typeof options === 'function') {
return errs.handle(errs.create({
message: 'Options required for create an instance.'
}), options);
}
// Not as clean as I'd like but async didn't seem to work properly.
if (options instanceof Array) {
for (var i = 0; i < options.length; i++) {
assessOptions(options[i]);
}
}
else {
assessOptions(options);
}
function makeRequest() {
var createOptions = {
method: 'POST',
path: 'instances/' + instanceId + '/users',
body: {
users: users
}
};
self._request(createOptions, function (err, body, response) {
return err
? callback(err)
: callback(null, response);
});
}
};
// Get the list of users for an Instance
// Need an Instance
// ### @options {Object} Set of options can be
// #### options['instance'] {string | Object} Could be the ID for the instance or a instance of Instance class (required)
// #### options['limit'] {Integer} Number of results you want
// #### options['offset'] {Integer} Offset mark for result list
// ### @callback {Function} Function to continue the call is cb(error, instances, offset)
exports.getUsers = function getUsers(options, callback) {
var self = this,
completeUrl = {},
requestOptions = {};
if (!options || typeof options === 'function') {
return errs.handle(errs.create({
message: 'An instance is required for get all databases.'
}), options);
}
// Check for instance
if (!options['instance']) {
return errs.handle(errs.create({
message: 'An instance is required for get all databases.'
}), Array.prototype.slice.call(arguments).pop());
}
// The limit parameter for truncate results
if (options && options.limit) {
completeUrl.limit = options.limit;
}
// The offset
if (options && options.offset) {
completeUrl.marker = options.offset;
}
var instanceId = options['instance'] instanceof Instance ? options['instance'].id : options['instance'];
requestOptions.qs = completeUrl;
requestOptions.path = 'instances/' + instanceId + '/users';
this._request(requestOptions, function (err, body) {
if (err) {
return callback(err);
}
var marker = null;
if (body.links && body.links.length > 0) {
marker = qs.parse(body.links[0].href.split('?').pop()).marker;
}
callback(null, body.users.map(function (result) {
return new User(self, result);
}), marker);
});
};
// Destroying the user
// Need an Instance and the user
// #### @instance {string | Object} Could be the ID for the instance or a instance of Instance class (required)
// #### @user {string | Object} Could be the name of the user or a instance of User class (required)
exports.destroyUser = function destroyUser(instance, user, callback) {
// Check for instance
if (!instance || typeof instance === 'function') {
return errs.handle(errs.create({
message: 'An instance is required.'
}), instance);
}
// Check for user
if (!user || typeof user === 'function') {
return errs.handle(errs.create({
message: 'An user is required.'
}), user);
}
var instanceId = instance instanceof Instance ? instance.id : instance;
var userId = user instanceof User ? user.name : user;
this._request({
method: 'DELETE',
path: 'instances/' + instanceId + '/users/' + userId
}, function (err, body, response) {
return err
? callback(err)
: callback(null, response);
});
};
// Enable the root user on a instance
// #### @instance {string | Object} Could be the ID for the instance or a instance of Instance class (required)
exports.enableRoot = function enableRoot(instance, callback) {
// Check for instance
if (typeof instance === 'function') {
return errs.handle(errs.create({
message: 'An instance is required.'
}), instance);
}
var self = this;
var instanceId = instance instanceof Instance ? instance.id : instance;
this._request({
method: 'POST',
path: 'instances/' + instanceId + '/root'
}, function (err, body, response) {
return err
? callback(err)
: callback(null, new User(self, body.user), response);
});
};
// Check the flag for root user access
// #### @instance {string | Object} Could be the ID for the instance or a instance of Instance class (required)
exports.rootEnabled = function rootEnabled(instance, callback) {
// Check for instance
if (typeof instance === 'function') {
return errs.handle(errs.create({
message: 'An instance is required.'
}), instance);
}
var instanceId = instance instanceof Instance ? instance.id : instance;
this._request({
path: '/instances/' + instanceId + '/root'
}, function (err, body, response) {
return err
? callback(err)
: callback(null, body.rootEnabled, response);
});
};