diff --git a/.travis.yml b/.travis.yml index d76fc89cc..25b0a3678 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ node_js: - "4" - "6" - "8" - - "0.12" os: - linux before_install: diff --git a/README.md b/README.md index 1ef3279ae..3b07141dd 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ npm version - + NPM Downloads @@ -70,6 +70,21 @@ Your app is now daemonized, monitored and kept alive forever. [More about Process Management](http://pm2.keymetrics.io/docs/usage/process-management/) +### Container Support + +With the drop-in replacement command for `node`, called `pm2-runtime`, run your Node.js application in a proper production environment. +We also offer an [officialy supported Docker image](https://hub.docker.com/r/keymetrics/pm2/). + +Using it is seamless: + +``` +FROM keymetrics/pm2:latest-alpine +[...] +CMD [ "pm2-runtime", "npm", "--", "start" ] +``` + +[Read More about the dedicated integration](http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/) + ### Managing a Process Once applications are started you can manage them easily: @@ -130,21 +145,6 @@ Seamlessly supported by all major Node.js frameworks and any Node.js application [More informations about how PM2 make clustering easy](https://keymetrics.io/2015/03/26/pm2-clustering-made-easy/) -### Container Support - -With the drop-in replacement command for `node`, called `pm2-runtime`, run your Node.js application in a proper production environment. -We also offer an [officialy supported Docker image](https://hub.docker.com/r/keymetrics/pm2/). - -Using it is seamless: - -``` -FROM keymetrics/pm2:latest-alpine -[...] -CMD [ "pm2-runtime", "npm", "--", "start" ] -``` - -[Read More about the dedicated integration](http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/) - ### Terminal Based Monitoring ![Monit](https://github.com/Unitech/pm2/raw/master/pres/pm2-monit.png) @@ -293,7 +293,6 @@ $ pm2 reset [app-name] # Reset all counters $ pm2 stop all # Stop all apps $ pm2 stop 0 # Stop process with id 0 $ pm2 restart all # Restart all apps -$ pm2 gracefulReload all # Gracefully reload all apps in cluster mode $ pm2 delete all # Kill and delete all apps $ pm2 delete 0 # Delete app with id 0 diff --git a/bin/pm2 b/bin/pm2 index 05072f4bc..840dc84c6 100755 --- a/bin/pm2 +++ b/bin/pm2 @@ -155,7 +155,7 @@ function checkCompletion(){ return data.short; }), data); // array containing commands after which process name should be listed - var cmdProcess = ['stop', 'restart', 'scale', 'reload', 'gracefulReload', 'delete', 'reset', 'pull', 'forward', 'backward', 'logs', 'describe', 'desc', 'show']; + var cmdProcess = ['stop', 'restart', 'scale', 'reload', 'delete', 'reset', 'pull', 'forward', 'backward', 'logs', 'describe', 'desc', 'show']; if (cmdProcess.indexOf(data.prev) > -1) { pm2.list(function(err, list){ @@ -390,21 +390,19 @@ commander.command('reload ') pm2.reload(pm2_id, commander); }); -// -// Reload process(es) -// -commander.command('gracefulReload ') - .description('gracefully reload a process. Send a "shutdown" message to close all connections.') - .action(function(pm2_id) { - pm2.gracefulReload(pm2_id, commander); - }); - commander.command('id ') .description('get process id by name') .action(function(name) { pm2.getProcessIdByName(name); }); +// Inspect a process +commander.command('inspect ') + .description('inspect a process') + .action(function(cmd) { + pm2.inspect(cmd, commander); + }); + // // Stop and delete a process by name from database // @@ -612,6 +610,15 @@ commander.command('dump') pm2.dump(); })); +// +// Delete dump file +// +commander.command('cleardump') + .description('Create empty dump file') + .action(failOnUnknown(function() { + pm2.clearDump(); + })); + // // Save processes to file // @@ -891,15 +898,6 @@ commander.command('backward ') pm2.backward(pm2_name); }); -// -// Force PM2 to trigger garbage collection -// -commander.command('gc') - .description('force PM2 to trigger garbage collection') - .action(function() { - pm2.forceGc(); - }); - // // Perform a deep update of PM2 // diff --git a/examples/misc-examples/graceful-exit.js b/examples/misc-examples/graceful-exit.js index df593d447..a35fc3e85 100644 --- a/examples/misc-examples/graceful-exit.js +++ b/examples/misc-examples/graceful-exit.js @@ -2,7 +2,7 @@ /* * Example of graceful exit * - * $ pm2 gracefulReload all + * $ pm2 reload all */ process.on('message', function(msg) { diff --git a/examples/sourcemap-auto-resolve/API.js b/examples/sourcemap-auto-resolve/API.js index ed62bdecb..544138794 100644 --- a/examples/sourcemap-auto-resolve/API.js +++ b/examples/sourcemap-auto-resolve/API.js @@ -399,33 +399,6 @@ API.prototype.update = function(cb) { return false; }; -/** - * Graceful Reload an application - * - * @param {String} process_name Application Name or All - * @param {Object} opts Options - * @param {Function} cb Callback - */ -API.prototype.gracefulReload = function(process_name, opts, cb) { - var that = this; - - if (typeof(opts) == "function") { - cb = opts; - opts = {}; - } - - //Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Warning gracefulReload will be soon deprecated')); - //Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Use http://pm2.keymetrics.io/docs/usage/signals-clean-restart/ instead')); - - if (Common.isConfigFile(process_name)) - that._startJson(process_name, commander, 'softReloadProcessId'); - else { - if (opts && !opts.updateEnv) - Common.printOut(IMMUTABLE_MSG); - that._operate('softReloadProcessId', process_name, opts, cb); - } -}; - /** * Reload an application * diff --git a/lib/API.js b/lib/API.js index 59bc227f1..0296c2d31 100644 --- a/lib/API.js +++ b/lib/API.js @@ -3,15 +3,16 @@ * Use of this source code is governed by a license that * can be found in the LICENSE file. */ +'use strict'; -var commander = require('commander'); -var fs = require('fs'); -var path = require('path'); -var async = require('async'); -var debug = require('debug')('pm2:cli'); -var util = require('util'); -var chalk = require('chalk'); -var fclone = require('fclone'); +const commander = require('commander'); +const fs = require('fs'); +const path = require('path'); +const async = require('async'); +const debug = require('debug')('pm2:cli'); +const util = require('util'); +const chalk = require('chalk'); +const fclone = require('fclone'); var conf = require('../constants.js'); var Client = require('./Client'); @@ -45,366 +46,351 @@ var IMMUTABLE_MSG = chalk.bold.blue('Use --update-env to update environment vari * @param {String} [opts.secret_key=null] keymetrics bucket secret key * @param {String} [opts.machine_name=null] keymetrics instance name */ -var API = module.exports = function(opts) { - if (!opts) opts = {}; - var that = this; +class API { - this.daemon_mode = typeof(opts.daemon_mode) == 'undefined' ? true : opts.daemon_mode; - this.pm2_home = conf.PM2_ROOT_PATH; - this.public_key = process.env.KEYMETRICS_SECRET || opts.public_key || null; - this.secret_key = process.env.KEYMETRICS_PUBLIC || opts.secret_key || null; - this.machine_name = process.env.INSTANCE_NAME || opts.machine_name || null + constructor (opts) { + if (!opts) opts = {}; + const that = this; - /** - * CWD resolution - */ - this.cwd = process.cwd(); - if (opts.cwd) { - this.cwd = path.resolve(opts.cwd); - } + this.daemon_mode = typeof(opts.daemon_mode) == 'undefined' ? true : opts.daemon_mode; + this.pm2_home = conf.PM2_ROOT_PATH; + this.public_key = process.env.KEYMETRICS_SECRET || opts.public_key || null; + this.secret_key = process.env.KEYMETRICS_PUBLIC || opts.secret_key || null; + this.machine_name = process.env.INSTANCE_NAME || opts.machine_name || null - /** - * PM2 HOME resolution - */ - if (opts.pm2_home && opts.independent == true) - throw new Error('You cannot set a pm2_home and independent instance in same time'); + /** + * CWD resolution + */ + this.cwd = process.cwd(); + if (opts.cwd) { + this.cwd = path.resolve(opts.cwd); + } - if (opts.pm2_home) { - // Override default conf file - this.pm2_home = opts.pm2_home; - conf = util._extend(conf, path_structure(this.pm2_home)); - } - else if (opts.independent == true && conf.IS_WINDOWS === false) { - // Create an unique pm2 instance - var crypto = require('crypto'); - var random_file = crypto.randomBytes(8).toString('hex'); - this.pm2_home = path.join('/tmp', random_file); - - // If we dont explicitly tell to have a daemon - // It will go as in proc - if (typeof(opts.daemon_mode) == 'undefined') - this.daemon_mode = false; - conf = util._extend(conf, path_structure(this.pm2_home)); - } + /** + * PM2 HOME resolution + */ + if (opts.pm2_home && opts.independent == true) + throw new Error('You cannot set a pm2_home and independent instance in same time'); - this._conf = conf; + if (opts.pm2_home) { + // Override default conf file + this.pm2_home = opts.pm2_home; + conf = util._extend(conf, path_structure(this.pm2_home)); + } + else if (opts.independent == true && conf.IS_WINDOWS === false) { + // Create an unique pm2 instance + const crypto = require('crypto'); + const random_file = crypto.randomBytes(8).toString('hex'); + this.pm2_home = path.join('/tmp', random_file); + + // If we dont explicitly tell to have a daemon + // It will go as in proc + if (typeof(opts.daemon_mode) == 'undefined') + this.daemon_mode = false; + conf = util._extend(conf, path_structure(this.pm2_home)); + } - if (conf.IS_WINDOWS) { - // Weird fix, may need to be dropped - // @todo windows connoisseur double check - if (process.stdout._handle && process.stdout._handle.setBlocking) - process.stdout._handle.setBlocking(true); - } + this._conf = conf; - this.Client = new Client({ - pm2_home : that.pm2_home, - conf : this._conf, - secret_key : this.secret_key, - public_key : this.public_key, - daemon_mode : this.daemon_mode, - machine_name : this.machine_name - }); - - this.gl_interact_infos = null; - this.gl_is_km_linked = false; - - try { - var pid = fs.readFileSync(conf.INTERACTOR_PID_PATH); - pid = parseInt(pid.toString().trim()); - process.kill(pid, 0); - that.gl_is_km_linked = true; - } catch(e) { - that.gl_is_km_linked = false; - } + if (conf.IS_WINDOWS) { + // Weird fix, may need to be dropped + // @todo windows connoisseur double check + if (process.stdout._handle && process.stdout._handle.setBlocking) + process.stdout._handle.setBlocking(true); + } - // For testing purposes - if (this.secret_key && process.env.NODE_ENV == 'local_test') - that.gl_is_km_linked = true; + this.Client = new Client({ + pm2_home: that.pm2_home, + conf: this._conf, + secret_key: this.secret_key, + public_key: this.public_key, + daemon_mode: this.daemon_mode, + machine_name: this.machine_name + }); - KMDaemon.getInteractInfo(this._conf, function(i_err, interact) { - that.gl_interact_infos = interact; - }); -}; + this.gl_interact_infos = null; + this.gl_is_km_linked = false; + try { + const pid = fs.readFileSync(conf.INTERACTOR_PID_PATH); + pid = parseInt(pid.toString().trim()); + process.kill(pid, 0); + that.gl_is_km_linked = true; + } catch (e) { + that.gl_is_km_linked = false; + } -////////////////////////// -// Load all API methods // -////////////////////////// + // For testing purposes + if (this.secret_key && process.env.NODE_ENV == 'local_test') + that.gl_is_km_linked = true; -require('./API/Extra.js')(API); -require('./API/Interaction.js')(API); -require('./API/Deploy.js')(API); -require('./API/Modules/Modules.js')(API); -require('./API/Keymetrics/cli-api.js')(API); -require('./API/Configuration.js')(API); -require('./API/Version.js')(API); -require('./API/Startup.js')(API); -require('./API/LogManagement.js')(API); -require('./API/Containerizer.js')(API); + KMDaemon.getInteractInfo(this._conf, function (i_err, interact) { + that.gl_interact_infos = interact; + }); -/** - * Connect to PM2 - * Calling this command is now optional - * - * @param {Function} cb callback once pm2 is ready for commands - */ -API.prototype.connect = function(noDaemon, cb) { - var that = this; - this.start_timer = new Date(); - - if (typeof(cb) == 'undefined') { - cb = noDaemon; - noDaemon = false; - } else if (noDaemon === true) { - // Backward compatibility with PM2 1.x - this.Client.daemon_mode = false; - this.daemon_mode = false; + this.gl_retry = 0; } - this.Client.start(function(err, meta) { - if (err) - return cb(err); + /** + * Connect to PM2 + * Calling this command is now optional + * + * @param {Function} cb callback once pm2 is ready for commands + */ + connect (noDaemon, cb) { + var that = this; + this.start_timer = new Date(); + + if (typeof(cb) == 'undefined') { + cb = noDaemon; + noDaemon = false; + } else if (noDaemon === true) { + // Backward compatibility with PM2 1.x + this.Client.daemon_mode = false; + this.daemon_mode = false; + } + + this.Client.start(function(err, meta) { + if (err) + return cb(err); - if (meta.new_pm2_instance == false && that.daemon_mode === true) - return cb(err, meta); + if (meta.new_pm2_instance == false && that.daemon_mode === true) + return cb(err, meta); - // If new pm2 instance has been popped - // Lauch all modules - Modularizer.launchAll(that, function(err_mod) { - return cb(err, meta); + // If new pm2 instance has been popped + // Lauch all modules + Modularizer.launchAll(that, function(err_mod) { + return cb(err, meta); + }); }); - }); -} + } -/** - * Usefull when custom PM2 created with independent flag set to true - * This will cleanup the newly created instance - * by removing folder, killing PM2 and so on - * - * @param {Function} cb callback once cleanup is successfull - */ -API.prototype.destroy = function(cb) { - var exec = require('shelljs').exec; - var that = this; + /** + * Usefull when custom PM2 created with independent flag set to true + * This will cleanup the newly created instance + * by removing folder, killing PM2 and so on + * + * @param {Function} cb callback once cleanup is successfull + */ + destroy (cb) { + var exec = require('shelljs').exec; + var that = this; - debug('Killing and deleting current deamon'); + debug('Killing and deleting current deamon'); - this.killDaemon(function() { - var cmd = 'rm -rf ' + that.pm2_home; - var test_path = path.join(that.pm2_home, 'module_conf.json'); - var test_path_2 = path.join(that.pm2_home, 'pm2.pid'); + this.killDaemon(function() { + var cmd = 'rm -rf ' + that.pm2_home; + var test_path = path.join(that.pm2_home, 'module_conf.json'); + var test_path_2 = path.join(that.pm2_home, 'pm2.pid'); - if (that.pm2_home.indexOf('.pm2') > -1) - return cb(new Error('Destroy is not a allowed method on .pm2')); + if (that.pm2_home.indexOf('.pm2') > -1) + return cb(new Error('Destroy is not a allowed method on .pm2')); - if (fs.accessSync) { fs.access(test_path, fs.R_OK, function(err) { if (err) return cb(err); debug('Deleting temporary folder %s', that.pm2_home); exec(cmd, cb); }); - return false; - } - - // Support for Node 0.10 - fs.exists(test_path, function(exist) { - if (exist) { - debug('Deleting temporary folder %s', that.pm2_home); - exec(cmd, cb); - } - return cb(null); }); - }); -}; + } -/** - * Disconnect from PM2 instance - * This will allow your software to exit by itself - * - * @param {Function} [cb] optional callback once connection closed - */ -API.prototype.disconnect = API.prototype.close = function(cb) { - var that = this; + /** + * Disconnect from PM2 instance + * This will allow your software to exit by itself + * + * @param {Function} [cb] optional callback once connection closed + */ + disconnect (cb) { + var that = this; - if (!cb) cb = function() {}; + if (!cb) cb = function() {}; - this.Client.close(function(err, data) { - debug('The session lasted %ds', (new Date() - that.start_timer) / 1000); - return cb(err, data); - }); -}; + this.Client.close(function(err, data) { + debug('The session lasted %ds', (new Date() - that.start_timer) / 1000); + return cb(err, data); + }); + }; -/** - * Launch modules - * - * @param {Function} cb callback once pm2 has launched modules - */ -API.prototype.launchModules = function(cb) { - Modularizer.launchAll(this, cb); -}; + /** + * Alias on disconnect + * @param cb + */ + close (cb) { + this.disconnect(cb); + } -/** - * Enable bus allowing to retrieve various process event - * like logs, restarts, reloads - * - * @param {Function} cb callback called with 1st param err and 2nb param the bus - */ -API.prototype.launchBus = function(cb) { - this.Client.launchBus(cb); -}; + /** + * Launch modules + * + * @param {Function} cb callback once pm2 has launched modules + */ + launchModules (cb) { + Modularizer.launchAll(this, cb); + } -/** - * Exit methods for API - * @param {Integer} code exit code for terminal - */ -API.prototype.exitCli = function(code) { - var that = this; - - // Do nothing if PM2 called programmatically (also in speedlist) - if (conf.PM2_PROGRAMMATIC && process.env.PM2_USAGE != 'CLI') return false; - - KMDaemon.disconnectRPC(function() { - that.Client.close(function() { - code = code || 0; - // Safe exits process after all streams are drained. - // file descriptor flag. - var fds = 0; - // exits process when stdout (1) and sdterr(2) are both drained. - function tryToExit() { - if ((fds & 1) && (fds & 2)) { - debug('This command took %ds to execute', (new Date() - that.start_timer) / 1000); - process.exit(code); + /** + * Enable bus allowing to retrieve various process event + * like logs, restarts, reloads + * + * @param {Function} cb callback called with 1st param err and 2nb param the bus + */ + launchBus (cb) { + this.Client.launchBus(cb); + } + + /** + * Exit methods for API + * @param {Integer} code exit code for terminal + */ + exitCli (code) { + var that = this; + + // Do nothing if PM2 called programmatically (also in speedlist) + if (conf.PM2_PROGRAMMATIC && process.env.PM2_USAGE != 'CLI') return false; + + KMDaemon.disconnectRPC(function() { + that.Client.close(function() { + code = code || 0; + // Safe exits process after all streams are drained. + // file descriptor flag. + var fds = 0; + // exits process when stdout (1) and sdterr(2) are both drained. + function tryToExit() { + if ((fds & 1) && (fds & 2)) { + debug('This command took %ds to execute', (new Date() - that.start_timer) / 1000); + process.exit(code); + } } - } - [process.stdout, process.stderr].forEach(function(std) { - var fd = std.fd; - if (!std.bufferSize) { - // bufferSize equals 0 means current stream is drained. - fds = fds | fd; - } else { - // Appends nothing to the std queue, but will trigger `tryToExit` event on `drain`. - std.write && std.write('', function() { + [process.stdout, process.stderr].forEach(function(std) { + var fd = std.fd; + if (!std.bufferSize) { + // bufferSize equals 0 means current stream is drained. fds = fds | fd; - tryToExit(); - }); - } - // Does not write anything more. - delete std.write; + } else { + // Appends nothing to the std queue, but will trigger `tryToExit` event on `drain`. + std.write && std.write('', function() { + fds = fds | fd; + tryToExit(); + }); + } + // Does not write anything more. + delete std.write; + }); + tryToExit(); }); - tryToExit(); }); - }); -}; + } //////////////////////////// // Application management // //////////////////////////// -/** - * Start a file or json with configuration - * @param {Object||String} cmd script to start or json - * @param {Function} cb called when application has been started - */ -API.prototype.start = function(cmd, opts, cb) { - if (typeof(opts) == "function") { - cb = opts; - opts = {}; - } - if (!opts) - opts = {}; + /** + * Start a file or json with configuration + * @param {Object||String} cmd script to start or json + * @param {Function} cb called when application has been started + */ + start (cmd, opts, cb) { + if (typeof(opts) == "function") { + cb = opts; + opts = {}; + } + if (!opts) + opts = {}; - var that = this; + var that = this; - if (util.isArray(opts.watch) && opts.watch.length === 0) - opts.watch = (opts.rawArgs ? !!~opts.rawArgs.indexOf('--watch') : !!~process.argv.indexOf('--watch')) || false; + if (util.isArray(opts.watch) && opts.watch.length === 0) + opts.watch = (opts.rawArgs ? !!~opts.rawArgs.indexOf('--watch') : !!~process.argv.indexOf('--watch')) || false; - if (Common.isConfigFile(cmd) || (typeof(cmd) === 'object')) - that._startJson(cmd, opts, 'restartProcessId', cb); - else { - that._startScript(cmd, opts, cb); + if (Common.isConfigFile(cmd) || (typeof(cmd) === 'object')) + that._startJson(cmd, opts, 'restartProcessId', cb); + else { + that._startScript(cmd, opts, cb); + } } -}; -/** - * Reset process counters - * - * @method resetMetaProcess - */ -API.prototype.reset = function(process_name, cb) { - var that = this; - - function processIds(ids, cb) { - async.eachLimit(ids, conf.CONCURRENT_ACTIONS, function(id, next) { - that.Client.executeRemote('resetMetaProcessId', id, function(err, res) { - if (err) console.error(err); - Common.printOut(conf.PREFIX_MSG + 'Resetting meta for process id %d', id); - return next(); + /** + * Reset process counters + * + * @method resetMetaProcess + */ + reset (process_name, cb) { + var that = this; + + function processIds(ids, cb) { + async.eachLimit(ids, conf.CONCURRENT_ACTIONS, function(id, next) { + that.Client.executeRemote('resetMetaProcessId', id, function(err, res) { + if (err) console.error(err); + Common.printOut(conf.PREFIX_MSG + 'Resetting meta for process id %d', id); + return next(); + }); + }, function(err) { + if (err) return cb(Common.retErr(err)); + return cb ? cb(null, {success:true}) : that.speedList(); }); - }, function(err) { - if (err) return cb(Common.retErr(err)); - return cb ? cb(null, {success:true}) : that.speedList(); - }); - } + } - if (process_name == 'all') { - that.Client.getAllProcessId(function(err, ids) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } - return processIds(ids, cb); - }); - } - else if (isNaN(process_name)) { - that.Client.getProcessIdByName(process_name, function(err, ids) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } - if (ids.length === 0) { - Common.printError('Unknown process name'); - return cb ? cb(new Error('Unknown process name')) : that.exitCli(conf.ERROR_EXIT); - } - return processIds(ids, cb); - }); - } else { - processIds([process_name], cb); + if (process_name == 'all') { + that.Client.getAllProcessId(function(err, ids) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + return processIds(ids, cb); + }); + } + else if (isNaN(process_name)) { + that.Client.getProcessIdByName(process_name, function(err, ids) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + if (ids.length === 0) { + Common.printError('Unknown process name'); + return cb ? cb(new Error('Unknown process name')) : that.exitCli(conf.ERROR_EXIT); + } + return processIds(ids, cb); + }); + } else { + processIds([process_name], cb); + } } -}; -/** - * Update daemonized PM2 Daemon - * - * @param {Function} cb callback when pm2 has been upgraded - */ -API.prototype.update = function(cb) { - var that = this; + /** + * Update daemonized PM2 Daemon + * + * @param {Function} cb callback when pm2 has been upgraded + */ + update (cb) { + var that = this; - Common.printOut('Be sure to have the latest version by doing `npm install pm2@latest -g` before doing this procedure.'); + Common.printOut('Be sure to have the latest version by doing `npm install pm2@latest -g` before doing this procedure.'); - // Dump PM2 processes - that.Client.executeRemote('notifyKillPM2', {}, function() {}); + // Dump PM2 processes + that.Client.executeRemote('notifyKillPM2', {}, function() {}); - that.getVersion(function(err, new_version) { - // If not linked to keymetrics, and update pm2 to latest, display motd.update - if (!that.gl_is_km_linked && !err && (pkg.version != new_version)) { - var dt = fs.readFileSync(path.join(__dirname, that._conf.KEYMETRICS_UPDATE)); - console.log(dt.toString()); - } + that.getVersion(function(err, new_version) { + // If not linked to keymetrics, and update pm2 to latest, display motd.update + if (!that.gl_is_km_linked && !err && (pkg.version != new_version)) { + var dt = fs.readFileSync(path.join(__dirname, that._conf.KEYMETRICS_UPDATE)); + console.log(dt.toString()); + } - that.dump(function(err) { - debug('Dumping successfull', err); - that.killDaemon(function() { - debug('------------------ Everything killed', arguments); - that.Client.launchDaemon({interactor:false}, function(err, child) { - that.Client.launchRPC(function() { - that.resurrect(function() { - Common.printOut(chalk.blue.bold('>>>>>>>>>> PM2 updated')); - Modularizer.launchAll(that, function() { - KMDaemon.launchAndInteract(that._conf, null, function(err, data, interactor_proc) { - // Interactor error can be skipped here - return cb ? cb(null, {success:true}) : that.speedList(); + that.dump(function(err) { + debug('Dumping successfull', err); + that.killDaemon(function() { + debug('------------------ Everything killed', arguments); + that.Client.launchDaemon({interactor:false}, function(err, child) { + that.Client.launchRPC(function() { + that.resurrect(function() { + Common.printOut(chalk.blue.bold('>>>>>>>>>> PM2 updated')); + Modularizer.launchAll(that, function() { + KMDaemon.launchAndInteract(that._conf, null, function(err, data, interactor_proc) { + // Interactor error can be skipped here + return cb ? cb(null, {success:true}) : that.speedList(); + }); }); }); }); @@ -412,1276 +398,1262 @@ API.prototype.update = function(cb) { }); }); }); - }); - - return false; -}; - -/** - * Graceful Reload an application - * - * @param {String} process_name Application Name or All - * @param {Object} opts Options - * @param {Function} cb Callback - */ -API.prototype.gracefulReload = function(process_name, opts, cb) { - var that = this; - if (typeof(opts) == "function") { - cb = opts; - opts = {}; - } - - //Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Warning gracefulReload will be soon deprecated')); - //Common.printOut(conf.PREFIX_MSG_WARNING + chalk.bold.yellow('Use http://pm2.keymetrics.io/docs/usage/signals-clean-restart/ instead')); - - if (Common.isConfigFile(process_name)) - that._startJson(process_name, commander, 'softReloadProcessId'); - else { - if (opts && !opts.updateEnv) - Common.printOut(IMMUTABLE_MSG); - that._operate('softReloadProcessId', process_name, opts, cb); + return false; } -}; -/** - * Reload an application - * - * @param {String} process_name Application Name or All - * @param {Object} opts Options - * @param {Function} cb Callback - */ -API.prototype.reload = function(process_name, opts, cb) { - var that = this; + /** + * Reload an application + * + * @param {String} process_name Application Name or All + * @param {Object} opts Options + * @param {Function} cb Callback + */ + reload (process_name, opts, cb) { + var that = this; - if (typeof(opts) == "function") { - cb = opts; - opts = {}; - } + if (typeof(opts) == "function") { + cb = opts; + opts = {}; + } - var delay = Common.lockReload(); + var delay = Common.lockReload(); - if (delay > 0 && opts.force != true) { - Common.printError(conf.PREFIX_MSG_ERR + 'Reload already in progress, please try again in ' + Math.floor((conf.RELOAD_LOCK_TIMEOUT - delay) / 1000) + ' seconds or use --force'); - return cb ? cb(new Error('Reload in progress')) : that.exitCli(conf.ERROR_EXIT); - } + if (delay > 0 && opts.force != true) { + Common.printError(conf.PREFIX_MSG_ERR + 'Reload already in progress, please try again in ' + Math.floor((conf.RELOAD_LOCK_TIMEOUT - delay) / 1000) + ' seconds or use --force'); + return cb ? cb(new Error('Reload in progress')) : that.exitCli(conf.ERROR_EXIT); + } - if (Common.isConfigFile(process_name)) - that._startJson(process_name, opts, 'reloadProcessId', function(err, apps) { - Common.unlockReload(); - if (err) - return cb ? cb(err) : that.exitCli(conf.ERROR_EXIT); - return cb ? cb(null, apps) : that.exitCli(conf.SUCCESS_EXIT);; - }); - else { - if (opts && !opts.updateEnv) - Common.printOut(IMMUTABLE_MSG); + if (Common.isConfigFile(process_name)) + that._startJson(process_name, opts, 'reloadProcessId', function(err, apps) { + Common.unlockReload(); + if (err) + return cb ? cb(err) : that.exitCli(conf.ERROR_EXIT); + return cb ? cb(null, apps) : that.exitCli(conf.SUCCESS_EXIT);; + }); + else { + if (opts && !opts.updateEnv) + Common.printOut(IMMUTABLE_MSG); - that._operate('reloadProcessId', process_name, opts, function(err, apps) { - Common.unlockReload(); + that._operate('reloadProcessId', process_name, opts, function(err, apps) { + Common.unlockReload(); - if (err) - return cb ? cb(err) : that.exitCli(conf.ERROR_EXIT); - return cb ? cb(null, apps) : that.exitCli(conf.SUCCESS_EXIT);; - }); + if (err) + return cb ? cb(err) : that.exitCli(conf.ERROR_EXIT); + return cb ? cb(null, apps) : that.exitCli(conf.SUCCESS_EXIT);; + }); + } } -}; -/** - * Restart process - * - * @param {String} cmd Application Name / Process id / JSON application file / 'all' - * @param {Object} opts Extra options to be updated - * @param {Function} cb Callback - */ -API.prototype.restart = function(cmd, opts, cb) { - if (typeof(opts) == "function") { - cb = opts; - opts = {}; - } - var that = this; - - if (typeof(cmd) === 'number') - cmd = cmd.toString(); - - if (cmd == "-") { - // Restart from PIPED JSON - process.stdin.resume(); - process.stdin.setEncoding('utf8'); - process.stdin.on('data', function (param) { - process.stdin.pause(); - that.actionFromJson('restartProcessId', param, opts, 'pipe', cb); - }); - } - else if (Common.isConfigFile(cmd) || typeof(cmd) === 'object') - that._startJson(cmd, opts, 'restartProcessId', cb); - else { - if (opts && !opts.updateEnv) - Common.printOut(IMMUTABLE_MSG); - that._operate('restartProcessId', cmd, opts, cb); + /** + * Restart process + * + * @param {String} cmd Application Name / Process id / JSON application file / 'all' + * @param {Object} opts Extra options to be updated + * @param {Function} cb Callback + */ + restart (cmd, opts, cb) { + if (typeof(opts) == "function") { + cb = opts; + opts = {}; + } + var that = this; + + if (typeof(cmd) === 'number') + cmd = cmd.toString(); + + if (cmd == "-") { + // Restart from PIPED JSON + process.stdin.resume(); + process.stdin.setEncoding('utf8'); + process.stdin.on('data', function (param) { + process.stdin.pause(); + that.actionFromJson('restartProcessId', param, opts, 'pipe', cb); + }); + } + else if (Common.isConfigFile(cmd) || typeof(cmd) === 'object') + that._startJson(cmd, opts, 'restartProcessId', cb); + else { + if (opts && !opts.updateEnv) + Common.printOut(IMMUTABLE_MSG); + that._operate('restartProcessId', cmd, opts, cb); + } } -}; -/** - * Delete process - * - * @param {String} process_name Application Name / Process id / Application file / 'all' - * @param {Function} cb Callback - */ -API.prototype.delete = function(process_name, jsonVia, cb) { - var that = this; - - if (typeof(jsonVia) === "function") { - cb = jsonVia; - jsonVia = null; - } - if (typeof(process_name) === "number") { - process_name = process_name.toString(); - } + /** + * Delete process + * + * @param {String} process_name Application Name / Process id / Application file / 'all' + * @param {Function} cb Callback + */ + delete (process_name, jsonVia, cb) { + var that = this; - if (jsonVia == 'pipe') - return that.actionFromJson('deleteProcessId', process_name, commander, 'pipe', cb); - if (Common.isConfigFile(process_name)) - return that.actionFromJson('deleteProcessId', process_name, commander, 'file', cb); - else - that._operate('deleteProcessId', process_name, cb); -}; + if (typeof(jsonVia) === "function") { + cb = jsonVia; + jsonVia = null; + } + if (typeof(process_name) === "number") { + process_name = process_name.toString(); + } -/** - * Stop process - * - * @param {String} process_name Application Name / Process id / Application file / 'all' - * @param {Function} cb Callback - */ -API.prototype.stop = function(process_name, cb) { - var that = this; - - if (typeof(process_name) === 'number') - process_name = process_name.toString(); - - if (process_name == "-") { - process.stdin.resume(); - process.stdin.setEncoding('utf8'); - process.stdin.on('data', function (param) { - process.stdin.pause(); - that.actionFromJson('stopProcessId', param, commander, 'pipe', cb); - }); + if (jsonVia == 'pipe') + return that.actionFromJson('deleteProcessId', process_name, commander, 'pipe', cb); + if (Common.isConfigFile(process_name)) + return that.actionFromJson('deleteProcessId', process_name, commander, 'file', cb); + else + that._operate('deleteProcessId', process_name, cb); } - else if (Common.isConfigFile(process_name)) - that.actionFromJson('stopProcessId', process_name, commander, 'file', cb); - else - that._operate('stopProcessId', process_name, cb); -}; - -/** - * Get list of all processes managed - * - * @param {Function} cb Callback - */ -API.prototype.list = function(opts, cb) { - var that = this; - if (typeof(opts) == 'function') { - cb = opts; - opts = null; + /** + * Stop process + * + * @param {String} process_name Application Name / Process id / Application file / 'all' + * @param {Function} cb Callback + */ + stop (process_name, cb) { + var that = this; + + if (typeof(process_name) === 'number') + process_name = process_name.toString(); + + if (process_name == "-") { + process.stdin.resume(); + process.stdin.setEncoding('utf8'); + process.stdin.on('data', function (param) { + process.stdin.pause(); + that.actionFromJson('stopProcessId', param, commander, 'pipe', cb); + }); + } + else if (Common.isConfigFile(process_name)) + that.actionFromJson('stopProcessId', process_name, commander, 'file', cb); + else + that._operate('stopProcessId', process_name, cb); } - that.Client.executeRemote('getMonitorData', {}, function(err, list) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + /** + * Get list of all processes managed + * + * @param {Function} cb Callback + */ + list (opts, cb) { + var that = this; + + if (typeof(opts) == 'function') { + cb = opts; + opts = null; } - if (opts && opts.rawArgs && opts.rawArgs.indexOf('--watch') > -1) { - var moment = require('moment'); - function show() { - process.stdout.write('\033[2J'); - process.stdout.write('\033[0f'); - console.log('Last refresh: ', moment().format('LTS')); - that.Client.executeRemote('getMonitorData', {}, function(err, list) { - UX.dispAsTable(list, null); - }); + that.Client.executeRemote('getMonitorData', {}, function(err, list) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); } - show(); - setInterval(show, 900); - return false; - } + if (opts && opts.rawArgs && opts.rawArgs.indexOf('--watch') > -1) { + var moment = require('moment'); + function show() { + process.stdout.write('\\033[2J'); + process.stdout.write('\\033[0f'); + console.log('Last refresh: ', moment().format('LTS')); + that.Client.executeRemote('getMonitorData', {}, function(err, list) { + UX.dispAsTable(list, null); + }); + } - return cb ? cb(null, list) : that.speedList(); - }); -}; + show(); + setInterval(show, 900); + return false; + } -/** - * Kill Daemon - * - * @param {Function} cb Callback - */ -API.prototype.killDaemon = API.prototype.kill = function(cb) { - var that = this; + return cb ? cb(null, list) : that.speedList(); + }); + } - var semver = require('semver'); - Common.printOut(conf.PREFIX_MSG + 'Stopping PM2...'); + /** + * Kill Daemon + * + * @param {Function} cb Callback + */ + killDaemon (cb) { + var that = this; - that.Client.executeRemote('notifyKillPM2', {}, function() {}); + var semver = require('semver'); + Common.printOut(conf.PREFIX_MSG + 'Stopping PM2...'); - that.killAllModules(function() { - that._operate('deleteProcessId', 'all', function(err, list) { - Common.printOut(conf.PREFIX_MSG + 'All processes have been stopped and deleted'); - process.env.PM2_SILENT = 'false'; + that.Client.executeRemote('notifyKillPM2', {}, function() {}); - that.killInteract(function(err, data) { - that.Client.killDaemon(function(err, res) { - if (err) Common.printError(err); - Common.printOut(conf.PREFIX_MSG + 'PM2 stopped'); - return cb ? cb(err, res) : that.exitCli(conf.SUCCESS_EXIT); + that.killAllModules(function() { + that._operate('deleteProcessId', 'all', function(err, list) { + Common.printOut(conf.PREFIX_MSG + 'All processes have been stopped and deleted'); + process.env.PM2_SILENT = 'false'; + + that.killInteract(function(err, data) { + that.Client.killDaemon(function(err, res) { + if (err) Common.printError(err); + Common.printOut(conf.PREFIX_MSG + 'PM2 stopped'); + return cb ? cb(err, res) : that.exitCli(conf.SUCCESS_EXIT); + }); }); }); }); - }); -}; - -///////////////////// -// Private methods // -///////////////////// + } -/** - * Method to START / RESTART a script - * - * @private - * @param {string} script script name (will be resolved according to location) - */ -API.prototype._startScript = function(script, opts, cb) { - if (typeof opts == "function") { - cb = opts; - opts = {}; + kill (cb) { + this.killDaemon(cb); } - var that = this; - var app_conf = Config.transCMDToConf(opts); - var appConf = {}; + ///////////////////// + // Private methods // + ///////////////////// - if (!!opts.executeCommand) - app_conf.exec_mode = 'fork'; - else if (opts.instances !== undefined) - app_conf.exec_mode = 'cluster'; - else - app_conf.exec_mode = 'fork'; + /** + * Method to START / RESTART a script + * + * @private + * @param {string} script script name (will be resolved according to location) + */ + _startScript (script, opts, cb) { + if (typeof opts == "function") { + cb = opts; + opts = {}; + } + var that = this; - // Options set via environment variables - if (process.env.PM2_DEEP_MONITORING) - app_conf.deep_monitoring = true; + var app_conf = Config.transCMDToConf(opts); + var appConf = {}; - if (typeof app_conf.name == 'function'){ - delete app_conf.name; - } + if (!!opts.executeCommand) + app_conf.exec_mode = 'fork'; + else if (opts.instances !== undefined) + app_conf.exec_mode = 'cluster'; + else + app_conf.exec_mode = 'fork'; - delete app_conf.args; + // Options set via environment variables + if (process.env.PM2_DEEP_MONITORING) + app_conf.deep_monitoring = true; - var argsIndex; + if (typeof app_conf.name == 'function'){ + delete app_conf.name; + } - if (opts.rawArgs && (argsIndex = opts.rawArgs.indexOf('--')) >= 0) { - app_conf.args = opts.rawArgs.slice(argsIndex + 1); - } - else if (opts.scriptArgs) { - app_conf.args = opts.scriptArgs; - } + delete app_conf.args; - app_conf.script = script; + var argsIndex; - if ((appConf = Common.verifyConfs(app_conf)) instanceof Error) - return cb ? cb(Common.retErr(appConf)) : that.exitCli(conf.ERROR_EXIT); + if (opts.rawArgs && (argsIndex = opts.rawArgs.indexOf('--')) >= 0) { + app_conf.args = opts.rawArgs.slice(argsIndex + 1); + } + else if (opts.scriptArgs) { + app_conf.args = opts.scriptArgs; + } - app_conf = appConf[0]; + app_conf.script = script; - app_conf.username = Common.getCurrentUsername(); + if ((appConf = Common.verifyConfs(app_conf)) instanceof Error) + return cb ? cb(Common.retErr(appConf)) : that.exitCli(conf.ERROR_EXIT); - /** - * If -w option, write configuration to configuration.json file - */ - if (appConf.write) { - var dst_path = path.join(process.env.PWD || process.cwd(), app_conf.name + '-pm2.json'); - Common.printOut(conf.PREFIX_MSG + 'Writing configuration to', chalk.blue(dst_path)); - // pretty JSON - try { - fs.writeFileSync(dst_path, JSON.stringify(app_conf, null, 2)); - } catch (e) { - console.error(e.stack || e); + app_conf = appConf[0]; + + app_conf.username = Common.getCurrentUsername(); + + /** + * If -w option, write configuration to configuration.json file + */ + if (appConf.write) { + var dst_path = path.join(process.env.PWD || process.cwd(), app_conf.name + '-pm2.json'); + Common.printOut(conf.PREFIX_MSG + 'Writing configuration to', chalk.blue(dst_path)); + // pretty JSON + try { + fs.writeFileSync(dst_path, JSON.stringify(app_conf, null, 2)); + } catch (e) { + console.error(e.stack || e); + } } - } - /** - * If start start/restart application - */ - function restartExistingProcessName(cb) { - if (!isNaN(script) || + /** + * If start start/restart application + */ + function restartExistingProcessName(cb) { + if (!isNaN(script) || (typeof script === 'string' && script.indexOf('/') != -1) || (typeof script === 'string' && path.extname(script) !== '')) - return cb(null); - - if (script !== 'all') { - that.Client.getProcessIdByName(script, function(err, ids) { - if (err && cb) return cb(err); - if (ids.length > 0) { - that._operate('restartProcessId', script, opts, function(err, list) { - if (err) return cb(err); - Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); - return cb(true, list); - }); - } - else return cb(null); - }); + return cb(null); + + if (script !== 'all') { + that.Client.getProcessIdByName(script, function(err, ids) { + if (err && cb) return cb(err); + if (ids.length > 0) { + that._operate('restartProcessId', script, opts, function(err, list) { + if (err) return cb(err); + Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); + return cb(true, list); + }); + } + else return cb(null); + }); + } + else { + that._operate('restartProcessId', 'all', function(err, list) { + if (err) return cb(err); + Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); + return cb(true, list); + }); + } } - else { - that._operate('restartProcessId', 'all', function(err, list) { + + function restartExistingProcessId(cb) { + if (isNaN(script)) return cb(null); + + that._operate('restartProcessId', script, opts, function(err, list) { if (err) return cb(err); Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); return cb(true, list); }); } - } - function restartExistingProcessId(cb) { - if (isNaN(script)) return cb(null); - - that._operate('restartProcessId', script, opts, function(err, list) { - if (err) return cb(err); - Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); - return cb(true, list); - }); - } - - /** - * Restart a process with the same full path - * Or start it - */ - function restartExistingProcessPath(cb) { - that.Client.executeRemote('getMonitorData', {}, function(err, procs) { - if (err) return cb ? cb(new Error(err)) : that.exitCli(conf.ERROR_EXIT); + /** + * Restart a process with the same full path + * Or start it + */ + function restartExistingProcessPath(cb) { + that.Client.executeRemote('getMonitorData', {}, function(err, procs) { + if (err) return cb ? cb(new Error(err)) : that.exitCli(conf.ERROR_EXIT); - var full_path = path.resolve(that.cwd, script); - var managed_script = null; + var full_path = path.resolve(that.cwd, script); + var managed_script = null; - procs.forEach(function(proc) { - if (proc.pm2_env.pm_exec_path == full_path && + procs.forEach(function(proc) { + if (proc.pm2_env.pm_exec_path == full_path && proc.pm2_env.name == app_conf.name) - managed_script = proc; - }); + managed_script = proc; + }); - if (managed_script && + if (managed_script && (managed_script.pm2_env.status == conf.STOPPED_STATUS || - managed_script.pm2_env.status == conf.STOPPING_STATUS || - managed_script.pm2_env.status == conf.ERRORED_STATUS)) { - // Restart process if stopped - var app_name = managed_script.pm2_env.name; + managed_script.pm2_env.status == conf.STOPPING_STATUS || + managed_script.pm2_env.status == conf.ERRORED_STATUS)) { + // Restart process if stopped + var app_name = managed_script.pm2_env.name; - that._operate('restartProcessId', app_name, opts, function(err, list) { - if (err) return cb ? cb(new Error(err)) : that.exitCli(conf.ERROR_EXIT); - Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); - return cb(true, list); - }); - return false; - } - else if (managed_script && !opts.force) { - Common.printError(conf.PREFIX_MSG_ERR + 'Script already launched, add -f option to force re-execution'); - return cb(new Error('Script already launched')); - } + that._operate('restartProcessId', app_name, opts, function(err, list) { + if (err) return cb ? cb(new Error(err)) : that.exitCli(conf.ERROR_EXIT); + Common.printOut(conf.PREFIX_MSG + 'Process successfully started'); + return cb(true, list); + }); + return false; + } + else if (managed_script && !opts.force) { + Common.printError(conf.PREFIX_MSG_ERR + 'Script already launched, add -f option to force re-execution'); + return cb(new Error('Script already launched')); + } - var resolved_paths = null; + var resolved_paths = null; - try { - resolved_paths = Common.resolveAppAttributes({ - cwd : that.cwd, - pm2_home : that.pm2_home - }, app_conf); - } catch(e) { - Common.printError(e); - return cb(Common.retErr(e)); - } + try { + resolved_paths = Common.resolveAppAttributes({ + cwd : that.cwd, + pm2_home : that.pm2_home + }, app_conf); + } catch(e) { + Common.printError(e); + return cb(Common.retErr(e)); + } - Common.printOut(conf.PREFIX_MSG + 'Starting %s in %s (%d instance' + (resolved_paths.instances > 1 ? 's' : '') + ')', - resolved_paths.pm_exec_path, resolved_paths.exec_mode, resolved_paths.instances); + Common.printOut(conf.PREFIX_MSG + 'Starting %s in %s (%d instance' + (resolved_paths.instances > 1 ? 's' : '') + ')', + resolved_paths.pm_exec_path, resolved_paths.exec_mode, resolved_paths.instances); - if (!resolved_paths.env) resolved_paths.env = {}; + if (!resolved_paths.env) resolved_paths.env = {}; - // Set PM2 HOME in case of child process using PM2 API - resolved_paths.env['PM2_HOME'] = that.pm2_home; + // Set PM2 HOME in case of child process using PM2 API + resolved_paths.env['PM2_HOME'] = that.pm2_home; - var additional_env = Modularizer.getAdditionalConf(resolved_paths.name); - util._extend(resolved_paths.env, additional_env); + var additional_env = Modularizer.getAdditionalConf(resolved_paths.name); + util._extend(resolved_paths.env, additional_env); - // Is KM linked? - resolved_paths.km_link = that.gl_is_km_linked; + // Is KM linked? + resolved_paths.km_link = that.gl_is_km_linked; - that.Client.executeRemote('prepare', resolved_paths, function(err, data) { - if (err) { - Common.printError(conf.PREFIX_MSG_ERR + 'Error while launching application', err.stack || err); - return cb(Common.retErr(err)); - } + that.Client.executeRemote('prepare', resolved_paths, function(err, data) { + if (err) { + Common.printError(conf.PREFIX_MSG_ERR + 'Error while launching application', err.stack || err); + return cb(Common.retErr(err)); + } - Common.printOut(conf.PREFIX_MSG + 'Done.'); - return cb(true, data); + Common.printOut(conf.PREFIX_MSG + 'Done.'); + return cb(true, data); + }); + return false; }); - return false; - }); - } - - async.series([ - restartExistingProcessName, - restartExistingProcessId, - restartExistingProcessPath - ], function(err, data) { + } - if (err instanceof Error) - return cb ? cb(err) : that.exitCli(conf.ERROR_EXIT); + async.series([ + restartExistingProcessName, + restartExistingProcessId, + restartExistingProcessPath + ], function(err, data) { - var ret = {}; - data.forEach(function(_dt) { - if (_dt !== undefined) - ret = _dt; - }); + if (err instanceof Error) + return cb ? cb(err) : that.exitCli(conf.ERROR_EXIT); - return cb ? cb(null, ret) : that.speedList(); - }); -}; + var ret = {}; + data.forEach(function(_dt) { + if (_dt !== undefined) + ret = _dt; + }); -/** - * Method to start/restart/reload processes from a JSON file - * It will start app not started - * Can receive only option to skip applications - * - * @private - */ -API.prototype._startJson = function(file, opts, action, pipe, cb) { - var config = {}; - var appConf = {}; - var deployConf = {}; - var apps_info = []; - var that = this; - - if (typeof(cb) === 'undefined' && typeof(pipe) === 'function') { - cb = pipe; + return cb ? cb(null, ret) : that.speedList(); + }); } - if (typeof(file) === 'object') { - config = file; - } else if (pipe === 'pipe') { - config = Common.parseConfig(file, 'pipe'); - } else { - var data = null; - - var isAbsolute = false + /** + * Method to start/restart/reload processes from a JSON file + * It will start app not started + * Can receive only option to skip applications + * + * @private + */ + _startJson (file, opts, action, pipe, cb) { + var config = {}; + var appConf = {}; + var deployConf = {}; + var apps_info = []; + var that = this; + + if (typeof(cb) === 'undefined' && typeof(pipe) === 'function') { + cb = pipe; + } - //node 0.11 compatibility #2815 - if (typeof path.isAbsolute === 'function') { - isAbsolute = path.isAbsolute(file) + if (typeof(file) === 'object') { + config = file; + } else if (pipe === 'pipe') { + config = Common.parseConfig(file, 'pipe'); } else { - isAbsolute = require('./tools/IsAbsolute.js')(file) - } + var data = null; - var file_path = isAbsolute ? file : path.join(that.cwd, file); + var isAbsolute = path.isAbsolute(file) + var file_path = isAbsolute ? file : path.join(that.cwd, file); - debug('Resolved filepath %s', file_path); + debug('Resolved filepath %s', file_path); - try { - data = fs.readFileSync(file_path); - } catch(e) { - Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file +' not found'); - return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); - } + try { + data = fs.readFileSync(file_path); + } catch(e) { + Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file +' not found'); + return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); + } - try { - config = Common.parseConfig(data, file); - } catch(e) { - Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file + ' malformated'); - console.error(e); - return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); + try { + config = Common.parseConfig(data, file); + } catch(e) { + Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file + ' malformated'); + console.error(e); + return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); + } } - } - - if (config.deploy) - deployConf = config.deploy; - if (config.apps) - appConf = config.apps; - else if (config.pm2) - appConf = config.pm2; - else - appConf = config; + if (config.deploy) + deployConf = config.deploy; - if (!Array.isArray(appConf)) - appConf = [appConf]; //convert to array + if (config.apps) + appConf = config.apps; + else if (config.pm2) + appConf = config.pm2; + else + appConf = config; - if ((appConf = Common.verifyConfs(appConf)) instanceof Error) - return cb ? cb(appConf) : that.exitCli(conf.ERROR_EXIT); + if (!Array.isArray(appConf)) + appConf = [appConf]; //convert to array - process.env.PM2_JSON_PROCESSING = true; + if ((appConf = Common.verifyConfs(appConf)) instanceof Error) + return cb ? cb(appConf) : that.exitCli(conf.ERROR_EXIT); - // Get App list - var apps_name = []; - var proc_list = {}; + process.env.PM2_JSON_PROCESSING = true; - // Here we pick only the field we want from the CLI when starting a JSON - appConf.forEach(function(app) { - // --only - if (opts.only && opts.only != app.name) - return false; - // --watch - if (!app.watch && opts.watch && opts.watch === true) - app.watch = true; - // --ignore-watch - if (!app.ignore_watch && opts.ignore_watch) - app.ignore_watch = opts.ignore_watch; - // --instances - if (opts.instances && typeof(opts.instances) === 'number') - app.instances = opts.instances; - // --uid - if (opts.uid) - app.uid = opts.uid; - // --gid - if (opts.gid) - app.gid = opts.gid; - // Specific - if (app.append_env_to_name && opts.env) - app.name += ('-' + opts.env); - app.username = Common.getCurrentUsername(); - apps_name.push(app.name); - }); - - that.Client.executeRemote('getMonitorData', {}, function(err, raw_proc_list) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } + // Get App list + var apps_name = []; + var proc_list = {}; - /** - * Uniquify in memory process list - */ - raw_proc_list.forEach(function(proc) { - proc_list[proc.name] = proc; + // Here we pick only the field we want from the CLI when starting a JSON + appConf.forEach(function(app) { + // --only + if (opts.only && opts.only != app.name) + return false; + // --watch + if (!app.watch && opts.watch && opts.watch === true) + app.watch = true; + // --ignore-watch + if (!app.ignore_watch && opts.ignore_watch) + app.ignore_watch = opts.ignore_watch; + // --instances + if (opts.instances && typeof(opts.instances) === 'number') + app.instances = opts.instances; + // --uid + if (opts.uid) + app.uid = opts.uid; + // --gid + if (opts.gid) + app.gid = opts.gid; + // Specific + if (app.append_env_to_name && opts.env) + app.name += ('-' + opts.env); + app.username = Common.getCurrentUsername(); + apps_name.push(app.name); }); - /** - * Auto detect application already started - * and act on them depending on action - */ - async.eachLimit(Object.keys(proc_list), conf.CONCURRENT_ACTIONS, function(proc_name, next) { - // Skip app name (--only option) - if (apps_name.indexOf(proc_name) == -1) - return next(); + that.Client.executeRemote('getMonitorData', {}, function(err, raw_proc_list) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + + /** + * Uniquify in memory process list + */ + raw_proc_list.forEach(function(proc) { + proc_list[proc.name] = proc; + }); - if (!(action == 'reloadProcessId' || + /** + * Auto detect application already started + * and act on them depending on action + */ + async.eachLimit(Object.keys(proc_list), conf.CONCURRENT_ACTIONS, function(proc_name, next) { + // Skip app name (--only option) + if (apps_name.indexOf(proc_name) == -1) + return next(); + + if (!(action == 'reloadProcessId' || action == 'softReloadProcessId' || action == 'restartProcessId')) - throw new Error('Wrong action called'); + throw new Error('Wrong action called'); - var apps = appConf.filter(function(app) { - return app.name == proc_name; - }); + var apps = appConf.filter(function(app) { + return app.name == proc_name; + }); - var envs = apps.map(function(app){ - // Binds env_diff to env and returns it. - return Common.mergeEnvironmentVariables(app, opts.env, deployConf); - }); + var envs = apps.map(function(app){ + // Binds env_diff to env and returns it. + return Common.mergeEnvironmentVariables(app, opts.env, deployConf); + }); - // Assigns own enumerable properties of all - // Notice: if people use the same name in different apps, - // duplicated envs will be overrode by the last one - var env = envs.reduce(function(e1, e2){ - return util._extend(e1, e2); - }); + // Assigns own enumerable properties of all + // Notice: if people use the same name in different apps, + // duplicated envs will be overrode by the last one + var env = envs.reduce(function(e1, e2){ + return util._extend(e1, e2); + }); - // When we are processing JSON, allow to keep the new env by default - env.updateEnv = true; + // When we are processing JSON, allow to keep the new env by default + env.updateEnv = true; - // Pass `env` option - that._operate(action, proc_name, env, function(err, ret) { - if (err) Common.printError(err); + // Pass `env` option + that._operate(action, proc_name, env, function(err, ret) { + if (err) Common.printError(err); - // For return - apps_info = apps_info.concat(ret); + // For return + apps_info = apps_info.concat(ret); - that.Client.notifyGod(action, proc_name); - // And Remove from array to spy - apps_name.splice(apps_name.indexOf(proc_name), 1); - return next(); - }); + that.Client.notifyGod(action, proc_name); + // And Remove from array to spy + apps_name.splice(apps_name.indexOf(proc_name), 1); + return next(); + }); - }, function(err) { - if (err) return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - if (apps_name.length > 0 && action != 'start') - Common.printOut(conf.PREFIX_MSG_WARNING + 'Applications %s not running, starting...', apps_name.join(', ')); - // Start missing apps - return startApps(apps_name, function(err, apps) { - apps_info = apps_info.concat(apps); - return cb ? cb(err, apps_info) : that.speedList(err ? 1 : 0); + }, function(err) { + if (err) return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + if (apps_name.length > 0 && action != 'start') + Common.printOut(conf.PREFIX_MSG_WARNING + 'Applications %s not running, starting...', apps_name.join(', ')); + // Start missing apps + return startApps(apps_name, function(err, apps) { + apps_info = apps_info.concat(apps); + return cb ? cb(err, apps_info) : that.speedList(err ? 1 : 0); + }); }); - }); - return false; - }); - - function startApps(app_name_to_start, cb) { - var apps_to_start = []; - var apps_started = []; - - appConf.forEach(function(app, i) { - if (app_name_to_start.indexOf(app.name) != -1) { - apps_to_start.push(appConf[i]); - } + return false; }); - async.eachLimit(apps_to_start, conf.CONCURRENT_ACTIONS, function(app, next) { - if (opts.cwd) - app.cwd = opts.cwd; - if (opts.force_name) - app.name = opts.force_name; - if (opts.started_as_module) - app.pmx_module = true; + function startApps(app_name_to_start, cb) { + var apps_to_start = []; + var apps_started = []; - var resolved_paths = null; - - // hardcode script name to use `serve` feature inside a process file - if (app.script === 'serve') { - app.script = path.resolve(__dirname, 'API', 'Serve.js') - } + appConf.forEach(function(app, i) { + if (app_name_to_start.indexOf(app.name) != -1) { + apps_to_start.push(appConf[i]); + } + }); - try { - resolved_paths = Common.resolveAppAttributes({ - cwd : that.cwd, - pm2_home : that.pm2_home - }, app); - } catch (e) { - return next(); - } + async.eachLimit(apps_to_start, conf.CONCURRENT_ACTIONS, function(app, next) { + if (opts.cwd) + app.cwd = opts.cwd; + if (opts.force_name) + app.name = opts.force_name; + if (opts.started_as_module) + app.pmx_module = true; - if (!resolved_paths.env) resolved_paths.env = {}; + var resolved_paths = null; - // Set PM2 HOME in case of child process using PM2 API - resolved_paths.env['PM2_HOME'] = that.pm2_home; + // hardcode script name to use `serve` feature inside a process file + if (app.script === 'serve') { + app.script = path.resolve(__dirname, 'API', 'Serve.js') + } - var additional_env = Modularizer.getAdditionalConf(resolved_paths.name); - util._extend(resolved_paths.env, additional_env); + try { + resolved_paths = Common.resolveAppAttributes({ + cwd : that.cwd, + pm2_home : that.pm2_home + }, app); + } catch (e) { + return next(); + } - resolved_paths.env = Common.mergeEnvironmentVariables(resolved_paths, opts.env, deployConf); + if (!resolved_paths.env) resolved_paths.env = {}; - delete resolved_paths.env.current_conf; + // Set PM2 HOME in case of child process using PM2 API + resolved_paths.env['PM2_HOME'] = that.pm2_home; - // Is KM linked? - resolved_paths.km_link = that.gl_is_km_linked; + var additional_env = Modularizer.getAdditionalConf(resolved_paths.name); + util._extend(resolved_paths.env, additional_env); - that.Client.executeRemote('prepare', resolved_paths, function(err, data) { - if (err) { - Common.printError(conf.PREFIX_MSG_ERR + 'Process failed to launch %s', err.message ? err.message : err); - return next(); - } - if (data.length === 0) { - Common.printError(conf.PREFIX_MSG_ERR + 'Process config loading failed', data); - return next(); - } + resolved_paths.env = Common.mergeEnvironmentVariables(resolved_paths, opts.env, deployConf); - Common.printOut(conf.PREFIX_MSG + 'App [%s] launched (%d instances)', data[0].pm2_env.name, data.length); - apps_started = apps_started.concat(data); - next(); - }); + delete resolved_paths.env.current_conf; - }, function(err) { - return cb ? cb(err || null, apps_started) : that.speedList(); - }); - return false; - } -}; + // Is KM linked? + resolved_paths.km_link = that.gl_is_km_linked; -/** - * Apply a RPC method on the json file - * @private - * @method actionFromJson - * @param {string} action RPC Method - * @param {object} options - * @param {string|object} file file - * @param {string} jsonVia action type (=only 'pipe' ?) - * @param {Function} - */ -API.prototype.actionFromJson = function(action, file, opts, jsonVia, cb) { - var appConf = {}; - var ret_processes = []; - var that = this; - - //accept programmatic calls - if (typeof file == 'object') { - cb = typeof jsonVia == 'function' ? jsonVia : cb; - appConf = file; - } - else if (jsonVia == 'file') { - var data = null; + that.Client.executeRemote('prepare', resolved_paths, function(err, data) { + if (err) { + Common.printError(conf.PREFIX_MSG_ERR + 'Process failed to launch %s', err.message ? err.message : err); + return next(); + } + if (data.length === 0) { + Common.printError(conf.PREFIX_MSG_ERR + 'Process config loading failed', data); + return next(); + } - try { - data = fs.readFileSync(file); - } catch(e) { - Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file +' not found'); - return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); - } + Common.printOut(conf.PREFIX_MSG + 'App [%s] launched (%d instances)', data[0].pm2_env.name, data.length); + apps_started = apps_started.concat(data); + next(); + }); - try { - appConf = Common.parseConfig(data, file); - } catch(e) { - Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file + ' malformated'); - console.error(e); - return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); + }, function(err) { + return cb ? cb(err || null, apps_started) : that.speedList(); + }); + return false; } - } else if (jsonVia == 'pipe') { - appConf = Common.parseConfig(file, 'pipe'); - } else { - Common.printError('Bad call to actionFromJson, jsonVia should be one of file, pipe'); - return that.exitCli(conf.ERROR_EXIT); } - // Backward compatibility - if (appConf.apps) - appConf = appConf.apps; + /** + * Apply a RPC method on the json file + * @private + * @method actionFromJson + * @param {string} action RPC Method + * @param {object} options + * @param {string|object} file file + * @param {string} jsonVia action type (=only 'pipe' ?) + * @param {Function} + */ + actionFromJson (action, file, opts, jsonVia, cb) { + var appConf = {}; + var ret_processes = []; + var that = this; + + //accept programmatic calls + if (typeof file == 'object') { + cb = typeof jsonVia == 'function' ? jsonVia : cb; + appConf = file; + } + else if (jsonVia == 'file') { + var data = null; - if (!Array.isArray(appConf)) - appConf = [appConf]; + try { + data = fs.readFileSync(file); + } catch(e) { + Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file +' not found'); + return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); + } - if ((appConf = Common.verifyConfs(appConf)) instanceof Error) - return cb ? cb(appConf) : that.exitCli(conf.ERROR_EXIT); + try { + appConf = Common.parseConfig(data, file); + } catch(e) { + Common.printError(conf.PREFIX_MSG_ERR + 'File ' + file + ' malformated'); + console.error(e); + return cb ? cb(Common.retErr(e)) : that.exitCli(conf.ERROR_EXIT); + } + } else if (jsonVia == 'pipe') { + appConf = Common.parseConfig(file, 'pipe'); + } else { + Common.printError('Bad call to actionFromJson, jsonVia should be one of file, pipe'); + return that.exitCli(conf.ERROR_EXIT); + } - async.eachLimit(appConf, conf.CONCURRENT_ACTIONS, function(proc, next1) { - var name = ''; - var new_env; + // Backward compatibility + if (appConf.apps) + appConf = appConf.apps; - if (!proc.name) - name = path.basename(proc.script); - else - name = proc.name; + if (!Array.isArray(appConf)) + appConf = [appConf]; - if (opts.only && opts.only != name) - return process.nextTick(next1); + if ((appConf = Common.verifyConfs(appConf)) instanceof Error) + return cb ? cb(appConf) : that.exitCli(conf.ERROR_EXIT); - if (opts && opts.env) - new_env = Common.mergeEnvironmentVariables(proc, opts.env); - else - new_env = Common.mergeEnvironmentVariables(proc); + async.eachLimit(appConf, conf.CONCURRENT_ACTIONS, function(proc, next1) { + var name = ''; + var new_env; - that.Client.getProcessIdByName(name, function(err, ids) { - if (err) { - Common.printError(err); - return next1(); - } - if (!ids) return next1(); + if (!proc.name) + name = path.basename(proc.script); + else + name = proc.name; - async.eachLimit(ids, conf.CONCURRENT_ACTIONS, function(id, next2) { - var opts = {}; + if (opts.only && opts.only != name) + return process.nextTick(next1); - //stopProcessId could accept options to? - if (action == 'restartProcessId') { - opts = {id : id, env : new_env}; - } else { - opts = id; + if (opts && opts.env) + new_env = Common.mergeEnvironmentVariables(proc, opts.env); + else + new_env = Common.mergeEnvironmentVariables(proc); + + that.Client.getProcessIdByName(name, function(err, ids) { + if (err) { + Common.printError(err); + return next1(); } + if (!ids) return next1(); - that.Client.executeRemote(action, opts, function(err, res) { - ret_processes.push(res); - if (err) { - Common.printError(err); - return next2(); - } + async.eachLimit(ids, conf.CONCURRENT_ACTIONS, function(id, next2) { + var opts = {}; + //stopProcessId could accept options to? if (action == 'restartProcessId') { - that.Client.notifyGod('restart', id); - } else if (action == 'deleteProcessId') { - that.Client.notifyGod('delete', id); - } else if (action == 'stopProcessId') { - that.Client.notifyGod('stop', id); + opts = {id : id, env : new_env}; + } else { + opts = id; } - Common.printOut(conf.PREFIX_MSG + '[%s](%d) \u2713', name, id); - return next2(); + that.Client.executeRemote(action, opts, function(err, res) { + ret_processes.push(res); + if (err) { + Common.printError(err); + return next2(); + } + + if (action == 'restartProcessId') { + that.Client.notifyGod('restart', id); + } else if (action == 'deleteProcessId') { + that.Client.notifyGod('delete', id); + } else if (action == 'stopProcessId') { + that.Client.notifyGod('stop', id); + } + + Common.printOut(conf.PREFIX_MSG + '[%s](%d) \u2713', name, id); + return next2(); + }); + }, function(err) { + return next1(null, ret_processes); }); - }, function(err) { - return next1(null, ret_processes); }); + }, function(err) { + if (cb) return cb(null, ret_processes); + else return that.speedList(); }); - }, function(err) { - if (cb) return cb(null, ret_processes); - else return that.speedList(); - }); -}; - - -/** - * Main function to operate with PM2 daemon - * - * @param {String} action_name Name of action (restartProcessId, deleteProcessId, stopProcessId) - * @param {String} process_name can be 'all', a id integer or process name - * @param {Object} envs object with CLI options / environment - */ -API.prototype._operate = function(action_name, process_name, envs, cb) { - var that = this; - var update_env = false; - var ret = []; - - // Make sure all options exist - if (!envs) - envs = {}; - - if (typeof(envs) == 'function'){ - cb = envs; - envs = {}; } - // Set via env.update (JSON processing) - if (envs.updateEnv === true) - update_env = true; - - var concurrent_actions = envs.parallel || conf.CONCURRENT_ACTIONS; - - if (!process.env.PM2_JSON_PROCESSING || envs.commands) { - envs = that._handleAttributeUpdate(envs); - } /** - * Set current updated configuration if not passed + * Main function to operate with PM2 daemon + * + * @param {String} action_name Name of action (restartProcessId, deleteProcessId, stopProcessId) + * @param {String} process_name can be 'all', a id integer or process name + * @param {Object} envs object with CLI options / environment */ - if (!envs.current_conf) { - var _conf = fclone(envs); - envs = { - current_conf : _conf + _operate (action_name, process_name, envs, cb) { + var that = this; + var update_env = false; + var ret = []; + + // Make sure all options exist + if (!envs) + envs = {}; + + if (typeof(envs) == 'function'){ + cb = envs; + envs = {}; } - // Is KM linked? - envs.current_conf.km_link = that.gl_is_km_linked; - } + // Set via env.update (JSON processing) + if (envs.updateEnv === true) + update_env = true; - /** - * Operate action on specific process id - */ - function processIds(ids, cb) { - Common.printOut(conf.PREFIX_MSG + 'Applying action %s on app [%s](ids: %s)', action_name, process_name, ids); + var concurrent_actions = envs.parallel || conf.CONCURRENT_ACTIONS; + + if (!process.env.PM2_JSON_PROCESSING || envs.commands) { + envs = that._handleAttributeUpdate(envs); + } + + /** + * Set current updated configuration if not passed + */ + if (!envs.current_conf) { + var _conf = fclone(envs); + envs = { + current_conf : _conf + } + + // Is KM linked? + envs.current_conf.km_link = that.gl_is_km_linked; + } + + /** + * Operate action on specific process id + */ + function processIds(ids, cb) { + Common.printOut(conf.PREFIX_MSG + 'Applying action %s on app [%s](ids: %s)', action_name, process_name, ids); - if (action_name == 'deleteProcessId') - concurrent_actions = 10; + if (action_name == 'deleteProcessId') + concurrent_actions = 10; - async.eachLimit(ids, concurrent_actions, function(id, next) { - var opts; + async.eachLimit(ids, concurrent_actions, function(id, next) { + var opts; - // These functions need extra param to be passed - if (action_name == 'restartProcessId' || + // These functions need extra param to be passed + if (action_name == 'restartProcessId' || action_name == 'reloadProcessId' || action_name == 'softReloadProcessId') { - var new_env = {}; + var new_env = {}; - if (update_env === true) { - if (conf.PM2_PROGRAMMATIC == true) - new_env = Common.safeExtend({}, process.env); - else - new_env = util._extend({}, process.env); + if (update_env === true) { + if (conf.PM2_PROGRAMMATIC == true) + new_env = Common.safeExtend({}, process.env); + else + new_env = util._extend({}, process.env); - Object.keys(envs).forEach(function(k) { - new_env[k] = envs[k]; - }); + Object.keys(envs).forEach(function(k) { + new_env[k] = envs[k]; + }); + } + else { + new_env = envs; + } + + opts = { + id : id, + env : new_env + }; } else { - new_env = envs; + opts = id; } - opts = { - id : id, - env : new_env - }; - } - else { - opts = id; - } - - that.Client.executeRemote(action_name, opts, function(err, res) { - if (err) { - Common.printError(conf.PREFIX_MSG_ERR + 'Process %s not found', id); - return next('Process not found'); - } + that.Client.executeRemote(action_name, opts, function(err, res) { + if (err) { + Common.printError(conf.PREFIX_MSG_ERR + 'Process %s not found', id); + return next('Process not found'); + } - if (action_name == 'restartProcessId') { - that.Client.notifyGod('restart', id); - } else if (action_name == 'deleteProcessId') { - that.Client.notifyGod('delete', id); - } else if (action_name == 'stopProcessId') { - that.Client.notifyGod('stop', id); - } else if (action_name == 'reloadProcessId') { - that.Client.notifyGod('reload', id); - } else if (action_name == 'softReloadProcessId') { - that.Client.notifyGod('graceful reload', id); - } + if (action_name == 'restartProcessId') { + that.Client.notifyGod('restart', id); + } else if (action_name == 'deleteProcessId') { + that.Client.notifyGod('delete', id); + } else if (action_name == 'stopProcessId') { + that.Client.notifyGod('stop', id); + } else if (action_name == 'reloadProcessId') { + that.Client.notifyGod('reload', id); + } else if (action_name == 'softReloadProcessId') { + that.Client.notifyGod('graceful reload', id); + } - if (!Array.isArray(res)) - res = [res]; + if (!Array.isArray(res)) + res = [res]; - // Filter return - res.forEach(function(proc) { - Common.printOut(conf.PREFIX_MSG + '[%s](%d) \u2713', proc.pm2_env ? proc.pm2_env.name : process_name, id); + // Filter return + res.forEach(function(proc) { + Common.printOut(conf.PREFIX_MSG + '[%s](%d) \u2713', proc.pm2_env ? proc.pm2_env.name : process_name, id); - if (!proc.pm2_env) return false; + if (!proc.pm2_env) return false; - ret.push({ - name : proc.pm2_env.name, - pm_id : proc.pm2_env.pm_id, - status : proc.pm2_env.status, - restart_time : proc.pm2_env.restart_time, - pm2_env : { + ret.push({ name : proc.pm2_env.name, pm_id : proc.pm2_env.pm_id, status : proc.pm2_env.status, restart_time : proc.pm2_env.restart_time, - env : proc.pm2_env.env - } + pm2_env : { + name : proc.pm2_env.name, + pm_id : proc.pm2_env.pm_id, + status : proc.pm2_env.status, + restart_time : proc.pm2_env.restart_time, + env : proc.pm2_env.env + } + }); }); - }); - return next(); + return next(); + }); + }, function(err) { + if (err) return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + return cb ? cb(null, ret) : that.speedList(); }); - }, function(err) { - if (err) return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - return cb ? cb(null, ret) : that.speedList(); - }); - } - - if (process_name == 'all') { - that.Client.getAllProcessId(function(err, ids) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } - if (!ids || ids.length === 0) { - Common.printError(conf.PREFIX_MSG_WARNING + 'No process found'); - return cb ? cb(new Error('process name not found')) : that.exitCli(conf.ERROR_EXIT); - } - - return processIds(ids, cb); - }); - } - // operate using regex - else if (isNaN(process_name) && process_name[0] === '/' && process_name[process_name.length - 1] === '/') { - var regex = new RegExp(process_name.replace(/\//g, '')); + } - that.Client.executeRemote('getMonitorData', {}, function(err, list) { - if (err) { - Common.printError('Error retrieving process list: ' + err); - return cb(err); - } - var found_proc = []; - list.forEach(function(proc) { - if (regex.test(proc.pm2_env.name)) { - found_proc.push(proc.pm_id); + if (process_name == 'all') { + that.Client.getAllProcessId(function(err, ids) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + if (!ids || ids.length === 0) { + Common.printError(conf.PREFIX_MSG_WARNING + 'No process found'); + return cb ? cb(new Error('process name not found')) : that.exitCli(conf.ERROR_EXIT); } - }); - if (found_proc.length === 0) { - Common.printError(conf.PREFIX_MSG_WARNING + 'No process found'); - return cb ? cb(new Error('process name not found')) : that.exitCli(conf.ERROR_EXIT); - } + return processIds(ids, cb); + }); + } + // operate using regex + else if (isNaN(process_name) && process_name[0] === '/' && process_name[process_name.length - 1] === '/') { + var regex = new RegExp(process_name.replace(/\//g, '')); - return processIds(found_proc, cb); - }); - } - else if (isNaN(process_name)) { - /** - * We can not stop or delete a module but we can restart it - * to refresh configuration variable - */ - var allow_module_restart = action_name == 'restartProcessId' ? true : false; + that.Client.executeRemote('getMonitorData', {}, function(err, list) { + if (err) { + Common.printError('Error retrieving process list: ' + err); + return cb(err); + } + var found_proc = []; + list.forEach(function(proc) { + if (regex.test(proc.pm2_env.name)) { + found_proc.push(proc.pm_id); + } + }); - that.Client.getProcessIdByName(process_name, allow_module_restart, function(err, ids) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } - if (!ids || ids.length === 0) { - Common.printError(conf.PREFIX_MSG_ERR + 'Process %s not found', process_name); - return cb ? cb(new Error('process name not found')) : that.exitCli(conf.ERROR_EXIT); - } + if (found_proc.length === 0) { + Common.printError(conf.PREFIX_MSG_WARNING + 'No process found'); + return cb ? cb(new Error('process name not found')) : that.exitCli(conf.ERROR_EXIT); + } + return processIds(found_proc, cb); + }); + } + else if (isNaN(process_name)) { /** - * Determine if the process to restart is a module - * if yes load configuration variables and merge with the current environment + * We can not stop or delete a module but we can restart it + * to refresh configuration variable */ - var additional_env = Modularizer.getAdditionalConf(process_name); - util._extend(envs, additional_env); - - return processIds(ids, cb); - }); - } else { - // Check if application name as number is an app name - that.Client.getProcessIdByName(process_name, function(err, ids) { - if (ids.length > 0) - return processIds(ids, cb); - // Else operate on pm id - return processIds([process_name], cb); - }); - } -}; - -/** - * Converts CamelCase Commander.js arguments - * to Underscore - * (nodeArgs -> node_args) - */ -API.prototype._handleAttributeUpdate = function(opts) { - var conf = Config.transCMDToConf(opts); - var that = this; - - if (typeof(conf.name) != 'string') - delete conf.name; + var allow_module_restart = action_name == 'restartProcessId' ? true : false; - var argsIndex = 0; - if (opts.rawArgs && (argsIndex = opts.rawArgs.indexOf('--')) >= 0) { - conf.args = opts.rawArgs.slice(argsIndex + 1); - } + that.Client.getProcessIdByName(process_name, allow_module_restart, function(err, ids) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + if (!ids || ids.length === 0) { + Common.printError(conf.PREFIX_MSG_ERR + 'Process %s not found', process_name); + return cb ? cb(new Error('process name not found')) : that.exitCli(conf.ERROR_EXIT); + } - var appConf = Common.verifyConfs(conf)[0]; + /** + * Determine if the process to restart is a module + * if yes load configuration variables and merge with the current environment + */ + var additional_env = Modularizer.getAdditionalConf(process_name); + util._extend(envs, additional_env); - if (appConf instanceof Error) { - Common.printError('Error while transforming CamelCase args to underscore'); - return appConf; + return processIds(ids, cb); + }); + } else { + // Check if application name as number is an app name + that.Client.getProcessIdByName(process_name, function(err, ids) { + if (ids.length > 0) + return processIds(ids, cb); + // Else operate on pm id + return processIds([process_name], cb); + }); + } } - if (argsIndex == -1) - delete appConf.args; - if (appConf.name == 'undefined') - delete appConf.name; - - delete appConf.exec_mode; + /** + * Converts CamelCase Commander.js arguments + * to Underscore + * (nodeArgs -> node_args) + */ + _handleAttributeUpdate (opts) { + var conf = Config.transCMDToConf(opts); + var that = this; - if (util.isArray(appConf.watch) && appConf.watch.length === 0) { - if (!~opts.rawArgs.indexOf('--watch')) - delete appConf.watch - } + if (typeof(conf.name) != 'string') + delete conf.name; - // Options set via environment variables - if (process.env.PM2_DEEP_MONITORING) - appConf.deep_monitoring = true; - - // Force deletion of defaults values set by commander - // to avoid overriding specified configuration by user - if (appConf.treekill === true) - delete appConf.treekill; - if (appConf.pmx === true) - delete appConf.pmx; - if (appConf.vizion === true) - delete appConf.vizion; - if (appConf.automation === true) - delete appConf.automation; - if (appConf.autorestart === true) - delete appConf.autorestart; - - return appConf; -}; + var argsIndex = 0; + if (opts.rawArgs && (argsIndex = opts.rawArgs.indexOf('--')) >= 0) { + conf.args = opts.rawArgs.slice(argsIndex + 1); + } -API.prototype.getProcessIdByName = function(name, cb) { - var that = this; + var appConf = Common.verifyConfs(conf)[0]; - this.Client.getProcessIdByName(name, function(err, id) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + if (appConf instanceof Error) { + Common.printError('Error while transforming CamelCase args to underscore'); + return appConf; } - console.log(id); - return cb ? cb(null, id) : that.exitCli(conf.SUCCESS_EXIT); - }); -}; -/** - * Description - * @method jlist - * @param {} debug - * @return - */ -API.prototype.jlist = function(debug) { - var that = this; + if (argsIndex == -1) + delete appConf.args; + if (appConf.name == 'undefined') + delete appConf.name; - that.Client.executeRemote('getMonitorData', {}, function(err, list) { - if (err) { - Common.printError(err); - that.exitCli(conf.ERROR_EXIT); - } + delete appConf.exec_mode; - if (debug) { - process.stdout.write(util.inspect(list, false, null, false)); - } - else { - process.stdout.write(JSON.stringify(list)); + if (util.isArray(appConf.watch) && appConf.watch.length === 0) { + if (!~opts.rawArgs.indexOf('--watch')) + delete appConf.watch } - that.exitCli(conf.SUCCESS_EXIT); + // Options set via environment variables + if (process.env.PM2_DEEP_MONITORING) + appConf.deep_monitoring = true; + + // Force deletion of defaults values set by commander + // to avoid overriding specified configuration by user + if (appConf.treekill === true) + delete appConf.treekill; + if (appConf.pmx === true) + delete appConf.pmx; + if (appConf.vizion === true) + delete appConf.vizion; + if (appConf.automation === true) + delete appConf.automation; + if (appConf.autorestart === true) + delete appConf.autorestart; - }); -}; + return appConf; + } -var gl_retry = 0; + getProcessIdByName (name, cb) { + var that = this; -/** - * Description - * @method speedList - * @return - */ -API.prototype.speedList = function(code) { - var that = this; + this.Client.getProcessIdByName(name, function(err, id) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + console.log(id); + return cb ? cb(null, id) : that.exitCli(conf.SUCCESS_EXIT); + }); + } - // Do nothing if PM2 called programmatically and not called from CLI (also in exitCli) - if (conf.PM2_PROGRAMMATIC && process.env.PM2_USAGE != 'CLI') return false; + /** + * Description + * @method jlist + * @param {} debug + * @return + */ + jlist (debug) { + var that = this; - that.Client.executeRemote('getMonitorData', {}, function(err, list) { - if (err) { - if (gl_retry == 0) { - gl_retry += 1; - return setTimeout(that.speedList.bind(that), 1400); + that.Client.executeRemote('getMonitorData', {}, function(err, list) { + if (err) { + Common.printError(err); + that.exitCli(conf.ERROR_EXIT); } - console.error('Error retrieving process list: %s.\nA process seems to be on infinite loop, retry in 5 seconds',err); - return that.exitCli(conf.ERROR_EXIT); - } - if (process.stdout.isTTY === false) { - UX.miniDisplay(list); - } - else if (commander.miniList && !commander.silent) - UX.miniDisplay(list); - else if (!commander.silent) { - if (that.gl_interact_infos) { - Common.printOut(chalk.green.bold('●') + ' Agent Online | Dashboard Access: ' + chalk.bold('https://app.keymetrics.io/#/r/%s') + ' | Server name: %s', that.gl_interact_infos.public_key, that.gl_interact_infos.machine_name); + + if (debug) { + process.stdout.write(util.inspect(list, false, null, false)); + } + else { + process.stdout.write(JSON.stringify(list)); } - UX.dispAsTable(list, commander); - Common.printOut(chalk.white.italic(' Use `pm2 show ` to get more details about an app')); - } - if (that.Client.daemon_mode == false) { - Common.printOut('[--no-daemon] Continue to stream logs'); - Common.printOut('[--no-daemon] Exit on target PM2 exit pid=' + fs.readFileSync(conf.PM2_PID_FILE_PATH).toString()); - global._auto_exit = true; - return that.streamLogs('all', 0, false, 'HH:mm:ss', false); - } - else if (commander.attach === true) { - return that.streamLogs('all', 0, false, null, false); - } - else { - return that.exitCli(code ? code : conf.SUCCESS_EXIT); - } - }); -} + that.exitCli(conf.SUCCESS_EXIT); -/** - * Scale up/down a process - * @method scale - */ -API.prototype.scale = function(app_name, number, cb) { - var that = this; - - function addProcs(proc, value, cb) { - (function ex(proc, number) { - if (number-- === 0) return cb(); - Common.printOut(conf.PREFIX_MSG + 'Scaling up application'); - that.Client.executeRemote('duplicateProcessId', proc.pm2_env.pm_id, ex.bind(this, proc, number)); - })(proc, number); + }); } - function rmProcs(procs, value, cb) { - var i = 0; + /** + * Description + * @method speedList + * @return + */ + speedList (code) { + var that = this; - (function ex(procs, number) { - if (number++ === 0) return cb(); - that._operate('deleteProcessId', procs[i++].pm2_env.pm_id, ex.bind(this, procs, number)); - })(procs, number); - } + // Do nothing if PM2 called programmatically and not called from CLI (also in exitCli) + if (conf.PM2_PROGRAMMATIC && process.env.PM2_USAGE != 'CLI') return false; - function end() { - return cb ? cb(null, {success:true}) : that.speedList(); - } + that.Client.executeRemote('getMonitorData', {}, function(err, list) { + if (err) { + if (gl_retry == 0) { + gl_retry += 1; + return setTimeout(that.speedList.bind(that), 1400); + } + console.error('Error retrieving process list: %s.\nA process seems to be on infinite loop, retry in 5 seconds',err); + return that.exitCli(conf.ERROR_EXIT); + } + if (process.stdout.isTTY === false) { + UX.miniDisplay(list); + } + else if (commander.miniList && !commander.silent) + UX.miniDisplay(list); + else if (!commander.silent) { + if (that.gl_interact_infos) { + Common.printOut(chalk.green.bold('●') + ' Agent Online | Dashboard Access: ' + chalk.bold('https://app.keymetrics.io/#/r/%s') + ' | Server name: %s', that.gl_interact_infos.public_key, that.gl_interact_infos.machine_name); + } + UX.dispAsTable(list, commander); + Common.printOut(chalk.white.italic(' Use `pm2 show ` to get more details about an app')); + } - this.Client.getProcessByName(app_name, function(err, procs) { - if (err) { - Common.printError(err); - return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); - } + if (that.Client.daemon_mode == false) { + Common.printOut('[--no-daemon] Continue to stream logs'); + Common.printOut('[--no-daemon] Exit on target PM2 exit pid=' + fs.readFileSync(conf.PM2_PID_FILE_PATH).toString()); + global._auto_exit = true; + return that.streamLogs('all', 0, false, 'HH:mm:ss', false); + } + else if (commander.attach === true) { + return that.streamLogs('all', 0, false, null, false); + } + else { + return that.exitCli(code ? code : conf.SUCCESS_EXIT); + } + }); + } - if (!procs || procs.length === 0) { - Common.printError(conf.PREFIX_MSG_ERR + 'Application %s not found', app_name); - return cb ? cb(new Error('App not found')) : that.exitCli(conf.ERROR_EXIT); + /** + * Scale up/down a process + * @method scale + */ + scale (app_name, number, cb) { + var that = this; + + function addProcs(proc, value, cb) { + (function ex(proc, number) { + if (number-- === 0) return cb(); + Common.printOut(conf.PREFIX_MSG + 'Scaling up application'); + that.Client.executeRemote('duplicateProcessId', proc.pm2_env.pm_id, ex.bind(this, proc, number)); + })(proc, number); } - var proc_number = procs.length; + function rmProcs(procs, value, cb) { + var i = 0; - if (typeof(number) === 'string' && number.indexOf('+') >= 0) { - number = parseInt(number, 10); - return addProcs(procs[0], number, end); + (function ex(procs, number) { + if (number++ === 0) return cb(); + that._operate('deleteProcessId', procs[i++].pm2_env.pm_id, ex.bind(this, procs, number)); + })(procs, number); } - else if (typeof(number) === 'string' && number.indexOf('-') >= 0) { - number = parseInt(number, 10); - return rmProcs(procs[0], number, end); + + function end() { + return cb ? cb(null, {success:true}) : that.speedList(); } - else { - number = parseInt(number, 10); - number = number - proc_number; - if (number < 0) - return rmProcs(procs, number, end); - else if (number > 0) + this.Client.getProcessByName(app_name, function(err, procs) { + if (err) { + Common.printError(err); + return cb ? cb(Common.retErr(err)) : that.exitCli(conf.ERROR_EXIT); + } + + if (!procs || procs.length === 0) { + Common.printError(conf.PREFIX_MSG_ERR + 'Application %s not found', app_name); + return cb ? cb(new Error('App not found')) : that.exitCli(conf.ERROR_EXIT); + } + + var proc_number = procs.length; + + if (typeof(number) === 'string' && number.indexOf('+') >= 0) { + number = parseInt(number, 10); return addProcs(procs[0], number, end); + } + else if (typeof(number) === 'string' && number.indexOf('-') >= 0) { + number = parseInt(number, 10); + return rmProcs(procs[0], number, end); + } else { - Common.printError(conf.PREFIX_MSG_ERR + 'Nothing to do'); - return cb ? cb(new Error('Same process number')) : that.exitCli(conf.ERROR_EXIT); + number = parseInt(number, 10); + number = number - proc_number; + + if (number < 0) + return rmProcs(procs, number, end); + else if (number > 0) + return addProcs(procs[0], number, end); + else { + Common.printError(conf.PREFIX_MSG_ERR + 'Nothing to do'); + return cb ? cb(new Error('Same process number')) : that.exitCli(conf.ERROR_EXIT); + } } - } - }); -}; + }); + } -/** - * Description - * @method describeProcess - * @param {} pm2_id - * @return - */ -API.prototype.describe = function(pm2_id, cb) { - var that = this; + /** + * Description + * @method describeProcess + * @param {} pm2_id + * @return + */ + describe (pm2_id, cb) { + var that = this; - var found_proc = []; + var found_proc = []; - that.Client.executeRemote('getMonitorData', {}, function(err, list) { - if (err) { - Common.printError('Error retrieving process list: ' + err); - that.exitCli(conf.ERROR_EXIT); - } + that.Client.executeRemote('getMonitorData', {}, function(err, list) { + if (err) { + Common.printError('Error retrieving process list: ' + err); + that.exitCli(conf.ERROR_EXIT); + } - list.forEach(function(proc) { - if ((!isNaN(pm2_id) && proc.pm_id == pm2_id) || + list.forEach(function(proc) { + if ((!isNaN(pm2_id) && proc.pm_id == pm2_id) || (typeof(pm2_id) === 'string' && proc.name == pm2_id)) { - found_proc.push(proc); + found_proc.push(proc); + } + }); + + if (found_proc.length === 0) { + Common.printError(conf.PREFIX_MSG_WARNING + '%s doesn\'t exist', pm2_id); + return cb ? cb(null, []) : that.exitCli(conf.ERROR_EXIT); + } + + if (!cb) { + found_proc.forEach(function(proc) { + UX.describeTable(proc); + }); } + + return cb ? cb(null, found_proc) : that.exitCli(conf.SUCCESS_EXIT); }); + } - if (found_proc.length === 0) { - Common.printError(conf.PREFIX_MSG_WARNING + '%s doesn\'t exist', pm2_id); - return cb ? cb(null, []) : that.exitCli(conf.ERROR_EXIT); - } + /** + * API method to perform a deep update of PM2 + * @method deepUpdate + */ + deepUpdate (cb) { + var that = this; - if (!cb) { - found_proc.forEach(function(proc) { - UX.describeTable(proc); - }); - } + Common.printOut(conf.PREFIX_MSG + 'Updating PM2...'); - return cb ? cb(null, found_proc) : that.exitCli(conf.SUCCESS_EXIT); - }); + var exec = require('shelljs').exec; + var child = exec("npm i -g pm2@latest; pm2 update", {async : true}); + + child.stdout.on('end', function() { + Common.printOut(conf.PREFIX_MSG + 'PM2 successfully updated'); + cb ? cb(null, {success:true}) : that.exitCli(conf.SUCCESS_EXIT); + }); + } }; -/** - * API method to perform a deep update of PM2 - * @method deepUpdate - */ -API.prototype.deepUpdate = function(cb) { - var that = this; - Common.printOut(conf.PREFIX_MSG + 'Updating PM2...'); +////////////////////////// +// Load all API methods // +////////////////////////// + +require('./API/Extra.js')(API); +require('./API/Interaction.js')(API); +require('./API/Deploy.js')(API); +require('./API/Modules/Modules.js')(API); +require('./API/Keymetrics/cli-api.js')(API); +require('./API/Configuration.js')(API); +require('./API/Version.js')(API); +require('./API/Startup.js')(API); +require('./API/LogManagement.js')(API); +require('./API/Containerizer.js')(API); - var exec = require('shelljs').exec; - var child = exec("npm i -g pm2@latest; pm2 update", {async : true}); - child.stdout.on('end', function() { - Common.printOut(conf.PREFIX_MSG + 'PM2 successfully updated'); - cb ? cb(null, {success:true}) : that.exitCli(conf.SUCCESS_EXIT); - }); -}; +module.exports = API; diff --git a/lib/API/Extra.js b/lib/API/Extra.js index 00f445dde..cf7a23fcf 100644 --- a/lib/API/Extra.js +++ b/lib/API/Extra.js @@ -15,6 +15,7 @@ var fs = require('fs'); var fmt = require('../tools/fmt.js'); var moment = require('moment'); var pkg = require('../../package.json'); +const semver = require('semver'); module.exports = function(CLI) { @@ -38,7 +39,6 @@ module.exports = function(CLI) { */ CLI.prototype.report = function() { var that = this; - var semver = require('semver'); function reporting(cb) { @@ -639,4 +639,27 @@ module.exports = function(CLI) { launchMonitor(); }; + + CLI.prototype.inspect = function(app_name, cb) { + const that = this; + if(semver.satisfies(process.versions.node, '>= 8.0.0')) { + this.trigger(app_name, 'internal:inspect', function (err, res) { + + if(res && res[0]) { + if (res[0].data.return === '') { + Common.printOut(`Inspect disabled on ${app_name}`); + } else { + Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`); + } + } else { + Common.printOut(`Unable to activate inspect mode on ${app_name} !!!`); + } + + that.exitCli(cst.SUCCESS_EXIT); + }); + } else { + Common.printOut('Inspect is available for node version >=8.x !'); + that.exitCli(cst.SUCCESS_EXIT); + } + }; }; diff --git a/lib/API/Modules/Modularizer.js b/lib/API/Modules/Modularizer.js index 7093324bf..e738255ed 100644 --- a/lib/API/Modules/Modularizer.js +++ b/lib/API/Modules/Modularizer.js @@ -6,6 +6,7 @@ var shelljs = require('shelljs'); var path = require('path'); var fs = require('fs'); +var os = require('os'); var async = require('async'); var p = path; var readline = require('readline'); @@ -185,7 +186,7 @@ Modularizer.installModule = function(CLI, module_name, opts, cb) { var install_path = path.join(cst.DEFAULT_MODULE_PATH, canonic_module_name); mkdirp(install_path, function() { - process.chdir(process.env.HOME); + process.chdir(os.homedir()); var install_instance = spawn(cst.IS_WINDOWS ? 'npm.cmd' : 'npm', ['install', module_name, '--loglevel=error', '--prefix', install_path ], { stdio : 'inherit', diff --git a/lib/API/Startup.js b/lib/API/Startup.js index 5249acc5d..b96877fe8 100644 --- a/lib/API/Startup.js +++ b/lib/API/Startup.js @@ -7,6 +7,7 @@ var debug = require('debug')('pm2:cli:startup'); var chalk = require('chalk'); var path = require('path'); var fs = require('fs'); +const fsExtra = require('fs-extra'); var async = require('async'); var exec = require('child_process').exec; var Common = require('../Common.js'); @@ -371,13 +372,32 @@ module.exports = function(CLI) { * @return */ function fin(err) { + + // try to fix issues with empty dump file + // like #3485 + if (env_arr.length === 0) { + + // fix : if no dump file, no process, only module and after pm2 update + if (!fs.existsSync(cst.DUMP_FILE_PATH)) { + that.clearDump(function(){}); + } + + // if no process in list don't modify dump file + // process list should not be empty + if(cb) { + return cb(null, {success: true}); + } else { + Common.printOut(cst.PREFIX_MSG + 'Nothing to save !!!'); + Common.printOut(cst.PREFIX_MSG + 'In this case we keep old dump file. To clear dump file you can delete it manually !'); + that.exitCli(cst.SUCCESS_EXIT); + return; + } + } + // Back up dump file try { if (fs.existsSync(cst.DUMP_FILE_PATH)) { - if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) { - fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH); - } - fs.renameSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); + fsExtra.copySync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); } } catch (e) { console.error(e.stack || e); @@ -390,8 +410,13 @@ module.exports = function(CLI) { } catch (e) { console.error(e.stack || e); try { - fs.unlinkSync(cst.DUMP_FILE_PATH); + // try to backup file + if(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) { + fsExtra.copySync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); + } } catch (e) { + // don't keep broken file + fs.unlinkSync(cst.DUMP_FILE_PATH); console.error(e.stack || e); } Common.printOut(cst.PREFIX_MSG_ERR + 'Failed to save dump file in %s', cst.DUMP_FILE_PATH); @@ -415,6 +440,21 @@ module.exports = function(CLI) { }); }; + /** + * Remove DUMP_FILE_PATH file and DUMP_BACKUP_FILE_PATH file + * @method dump + * @param {} cb + * @return + */ + CLI.prototype.clearDump = function(cb) { + fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify([])); + + if(cb && typeof cb === 'function') return cb(); + + Common.printOut(cst.PREFIX_MSG + 'Successfully created %s', cst.DUMP_FILE_PATH); + return this.exitCli(cst.SUCCESS_EXIT); + }; + /** * Resurrect processes * @method resurrect diff --git a/lib/API/Version.js b/lib/API/Version.js index 8f5bb93ba..844953174 100644 --- a/lib/API/Version.js +++ b/lib/API/Version.js @@ -21,11 +21,11 @@ module.exports = function(CLI) { printOut(cst.PREFIX_MSG + 'Updating repository for process name %s', process_name); - that.Client.getProcessByName(process_name, function(err, processes) { + that.Client.getProcessByNameOrId(process_name, function (err, processes) { - if (processes.length === 0) { - printError('No processes with this name: %s', process_name); - return cb ? cb({msg:'Process not found: '+process_name}) : that.exitCli(cst.ERROR_EXIT); + if (err || processes.length === 0) { + printError('No processes with this name or id : %s', process_name); + return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT); } var proc = processes[0]; @@ -82,11 +82,11 @@ module.exports = function(CLI) { printOut(cst.PREFIX_MSG + 'Updating repository for process name %s', process_name); - that.Client.getProcessByName(process_name, function(err, processes) { + that.Client.getProcessByNameOrId(process_name, function (err, processes) { - if (processes.length === 0) { - printError('No processes with this name: %s', process_name); - return cb ? cb({msg:'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT); + if (err || processes.length === 0) { + printError('No processes with this name or id : %s', process_name); + return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT); } var proc = processes[0]; @@ -138,14 +138,16 @@ module.exports = function(CLI) { var that = this; printOut(cst.PREFIX_MSG + 'Downgrading to previous commit repository for process name %s', process_name); - that.Client.getProcessByName(process_name, function(err, processes) { + that.Client.getProcessByNameOrId(process_name, function (err, processes) { - if (processes.length === 0) { - printError('No processes with this name: %s', process_name); - return cb ? cb({msg:'Process not found: '+process_name}) : that.exitCli(cst.ERROR_EXIT); + if (err || processes.length === 0) { + printError('No processes with this name or id : %s', process_name); + return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT); } var proc = processes[0]; + // in case user searched by id/pid + process_name = proc.name; if (proc.pm2_env.versioning === undefined || proc.pm2_env.versioning === null) @@ -194,14 +196,16 @@ module.exports = function(CLI) { var that = this; printOut(cst.PREFIX_MSG + 'Updating to next commit repository for process name %s', process_name); - that.Client.getProcessByName(process_name, function(err, processes) { + that.Client.getProcessByNameOrId(process_name, function (err, processes) { - if (processes.length === 0) { - printError('No processes with this name: %s', process_name); - return cb ? cb({msg:'Process not found: '+process_name}) : that.exitCli(cst.ERROR_EXIT); + if (err || processes.length === 0) { + printError('No processes with this name or id: %s', process_name); + return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT); } var proc = processes[0]; + // in case user searched by id/pid + process_name = proc.name; if (proc.pm2_env.versioning) { vizion.next({folder: proc.pm2_env.versioning.repo_path}, function(err, meta) { if (err !== null) @@ -366,16 +370,6 @@ module.exports = function(CLI) { this._pull({process_name: process_name, action: 'reload'}, cb); }; - /** - * CLI method for updating a repository - * @method pullAndGracefulReload - * @param {string} process_name name of processes to pull - * @return - */ - CLI.prototype.pullAndGracefulReload = function (process_name, cb) { - this._pull({process_name: process_name, action: 'gracefulReload'}, cb); - }; - /** * CLI method for updating a repository to a specific commit id * @method pullCommitId diff --git a/lib/API/schema.json b/lib/API/schema.json index 79bef624e..7bafbea8a 100644 --- a/lib/API/schema.json +++ b/lib/API/schema.json @@ -246,21 +246,6 @@ "boolean" ] }, - "v8": { - "type": [ - "boolean" - ] - }, - "event_loop_inspector": { - "type": [ - "boolean" - ] - }, - "deep_monitoring": { - "type": [ - "boolean" - ] - }, "increment_var": { "type": "string", "docDescription": "Specify the name of an environment variable to inject which increments for each cluster" diff --git a/lib/Client.js b/lib/Client.js index 74103fd3b..0b7855157 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -717,3 +717,25 @@ Client.prototype.getProcessByName = function(name, cb) { return cb(null, found_proc); }); }; + +Client.prototype.getProcessByNameOrId = function (nameOrId, cb) { + var foundProc = []; + + this.executeRemote('getMonitorData', {}, function (err, list) { + if (err) { + Common.printError('Error retrieving process list: ' + err); + return cb(err); + } + + list.forEach(function (proc) { + if (proc.pm2_env.name === nameOrId || + proc.pm2_env.pm_exec_path === path.resolve(nameOrId) || + proc.pid === parseInt(nameOrId) || + proc.pm2_env.pm_id === parseInt(nameOrId)) { + foundProc.push(proc); + } + }); + + return cb(null, foundProc); + }); +}; diff --git a/lib/Common.js b/lib/Common.js index 2dd053aab..a8eeec1ff 100644 --- a/lib/Common.js +++ b/lib/Common.js @@ -247,15 +247,17 @@ Common.prepareAppConf = function(opts, app) { * @param {string} filename * @return {mixed} null if not conf file, json or yaml if conf */ -Common.isConfigFile = function(filename) { - if (typeof(filename) != 'string') +Common.isConfigFile = function (filename) { + if (typeof (filename) !== 'string') return null; - if (filename.indexOf('.json') != -1) + if (filename.indexOf('.json') !== -1) return 'json'; if (filename.indexOf('.yml') > -1 || filename.indexOf('.yaml') > -1) return 'yaml'; - if (filename.indexOf('.config.js') != -1) + if (filename.indexOf('.config.js') !== -1) return 'js'; + if (filename.indexOf('.config.mjs') !== -1) + return 'mjs'; return null; }; @@ -288,7 +290,7 @@ Common.parseConfig = function(confObj, filename) { filename.indexOf('.yaml') > -1) { return yamljs.parse(confObj.toString()); } - else if (filename.indexOf('.config.js') > -1) { + else if (filename.indexOf('.config.js') > -1 || filename.indexOf('.config.mjs') > -1) { var confPath = require.resolve(path.resolve(filename)); delete require.cache[confPath]; return require(confPath); diff --git a/lib/Daemon.js b/lib/Daemon.js index 26c9c98ef..c1d7019ff 100644 --- a/lib/Daemon.js +++ b/lib/Daemon.js @@ -153,7 +153,7 @@ Daemon.prototype.innerStart = function(cb) { var profiler; try { - profiler = require('v8-profiler'); + profiler = require('v8-profiler-node8'); } catch(e) { profiler = null; } @@ -231,7 +231,6 @@ Daemon.prototype.innerStart = function(cb) { notifyByProcessId : God.notifyByProcessId, notifyKillPM2 : God.notifyKillPM2, - forceGc : God.forceGc, monitor : God.monitor, unmonitor : God.unmonitor, diff --git a/lib/God/ActionMethods.js b/lib/God/ActionMethods.js index 65cb64157..1556a1652 100644 --- a/lib/God/ActionMethods.js +++ b/lib/God/ActionMethods.js @@ -12,6 +12,7 @@ */ var fs = require('fs'); +const fsExtra = require('fs-extra'); var path = require('path'); var async = require('async'); var os = require('os'); @@ -137,13 +138,25 @@ module.exports = function(God) { } function fin(err) { + + // try to fix issues with empty dump file + // like #3485 + if (process_list.length === 0) { + + // fix : if no dump file, no process, only module and after pm2 update + if (!fs.existsSync(cst.DUMP_FILE_PATH)) { + that.clearDump(function(){}); + } + + // if no process in list don't modify dump file + // process list should not be empty + return cb(null, {success:true, process_list: process_list}); + } + // Back up dump file try { if (fs.existsSync(cst.DUMP_FILE_PATH)) { - if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) { - fs.unlinkSync(cst.DUMP_BACKUP_FILE_PATH); - } - fs.renameSync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); + fsExtra.copySync(cst.DUMP_FILE_PATH, cst.DUMP_BACKUP_FILE_PATH); } } catch (e) { console.error(e.stack || e); @@ -155,8 +168,13 @@ module.exports = function(God) { } catch (e) { console.error(e.stack || e); try { - fs.unlinkSync(cst.DUMP_FILE_PATH); + // try to backup file + if(fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) { + fsExtra.copySync(cst.DUMP_BACKUP_FILE_PATH, cst.DUMP_FILE_PATH); + } } catch (e) { + // don't keep broken file + fs.unlinkSync(cst.DUMP_FILE_PATH); console.error(e.stack || e); } } diff --git a/lib/God/Methods.js b/lib/God/Methods.js index e7b8e9fa3..ea6753a2c 100644 --- a/lib/God/Methods.js +++ b/lib/God/Methods.js @@ -247,21 +247,4 @@ module.exports = function(God) { pm2_env.unstable_restarts = 0; }; - /** - * Description - * @method forcegc - * @return - */ - God.forceGc = function(opts, cb) { - if (global.gc) { - global.gc(); - debug('Garbage collection triggered successfully'); - if (cb) cb(null, {success: true}); - } - else { - debug('Garbage collection failed'); - if (cb) cb(null, {success: false}); - } - }; - }; diff --git a/lib/God/Reload.js b/lib/God/Reload.js index d55cad1cc..5472f3b4e 100644 --- a/lib/God/Reload.js +++ b/lib/God/Reload.js @@ -174,7 +174,7 @@ function hardReload(God, id, wait_msg, cb) { module.exports = function(God) { /** - * GracefulReload + * Reload * @method softReloadProcessId * @param {} id * @param {} cb diff --git a/lib/Interactor/RemoteActions/Pm2Actions.js b/lib/Interactor/RemoteActions/Pm2Actions.js index a6de7c611..b5edd93bb 100644 --- a/lib/Interactor/RemoteActions/Pm2Actions.js +++ b/lib/Interactor/RemoteActions/Pm2Actions.js @@ -21,7 +21,6 @@ var Password = require('../Password.js'); var PM2_REMOTE_METHOD_ALLOWED = { 'restart' : {}, 'reload' : {}, - 'gracefulReload' : {}, 'reset' : {}, 'scale' : {}, diff --git a/lib/ProcessContainer.js b/lib/ProcessContainer.js index db9540dd6..0d739bac9 100644 --- a/lib/ProcessContainer.js +++ b/lib/ProcessContainer.js @@ -30,15 +30,7 @@ delete process.env.pm2_env; (function ProcessContainer() { var fs = require('fs'); - if (process.env.pmx !== 'false') { - require('pmx').init({ - transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, - http: process.env.km_link === 'true' || false, - v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, - event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, - deep_metrics: process.env.deep_monitoring === 'true' || false - }); - } + require('./ProcessUtils').injectModules(); var stdFile = pm2_env.pm_log_path; var outFile = pm2_env.pm_out_log_path; diff --git a/lib/ProcessContainerFork.js b/lib/ProcessContainerFork.js index 6d1b0cebb..59c45d3fb 100644 --- a/lib/ProcessContainerFork.js +++ b/lib/ProcessContainerFork.js @@ -1,18 +1,10 @@ -/** + /** * Copyright 2013 the PM2 project authors. All rights reserved. * Use of this source code is governed by a license that * can be found in the LICENSE file. */ // Inject custom modules -if (process.env.pmx !== 'false') { - require('pmx').init({ - transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, - http: process.env.km_link === 'true' || false, - v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, - event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, - deep_metrics: process.env.deep_monitoring === 'true' || false - }); -} +require('./ProcessUtils').injectModules(); if (typeof(process.env.source_map_support) != "undefined" && process.env.source_map_support !== "false") { diff --git a/lib/ProcessUtils.js b/lib/ProcessUtils.js new file mode 100644 index 000000000..3e90117e3 --- /dev/null +++ b/lib/ProcessUtils.js @@ -0,0 +1,29 @@ +module.exports = { + injectModules: function() { + if (process.env.pmx !== 'false') { + const pmx = require('pmx'); + pmx.init({ + transactions: (process.env.km_link === 'true' && (process.env.trace === 'true' || process.env.deep_monitoring === 'true')) || false, + http: process.env.km_link === 'true' || false, + v8: process.env.v8 === 'true' || process.env.deep_monitoring === 'true' || false, + event_loop_dump: process.env.event_loop_inspector === 'true' || process.env.deep_monitoring === 'true' || false, + deep_metrics: process.env.deep_monitoring === 'true' || false + }); + + if(require('semver').satisfies(process.versions.node, '>= 8.0.0')) { + var url = ''; + pmx.action('internal:inspect', function(reply) { + const inspector = require('inspector'); + if(url === '') { + inspector.open(); + url = inspector.url(); + } else { + inspector.close(); + url = ''; + } + reply(url); + }); + } + } + } +}; diff --git a/lib/Satan.js b/lib/Satan.js index e6df06ba9..1fc6651e7 100644 --- a/lib/Satan.js +++ b/lib/Satan.js @@ -215,7 +215,6 @@ Satan.remoteWrapper = function() { killMe : God.killMe, notifyKillPM2 : God.notifyKillPM2, - forceGc : God.forceGc, findByFullPath : God.findByFullPath, diff --git a/package.json b/package.json index 1855d6c34..4acaa133d 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "preferGlobal": true, "version": "2.10.1", "engines": { - "node": ">=0.12" + "node": ">=4.0.0" }, "directories": { "bin": "./bin", @@ -161,17 +161,18 @@ "dependencies": { "async": "^2.5", "blessed": "^0.1.81", - "chalk": "^1.1", - "chokidar": "^2", + "chalk": "^2.3.1", + "chokidar": "^2.0.2", "cli-table-redemption": "^1.0.0", - "commander": "2.13.0", + "commander": "2.14.1", "cron": "^1.3", "debug": "^3.0", - "eventemitter2": "1.0.5", + "eventemitter2": "5.0.1", "fclone": "1.0.11", + "fs-extra": "^5.0.0", "mkdirp": "0.5.1", "moment": "^2.19", - "needle": "^2.1.0", + "needle": "^2.2.0", "nssocket": "0.6.0", "pidusage": "^1.2.0", "pm2-axon": "3.1.0", @@ -181,7 +182,7 @@ "pmx": "^1.6", "promptly": "2.2.0", "semver": "^5.3", - "shelljs": "0.7.8", + "shelljs": "0.8.1", "source-map-support": "^0.5", "sprintf-js": "1.1.1", "v8-compile-cache": "^1.1.0", @@ -190,7 +191,7 @@ }, "devDependencies": { "mocha": "^3.5", - "should": "^11" + "should": "^13" }, "optionalDependencies": { "gkt": "https://tgz.pm2.io/gkt-1.0.0.tgz" diff --git a/test/bash/app-config-update.sh b/test/bash/app-config-update.sh index 8ef0a532c..1807110eb 100644 --- a/test/bash/app-config-update.sh +++ b/test/bash/app-config-update.sh @@ -58,14 +58,10 @@ $pm2 reload app-config-update/echo.js --node-args="--harmony" $pm2 prettylist | grep "node_args: \[ '--harmony' \]" spec "Should application have one node argument" -$pm2 gracefulReload app-config-update/echo.js --node-args="--harmony" -$pm2 prettylist | grep "node_args: \[ '--harmony' \]" -spec "Should application have two node arguments" - $pm2 prettylist | grep "node_args" spec "Should have found parameter" # Now set node-args to null -$pm2 gracefulReload app-config-update/echo.js --node-args=null +$pm2 reload app-config-update/echo.js --node-args=null # Should not find node_args anymore $pm2 prettylist | grep "node_args" ispec "Should have deleted cli parameter when passing null" @@ -74,8 +70,3 @@ $pm2 reload echo --name="new-name" $pm2 reset all $pm2 restart new-name should 'should reload processes with new name' 'restart_time: 1' 1 - -$pm2 gracefulReload new-name --name="new-name-2" -$pm2 reset all -$pm2 restart new-name-2 -should 'should graceful reload processes with new name' 'restart_time: 1' 1 diff --git a/test/bash/gracefulReload.sh b/test/bash/gracefulReload.sh deleted file mode 100644 index e7ed9fce5..000000000 --- a/test/bash/gracefulReload.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" - -cd $file_path - -echo "################## GRACEFUL RELOAD ###################" - -############### - -echo "Launching" -$pm2 start graceful-exit.js -i 4 --name="graceful" -o "grace.log" -e "grace-err.log" -should 'should start processes' 'online' 4 - -OUT_LOG=`$pm2 prettylist | grep -m 1 -E "pm_out_log_path:" | sed "s/.*'\([^']*\)',/\1/"` -cat /dev/null > $OUT_LOG - -#### Graceful reload all - -$pm2 gracefulReload all - -OUT=`grep "Finished closing connections" "$OUT_LOG" | wc -l` -[ $OUT -eq 1 ] || fail "Process not restarted gracefuly" -success "Process restarted gracefuly" - - -cat /dev/null > $OUT_LOG - -#### Graceful reload name -$pm2 gracefulReload graceful - -OUT=`grep "Finished closing connections" "$OUT_LOG" | wc -l` -[ $OUT -eq 1 ] || fail "Process not restarted gracefuly" -success "Process restarted gracefuly" diff --git a/test/bash/gracefulReload2.sh b/test/bash/gracefulReload2.sh deleted file mode 100644 index b7c25fdd4..000000000 --- a/test/bash/gracefulReload2.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" - -cd $file_path - -echo "################## GRACEFUL RELOAD 2 ###################" - -echo "Launching" -$pm2 start graceful-exit-no-listen.js -i 2 --name="graceful2" -o "grace2.log" -e "grace-err2.log" -should 'should start processes' 'online' 2 - -OUT_LOG=`$pm2 prettylist | grep -m 1 -E "pm_out_log_path:" | sed "s/.*'\([^']*\)',/\1/"` -cat /dev/null > $OUT_LOG - -#### Graceful reload name -$pm2 gracefulReload graceful2 - -echo "PATH: $OUT_LOG" - -TEXT=$(cat $OUT_LOG) - -echo "TEXT: $TEXT" - -OUT=`grep "Finished closing connections" "$OUT_LOG" | wc -l` -[ $OUT -eq 1 ] || fail "Non-listening process not restarted gracefuly" -success "Non-listening process restarted gracefuly" diff --git a/test/bash/gracefulReload3.sh b/test/bash/gracefulReload3.sh deleted file mode 100644 index 307d74f6b..000000000 --- a/test/bash/gracefulReload3.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -SRC=$(cd $(dirname "$0"); pwd) -source "${SRC}/include.sh" - -cd $file_path - -echo "################## GRACEFUL RELOAD 3 ###################" - -echo "Launching" -$pm2 start graceful-exit-send.js -i 2 --name="graceful3" -o "grace3.log" -e "grace-err3.log" -should 'should start processes' 'online' 2 - -OUT_LOG=`$pm2 prettylist | grep -m 1 -E "pm_out_log_path:" | sed "s/.*'\([^']*\)',/\1/"` -cat /dev/null > $OUT_LOG - -#### Graceful reload name -$pm2 gracefulReload graceful3 - -OUT=`grep "Finished closing connections" "$OUT_LOG" | wc -l` -[ $OUT -eq 1 ] || fail "Process that sends 'online' not restarted gracefuly" -success "Process that sends 'online' restarted gracefuly" diff --git a/test/bash/json-file.sh b/test/bash/json-file.sh index 50c3ff352..08ce5543b 100644 --- a/test/bash/json-file.sh +++ b/test/bash/json-file.sh @@ -36,18 +36,13 @@ sleep 1 should 'should reload processes' 'online' 6 should 'should all script been restarted one time' 'restart_time: 2' 6 -$pm2 gracefulReload all.json -sleep 1 -should 'should graceful reload processes' 'online' 6 -should 'should all script been restarted one time' 'restart_time: 3' 6 - ## ## Smart restart ## $pm2 start all.json sleep 1 should 'should smart restart processes' 'online' 6 -should 'should all script been restarted one time' 'restart_time: 4' 6 +should 'should all script been restarted one time' 'restart_time: 3' 6 $pm2 stop all.json sleep 1 diff --git a/test/bash/reload.sh b/test/bash/reload.sh index d659a1b6c..88ad94165 100644 --- a/test/bash/reload.sh +++ b/test/bash/reload.sh @@ -50,8 +50,6 @@ $pm2 restart delayed_exit.js should 'should restart processes' 'restart_time: 1' 2 $pm2 reload delayed_exit.js should 'should restart processes' 'restart_time: 2' 2 -$pm2 gracefulReload delayed_exit.js -should 'should restart processes' 'restart_time: 3' 2 $pm2 kill $pm2 start child.js -i 4 diff --git a/test/fixtures/graceful-exit-no-listen.js b/test/fixtures/graceful-exit-no-listen.js index 37cfba2dc..814d3845c 100644 --- a/test/fixtures/graceful-exit-no-listen.js +++ b/test/fixtures/graceful-exit-no-listen.js @@ -2,7 +2,7 @@ /* * Example of graceful exit that does not listen * - * $ pm2 gracefulReload all + * $ pm2 reload all */ process.on('message', function(msg) { diff --git a/test/fixtures/graceful-exit-send.js b/test/fixtures/graceful-exit-send.js index 7142c3f5d..94d461f00 100644 --- a/test/fixtures/graceful-exit-send.js +++ b/test/fixtures/graceful-exit-send.js @@ -2,7 +2,7 @@ /* * Example of graceful exit that does not listen but sends 'online' * - * $ pm2 gracefulReload all + * $ pm2 reload all */ process.on('message', function(msg) { diff --git a/test/fixtures/graceful-exit.js b/test/fixtures/graceful-exit.js index 43e8212a9..5b1461a18 100644 --- a/test/fixtures/graceful-exit.js +++ b/test/fixtures/graceful-exit.js @@ -2,7 +2,7 @@ /* * Example of graceful exit * - * $ pm2 gracefulReload all + * $ pm2 reload all */ process.on('message', function(msg) { diff --git a/test/interface/remote.mocha.js b/test/interface/remote.mocha.js index d1ded5a12..87adbcd41 100644 --- a/test/interface/remote.mocha.js +++ b/test/interface/remote.mocha.js @@ -145,30 +145,6 @@ describe('REMOTE PM2 ACTIONS', function() { }); }); - it('should gracefulRELOAD', function(done) { - send_cmd.once('trigger:pm2:result', function(pck) { - /** - * Once remote command is finished... - */ - - should(pck.ret.err).be.null(); - - pm2.list(function(err, ret) { - ret.forEach(function(proc) { - proc.pm2_env.restart_time.should.eql(3); - }); - }); - - done(); - }); - - send_cmd.emit('cmd', { - _type : 'trigger:pm2:action', - method_name : 'gracefulReload', - parameters : {name : 'child' } - }); - }); - it('should RESET metadata', function(done) { send_cmd.once('trigger:pm2:result', function(pck) { /** diff --git a/test/pm2_behavior_tests.sh b/test/pm2_behavior_tests.sh index 6b1fa6306..9d212a11d 100644 --- a/test/pm2_behavior_tests.sh +++ b/test/pm2_behavior_tests.sh @@ -81,12 +81,6 @@ bash ./test/bash/right-exit-code.sh spec "Verification exit code" bash ./test/bash/log-reload.sh spec "Log reload" -bash ./test/bash/gracefulReload.sh -spec "gracefulReload system 1" -bash ./test/bash/gracefulReload2.sh -spec "gracefulReload system 2" -bash ./test/bash/gracefulReload3.sh -spec "gracefulReload system 3" bash ./test/bash/misc.sh spec "MISC features" bash ./test/bash/fork.sh diff --git a/test/programmatic/programmatic.js b/test/programmatic/programmatic.js index e71f0aecf..478e13618 100644 --- a/test/programmatic/programmatic.js +++ b/test/programmatic/programmatic.js @@ -18,7 +18,12 @@ describe('PM2 programmatic calls', function() { }); after(function(done) { - pm2.kill(done); + pm2.delete('all', function(err, ret) { + // clean dump file + pm2.clearDump(function(err) { + pm2.kill(done); + }); + }); }); before(function(done) { diff --git a/test/programmatic/signals.js b/test/programmatic/signals.js index 6c9c93b30..fad65206e 100644 --- a/test/programmatic/signals.js +++ b/test/programmatic/signals.js @@ -162,21 +162,6 @@ describe('Signal kill (+delayed)', function() { }); }); - - it('should graceful reload script', function(done) { - setTimeout(function() { - pm2.list(function(err, list) { - list[0].pm2_env.status.should.eql('online'); - list[0].pm2_env.restart_time.should.eql(2); - done(); - }); - }, 1500); - - pm2.gracefulReload('delayed-sigint', function(err, app) { - //done(err); - }); - - }); }); describe('with 4000ms via kill_timeout (json/cli option)', function() {