UNPKG

vortex

Version:
615 lines (577 loc) 19.2 kB
(function() { var async, child_process, fs, logsmith, path, roost, shell, shell_quote, __slice = [].slice; fs = require('fs'); path = require('path'); async = require('async'); roost = require('roost'); logsmith = require('logsmith'); shell_quote = require('shell-quote'); child_process = require('child_process'); shell = require('./shell'); exports.actions = function(opt, manifest, provider, node_name, callback) { /* Prints out the available actions. */ var action_fn, action_name, desc, _ref, _results; _results = []; for (action_name in exports) { action_fn = exports[action_name]; desc = (_ref = action_fn.toString().split('\n').slice(2, 3)[0]) != null ? _ref.trim() : void 0; _results.push(logsmith.info(action_name, '-', desc)); } return _results; }; exports.status = function(opt, manifest, provider, node_names, callback) { /* Obtains state and network address if the selected node is running. */ var process_node; process_node = function(node_name, callback) { logsmith.verbose("query status for node " + node_name); return provider.status(node_name, function(err, state, address) { var args; if (err) { return callback(err); } args = ['node', node_name, 'is', state]; if (address) { args.push('at'); args.push(address); } logsmith.info.apply(logsmith, args); return callback(null); }); }; return async.eachSeries(node_names, process_node, callback); }; exports.shellspec = function(opt, manifest, provider, node_names, callback) { /* Obtains the shell specification (typically ssh url) for the selected node. */ var process_node; process_node = function(node_name, callback) { logsmith.verbose("query shell spec for node " + node_name); return provider.shell_spec(node_name, function(err, spec) { if (err) { return callback(err); } logsmith.info(node_name, '->', spec); return callback(null, spec); }); }; return async.eachSeries(node_names, process_node, callback); }; exports.boot = function(opt, manifest, provider, node_names, callback) { /* Ensures that the node is running. */ var process_node; process_node = function(node_name, callback) { logsmith.verbose("boot node " + node_name); return provider.boot(node_name, function(err, state, address) { var args; if (err) { logsmith.error(err.message); } if (err) { return callback(null); } args = ['node', node_name, 'is', state]; if (address) { args.push('at'); args.push(address); } logsmith.info.apply(logsmith, args); return callback(null); }); }; return async.eachSeries(node_names, process_node, callback); }; exports.halt = function(opt, manifest, provider, node_names, callback) { /* Ensures that the node is stopped. */ var process_node; process_node = function(node_name, callback) { logsmith.verbose("halt node " + node_name); return provider.halt(node_name, function(err, state, address) { var args; if (err) { logsmith.error(err.message); } if (err) { return callback(null); } args = ['node', node_name, 'is', state]; if (address) { args.push('at'); args.push(address); } logsmith.info.apply(logsmith, args); return callback(null); }); }; return async.eachSeries(node_names, process_node, callback); }; exports.pause = function(opt, manifest, provider, node_names, callback) { /* Ensures that the node is paused. */ var process_node; process_node = function(node_name, callback) { logsmith.verbose("pause node " + node_name); return provider.pause(node_name, function(err, state, address) { var args; if (err) { logsmith.error(err.message); } if (err) { return callback(null); } args = ['node', node_name, 'is', state]; if (address) { args.push('at'); args.push(address); } logsmith.info.apply(logsmith, args); return callback(null); }); }; return async.eachSeries(node_names, process_node, callback); }; exports.resume = function(opt, manifest, provider, node_names, callback) { /* Ensures that the node is resumed. */ var process_node; process_node = function(node_name, callback) { logsmith.verbose("resume node " + node_name); return provider.resume(node_name, function(err, state, address) { var args; if (err) { logsmith.error(err.message); } if (err) { return callback(null); } args = ['node', node_name, 'is', state]; if (address) { args.push('at'); args.push(address); } logsmith.info.apply(logsmith, args); return callback(null); }); }; return async.eachSeries(node_names, process_node, callback); }; exports.restart = function(opt, manifest, provider, node_names, callback) { /* Chains actions halt and then boot for every node. */ var actions, process_node; actions = []; actions.push(function(node_name, callback) { return exports.halt(opt, manifest, provider, [node_name], function(err) { if (err) { return callback(err); } return callback(null, node_name); }); }); actions.push(function(node_name, callback) { return exports.boot(opt, manifest, provider, [node_name], function(err) { if (err) { return callback(err); } return callback(null, node_name); }); }); process_node = function(node_name, callback) { var current_actions; logsmith.verbose("restart node " + node_name); current_actions = [(function(callback) { return callback(null, node_name); })].concat(__slice.call(actions)); return async.waterfall(current_actions, callback); }; return async.eachSeries(node_names, process_node, callback); }; exports.provision = function(opt, manifest, provider, node_names, callback) { /* Starts the provisioner on the selected node. */ var actions, merge_objects, merge_roost, process_node; actions = []; merge_objects = function(a, b) { var key, value; for (key in b) { value = b[key]; if (a[key] != null) { a[key] = (function() { switch (false) { case !Array.isArray(a[key]): return a[key].concat(b[key]); case !(typeof a[key] === 'number' || a[key] instanceof Number): return b[key]; case !(typeof a[key] === 'string' || a[key] instanceof String): return b[key]; case !(typeof a[key] === 'boolean' || a[key] instanceof Boolean): return b[key]; default: return arguments.callee(a[key], b[key]); } }).apply(this, arguments); } else { a[key] = b[key]; } } return a; }; merge_roost = function(manifest, configs) { if (configs.length === 0) { return null; } return configs.map((function(config) { if (typeof config === 'string' || config instanceof String) { return roost.manifest.load(path.resolve(path.dirname(manifest.meta.location), config)); } else { return config; } })).reduce((function(previous_value, current_value) { if (!previous_value) { return JSON.parse(JSON.stringify(current_value)); } if ((current_value.merge != null) && current_value.merge) { return merge_objects(previous_value, current_value); } else { return current_value; } }), null); }; actions.push(function(node_name, callback) { return provider.bootstrap(node_name, function(err) { if (err) { return callback(err); } return callback(null, node_name); }); }); actions.push(function(node_name, callback) { var e, merge_configs, node_manifest, roost_manifest, roost_plugins, _ref; node_manifest = manifest.nodes[node_name]; merge_configs = []; if (typeof manifestroost !== "undefined" && manifestroost !== null) { merge_configs.push(manifest.roost); } if (node_manifest.roost != null) { merge_configs.push(node_manifest.roost); } if (((_ref = node_manifest[provider.name]) != null ? _ref.roost : void 0) != null) { merge_configs.push(node_manifest[provider.name].roost); } roost_manifest = merge_roost(manifest, merge_configs); if (!roost_manifest) { return callback(new Error("no roost configuration defined for node " + node_name)); } if (merge_configs.length > 0 && (roost_manifest.meta == null)) { roost_manifest.meta = { location: manifest.meta.location }; } try { roost_plugins = roost.plugins.obtain(roost_manifest); } catch (_error) { e = _error; return callback(e); } node_manifest.roost = roost_manifest; return callback(null, node_name, roost_manifest, roost_plugins); }); actions.push(function(node_name, roost_manifest, roost_plugins, callback) { return provider.shell_spec(node_name, function(err, spec) { if (err) { return callback(err); } return callback(null, node_name, roost_manifest, roost_plugins, spec); }); }); actions.push(function(node_name, roost_manifest, roost_plugins, spec, callback) { var obtain_status; if (roost_manifest.bootstrap == null) { roost_manifest.bootstrap = []; } roost_manifest.bootstrap.push('sudo mkdir -p /etc/vortex/nodes/'); obtain_status = function(node_name, callback) { return provider.status(node_name, function(err, state, address) { if (err) { return callback(err); } return callback(null, { node_name: node_name, address: address }); }); }; return async.map(Object.keys(manifest.nodes), obtain_status, function(err, results) { var address, file, result, _i, _len; if (err) { return callback(err); } for (_i = 0, _len = results.length; _i < _len; _i++) { result = results[_i]; if (result.node_name === node_name) { continue; } if (!result.address) { logsmith.error("node " + node_name + " does not expose address"); continue; } address = shell_quote.quote([result.address]); file = shell_quote.quote(["/etc/vortex/nodes/" + result.node_name]); roost_manifest.bootstrap.unshift("echo " + address + " | sudo tee " + file); } return callback(null, node_name, roost_manifest, roost_plugins, spec); }); }); actions.push(function(node_name, roost_manifest, roost_plugins, spec, callback) { var e, roost_opt, roost_target; try { roost_target = roost.targets.create(spec, roost_manifest); } catch (_error) { e = _error; return callback(e); } roost_opt = { options: {}, argv: [] }; if (opt.options.dry != null) { roost_opt.options.dry = opt.options.dry; } return roost.engine.launch(roost_opt, roost_manifest, roost_plugins, roost_target, callback); }); process_node = function(node_name, callback) { var current_actions; logsmith.info("provision node " + node_name); current_actions = [(function(callback) { return callback(null, node_name); })].concat(__slice.call(actions)); return async.waterfall(current_actions, callback); }; return async.eachSeries(node_names, process_node, callback); }; exports.up = function(opt, manifest, provider, node_names, callback) { /* Will bring up a node by first booting/resuming it and than starting the provisioning process. */ var process_node; process_node = function(node_name, callback) { return provider.status(node_name, function(err, state, address) { var perform_provision; if (err) { return callback(err); } perform_provision = function(state, address) { var callee, timeout_handler; if (state === 'running' && address) { return exports.provision(opt, manifest, provider, [node_name], callback); } else { callee = arguments.callee; timeout_handler = function() { return provider.status(node_name, function(err, state, address) { if (err) { return callback(err); } return callee(state, address); }); }; return setTimeout(timeout_handler, 1000); } }; switch (state) { case 'stopped': return provider.boot(node_name, function(err, state, address) { if (err) { return callback(err); } return perform_provision(state, address); }); case 'paused': return provider.resume(node_name, function(err, state, address) { if (err) { return callback(err); } return perform_provision(state, address); }); default: return callback(null); } }); }; return async.eachSeries(node_names, process_node, callback); }; exports.down = function(opt, manifest, provider, node_names, callback) { /* Will bring down a node. At the moment this action is a alias for action halt. */ var process_node; process_node = function(node_name, callback) { return provider.status(node_name, function(err, state, address) { if (err) { return callback(err); } if (state === 'stopped') { return callback(null); } return provider.halt(node_name, callback); }); }; return async.eachSeries(node_names, process_node, callback); }; exports.reload = function(opt, manifest, provider, node_names, callback) { /* Chains actions down and then up for every node. */ var actions, process_node; actions = []; actions.push(function(node_name, callback) { return exports.down(opt, manifest, provider, [node_name], function(err) { if (err) { return callback(err); } return callback(null, node_name); }); }); actions.push(function(node_name, callback) { return exports.up(opt, manifest, provider, [node_name], function(err) { if (err) { return callback(err); } return callback(null, node_name); }); }); process_node = function(node_name, callback) { var current_actions; logsmith.verbose("reload node " + node_name); current_actions = [(function(callback) { return callback(null, node_name); })].concat(__slice.call(actions)); return async.waterfall(current_actions, callback); }; return async.eachSeries(node_names, process_node, callback); }; exports.shell = function(opt, manifest, provider, node_names, callback) { /* Starts a shell or executes a command on the selected node. */ var actions, process_node; actions = []; actions.push(function(node_name, callback) { return provider.shell_spec(node_name, function(err, spec) { if (err) { return callback(err); } if (!spec.match(/^ssh:/i)) { return callback(new Error("unsupported shell spec " + spec)); } return callback(null, spec); }); }); actions.push(function(spec, callback) { var command, ssh; ssh = new shell.Ssh(spec, manifest); command = opt.argv.slice(opt.argv.indexOf('--') + 1); if (command.length === opt.argv.length) { command = null; } else { command = command.join(' '); } if (command) { ssh.exec(command); } else { ssh.shell(); } return ssh.ignite(false, function(err) { if (err) { return callback(err); } return callback(null); }); }); process_node = function(node_name, callback) { var current_actions; logsmith.info("shell into node " + node_name); current_actions = [(function(callback) { return callback(null, node_name); })].concat(__slice.call(actions)); return async.waterfall(current_actions, callback); }; return async.eachSeries(node_names, process_node, callback); }; exports.openurl = function(opt, manifest, provider, node_names, callback) { /* Open node url in browser. */ var command, process_node; command = (function() { switch (false) { case !process.platform.match(/^win/): return 'start'; case !process.platform.match(/^dar/): return 'open'; default: return 'firefox'; } })(); process_node = function(node_name, callback) { var node_def, port, scheme, web_def; node_def = manifest.nodes[node_name]; web_def = node_def.web || {}; path = (function() { switch (false) { case !web_def.path: return web_def.path; default: return '/'; } })(); port = (function() { switch (false) { case !web_def.port: return web_def.port; default: return 80; } })(); scheme = (function() { switch (false) { case !web_def.scheme: return web_def.scheme; case port !== 443: return 'https'; default: return 'http'; } })(); return provider.status(node_name, function(err, state, address) { var url; if (err) { return callback(err); } if (!address) { return callback(new Error("cannot identify address for node " + node_name)); } url = "" + scheme + "://" + address + ":" + port + path; return child_process.exec(shell_quote.quote([command, url]), function(err) { if (err) { return callback(err); } return callback(null); }); }); }; return async.eachSeries(node_names, process_node, callback); }; }).call(this);