SIGN IN SIGN UP
Unitech / pm2 UNCLAIMED

Node.js Production Process Manager with a built-in Load Balancer.

0 0 699 JavaScript
var commander = require('commander');
var fs = require('fs');
var path = require('path');
var util = require('util');
var async = require('async');
var Monit = require('./Monit');
var UX = require('./CliUx');
var Log = require('./Log');
var Satan = require('./Satan');
var Common = require('./Common');
var cst = require('../constants.js');
var pkg = require('../package.json');
var extItps = require('./interpreter.json');
2014-01-11 18:48:41 +01:00
var InteractorDaemonizer = require('./InteractorDaemonizer');
var p = path;
2014-01-11 18:48:41 +01:00
2013-09-28 17:33:46 +02:00
var CLI = module.exports = {};
require('colors');
2013-09-28 17:33:46 +02:00
/**
* Method to start a script
2014-06-13 16:11:43 +02:00
* @method startFile
* @param {string} script script name (will be resolved according to location)
2014-06-13 16:24:16 +02:00
* @return
*/
2013-09-28 17:33:46 +02:00
CLI.startFile = function(script) {
var appConf = {
script : script,
name : p.basename(script, '.js')
};
if (commander.nodeArgs)
appConf['nodeArgs'] = commander.nodeArgs;
2013-09-28 17:33:46 +02:00
if (commander.name)
2013-10-15 13:11:05 +02:00
appConf['name'] = commander.name;
2013-09-28 17:33:46 +02:00
if (commander.instances)
2013-11-13 15:10:59 +01:00
appConf['instances'] = commander.instances;
2013-09-28 17:33:46 +02:00
if (commander.error)
2013-10-15 13:11:05 +02:00
appConf['error_file'] = commander.error;
2013-09-28 17:33:46 +02:00
if (commander.output)
2013-10-15 13:11:05 +02:00
appConf['out_file'] = commander.output;
2013-09-28 17:33:46 +02:00
if (commander.pid)
2013-10-15 13:11:05 +02:00
appConf['pid_file'] = commander.pid;
2013-09-28 17:33:46 +02:00
if (commander.cron)
2013-10-15 13:11:05 +02:00
appConf['cron_restart'] = commander.cron;
2014-04-11 18:22:36 +08:00
if (commander.mergeLogs)
appConf['merge_logs'] = true;
if (commander.watch)
appConf['watch'] = true;
if (commander.runAsUser)
appConf['run_as_user'] = commander.runAsUser;
if (commander.runAsGroup)
appConf['run_as_group'] = commander.runAsGroup;
2013-11-13 15:10:59 +01:00
if (commander.executeCommand) {
2013-10-15 13:11:05 +02:00
appConf['exec_mode'] = 'fork_mode';
2013-11-13 15:10:59 +01:00
if (commander.interpreter)
appConf['exec_interpreter'] = commander.interpreter;
else if (extItps[path.extname(script)])
appConf['exec_interpreter'] = extItps[path.extname(script)];
else
appConf['exec_interpreter'] = 'none';
}
else {
appConf['exec_mode'] = 'cluster_mode';
appConf['exec_interpreter'] = 'node';
}
2013-10-15 13:11:05 +02:00
if (commander.startOneTime)
appConf['one_launch_only'] = cst.ONE_LAUNCH_STATUS;
2013-10-30 17:10:58 +01:00
// if (appConf['exec_mode'] == 'cluster_mode' && process.version.match(/0.10/)) {
// printOut(cst.PREFIX_MSG_ERR + ' [Warning], you\'re using the 0.10.x node version, it\'s prefered that you switch to fork mode by adding the -x parameter.');
2013-10-30 17:10:58 +01:00
// }
2013-11-13 15:10:59 +01:00
2013-09-28 17:33:46 +02:00
// Script arguments
2013-09-29 18:39:41 +02:00
var env = commander.rawArgs.indexOf('--') + 1;
if (env > 1)
appConf['args'] = JSON.stringify(commander.rawArgs.slice(env, commander.rawArgs.length));
2013-10-27 15:43:32 +01:00
2013-09-28 17:33:46 +02:00
if (commander.write) {
var dst_path = path.join(process.env.PWD, path.basename(script, '.js') + '-pm2.json');
printOut(cst.PREFIX_MSG + 'Writing configuration to ', dst_path);
2013-09-28 17:33:46 +02:00
fs.writeFileSync(dst_path, JSON.stringify(appConf));
}
2013-11-13 15:10:59 +01:00
/*
* Re start script name that is already launched
*/
2013-10-15 13:11:05 +02:00
Satan.executeRemote('findByFullPath', path.resolve(process.cwd(), script), function(err, exec) {
if (exec &&
(exec[0].pm2_env.status == cst.STOPPED_STATUS ||
exec[0].pm2_env.status == cst.STOPPING_STATUS)) {
2013-10-15 13:11:05 +02:00
var app_name = exec[0].pm2_env.name;
Satan.executeRemote('restartProcessName', app_name, function(err, list) {
printOut(cst.PREFIX_MSG + 'Process successfully started');
2013-10-15 13:11:05 +02:00
return speedList();
});
return false;
}
else if (exec && !commander.force) {
2013-09-28 17:33:46 +02:00
console.error(cst.PREFIX_MSG_ERR + 'Script already launched, add -f option to force re execution');
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
Satan.executeRemote('prepare', resolvePaths(appConf), function(err) {
if (err) {
console.error(cst.PREFIX_MSG_ERR + 'Error while launching application', err.stack || err);
return speedList();
}
printOut(cst.PREFIX_MSG + 'Process launched');
return speedList();
2013-09-28 17:33:46 +02:00
});
2014-01-10 18:04:03 +01:00
return false;
2013-09-28 17:33:46 +02:00
});
};
2014-06-13 16:11:43 +02:00
/**
2014-06-13 16:24:16 +02:00
* Get version of the daemonized PM2
2014-06-13 16:11:43 +02:00
* @method getVersion
2014-06-13 16:24:16 +02:00
* @callback cb
2014-06-13 16:11:43 +02:00
*/
CLI.getVersion = function(cb) {
Satan.executeRemote('getVersion', {}, function(err, version) {
cb ? cb.apply(null, arguments) : exitCli(cst.SUCCESS_EXIT);
});
};
/**
2014-06-13 16:24:16 +02:00
* Apply a RPC method on the json file
2014-06-13 16:11:43 +02:00
* @method actionFromJson
* @param {string} action RPC Method
2014-06-13 16:24:16 +02:00
* @param {string} JSON file
* @param {string} jsonVia action type
*/
CLI.actionFromJson = function(action, file, jsonVia) {
if (jsonVia == 'pipe')
var appConf = JSON.parse(file);
else {
var data = fs.readFileSync(file);
var appConf = JSON.parse(data);
}
if (!Array.isArray(appConf)) appConf = [appConf]; //convert to array
async.eachLimit(appConf, cst.CONCURRENT_ACTIONS, function(proc, next) {
var name;
if (!proc.name)
name = p.basename(proc.script);
else
name = proc.name;
Satan.executeRemote(action, name, function(err, list) {
if (err)
console.error(err);
printOut(cst.PREFIX_MSG + 'Stopping process by name ' + name);
next();
});
}, function(err) {
if (err) {
printOut(err);
return exitCli(cst.ERROR_EXIT);
}
return setTimeout(speedList, 800);
});
};
2014-06-13 16:11:43 +02:00
/**
2014-06-13 16:24:16 +02:00
* Process and start a JSON file
2014-06-13 16:11:43 +02:00
* @method startFromJson
2014-06-13 16:24:16 +02:00
* @param {string} cmd
* @param {string} jsonVia
2014-06-13 16:11:43 +02:00
*/
CLI.startFromJson = function(cmd,jsonVia) {
var appConf;
if (jsonVia == 'pipe')
appConf = JSON.parse(cmd);
else {
var data = fs.readFileSync(cmd);
appConf = JSON.parse(data);
}
2013-09-28 17:33:46 +02:00
2013-10-27 14:16:58 +01:00
if (!Array.isArray(appConf)) appConf = [appConf]; //convert to array
2014-01-11 18:48:41 +01:00
(function ex(apps) {
if (apps.length == 0) return speedList();
var appPaths = resolvePaths(apps[0]);
2013-10-27 14:16:58 +01:00
if(commander.watch)
appPaths.watch = true;
2014-01-11 18:48:41 +01:00
var rpcCall = 'findByScript';
var rpcArg = p.basename(appPaths.script);
2013-10-27 14:16:58 +01:00
2014-01-11 18:48:41 +01:00
//find script by port
if (appPaths.port) {
2014-01-11 18:48:41 +01:00
rpcCall = 'findByPort';
rpcArg = appPaths.port;
}
2013-10-27 14:16:58 +01:00
2014-01-11 18:48:41 +01:00
Satan.executeRemote(rpcCall, rpcArg , function(err, exec) {
if (exec && !commander.force) {
console.error(cst.PREFIX_MSG + 'Script already launched, add -f option to force re execution');
nextApp();
return false;
} else {
2014-01-11 18:48:41 +01:00
launchApp(appPaths);
return false;
2013-10-27 14:16:58 +01:00
}
2014-01-11 18:48:41 +01:00
});
2013-10-27 14:16:58 +01:00
2014-06-13 16:11:43 +02:00
/**
* Description
* @method launchApp
* @param {} appPaths
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2014-01-11 18:48:41 +01:00
function launchApp(appPaths){
Satan.executeRemote('prepare', appPaths, function(err) {
printOut(cst.PREFIX_MSG + 'Process launched');
2014-01-11 18:48:41 +01:00
nextApp();
2013-10-27 14:16:58 +01:00
});
2014-01-11 18:48:41 +01:00
}
2013-10-27 14:16:58 +01:00
2014-06-13 16:11:43 +02:00
/**
* Description
* @method nextApp
* @return CallExpression
*/
2014-01-11 18:48:41 +01:00
function nextApp(){
apps.shift();
return ex(apps);
}
2013-10-27 14:16:58 +01:00
2014-01-11 18:48:41 +01:00
return false;
})(appConf);
};
2013-09-28 17:33:46 +02:00
2014-06-13 16:11:43 +02:00
/**
2014-06-13 16:24:16 +02:00
* Startup script generation
2014-06-13 16:11:43 +02:00
* @method startup
2014-06-13 16:24:16 +02:00
* @param {string} platform type (centos|redhat|amazon|systemd)
2014-06-13 16:11:43 +02:00
*/
CLI.startup = function(platform) {
var exec = require('child_process').exec;
2013-09-28 17:33:46 +02:00
if (process.getuid() != 0) {
exec('whoami', function(err, stdout, stderr) {
console.error(cst.PREFIX_MSG + 'You have to run this command as root');
console.error(cst.PREFIX_MSG + 'Execute the following command :');
if (platform === undefined) platform = '';
2013-12-26 14:22:00 +09:00
console.error(cst.PREFIX_MSG + 'sudo env PATH=$PATH:' + p.dirname(process.execPath) + ' pm2 startup ' + platform + ' -u ' + stdout.trim());
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
});
return;
}
2013-11-13 15:10:59 +01:00
var INIT_SCRIPT = "/etc/init.d/pm2-init.sh";
2014-01-27 17:07:24 +01:00
var script;
if (platform == 'systemd') {
script = fs.readFileSync(path.join(__dirname, cst.SYSTEMD_STARTUP_SCRIPT));
INIT_SCRIPT = '/etc/systemd/system/pm2.service';
}
else if (platform == 'centos' || platform == 'redhat')
2014-01-27 17:07:24 +01:00
script = fs.readFileSync(path.join(__dirname, cst.CENTOS_STARTUP_SCRIPT));
else if (platform == 'amazon')
script = fs.readFileSync(path.join(__dirname, cst.AMAZON_STARTUP_SCRIPT));
2014-01-27 17:07:24 +01:00
else
script = fs.readFileSync(path.join(__dirname, cst.UBUNTU_STARTUP_SCRIPT));
2013-11-13 15:10:59 +01:00
var user = commander.user || 'root';
2013-09-28 17:33:46 +02:00
script = script.toString().replace(/%PM2_PATH%/g, process.mainModule.filename);
script = script.toString().replace(/%HOME_PATH%/g, process.env.HOME);
script = script.toString().replace(/%NODE_PATH%/g, p.dirname(process.execPath));
script = script.toString().replace(/%USER%/g, user);
2013-11-13 15:10:59 +01:00
printOut(cst.PREFIX_MSG + 'Generating system init script in ' + INIT_SCRIPT);
2013-09-28 17:33:46 +02:00
fs.writeFileSync(INIT_SCRIPT, script);
2013-11-13 15:10:59 +01:00
if (fs.existsSync(INIT_SCRIPT) == false) {
printOut(script);
printOut(cst.PREFIX_MSG_ERR + ' There is a problem when trying to write file : ' + INIT_SCRIPT);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
}
2013-11-13 15:10:59 +01:00
2013-09-28 17:33:46 +02:00
var cmd;
printOut(cst.PREFIX_MSG + 'Making script booting at startup...');
2014-01-27 17:07:24 +01:00
if (platform == 'systemd') {
cmd = [
'sudo -Ei -u ' + user + ' pm2 dump', //We need an empty dump so that the first resurrect works correctly
'pm2 kill',
'systemctl daemon-reload',
2014-03-06 18:01:44 -03:00
'systemctl enable pm2',
'systemctl start pm2'
].join(' && ');
printOut(cst.PREFIX_MSG + '-systemd- Using the command %s', cmd);
}
else if (platform == 'centos' || platform == 'redhat' || platform == 'amazon') {
2014-01-27 17:07:24 +01:00
cmd = 'chmod +x ' + INIT_SCRIPT + '; chkconfig --add ' + p.basename(INIT_SCRIPT);
printOut(cst.PREFIX_MSG + '-centos- Using the command %s', cmd);
2014-01-27 17:07:24 +01:00
fs.openSync('/var/lock/subsys/pm2-init.sh', 'w');
printOut('/var/lock/subsys/pm2-init.sh lockfile has been added');
}
else {
2013-09-28 17:33:46 +02:00
cmd = 'chmod +x ' + INIT_SCRIPT + '; update-rc.d ' + p.basename(INIT_SCRIPT) + ' defaults';
printOut(cst.PREFIX_MSG + '-ubuntu- Using the command %s', cmd);
}
2013-09-28 17:33:46 +02:00
exec(cmd, function(err, stdo, stde) {
if (err) {
console.error(err);
printOut('----- Are you sure you use the right platform command line option ? centos / redhat, amazon, ubuntu or systemd?');
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
printOut(stdo);
printOut(cst.PREFIX_MSG + 'Done.');
2014-01-29 12:45:46 +01:00
exitCli(cst.SUCCESS_EXIT);
2013-09-28 17:33:46 +02:00
});
2014-01-11 18:48:41 +01:00
};
/**
2014-06-13 16:24:16 +02:00
* Launch interactor
2014-06-13 16:11:43 +02:00
* @method interact
2014-06-13 16:24:16 +02:00
* @param {string} secret_key
* @param {string} public_key
* @param {string} machine_name
*/
2014-03-24 18:51:02 +08:00
CLI.interact = function(secret_key, public_key, machine_name) {
InteractorDaemonizer.launchOrAttach(secret_key, public_key, machine_name, function(status) {
2014-01-11 18:48:41 +01:00
if (status == false)
printOut('Interactor already launched');
2014-01-11 18:48:41 +01:00
else
printOut('Successfully launched interactor');
2014-01-29 12:45:46 +01:00
exitCli(cst.SUCCESS_EXIT);
2014-01-11 18:48:41 +01:00
});
};
2014-06-13 16:11:43 +02:00
/**
2014-06-13 16:24:16 +02:00
* Kill interactor
2014-06-13 16:11:43 +02:00
* @method killInteract
*/
2014-06-13 16:24:16 +02:00
CLI.killInteract = function() {
InteractorDaemonizer.ping(function(online) {
if (!online) {
console.error('Interactor not launched');
return exitCli(cst.ERROR_EXIT);
}
InteractorDaemonizer.launchRPC(function() {
InteractorDaemonizer.rpc.kill(function(err) {
if (err) {
console.error(err);
return exitCli(cst.ERROR_EXIT);
}
printOut('Interactor successfully killed');
return exitCli(cst.SUCCESS_EXIT);
});
2014-01-11 18:48:41 +01:00
});
return false;
2014-01-11 18:48:41 +01:00
});
2013-09-28 17:33:46 +02:00
};
2014-06-13 16:11:43 +02:00
/**
2014-06-13 16:24:16 +02:00
* Get information about interactor connection
2014-06-13 16:11:43 +02:00
* @method infoInteract
*/
CLI.infoInteract = function() {
getInteractInfo(function(err, data) {
if (err) {
console.error('Interactor not launched');
return exitCli(cst.ERROR_EXIT);
}
console.log(data);
return exitCli(cst.SUCCESS_EXIT);
});
};
2014-06-13 16:11:43 +02:00
/**
2014-06-13 16:24:16 +02:00
* Ping daemon - if PM2 daemon not launched, it will launch it
2014-06-13 16:11:43 +02:00
* @method ping
*/
2014-01-10 18:04:03 +01:00
CLI.ping = function() {
Satan.executeRemote('ping', {}, function(err, res) {
if (err) {
console.error(err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2014-01-10 18:04:03 +01:00
}
printOut(res);
2014-01-29 12:45:46 +01:00
exitCli(cst.SUCCESS_EXIT);
2014-01-10 18:04:03 +01:00
});
};
2014-06-13 16:11:43 +02:00
/**
2014-06-13 16:24:16 +02:00
* Resurrect processes
2014-06-13 16:11:43 +02:00
* @method resurrect
* @param {} cb
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
CLI.resurrect = function(cb) {
try {
2014-03-20 16:54:56 +08:00
var apps = fs.readFileSync(cst.DUMP_FILE_PATH);
} catch(e) {
2014-03-20 16:54:56 +08:00
console.error(cst.PREFIX_MSG + 'No processes saved; DUMP file doesn\'t exist');
if (cb) return cb(e);
else return exitCli(cst.ERROR_EXIT);
}
(function ex(apps) {
if (!apps[0]) return cb ? cb() : speedList();
Satan.executeRemote('prepare', apps[0], function(err) {
if (err)
console.error(cst.PREFIX_MSG_ERR + ' Process %s not launched - (script missing)', apps[0].pm_exec_path);
else
printOut(cst.PREFIX_MSG + 'Process %s launched', apps[0].pm_exec_path);
apps.shift();
return ex(apps);
});
return false;
})(JSON.parse(apps));
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method updatePM2
* @param {} cb
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
CLI.updatePM2 = function(cb) {
console.log('Be sure to haave the latest version by doing `npm install pm2@latest -g` before doing this procedure.');
CLI.dump(function(err) {
console.log(cst.PREFIX_MSG + '--- dumped');
CLI.killDaemon(function(err) {
console.log(cst.PREFIX_MSG + '--- killed');
Satan.launchDaemon(function(err, child) {
console.log(cst.PREFIX_MSG + '--- resurrected');
if (err) {
console.error(err);
}
CLI.resurrect(function() {
console.log('>>>>>>>>>> PM2 updated'.blue.bold);
cb ? cb() : speedList();
});
});
});
});
};
/**
* Dump current processes managed by pm2 into DUMP_FILE_PATH file
2014-06-13 16:11:43 +02:00
* @method dump
* @param {} cb
2014-06-13 16:24:16 +02:00
* @return
*/
CLI.dump = function(cb) {
2013-09-29 18:39:41 +02:00
var env_arr = [];
2013-09-28 17:33:46 +02:00
Satan.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
console.error('Error retrieving process list: ' + err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
2014-06-13 16:11:43 +02:00
/**
* Description
* @method fin
* @param {} err
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
function fin(err) {
2013-09-29 18:39:41 +02:00
fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify(env_arr));
2013-09-28 17:33:46 +02:00
UX.processing.stop();
if (cb) return cb(null);
else return exitCli(cst.SUCCESS_EXIT);
2013-09-28 17:33:46 +02:00
}
(function ex(apps) {
if (!apps[0]) return fin(null);
2013-09-29 18:39:41 +02:00
delete apps[0].pm2_env.instances;
2013-12-16 15:57:36 +01:00
delete apps[0].pm2_env.pm_id;
2013-09-29 18:39:41 +02:00
env_arr.push(apps[0].pm2_env);
2013-09-28 17:33:46 +02:00
apps.shift();
return ex(apps);
})(list);
});
};
/**
* Launch API interface
2014-06-13 16:11:43 +02:00
* @method web
2014-06-13 16:24:16 +02:00
* @return
*/
2013-09-28 17:33:46 +02:00
CLI.web = function() {
2013-11-21 16:49:40 -05:00
Satan.executeRemote('prepare', resolvePaths({
2013-09-28 17:33:46 +02:00
script : p.resolve(p.dirname(module.filename), './HttpInterface.js'),
2013-12-04 19:52:21 +01:00
name : 'Pm2Http' + cst.WEB_INTERFACE,
exec_mode : 'fork_mode'
}), function(err) {
if (err) {
console.error(cst.PREFIX_MSG_ERR + 'Error while launching application', err.stack || err);
return speedList();
}
printOut(cst.PREFIX_MSG + 'Process launched');
2013-09-28 17:33:46 +02:00
speedList();
});
};
/**
* CLI method for reloading
2014-06-13 16:11:43 +02:00
* @method reload
* @param {string} reload_method RPC method to hit (can be reloadProcessId or softReloadProcessId)
2014-06-13 16:24:16 +02:00
* @return
*/
CLI.reload = function (reload_method) {
Satan.executeRemote('getMonitorData', {}, function(err, list) {
2013-09-28 17:33:46 +02:00
if (err) {
console.error('Error retrieving process list: ' + err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
async.eachLimit(list, 1, function(proc, next) {
if ((proc.state == cst.STOPPED_STATUS ||
proc.state == cst.STOPPING_STATUS) &&
proc.pm2_env.exec_mode != 'cluster_mode') {
return next();
}
Satan.executeRemote(reload_method, proc.pm2_env.pm_id, function(err, res) {
if (err) {
console.error('Error : ' + err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
}
printOut(cst.PREFIX_MSG + 'Process %s succesfully reloaded', proc.pm2_env.name);
return next();
});
return false;
}, function(err) {
printOut(cst.PREFIX_MSG + 'All processes reloaded');
return setTimeout(speedList, 500);
});
2013-09-28 17:33:46 +02:00
});
};
/**
* CLI method for reloading
2014-06-13 16:11:43 +02:00
* @method reloadProcessName
* @param {string} process_name name of processes to reload
* @param {string} reload_method RPC method to hit (can be reloadProcessId or softReloadProcessId)
2014-06-13 16:24:16 +02:00
* @return
*/
CLI.reloadProcessName = function (process_name, reload_method) {
printOut(cst.PREFIX_MSG + 'Reloading process by name %s', process_name);
getProcessByName(process_name, function(err, processes) {
2014-04-15 22:48:05 +08:00
if (processes.length === 0) {
printError('No processes with this name: %s', process_name);
return exitCli(cst.ERROR_EXIT);
}
async.eachLimit(processes, 1, function(proc, next) {
if (proc.state == cst.STOPPED_STATUS ||
proc.state == cst.STOPPING_STATUS ||
proc.pm2_env.exec_mode != 'cluster_mode') {
return next();
}
Satan.executeRemote(reload_method, proc.pm2_env.pm_id, function(err, res) {
if (err) {
console.error('Error : ' + err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
}
printOut(cst.PREFIX_MSG + 'Process %s succesfully reloaded', proc.pm2_env.name);
return next();
});
return false;
}, function(err) {
printOut(cst.PREFIX_MSG + 'All processes reloaded');
return setTimeout(speedList, 500);
});
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method restartProcessByName
* @param {} pm2_name
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-29 18:39:41 +02:00
CLI.restartProcessByName = function(pm2_name) {
Satan.executeRemote('restartProcessName', pm2_name, function(err, list) {
2013-09-28 17:33:46 +02:00
if (err) {
printError(err);
return exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
2013-10-27 14:16:58 +01:00
UX.processing.stop();
printOut(cst.PREFIX_MSG + 'Process ' + pm2_name + ' restarted');
2013-10-15 13:11:05 +02:00
speedList();
2013-09-29 18:39:41 +02:00
});
};
2013-09-28 17:33:46 +02:00
2014-06-13 16:11:43 +02:00
/**
* Description
* @method restartProcessById
* @param {} pm2_id
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-29 18:39:41 +02:00
CLI.restartProcessById = function(pm2_id) {
Satan.executeRemote('restartProcessId', pm2_id, function(err, res) {
if (err) {
printError(err);
return exitCli(cst.ERROR_EXIT);
2013-09-29 18:39:41 +02:00
}
2013-10-27 14:16:58 +01:00
UX.processing.stop();
printOut(cst.PREFIX_MSG + 'Process ' + pm2_id + ' restarted');
2013-10-15 13:11:05 +02:00
speedList();
2013-09-28 17:33:46 +02:00
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method restartAll
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
CLI.restartAll = function() {
Satan.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
printError(err);
return exitCli(cst.ERROR_EXIT);
}
if (list && list.length === 0) {
printError('No process launched');
return exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
2013-11-13 15:10:59 +01:00
(function rec(processes) {
var proc = processes[0];
if (proc == null) {
printOut(cst.PREFIX_MSG + 'Process restarted...');
2013-12-22 16:50:04 +01:00
return setTimeout(speedList, 1000);
}
Satan.executeRemote('restartProcessId', proc.pm2_env.pm_id, function(err, res) {
if (err) {
printError(err);
return exitCli(cst.ERROR_EXIT);
}
printOut(cst.PREFIX_MSG + 'Process ' + proc.pm2_env.name + ' restarted');
processes.shift();
return rec(processes);
2013-11-13 15:10:59 +01:00
});
2014-01-10 18:04:03 +01:00
return false;
})(list);
2013-09-28 17:33:46 +02:00
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method stopAll
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
CLI.stopAll = function() {
Satan.executeRemote('stopAll', {}, function(err, list) {
if (err) {
printError(err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
UX.processing.stop();
2013-10-15 13:11:05 +02:00
speedList();
2013-09-28 17:33:46 +02:00
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method deleteProcess
* @param {} process_name
* @param {} jsonVia
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
CLI.deleteProcess = function(process_name, jsonVia) {
if (jsonVia == 'pipe')
return CLI.actionFromJson('deleteProcessName', process_name, 'pipe');
if (process_name.indexOf('.json') > 0)
return CLI.actionFromJson('deleteProcessName', process_name, 'file');
else if (process_name == 'all') {
printOut(cst.PREFIX_MSG + 'Stopping and deleting all processes');
2013-09-29 18:39:41 +02:00
Satan.executeRemote('deleteAll', {}, function(err, list) {
if (err) {
printError(err);
return exitCli(cst.ERROR_EXIT);
2013-09-29 18:39:41 +02:00
}
UX.processing.stop();
2013-11-13 15:10:59 +01:00
speedList();
2013-10-15 13:11:05 +02:00
});
}
else if (!isNaN(parseInt(process_name))) {
printOut('Stopping and deleting process by id : %s', process_name);
2013-10-15 13:11:05 +02:00
Satan.executeRemote('deleteProcessId', process_name, function(err, list) {
if (err) {
printError(err);
return exitCli(cst.ERROR_EXIT);
2013-10-15 13:11:05 +02:00
}
UX.processing.stop();
speedList();
2013-09-29 18:39:41 +02:00
});
}
else {
printOut(cst.PREFIX_MSG + 'Stopping and deleting process by name %s', process_name);
2013-10-15 13:11:05 +02:00
Satan.executeRemote('deleteProcessName', process_name, function(err, list) {
2013-09-29 18:39:41 +02:00
if (err) {
printError(err);
return exitCli(cst.ERROR_EXIT);
2013-09-29 18:39:41 +02:00
}
UX.processing.stop();
2013-10-15 13:11:05 +02:00
speedList();
2013-09-29 18:39:41 +02:00
});
}
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method stopProcessName
* @param {} name
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
CLI.stopProcessName = function(name) {
Satan.executeRemote('stopProcessName', name, function(err, list) {
if (err) {
printError(err);
return exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
printOut(cst.PREFIX_MSG + 'Stopping process by name ' + name);
2013-09-28 17:33:46 +02:00
UX.processing.stop();
2013-10-15 13:11:05 +02:00
speedList();
2013-09-28 17:33:46 +02:00
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method stopId
* @param {} pm2_id
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
CLI.stopId = function(pm2_id) {
Satan.executeRemote('stopProcessId', pm2_id, function(err, list) {
if (err) {
printError(err);
return exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
printOut(cst.PREFIX_MSG + ' Process stopped');
2013-09-28 17:33:46 +02:00
UX.processing.stop();
2013-10-15 13:11:05 +02:00
speedList();
2013-09-28 17:33:46 +02:00
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method generateSample
* @param {} name
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
CLI.generateSample = function(name) {
var sample = fs.readFileSync(path.join(__dirname, cst.SAMPLE_FILE_PATH));
var dt = sample.toString().replace(/VARIABLE/g, name);
var f_name = name + '-pm2.json';
fs.writeFileSync(path.join(process.env.PWD, f_name), dt);
console.info('Sample generated on current folder\n%s :\n', f_name);
console.info(dt);
2014-01-29 12:45:46 +01:00
exitCli(cst.SUCCESS_EXIT);
2013-09-28 17:33:46 +02:00
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method list
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
CLI.list = function() {
speedList();
2013-09-28 17:33:46 +02:00
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method jlist
* @param {} debug
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
CLI.jlist = function(debug) {
Satan.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
printError(err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
if (debug)
printOut(list);
2013-09-28 17:33:46 +02:00
else
printOut(JSON.stringify(list));
2014-01-29 12:45:46 +01:00
exitCli(cst.SUCCESS_EXIT);
2013-09-28 17:33:46 +02:00
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method flush
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
CLI.flush = function() {
printOut(cst.PREFIX_MSG + 'Flushing ' + cst.PM2_LOG_FILE_PATH);
2013-09-28 17:33:46 +02:00
fs.openSync(cst.PM2_LOG_FILE_PATH, 'w');
Satan.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
printError(err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
list.forEach(function(l) {
printOut(cst.PREFIX_MSG + 'Flushing');
printOut(cst.PREFIX_MSG + l.pm2_env.pm_out_log_path);
printOut(cst.PREFIX_MSG + l.pm2_env.pm_err_log_path);
2013-09-28 17:33:46 +02:00
2013-09-29 18:39:41 +02:00
fs.openSync(l.pm2_env.pm_out_log_path, 'w');
fs.openSync(l.pm2_env.pm_err_log_path, 'w');
2013-09-28 17:33:46 +02:00
});
2014-01-29 12:45:46 +01:00
exitCli(cst.SUCCESS_EXIT);
2013-09-28 17:33:46 +02:00
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method describeProcess
* @param {} pm2_id
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
CLI.describeProcess = function(pm2_id) {
var found = false;
Satan.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
console.error('Error retrieving process list: ' + err);
exitCli(cst.ERROR_EXIT);
}
list.forEach(function(proc) {
if (proc.pm_id == pm2_id) {
found = true;
UX.describeTable(proc);
}
});
if (found === false) {
printError('%d id doesn\'t exist', pm2_id);
return exitCli(cst.ERROR_EXIT);
}
return exitCli(cst.SUCCESS_EXIT);
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method reloadLogs
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
CLI.reloadLogs = function() {
printOut('Reloading all logs...');
Satan.executeRemote('reloadLogs', {}, function(err, logs) {
if (err) printError(err);
printOut('All logs reloaded');
exitCli(cst.SUCCESS_EXIT);
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method sendSignalToProcessName
* @param {} signal
* @param {} process_name
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2014-01-08 16:12:57 +01:00
CLI.sendSignalToProcessName = function(signal, process_name) {
Satan.executeRemote('sendSignalToProcessName', {
signal : signal,
process_name : process_name
}, function(err, list) {
if (err) {
printError(err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2014-01-08 16:12:57 +01:00
}
printOut(cst.PREFIX_MSG + 'Succesfully sent signal %s to process name %s', signal, process_name);
2014-01-08 16:12:57 +01:00
UX.processing.stop();
speedList();
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method sendSignalToProcessId
* @param {} signal
* @param {} process_id
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2014-01-08 16:12:57 +01:00
CLI.sendSignalToProcessId = function(signal, process_id) {
Satan.executeRemote('sendSignalToProcessId', {
signal : signal,
process_id : process_id
}, function(err, list) {
if (err) {
printError(err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2014-01-08 16:12:57 +01:00
}
printOut(cst.PREFIX_MSG + 'Succesfully sent signal %s to process id %s', signal, process_id);
2014-01-08 16:12:57 +01:00
UX.processing.stop();
speedList();
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method monit
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
CLI.monit = function() {
Satan.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
printError(err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
if (Object.keys(list).length == 0) {
printOut(cst.PREFIX_MSG + 'No online process to monitor');
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
2013-11-13 15:10:59 +01:00
2013-09-28 17:33:46 +02:00
Monit.init(list);
2014-06-13 16:11:43 +02:00
/**
* Description
* @method refresh
* @param {} cb
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
function refresh(cb) {
Satan.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
console.error('Error retrieving process list: ' + err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
setTimeout(function() {
Monit.refresh(list);
refresh();
}, 400);
});
}
refresh();
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method streamLogs
* @param {} id
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
CLI.streamLogs = function(id) {
var tdb = {};
2013-11-13 15:10:59 +01:00
2013-09-28 17:33:46 +02:00
Satan.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
printError(err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
2013-11-13 15:10:59 +01:00
printOut('########### Starting streaming logs for [%s] process', id || 'all');
list.forEach(function(proc) {
if ((!id || (id && !isNaN(parseInt(id)) && proc.pm_id == id)) ||
(!id || (id && isNaN(parseInt(id)) && proc.pm2_env.name == id))) {
var app_name = proc.pm2_env.name || p.basename(proc.pm2_env.pm_exec_path);
if (proc.pm2_env.pm_out_log_path)
Log.stream(proc.pm2_env.pm_out_log_path,
app_name + '-' + proc.pm_id + ' (out)');
if (proc.pm2_env.pm_err_log_path)
Log.stream(proc.pm2_env.pm_err_log_path,
app_name + '-' + proc.pm_id + ' (err)');
2013-09-28 17:33:46 +02:00
}
});
2013-09-28 17:33:46 +02:00
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method killDaemon
* @param {} cb
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
CLI.killDaemon = function(cb) {
printOut(cst.PREFIX_MSG + 'Killing pm2...');
Satan.executeRemote('getMonitorData', {}, function(err, list) {
2013-09-28 17:33:46 +02:00
if (err) {
console.error('Error retrieving process list: ' + err);
cb ? cb() : exitCli(cst.ERROR_EXIT);
2013-09-28 17:33:46 +02:00
}
async.eachLimit(list, 2, function(proc, next) {
Satan.executeRemote('deleteProcessId', proc.pm2_env.pm_id, function(err, res) {
if (err)
printError('Error : ' + err);
printOut(cst.PREFIX_MSG + 'Process %s stopped', proc.pm2_env.name);
return next();
});
return false;
}, function(err) {
printOut(cst.PREFIX_MSG + 'All processes stopped');
Satan.killDaemon(function(err, res) {
if (err) {
printError(err);
if (cb) return cb(err);
else exitCli(cst.ERROR_EXIT);
}
console.info('PM2 stopped');
cb ? cb(null, res) : exitCli(cst.SUCCESS_EXIT);
});
});
2013-09-28 17:33:46 +02:00
});
2013-09-28 17:33:46 +02:00
};
//
// Private methods
//
2014-01-10 16:08:52 +01:00
var gl_retry = 0;
2014-06-13 16:11:43 +02:00
/**
* Description
* @method speedList
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2013-09-28 17:33:46 +02:00
function speedList() {
2014-01-08 16:12:57 +01:00
var self = this;
2014-01-10 16:08:52 +01:00
UX.processing.stop();
2014-01-27 13:18:11 +01:00
getInteractInfo(function(i_err, interact_infos) {
Satan.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
if (gl_retry == 0) {
gl_retry += 1;
return setTimeout(speedList, 1400);
}
console.error('Error retrieving process list: %s.\nA process seems to be on infinite loop, retry in 5 seconds',err);
exitCli(cst.ERROR_EXIT);
}
if (commander.miniList && !commander.silent)
UX.miniDisplay(list);
else if (!commander.silent) {
if (interact_infos) {
printOut('●'.green.bold + ' Connected to VitalSigns public id : %s - machine name : %s', interact_infos.public_key, interact_infos.machine_name);
}
UX.dispAsTable(list, interact_infos);
printOut(' Use `pm2 desc[ribe] <id>` to get more details');
2014-01-08 16:12:57 +01:00
}
if (commander.daemon) {
return exitCli(cst.SUCCESS_EXIT);
}
else {
printOut('--no-daemon option enabled = do not exit pm2 CLI');
printOut('PM2 dameon PID = %s', fs.readFileSync(cst.PM2_PID_FILE_PATH));
return Log.stream(cst.PM2_LOG_FILE_PATH);
}
});
2013-09-28 17:33:46 +02:00
});
}
2014-06-13 16:11:43 +02:00
/**
* Description
* @method printError
* @param {} msg
* @return CallExpression
*/
function printError(msg) {
if (msg instanceof Error)
return console.error(msg.message);
2014-04-14 13:14:13 +08:00
return console.error.apply(console, arguments);
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method printOut
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
2014-04-14 13:14:13 +08:00
function printOut() {
console.log.apply(console, arguments);
}
2014-06-13 16:11:43 +02:00
/**
* Description
* @method getInteractInfo
* @param {} cb
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
function getInteractInfo(cb) {
InteractorDaemonizer.ping(function(online) {
if (!online) {
return cb({msg : 'offline'});
}
InteractorDaemonizer.launchRPC(function() {
InteractorDaemonizer.rpc.getInfos(function(err, infos) {
if (err) {
return cb(err);
}
return cb(null, infos);
});
});
return false;
});
};
2014-06-13 16:11:43 +02:00
/**
* Description
* @method exitCli
* @param {} code
* @return CallExpression
*/
2014-01-29 12:45:46 +01:00
function exitCli(code) {
Satan.client.sock.close();
return process.exit(code);
}
2014-06-13 16:11:43 +02:00
/**
* Description
* @method resolvePaths
* @param {} appConf
* @return app
*/
function resolvePaths(appConf) {
2014-05-23 10:23:52 +02:00
var cwd = null;
if (appConf.cwd) {
cwd = p.resolve(appConf.cwd);
process.env.PWD = appConf.cwd;
}
2014-05-15 17:47:58 +02:00
var app = Common.resolveAppPaths(appConf, cwd, console.log);
2013-11-21 16:43:26 -05:00
if (app instanceof Error) {
console.error(cst.PREFIX_MSG_ERR + app.message);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
2013-09-29 21:45:36 +02:00
}
2013-11-21 16:43:26 -05:00
return app;
2013-09-28 17:33:46 +02:00
}
2014-06-13 16:11:43 +02:00
/**
* Description
* @method getProcessByName
* @param {} name
* @param {} cb
2014-06-13 16:24:16 +02:00
* @return
2014-06-13 16:11:43 +02:00
*/
function getProcessByName(name, cb) {
var arr = [];
Satan.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
console.error('Error retrieving process list: ' + err);
2014-01-29 12:45:46 +01:00
exitCli(cst.ERROR_EXIT);
}
list.forEach(function(proc) {
if (p.basename(proc.pm2_env.pm_exec_path) == name ||
p.basename(proc.pm2_env.pm_exec_path) == p.basename(name) ||
proc.pm2_env.name == name) {
arr.push(proc);
}
});
return cb(null, arr);
});
}