masson
Version:
Module execution engine for cluster deployments.
233 lines (211 loc) • 7.11 kB
JavaScript
// 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);
};