UNPKG

@yawetse/pkgcloud

Version:

An infrastructure-as-a-service agnostic cloud library for node.js

390 lines (338 loc) 12.4 kB
/* * instances.js: Instance methods for working with database instances from Openstack Trove * * (C) 2014 Hewlett-Packard Development Company, L.P. * */ var pkgcloud = require('../../../../../lib/pkgcloud'), Flavor = pkgcloud.providers.rackspace.database.Flavor, Instance = pkgcloud.providers.rackspace.database.Instance, errs = require('errs'), qs = require('querystring'); // Create Database Instance // Need a flavor // ### @options {Object} Set of options can be // #### options['name'] {string} Name of instance (required) // #### options['flavor'] {string | Object} Should be the HREF for the flavor or a instance of Flavor class (required) // #### options['size'] {number} The Volume size in Gigabytes, must be between 1 and 8 // #### options['databases'] {array} Array of strings with database names to create when the instance is ready. // ### @callback {Function} Function to continue the call is cb(error, Instance) exports.createInstance = function createInstance(options, callback) { var self = this, flavorRef, size; // Check for options if (!options || typeof options === 'function') { return errs.handle(errs.create({ message: 'Options required for create an instance.' }), options); } if (!options['name']) { return errs.handle(errs.create({ message: 'options. name is a required argument' }), callback); } if (!options['flavor']) { return errs.handle(errs.create({ message: 'options. flavor is a required argument' }), callback); } // If the 'databases' are specified we create a template for each database name. if (options && options['databases'] && Array.isArray(options['databases']) && options['databases'].length > 0) { options['databases'].forEach(function (item, idx) { if (typeof item === 'string') { // This template is according to the defaults of rackspace. options['databases'][idx] = { name: item, character_set: 'utf8', collate: 'utf8_general_ci' }; } }); } // Check for the correct value of 'size', should be between 1 and 8 otherwise will be 1 if (options && options['size']) { // Ensure size is an Integer if (typeof options['size'] !== 'number') { return errs.handle(errs.create({ message: 'options. Volume size should be a Number, not a String' }), callback); } size = (options['size'] > 0 && options['size'] < 9) ? options['size'] : 1; } // Extract the href value of the Flavor instance // Should be always true because above we return an error if not exists if (options && options['flavor']) { flavorRef = options['flavor'] instanceof Flavor ? options['flavor'].href : options['flavor']; } var createOptions = { method: 'POST', path: 'instances', body: { instance: { name: options['name'], flavorRef: flavorRef, databases: options['databases'] || [], volume: { size: size || 1 } } } }; this._request(createOptions, function (err, body) { return err ? callback(err) : callback(null, new Instance(self, body.instance)); }); }; // Gets all instances info // ### @options {Object} Set of options can be // #### 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.getInstances = function getInstances(options, callback) { var self = this, completeUrl = {}, requestOptions = {}; if (typeof options === 'function') { callback = options; options = {}; } // The limit parameter for truncate results if (options && options.limit) { completeUrl.limit = options.limit; } // The offset if (options && options.offset) { completeUrl.marker = options.offset; } requestOptions.qs = completeUrl; requestOptions.path = 'instances'; 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.instances.map(function (result) { return new Instance(self, result); }), marker); }); }; // Destroying the database instance // ### @instance {string | Object} The ID of the istance of a instance of Instance class (required) // ### @callback {Function} Function to continue the call is cb(error, res) exports.destroyInstance = function destroyInstance(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({ method: 'DELETE', path: 'instances/' + instanceId }, function (err, body, response) { return err ? callback(err) : callback(null, response); }); }; // Details of specific instance // ### @instance {string | Object} The ID of the istance of a instance of Instance class (required) // ### @callback {Function} Function to continue the call is cb(error, instances, offset) exports.getInstance = function getInstance(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({ path: 'instances/' + instanceId }, function (err, body) { return err ? callback(err) : callback(null, new Instance(self, body.instance)); }); }; // Restart the Instance // Call this function cause a restart in the instance specified // ### @instance {string | Object} The ID of the istance of a instance of Instance class (required) // ### @callback {Function} Function to continue the call is cb(error) exports.restartInstance = function restartInstance(instance, callback) { // Check for instance if (typeof instance === 'function' || typeof instance === 'undefined') { return errs.handle(errs.create({ message: 'An instance is required.' }), Array.prototype.slice.call(arguments).pop()); } var instanceId = instance instanceof Instance ? instance.id : instance; var restartOptions = { method: 'POST', path: 'instances/' + instanceId + '/action', body: { restart: {} } }; this._request(restartOptions, function (err, body, response) { if (err) { return callback(err); } if (response.statusCode === 202) { return callback(null); } errs.handle(errs.create({ message: 'Bad response from restart action.' }), callback); }); }; // Resize the memory of the database instance. // You can use this to change the flavor of the database instance, need a new flavor. // ### @instance {string | Object} The ID of the istance of a instance of Instance class (required) // ### @flavor {Flavor class} The flavor to resize the instance, should be different (required) // ### @callback {Function} Function to continue, no params are passed. exports.setFlavor = function setFlavor(instance, flavor, callback) { // Check for the flavor if (typeof flavor === 'function' || typeof flavor === 'undefined') { return errs.handle(errs.create({ message: 'A flavor is required.' }), Array.prototype.slice.call(arguments).pop()); } // Check for instance if (typeof instance === 'function' || typeof instance === 'undefined') { return errs.handle(errs.create({ message: 'An instance is required.' }), Array.prototype.slice.call(arguments).pop()); } if (!(flavor instanceof Flavor)) { return errs.handle(errs.create({ message: 'A valid flavor is required.' }), Array.prototype.slice.call(arguments).pop()); } //@todo: Check if the new flavor are different from the old. var instanceId = instance instanceof Instance ? instance.id : instance; var resizeOptions = { method: 'POST', path: 'instances/' + instanceId + '/action', body: { resize: { flavorRef: flavor.href } } }; this._request(resizeOptions, function (err, body, response) { if (err) { return callback(err); } if (response.statusCode === 202) { return callback(null); } return errs.handle(errs.create({ message: 'Bad response from resize action.' }), callback); }); }; // Resize the volume size of the database instance. // You can use this to change the size of the volume for a database instance. // ### @instance {string | Object} The ID of the istance of a instance of Instance class (required) // ### @newSize {Number} The new size for the volume (require) // ### @callback {Function} Function to continue, no params are passed. exports.setVolumeSize = function setVolumeSize(instance, newSize, callback) { // Check for instance if (typeof instance === 'function' || typeof instance === 'undefined') { return errs.handle(errs.create({ message: 'An instance is required.' }), Array.prototype.slice.call(arguments).pop()); } // Check for the volume size if (typeof newSize === 'function' || typeof newSize === 'undefined') { return errs.handle(errs.create({ message: 'An correct volume size is required.' }), Array.prototype.slice.call(arguments).pop()); } if (newSize > 10 || newSize < 1) { return errs.handle(errs.create({ message: 'An correct volume size is required.' }), Array.prototype.slice.call(arguments).pop()); } var instanceId = instance instanceof Instance ? instance.id : instance; var resizeOptions = { method: 'POST', path: 'instances/' + instanceId + '/action', body: { resize: { volume: { size: newSize } } } }; this._request(resizeOptions, function (err, body, response) { if (err) { return callback(err); } if (response.statusCode === 202) { return callback(null); } return errs.handle(errs.create({ message: 'Bad response from resize action.' }), callback); }); }; // Enable the root user for the given database instance. // ### @instance {string | Object} The ID of the instance or a instance or Instance class (required) // ### @callback {Function} Function to continue, the call is cb(error, res) exports.enableRootUser = function enableRootUser(instance, callback) { // Check for instance if (typeof instance === 'function' || typeof instance === 'undefined') { return errs.handle(errs.create({ message: 'An instance is required.' }), Array.prototype.slice.call(arguments).pop()); } var instanceId = instance instanceof Instance ? instance.id : instance; var options = { method: 'POST', path: 'instances/' + instanceId + '/root' }; this._request(options, function (err, body, response) { if (err) { return callback(err); } if (response.statusCode === 200) { return callback(null, body); } return errs.handle(errs.create({ message: 'Bad response from enabling root user' }), callback); }); }; // List the root status for the database instance. // `res` will be an object like `{ rootEnabled: true }` // ### @instance {string | Object} The ID of the instance or a instance or Instance class (required) // ### @callback {Function} Function to continue, the call is cb(error, res) exports.listRootStatus = function listRootStatus(instance, callback) { // Check for instance if (typeof instance === 'function' || typeof instance === 'undefined') { return errs.handle(errs.create({ message: 'An instance is required.' }), Array.prototype.slice.call(arguments).pop()); } var instanceId = instance instanceof Instance ? instance.id : instance; var options = { method: 'GET', path: 'instances/' + instanceId + '/root' }; this._request(options, function (err, body, response) { if (err) { return callback(err); } if (response.statusCode === 200) { return callback(null, body); } return errs.handle(errs.create({ message: 'Bad response from listing root-enabled status' }), callback); }); };