UNPKG

masson

Version:

Module execution engine for cluster deployments.

233 lines (211 loc) 7.11 kB
// Generated by CoffeeScript 1.7.1 var EventEmitter, Run, Tree, context, crypto, each, flatten, merge, pad, util, _ref; crypto = require('crypto'); util = require('util'); pad = require('pad'); each = require('each'); EventEmitter = require('events').EventEmitter; _ref = require('./misc'), flatten = _ref.flatten, merge = _ref.merge; context = require('./context'); Tree = require('./tree').Tree; /* The execution is done in 2 passes. On the first pass, a context object is build for each server. A context is the same object inject to a callback action as first argument. In a context, other server contexts are available through the `hosts` object where keys are the server name. A context object is enriched with the "actions" and "modules" properties which are respectively a list of "actions" and a list of modules. On the second pass, the action are executed. */ Run = function(config, params) { EventEmitter.call(this); this.setMaxListeners(100); this.config = config; this.params = params; this.tree = new Tree; setImmediate((function(_this) { return function() { var contexts, shared; contexts = {}; shared = {}; return each(config.servers).parallel(true).on('item', function(server, next) { var ctx; ctx = contexts[server.host] = context(merge({}, config, server), params.command); ctx.hosts = contexts; ctx.shared = shared; return _this.actions(server.host, 'install', {}, function(err, actions) { if (err) { return next(err); } ctx.actions = actions || []; return _this.modules(server.host, 'install', {}, function(err, modules) { if (err) { return next(err); } ctx.modules = modules || []; return next(); }); }); }).on('error', function(err) { return _this.emit('error', err); }).on('end', function() { process.on('uncaughtException', function(err) { var ctx, host; for (host in contexts) { ctx = contexts[host]; if (ctx.listeners('error').length) { ctx.emit('error', err); } } return _this.emit('error', err); }); return each(config.servers).parallel(true).on('item', function(server, next) { var ctx; if ((params.hosts != null) && params.hosts.indexOf(server.host) === -1) { return next(); } ctx = contexts[server.host]; ctx.run = _this; _this.emit('context', ctx); return _this.actions(server.host, params.command, params, function(err, actions) { var actionRun; if (actions == null) { return next(); } return actionRun = each(actions).on('item', function(action, next) { var done, e, emit_action, timedout, timeout; if (action.skip) { return next(); } ctx.action = action; timedout = null; emit_action = function(status) { return ctx.emit('action', status); }; emit_action(ctx.STARTED); done = function(err, statusOrMsg) { if (timeout) { clearTimeout(timeout); } timedout = true; if (err) { emit_action(ctx.FAILED); } else { emit_action(statusOrMsg); } return next(err); }; if (action.timeout == null) { action.timeout = 100000; } if (action.timeout > 0) { timeout = setTimeout(function() { timedout = true; return done(new Error('TIMEOUT')); }, action.timeout); } try { return setImmediate(function() { if (action.callback.length === 1) { merge(action, action.callback.call(ctx, ctx)); return process.nextTick(function() { action.timeout = -1; return done(null, ctx.DISABLED); }); } else { return merge(action, action.callback.call(ctx, ctx, function(err, statusOrMsg) { if (statusOrMsg === ctx.STOP) { actionRun.end(); } return done(err, statusOrMsg); })); } }); } catch (_error) { e = _error; return done(e); } }).on('both', function(err) { _this.emit('server', ctx, err ? ctx.FAILED : ctx.OK); if (err) { if (ctx.listeners('error').length) { ctx.emit('error', err); } } else { ctx.emit('end'); } return next(err); }); }); }).on('error', function(err) { return _this.emit('error', err); }).on('end', function(err) { return _this.emit('end'); }); }); }; })(this)); return this; }; util.inherits(Run, EventEmitter); /* Return all the actions for a given host and the current command or null if the host didnt register any run list for this command. */ Run.prototype.actions = function(host, command, options, callback) { var config, run, server, _i, _len, _ref1; _ref1 = this.config.servers; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { server = _ref1[_i]; if (server.host === host) { config = server; } } if (!config) { return callback(new Error("Invalid host: " + host)); } run = config.run[command]; if (!run) { return callback(null); } return this.tree.actions(run, options, (function(_this) { return function(err, actions) { if (err) { return callback(err); } return callback(null, actions); }; })(this)); }; /* Return all the modules for a given host and the current command or null if the host didnt register any run list for this command. */ Run.prototype.modules = function(host, command, options, callback) { var config, run, server, _i, _len, _ref1; _ref1 = this.config.servers; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { server = _ref1[_i]; if (server.host === host) { config = server; } } if (!config) { return callback(new Error("Invalid host: " + host)); } run = config.run[command]; if (!run) { return callback(null); } return this.tree.modules(run, options, (function(_this) { return function(err, modules) { if (err) { return callback(err); } return callback(null, modules); }; })(this)); }; module.exports = function(config, params) { return new Run(config, params); };