pkgcloud
Version:
An infrastructure-as-a-service agnostic cloud library for node.js
290 lines (259 loc) • 9.98 kB
JavaScript
/*
* instances.js: Instance methods for working with database instances from Rackspace Cloud
*
* (C) 2011 Nodejitsu Inc.
*
*/
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'] &&
typeof options['databases'] === 'array' &&
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, callback, function (body, response) {
var instance = new Instance(self, body.instance);
callback(null, 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 = {};
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;
}
this.request('instances' + '?' + qs.stringify(completeUrl), callback, function (body, res) {
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('DELETE', 'instances/' + instanceId, callback, function (body, response) {
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('instances/' + instanceId, callback, function (body, response) {
var instance = new Instance(self, body.instance);
callback(null, 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, callback, function (body, response) {
if (response.statusCode === 202) {
return callback(null);
}
return 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, callback, function (body, response) {
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, callback, function (body, response) {
if (response.statusCode === 202) {
return callback(null);
}
return errs.handle(errs.create({
message: 'Bad response from resize action.'
}), callback);
});
};