202 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
 | |
|  *
 | |
|  * Core Joyent driver class.
 | |
|  */
 | |
| 
 | |
| var p = console.log;
 | |
| var assert = require('assert-plus');
 | |
| var async = require('async');
 | |
| var format = require('util').format;
 | |
| var fs = require('fs');
 | |
| var path = require('path');
 | |
| var smartdc = require('smartdc');
 | |
| 
 | |
| var common = require('./common');
 | |
| var loadConfigSync = require('./config').loadConfigSync;
 | |
| 
 | |
| 
 | |
| 
 | |
| //---- Joyent class
 | |
| 
 | |
| /**
 | |
|  * Create a Joyent.
 | |
|  *
 | |
|  * @param options {Object}
 | |
|  *      - log {Bunyan Logger}
 | |
|  *      - profile {String} Optional. Name of profile to use. Defaults to
 | |
|  *        'defaultProfile' in the config.
 | |
|  */
 | |
| function Joyent(options) {
 | |
|     assert.object(options, 'options');
 | |
|     assert.object(options.log, 'options.log');
 | |
|     assert.optionalString(options.profile, 'options.profile');
 | |
|     var self = this;
 | |
| 
 | |
|     this.config = loadConfigSync();
 | |
|     this.profiles = this.config.profiles;
 | |
|     this.profile = this.getProfile(
 | |
|         options.profile || this.config.defaultProfile);
 | |
| 
 | |
|     this.log = options.log;
 | |
|     this.log.trace({profile: this.profile}, 'profile data');
 | |
| }
 | |
| 
 | |
| 
 | |
| Joyent.prototype.setDefaultProfile = function setDefaultProfile(name, callback) {
 | |
|     if (!this.getProfile(name)) {
 | |
|         return callback(new Error('no such profile: ' + name));
 | |
|     }
 | |
|     this.defaultProfileName = this.config.defaultProfile = name;
 | |
|     common.saveConfigSync(this.config);
 | |
|     callback();
 | |
| };
 | |
| 
 | |
| Joyent.prototype.getProfile = function getProfile(name) {
 | |
|     for (var i = 0; i < this.profiles.length; i++) {
 | |
|         if (this.profiles[i].name === name) {
 | |
|             return this.profiles[i];
 | |
|         }
 | |
|     }
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Create or update a profile.
 | |
|  *
 | |
|  * @param profile {Object}
 | |
|  * @param options {Object}
 | |
|  *      - setDefault {Boolean}
 | |
|  * @param callback {Function} `function (err)`
 | |
|  */
 | |
| Joyent.prototype.createOrUpdateProfile = function createOrUpdateProfile(
 | |
|         profile, options, callback) {
 | |
|     assert.object(profile, 'profile');
 | |
|     if (typeof(options) === 'function') {
 | |
|         callback = options;
 | |
|         options = {};
 | |
|     }
 | |
|     assert.object(options, 'options')
 | |
|     assert.optionalBool(options.setDefault, 'options.setDefault')
 | |
|     assert.func(callback, 'callback')
 | |
| 
 | |
|     var found = false;
 | |
|     for (var i = 0; i < this.profiles.length; i++) {
 | |
|         if (this.profiles[i].name === profile.name) {
 | |
|             this.profiles[i] = profile;
 | |
|             found = true;
 | |
|         }
 | |
|     }
 | |
|     if (!found) {
 | |
|         this.profiles.push(profile);
 | |
|     }
 | |
|     if (options.setDefault) {
 | |
|         this.defaultProfileName = this.config.defaultProfile = profile.name;
 | |
|     }
 | |
|     common.saveConfigSync(this.config);
 | |
|     callback();
 | |
| };
 | |
| 
 | |
| Joyent.prototype.deleteProfile = function deleteProfile(name, callback) {
 | |
|     var found = false;
 | |
|     for (var i = 0; i < this.profiles.length; i++) {
 | |
|         if (this.profiles[i].name === name) {
 | |
|             found = true;
 | |
|             this.profiles.splice(i, 1);
 | |
|         }
 | |
|     }
 | |
|     if (!found) {
 | |
|         return callback(new Error('no such profile: ' + name));
 | |
|     }
 | |
|     if (this.defaultProfileName === name) {
 | |
|         this.defaultProfileName = this.config.defaultProfile = null;
 | |
|     }
 | |
|     common.saveConfigSync(this.config);
 | |
|     callback();
 | |
| };
 | |
| 
 | |
| 
 | |
| Joyent.prototype._clientFromDc = function _clientFromDc(dc) {
 | |
|     assert.string(dc, 'dc');
 | |
| 
 | |
|     if (!this._clientFromDcCache) {
 | |
|         this._clientFromDcCache = {};
 | |
|     }
 | |
|     if (!this._clientFromDcCache[dc]) {
 | |
|         var prof = this.profile;
 | |
|         var sign;
 | |
|         if (prof.privKey) {
 | |
|             sign = smartdc.privateKeySigner({
 | |
|                 user: prof.account,
 | |
|                 keyId: prof.keyId,
 | |
|                 key: prof.privKey
 | |
|             });
 | |
|         } else {
 | |
|             sign = smartdc.cliSigner({keyId: prof.keyId, user: prof.account});
 | |
|         }
 | |
|         var client = smartdc.createClient({
 | |
|             url: this.config.dcs[dc],
 | |
|             account: prof.account,
 | |
|             version: '*',
 | |
|             noCache: true, //XXX
 | |
|             rejectUnauthorized: Boolean(prof.rejectUnauthorized),
 | |
|             sign: sign,
 | |
|             // XXX cloudapi.js stupidly uses its own logger, but takes logLevel
 | |
|             logLevel: this.log && this.log.level(),
 | |
|             // Pass our logger to underlying restify client.
 | |
|             log: this.log
 | |
|         });
 | |
|         this._clientFromDcCache[dc] = client;
 | |
|     }
 | |
|     return this._clientFromDcCache[dc];
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * List machines for the current profile.
 | |
|  *
 | |
|  * @param {Object} options  Optional
 | |
|  *      - {Function} onDcError  `function (dc, err)` called for each DC client
 | |
|  *        error.
 | |
|  */
 | |
| Joyent.prototype.listMachines = function listMachines(options, callback) {
 | |
|     var self = this;
 | |
|     if (callback === undefined) {
 | |
|         callback = options;
 | |
|         options = {}
 | |
|     }
 | |
|     assert.object(options, 'options');
 | |
|     assert.optionalFunc(options.onDcError, 'options.onDcError');
 | |
|     assert.func(callback, 'callback');
 | |
| 
 | |
|     var allMachines = [];
 | |
|     async.each(
 | |
|         self.profile.dcs || Object.keys(self.config.dcs),
 | |
|         function oneDc(dc, next) {
 | |
|             var client = self._clientFromDc(dc);
 | |
|             client.listMachines(function (err, machines) {
 | |
|                 if (err) {
 | |
|                     if (options.onDcError) {
 | |
|                         options.onDcError(dc, err);
 | |
|                     }
 | |
|                 } else {
 | |
|                     for (var i = 0; i < machines.length; i++) {
 | |
|                         machines[i].dc = dc;
 | |
|                         allMachines.push(machines[i]);
 | |
|                     }
 | |
|                 }
 | |
|                 next();
 | |
|             });
 | |
|         },
 | |
|         function done(err) {
 | |
|             callback(err, allMachines);
 | |
|         }
 | |
|     );
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| //---- exports
 | |
| 
 | |
| module.exports = Joyent;
 |