UNPKG

@yawetse/pkgcloud

Version:

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

192 lines (172 loc) 5.97 kB
/* * client.js: Database client for Iriscouch Cloud Databases * * (C) 2011 Charlie Robbins, Ken Perkins, Ross Kukulinski & the Contributors. * */ var util = require('util'), request = require('request'), pkgcloud = require('../../../../pkgcloud'), errs = require('errs'); var Client = exports.Client = function (options) { this.username = options.username; this.password = options.password; this.protocol = options.protocol || 'https://'; this.databaseUrl = options.databaseUrl || 'hosting.iriscouch.com/hosting_public'; }; Client.prototype.create = function (attrs, callback) { // Check for options. if (!attrs || typeof attrs === 'function') { return errs.handle(errs.create({ message: 'Options required for create a database.' }), Array.prototype.slice.call(arguments).pop()); } // Check for obligatory fields if (!attrs['first_name'] || !attrs['last_name']) { return errs.handle(errs.create({ message: 'Options. first_name and last_name are required arguments' }), Array.prototype.slice.call(arguments).pop()); } if (!attrs['subdomain'] || !attrs['email']) { return errs.handle(errs.create({ message: 'Options. subdomain and email are required arguments' }), Array.prototype.slice.call(arguments).pop()); } // If is a redis provisioning request so we have to define a password if (attrs['type'] && attrs['type'] === 'redis' && !attrs['password']) { return errs.handle(errs.create({ message: 'Options. password for redis is a required argument' }), Array.prototype.slice.call(arguments).pop()); } var self = this, couch = { // The ID needs the prefix of the type of database _id: ((attrs['type'] && attrs['type'] === 'redis') ? 'Redis/' : 'Server/') + attrs.subdomain, partner: this.username, creation: { first_name: attrs.first_name, last_name: attrs.last_name, email: attrs.email, subdomain: attrs.subdomain } }; // When redis so we have to add the password if (attrs['type'] && attrs['type'] === 'redis') { couch.creation.password = attrs['password']; } var options = { uri : this._getUrl(), method : 'POST', body : JSON.stringify(couch), followRedirect: false, headers: { 'Content-Type': 'application/json', 'Authorization': 'Basic ' + new Buffer(this.username + ':' + this.password).toString('base64'), 'User-Agent': util.format('nodejs-pkgcloud/%s', pkgcloud.version) } }; request(options, function (err, response, body) { if (err) { return callback(err); } if (typeof body === 'string') { try { body = JSON.parse(body) } catch (ex) { } } if (response.statusCode === 201) { if (body.ok === true) { // // For Redis we dont have any polling method yet, so just trust on iriscouch for provisioning correctly // if (attrs['type'] && attrs['type'] === 'redis') { var subdomain = body.id.split('/').pop(); callback(err, { id: subdomain, port: 6379, host: subdomain + '.redis.irstack.com', uri: 'redis://' + subdomain + '.redis.irstack.com/', username: '', password: subdomain + '.redis.irstack.com:' + attrs['password'] }); } else { // // Remark: Begin polling iriscouch to determine when the couch database is ready. // self._checkCouch(attrs.subdomain, function (err, response) { response.subdomain = attrs.subdomain; var database = self.formatResponse(response); callback(err, database); }); } } else { callback('There was an issue creating the couch', { created: false }); } } else if (response.statusCode === 403 || response.statusCode === 401 || response.statusCode === 302) { callback('incorrect partner name or password.', { created: false }); } else if (response.statusCode === 409) { callback('subdomain is already taken.', { created: false }); } else { callback('unknown error', { created: false }); } }); }; Client.prototype.formatResponse = function (response) { var database = { id: response.subdomain, port: 6984, host: response.subdomain + '.iriscouch.com', uri: 'https://' + response.subdomain + '.iriscouch.com:6984/', username: '', password: '' }; return database; }; Client.prototype._getUrl = function () { return this.protocol + this.databaseUrl; }; Client.prototype._checkCouch = function (couchName, callback) { // // Remark: Poll the couch with a GET every interval to determine if couch is up yet // We perform a poll since there is no real database available notification event from couchone // var interval = 4000, maxAttempts = 20, count = 0, options = { uri : this._getCouchPollingUrl(couchName), method : 'GET', followRedirect: false, headers: { 'Content-Type': 'application/json', 'User-Agent': util.format('nodejs-pkgcloud/%s', pkgcloud.version) } }, t = function () { count = count + 1; if (count > maxAttempts) { return callback('Max Attempts hit', { created: false }); } request(options, function (err, response) { if (err) { return callback(err, { created: false }); } if (response.statusCode === 200) { return callback(null, { created: true }); } setTimeout(t, interval); }); }; t(); }; Client.prototype.remove = function (id, callback) { callback('Destroy method not available for iriscouch.'); }; // This function gets overriden in tests to trap the polling request Client.prototype._getCouchPollingUrl = function(couchName) { return 'http://' + couchName + '.iriscouch.com/'; };