2016-03-22 23:33:43 +01:00
/**
2021-01-28 11:05:59 +01:00
* Copyright 2013-2021 the PM2 project authors. All rights reserved.
2016-03-22 23:33:43 +01:00
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
2018-02-27 16:53:40 +01:00
'use strict' ;
2015-02-07 22:37:38 -05:00
2018-02-27 15:47:37 +01:00
const commander = require ( 'commander' ) ;
const fs = require ( 'fs' ) ;
const path = require ( 'path' ) ;
2018-07-19 09:44:06 -04:00
const eachLimit = require ( 'async/eachLimit' ) ;
const series = require ( 'async/series' ) ;
2018-02-27 15:47:37 +01:00
const debug = require ( 'debug' ) ( 'pm2:cli' ) ;
const util = require ( 'util' ) ;
const chalk = require ( 'chalk' ) ;
const fclone = require ( 'fclone' ) ;
2016-06-04 14:04:26 +02:00
2019-05-06 18:59:37 +02:00
var DockerMgmt = require ( './API/ExtraMgmt/Docker.js' )
var conf = require ( '../constants.js' ) ;
2016-06-05 14:10:05 +02:00
var Client = require ( './Client' ) ;
2016-06-04 14:04:26 +02:00
var Common = require ( './Common' ) ;
2018-05-17 15:42:43 +02:00
var KMDaemon = require ( '@pm2/agent/src/InteractorClient' ) ;
2016-06-04 14:04:26 +02:00
var Config = require ( './tools/Config' ) ;
2016-07-23 19:13:55 +02:00
var Modularizer = require ( './API/Modules/Modularizer.js' ) ;
2016-06-08 19:21:37 +02:00
var path _structure = require ( '../paths.js' ) ;
2019-11-04 12:04:05 +01:00
var UX = require ( './API/UX' ) ;
2017-11-22 15:44:18 +01:00
var pkg = require ( '../package.json' ) ;
2018-09-27 17:24:24 +02:00
var hf = require ( './API/Modules/flagExt.js' ) ;
var Configuration = require ( './Configuration.js' ) ;
2019-03-05 17:31:41 +01:00
const semver = require ( 'semver' )
2020-04-23 17:33:35 +02:00
const sexec = require ( './tools/sexec.js' )
2015-02-07 22:37:38 -05:00
2017-01-12 01:18:38 +01:00
var IMMUTABLE _MSG = chalk . bold . blue ( 'Use --update-env to update environment variables' ) ;
2017-01-11 18:21:06 +01:00
2016-06-08 19:21:37 +02:00
/**
* Main Function to be imported
* can be aliased to PM2
*
* To use it when PM2 is installed as a module:
*
* var PM2 = require('pm2');
*
* var pm2 = PM2(<opts>);
*
*
* @param {Object} opts
* @param {String} [opts.cwd=<current>] override pm2 cwd for starting scripts
* @param {String} [opts.pm2_home=[<paths.js>]] pm2 directory for log, pids, socket files
2016-07-02 13:52:12 +02:00
* @param {Boolean} [opts.independent=false] unique PM2 instance (random pm2_home)
2016-06-08 19:21:37 +02:00
* @param {Boolean} [opts.daemon_mode=true] should be called in the same process or not
2018-05-10 20:09:13 +02:00
* @param {String} [opts.public_key=null] pm2 plus bucket public key
* @param {String} [opts.secret_key=null] pm2 plus bucket secret key
* @param {String} [opts.machine_name=null] pm2 plus instance name
2016-06-08 19:21:37 +02:00
*/
2018-02-27 10:52:12 +01:00
class API {
2016-06-05 12:39:04 +02:00
2018-02-27 10:52:12 +01:00
constructor ( opts ) {
if ( ! opts ) opts = { } ;
2018-05-11 00:12:01 +02:00
var that = this ;
2016-06-09 01:22:57 +02:00
2018-02-27 10:52:12 +01:00
this . daemon _mode = typeof ( opts . daemon _mode ) == 'undefined' ? true : opts . daemon _mode ;
this . pm2 _home = conf . PM2 _ROOT _PATH ;
2018-05-10 20:09:13 +02:00
this . public _key = conf . PUBLIC _KEY || opts . public _key || null ;
this . secret _key = conf . SECRET _KEY || opts . secret _key || null ;
this . machine _name = conf . MACHINE _NAME || opts . machine _name || null
2016-06-08 19:21:37 +02:00
2018-02-27 10:52:12 +01:00
/**
* CWD resolution
*/
this . cwd = process . cwd ( ) ;
if ( opts . cwd ) {
this . cwd = path . resolve ( opts . cwd ) ;
}
2016-06-08 19:21:37 +02:00
2018-02-27 10:52:12 +01:00
/**
* 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' ) ;
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
2018-02-27 15:47:37 +01:00
const crypto = require ( 'crypto' ) ;
2018-05-11 00:12:01 +02:00
var random _file = crypto . randomBytes ( 8 ) . toString ( 'hex' ) ;
2018-02-27 10:52:12 +01:00
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 ) ) ;
}
2016-06-08 19:21:37 +02:00
2018-02-27 10:52:12 +01:00
this . _conf = conf ;
2016-06-11 22:09:14 +02:00
2018-02-27 10:52:12 +01:00
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 ) ;
}
2016-06-08 19:21:37 +02:00
2018-02-27 10:52:12 +01:00
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
} ) ;
2016-06-05 12:39:04 +02:00
2019-05-29 00:33:11 +02:00
this . pm2 _configuration = Configuration . getSync ( 'pm2' ) || { }
2018-10-03 18:03:37 +02:00
2018-02-27 10:52:12 +01:00
this . gl _interact _infos = null ;
this . gl _is _km _linked = false ;
2017-01-17 14:30:50 +01:00
2018-02-27 10:52:12 +01:00
try {
2018-05-11 00:12:01 +02:00
var pid = fs . readFileSync ( conf . INTERACTOR _PID _PATH ) ;
2018-02-27 10:52:12 +01:00
pid = parseInt ( pid . toString ( ) . trim ( ) ) ;
process . kill ( pid , 0 ) ;
that . gl _is _km _linked = true ;
} catch ( e ) {
that . gl _is _km _linked = false ;
}
2016-06-05 12:39:04 +02:00
2018-02-27 10:52:12 +01:00
// For testing purposes
if ( this . secret _key && process . env . NODE _ENV == 'local_test' )
that . gl _is _km _linked = true ;
2017-01-19 21:59:38 +01:00
2018-07-12 14:50:17 +02:00
KMDaemon . ping ( this . _conf , function ( err , result ) {
if ( ! err && result === true ) {
fs . readFile ( conf . INTERACTION _CONF , ( err , _conf ) => {
if ( ! err ) {
try {
that . gl _interact _infos = JSON . parse ( _conf . toString ( ) )
} catch ( e ) {
var json5 = require ( './tools/json5.js' )
try {
that . gl _interact _infos = json5 . parse ( _conf . toString ( ) )
} catch ( e ) {
console . error ( e )
that . gl _interact _infos = null
}
}
}
} )
}
} )
2018-02-27 11:25:32 +01:00
this . gl _retry = 0 ;
2018-02-27 10:52:12 +01:00
}
2016-06-05 12:39:04 +02:00
2018-02-27 11:25:32 +01:00
/**
* 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 ;
}
2017-12-21 11:45:12 +01:00
2018-02-27 11:25:32 +01:00
this . Client . start ( function ( err , meta ) {
if ( err )
return cb ( err ) ;
2017-12-21 11:45:12 +01:00
2018-02-27 11:25:32 +01:00
if ( meta . new _pm2 _instance == false && that . daemon _mode === true )
return cb ( err , meta ) ;
2017-12-21 11:45:12 +01:00
2018-02-27 11:25:32 +01:00
// If new pm2 instance has been popped
// Lauch all modules
2018-09-24 22:55:18 +02:00
that . launchAll ( that , function ( err _mod ) {
2018-02-27 11:25:32 +01:00
return cb ( err , meta ) ;
} ) ;
} ) ;
2016-08-06 13:45:10 -07:00
}
2016-07-04 23:59:46 +02:00
2018-02-27 11:25:32 +01:00
/**
* 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 that = this ;
2016-06-05 12:39:04 +02:00
2018-02-27 11:25:32 +01:00
debug ( 'Killing and deleting current deamon' ) ;
2016-06-08 19:21:37 +02:00
2018-02-27 11:25:32 +01:00
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' ) ;
2016-06-08 19:21:37 +02:00
2018-02-27 11:25:32 +01:00
if ( that . pm2 _home . indexOf ( '.pm2' ) > - 1 )
return cb ( new Error ( 'Destroy is not a allowed method on .pm2' ) ) ;
2016-06-08 19:21:37 +02:00
2018-02-27 12:28:43 +01:00
fs . access ( test _path , fs . R _OK , function ( err ) {
if ( err ) return cb ( err ) ;
debug ( 'Deleting temporary folder %s' , that . pm2 _home ) ;
2020-04-23 17:33:35 +02:00
sexec ( cmd , cb ) ;
2016-06-11 17:19:07 +02:00
} ) ;
2016-06-08 19:21:37 +02:00
} ) ;
2018-02-27 11:25:32 +01:00
}
2016-06-08 19:21:37 +02:00
2018-02-27 11:25:32 +01:00
/**
* 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 ;
2016-06-08 19:21:37 +02:00
2018-02-27 11:25:32 +01:00
if ( ! cb ) cb = function ( ) { } ;
2016-06-14 00:16:14 +02:00
2018-02-27 11:25:32 +01:00
this . Client . close ( function ( err , data ) {
debug ( 'The session lasted %ds' , ( new Date ( ) - that . start _timer ) / 1000 ) ;
return cb ( err , data ) ;
} ) ;
} ;
2016-06-08 19:21:37 +02:00
2018-02-27 16:15:41 +01:00
/**
* Alias on disconnect
* @param cb
*/
close ( cb ) {
this . disconnect ( cb ) ;
}
2018-02-27 11:25:32 +01:00
/**
* Launch modules
*
* @param {Function} cb callback once pm2 has launched modules
*/
launchModules ( cb ) {
2018-09-24 22:55:18 +02:00
this . launchAll ( this , cb ) ;
2018-02-27 11:25:32 +01:00
}
2016-11-08 12:43:30 -05:00
2018-02-27 11:25:32 +01:00
/**
* 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 ) ;
}
2016-06-08 19:21:37 +02:00
2018-02-27 11:25:32 +01:00
/**
* 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 ) ;
}
2016-06-05 12:39:04 +02:00
}
2018-02-27 11:25:32 +01:00
[ process . stdout , process . stderr ] . forEach ( function ( std ) {
var fd = std . fd ;
if ( ! std . bufferSize ) {
// bufferSize equals 0 means current stream is drained.
2016-06-05 12:39:04 +02:00
fds = fds | fd ;
2018-02-27 11:25:32 +01:00
} 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 ( ) ;
2016-06-05 12:39:04 +02:00
} ) ;
} ) ;
2018-02-27 11:25:32 +01:00
}
2016-06-05 12:39:04 +02:00
2016-06-04 14:04:26 +02:00
////////////////////////////
// Application management //
////////////////////////////
2016-05-27 04:49:46 +02:00
2018-02-27 11:25:32 +01:00
/**
* 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 = { } ;
}
2019-03-05 17:31:41 +01:00
if ( ! opts ) opts = { } ;
if ( semver . lt ( process . version , '6.0.0' ) ) {
Common . printOut ( conf . PREFIX _MSG _WARNING + 'Node 4 is deprecated, please upgrade to use pm2 to have all features' ) ;
}
2016-07-13 00:56:44 +02:00
2018-02-27 11:25:32 +01:00
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 ;
2016-03-12 14:12:26 +01:00
2019-05-29 00:33:11 +02:00
if ( Common . isConfigFile ( cmd ) || ( typeof ( cmd ) === 'object' ) ) {
that . _startJson ( cmd , opts , 'restartProcessId' , ( err , procs ) => {
2020-06-29 11:20:57 +02:00
return cb ? cb ( err , procs ) : this . speedList ( )
2019-05-29 00:33:11 +02:00
} )
}
2018-02-27 11:25:32 +01:00
else {
2019-05-29 00:33:11 +02:00
that . _startScript ( cmd , opts , ( err , procs ) => {
2020-06-30 10:47:15 +02:00
return cb ? cb ( err , procs ) : this . speedList ( 0 )
2019-05-29 00:33:11 +02:00
} )
2018-02-27 11:25:32 +01:00
}
2017-06-27 23:53:52 +02:00
}
2015-04-15 00:04:07 -04:00
2018-02-27 11:25:32 +01:00
/**
* Reset process counters
*
* @method resetMetaProcess
*/
reset ( process _name , cb ) {
var that = this ;
function processIds ( ids , cb ) {
2018-07-19 09:44:06 -04:00
eachLimit ( ids , conf . CONCURRENT _ACTIONS , function ( id , next ) {
2018-02-27 11:25:32 +01:00
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 ( ) ;
2016-07-23 19:13:55 +02:00
} ) ;
2018-02-27 11:25:32 +01:00
}
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
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 ) ;
}
2016-07-23 19:13:55 +02:00
}
2018-02-27 11:25:32 +01:00
/**
* Update daemonized PM2 Daemon
*
* @param {Function} cb callback when pm2 has been upgraded
*/
update ( cb ) {
var that = this ;
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
Common . printOut ( 'Be sure to have the latest version by doing `npm install pm2@latest -g` before doing this procedure.' ) ;
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
// Dump PM2 processes
that . Client . executeRemote ( 'notifyKillPM2' , { } , function ( ) { } ) ;
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
that . getVersion ( function ( err , new _version ) {
2018-05-10 20:09:13 +02:00
// If not linked to PM2 plus, and update PM2 to latest, display motd.update
2018-02-27 11:25:32 +01:00
if ( ! that . gl _is _km _linked && ! err && ( pkg . version != new _version ) ) {
2018-07-13 18:29:33 +02:00
var dt = fs . readFileSync ( path . join ( _ _dirname , that . _conf . PM2 _UPDATE ) ) ;
2018-02-27 11:25:32 +01:00
console . log ( dt . toString ( ) ) ;
}
2017-11-22 15:44:18 +01:00
2018-02-27 11:25:32 +01:00
that . dump ( function ( err ) {
that . killDaemon ( function ( ) {
that . Client . launchDaemon ( { interactor : false } , function ( err , child ) {
that . Client . launchRPC ( function ( ) {
that . resurrect ( function ( ) {
Common . printOut ( chalk . blue . bold ( '>>>>>>>>>> PM2 updated' ) ) ;
2018-09-24 22:55:18 +02:00
that . launchAll ( that , function ( ) {
2019-11-08 14:36:05 +01:00
KMDaemon . launchAndInteract ( that . _conf , {
pm2 _version : pkg . version
} , function ( err , data , interactor _proc ) {
2019-05-26 04:34:26 +02:00
} )
setTimeout ( ( ) => {
2018-02-27 11:25:32 +01:00
return cb ? cb ( null , { success : true } ) : that . speedList ( ) ;
2019-05-26 04:34:26 +02:00
} , 250 )
2017-11-22 15:44:18 +01:00
} ) ;
2016-07-23 19:13:55 +02:00
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
2018-02-27 11:25:32 +01:00
return false ;
}
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
/**
* 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 ;
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
if ( typeof ( opts ) == "function" ) {
cb = opts ;
opts = { } ;
}
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
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 ) ;
}
2017-06-27 23:53:52 +02:00
2018-02-27 11:25:32 +01:00
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 ) ;
2018-11-19 21:03:07 +03:00
return cb ? cb ( null , apps ) : that . exitCli ( conf . SUCCESS _EXIT ) ;
2018-02-27 11:25:32 +01:00
} ) ;
else {
2018-12-04 13:14:14 +01:00
if ( opts && opts . env ) {
var err = 'Using --env [env] without passing the ecosystem.config.js does not work'
Common . err ( err ) ;
Common . unlockReload ( ) ;
return cb ? cb ( Common . retErr ( err ) ) : that . exitCli ( conf . ERROR _EXIT ) ;
}
2018-02-27 11:25:32 +01:00
if ( opts && ! opts . updateEnv )
Common . printOut ( IMMUTABLE _MSG ) ;
2017-06-27 23:53:52 +02:00
2018-02-27 11:25:32 +01:00
that . _operate ( 'reloadProcessId' , process _name , opts , function ( err , apps ) {
Common . unlockReload ( ) ;
2017-06-27 23:53:52 +02:00
2018-02-27 11:25:32 +01:00
if ( err )
return cb ? cb ( err ) : that . exitCli ( conf . ERROR _EXIT ) ;
2018-11-19 21:03:07 +03:00
return cb ? cb ( null , apps ) : that . exitCli ( conf . SUCCESS _EXIT ) ;
2018-02-27 11:25:32 +01:00
} ) ;
}
2016-10-27 12:55:39 +02:00
}
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
/**
* 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 ;
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
if ( typeof ( cmd ) === 'number' )
cmd = cmd . toString ( ) ;
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
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 {
2018-12-04 13:14:14 +01:00
if ( opts && opts . env ) {
var err = 'Using --env [env] without passing the ecosystem.config.js does not work'
Common . err ( err ) ;
return cb ? cb ( Common . retErr ( err ) ) : that . exitCli ( conf . ERROR _EXIT ) ;
}
2018-02-27 11:25:32 +01:00
if ( opts && ! opts . updateEnv )
Common . printOut ( IMMUTABLE _MSG ) ;
that . _operate ( 'restartProcessId' , cmd , opts , cb ) ;
}
2016-07-23 19:13:55 +02:00
}
2018-02-27 11:25:32 +01:00
/**
* 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 ;
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
if ( typeof ( jsonVia ) === "function" ) {
cb = jsonVia ;
jsonVia = null ;
}
2019-05-29 00:33:11 +02:00
2018-02-27 11:25:32 +01:00
if ( typeof ( process _name ) === "number" ) {
process _name = process _name . toString ( ) ;
}
if ( jsonVia == 'pipe' )
2019-05-29 00:33:11 +02:00
return that . actionFromJson ( 'deleteProcessId' , process _name , commander , 'pipe' , ( err , procs ) => {
2020-06-29 11:20:57 +02:00
return cb ? cb ( err , procs ) : this . speedList ( )
2019-05-29 00:33:11 +02:00
} ) ;
2018-02-27 11:25:32 +01:00
if ( Common . isConfigFile ( process _name ) )
2019-05-29 00:33:11 +02:00
return that . actionFromJson ( 'deleteProcessId' , process _name , commander , 'file' , ( err , procs ) => {
2020-06-29 11:20:57 +02:00
return cb ? cb ( err , procs ) : this . speedList ( )
2019-05-29 00:33:11 +02:00
} ) ;
2018-09-24 22:55:18 +02:00
else {
2019-05-29 00:33:11 +02:00
that . _operate ( 'deleteProcessId' , process _name , ( err , procs ) => {
2020-06-29 11:20:57 +02:00
return cb ? cb ( err , procs ) : this . speedList ( )
2019-05-29 00:33:11 +02:00
} ) ;
2018-09-24 22:55:18 +02:00
}
2016-07-23 19:13:55 +02:00
}
2018-02-27 11:25:32 +01:00
/**
* 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 ( ) ;
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
if ( process _name == "-" ) {
process . stdin . resume ( ) ;
process . stdin . setEncoding ( 'utf8' ) ;
process . stdin . on ( 'data' , function ( param ) {
process . stdin . pause ( ) ;
2019-05-29 00:33:11 +02:00
that . actionFromJson ( 'stopProcessId' , param , commander , 'pipe' , ( err , procs ) => {
2020-06-29 11:20:57 +02:00
return cb ? cb ( err , procs ) : this . speedList ( )
2019-05-29 00:33:11 +02:00
} )
2018-02-27 11:25:32 +01:00
} ) ;
}
else if ( Common . isConfigFile ( process _name ) )
2019-05-29 00:33:11 +02:00
that . actionFromJson ( 'stopProcessId' , process _name , commander , 'file' , ( err , procs ) => {
2020-06-29 11:20:57 +02:00
return cb ? cb ( err , procs ) : this . speedList ( )
2019-05-29 00:33:11 +02:00
} ) ;
2018-02-27 11:25:32 +01:00
else
2019-05-29 00:33:11 +02:00
that . _operate ( 'stopProcessId' , process _name , ( err , procs ) => {
2020-06-29 11:20:57 +02:00
return cb ? cb ( err , procs ) : this . speedList ( )
2019-05-29 00:33:11 +02:00
} ) ;
2016-07-23 19:13:55 +02:00
}
2018-02-27 11:25:32 +01:00
/**
* Get list of all processes managed
*
* @param {Function} cb Callback
*/
list ( opts , cb ) {
var that = this ;
if ( typeof ( opts ) == 'function' ) {
cb = opts ;
opts = null ;
2016-07-23 19:13:55 +02:00
}
2018-02-27 11:25:32 +01:00
that . Client . executeRemote ( 'getMonitorData' , { } , function ( err , list ) {
if ( err ) {
Common . printError ( err ) ;
return cb ? cb ( Common . retErr ( err ) ) : that . exitCli ( conf . ERROR _EXIT ) ;
2016-07-23 19:13:55 +02:00
}
2018-02-27 11:25:32 +01:00
if ( opts && opts . rawArgs && opts . rawArgs . indexOf ( '--watch' ) > - 1 ) {
2019-12-02 15:17:42 +01:00
var dayjs = require ( 'dayjs' ) ;
2018-02-27 11:25:32 +01:00
function show ( ) {
2019-05-07 10:10:56 +03:00
process . stdout . write ( '\x1b[2J' ) ;
process . stdout . write ( '\x1b[0f' ) ;
2019-12-02 15:17:42 +01:00
console . log ( 'Last refresh: ' , dayjs ( ) . format ( ) ) ;
2018-02-27 11:25:32 +01:00
that . Client . executeRemote ( 'getMonitorData' , { } , function ( err , list ) {
2019-11-04 12:04:05 +01:00
UX . list ( list , null ) ;
2018-02-27 11:25:32 +01:00
} ) ;
}
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
show ( ) ;
setInterval ( show , 900 ) ;
return false ;
}
2016-07-23 19:13:55 +02:00
2020-06-30 10:47:15 +02:00
return cb ? cb ( null , list ) : that . speedList ( null ) ;
2018-02-27 11:25:32 +01:00
} ) ;
}
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
/**
* Kill Daemon
*
* @param {Function} cb Callback
*/
killDaemon ( cb ) {
2018-09-25 00:07:45 +02:00
process . env . PM2 _STATUS = 'stopping'
2018-02-27 11:25:32 +01:00
var that = this ;
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
that . Client . executeRemote ( 'notifyKillPM2' , { } , function ( ) { } ) ;
2016-07-23 19:13:55 +02:00
2018-09-24 22:55:18 +02:00
that . _operate ( 'deleteProcessId' , 'all' , function ( err , list ) {
Common . printOut ( conf . PREFIX _MSG + '[v] All Applications Stopped' ) ;
process . env . PM2 _SILENT = 'false' ;
2018-02-27 11:25:32 +01:00
2018-09-24 22:55:18 +02:00
that . killAgent ( function ( err , data ) {
2018-09-25 00:06:22 +02:00
if ( ! err ) {
Common . printOut ( conf . PREFIX _MSG + '[v] Agent Stopped' ) ;
}
2018-07-23 18:46:36 +02:00
2018-09-24 22:55:18 +02:00
that . Client . killDaemon ( function ( err , res ) {
if ( err ) Common . printError ( err ) ;
2018-09-25 00:06:22 +02:00
Common . printOut ( conf . PREFIX _MSG + '[v] PM2 Daemon Stopped' ) ;
2018-09-24 22:55:18 +02:00
return cb ? cb ( err , res ) : that . exitCli ( conf . SUCCESS _EXIT ) ;
2016-07-23 19:13:55 +02:00
} ) ;
2018-09-25 00:06:22 +02:00
2016-07-23 19:13:55 +02:00
} ) ;
2018-09-25 00:06:22 +02:00
} )
2018-02-27 11:25:32 +01:00
}
2016-07-23 19:13:55 +02:00
2018-02-27 16:15:41 +01:00
kill ( cb ) {
this . killDaemon ( cb ) ;
}
2018-02-27 11:25:32 +01:00
/////////////////////
// Private methods //
/////////////////////
2016-07-23 19:13:55 +02:00
2018-02-27 11:25:32 +01:00
/**
* 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 ;
2014-08-09 14:08:38 +02:00
2018-09-20 13:36:51 +02:00
/**
* Commander.js tricks
*/
2018-09-23 19:28:13 +02:00
var app _conf = Config . filterOptions ( opts ) ;
2018-02-27 11:25:32 +01:00
var appConf = { } ;
2014-09-04 12:03:44 +02:00
2018-05-27 16:07:54 +02:00
if ( typeof app _conf . name == 'function' )
2018-02-27 11:25:32 +01:00
delete app _conf . name ;
2013-11-22 13:27:40 +01:00
2018-02-27 11:25:32 +01:00
delete app _conf . args ;
2014-11-25 22:19:02 +01:00
2018-09-20 13:36:51 +02:00
// Retrieve arguments via -- <args>
2018-02-27 11:25:32 +01:00
var argsIndex ;
2015-01-12 14:23:21 -05:00
2018-05-27 16:07:54 +02:00
if ( opts . rawArgs && ( argsIndex = opts . rawArgs . indexOf ( '--' ) ) >= 0 )
2018-02-27 11:25:32 +01:00
app _conf . args = opts . rawArgs . slice ( argsIndex + 1 ) ;
2018-05-27 16:07:54 +02:00
else if ( opts . scriptArgs )
2018-02-27 11:25:32 +01:00
app _conf . args = opts . scriptArgs ;
2014-08-11 15:21:59 +02:00
2018-02-27 11:25:32 +01:00
app _conf . script = script ;
2019-10-28 17:28:15 +05:30
if ( ! app _conf . namespace )
app _conf . namespace = 'default' ;
2014-08-30 19:33:06 +02:00
2019-06-29 01:37:04 -07:00
if ( ( appConf = Common . verifyConfs ( app _conf ) ) instanceof Error ) {
Common . err ( appConf )
2018-02-27 11:25:32 +01:00
return cb ? cb ( Common . retErr ( appConf ) ) : that . exitCli ( conf . ERROR _EXIT ) ;
2019-06-29 01:37:04 -07:00
}
2014-11-24 14:44:20 +08:00
2018-02-27 11:25:32 +01:00
app _conf = appConf [ 0 ] ;
2018-01-16 11:17:54 +01:00
2018-06-22 18:02:15 +03:00
if ( opts . watchDelay ) {
if ( typeof opts . watchDelay === "string" && opts . watchDelay . indexOf ( "ms" ) !== - 1 )
app _conf . watch _delay = parseInt ( opts . watchDelay ) ;
else {
app _conf . watch _delay = parseFloat ( opts . watchDelay ) * 1000 ;
}
}
2018-07-24 16:04:22 +03:00
var mas = [ ] ;
if ( typeof opts . ext != 'undefined' )
hf . make _available _extension ( opts , mas ) ; // for -e flag
mas . length > 0 ? app _conf . ignore _watch = mas : 0 ;
2018-02-27 11:25:32 +01:00
/**
* If -w option, write configuration to configuration.json file
*/
2018-07-06 15:29:12 +08:00
if ( app _conf . write ) {
2018-02-27 11:25:32 +01:00
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 ) ;
}
2015-03-20 18:28:02 +01:00
}
2013-11-13 15:10:59 +01:00
2018-09-20 13:36:51 +02:00
series ( [
restartExistingProcessName ,
2019-10-28 13:33:28 +05:30
restartExistingNameSpace ,
2018-09-20 13:36:51 +02:00
restartExistingProcessId ,
restartExistingProcessPathOrStartNew
] , function ( err , data ) {
if ( err instanceof Error )
return cb ? cb ( err ) : that . exitCli ( conf . ERROR _EXIT ) ;
var ret = { } ;
data . forEach ( function ( _dt ) {
if ( _dt !== undefined )
ret = _dt ;
} ) ;
return cb ? cb ( null , ret ) : that . speedList ( ) ;
} ) ;
2018-02-27 11:25:32 +01:00
/**
* If start <app_name> start/restart application
*/
function restartExistingProcessName ( cb ) {
if ( ! isNaN ( script ) ||
2016-03-15 17:52:32 +01:00
( typeof script === 'string' && script . indexOf ( '/' ) != - 1 ) ||
( typeof script === 'string' && path . extname ( script ) !== '' ) )
2018-02-27 11:25:32 +01:00
return cb ( null ) ;
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 ) ;
2019-10-30 14:41:45 +01:00
} ) ;
2019-10-28 13:33:28 +05:30
}
/**
* If start <namespace> start/restart namespace
*/
function restartExistingNameSpace ( cb ) {
if ( ! isNaN ( script ) ||
( typeof script === 'string' && script . indexOf ( '/' ) != - 1 ) ||
( typeof script === 'string' && path . extname ( script ) !== '' ) )
return cb ( null ) ;
if ( script !== 'all' ) {
that . Client . getProcessIdsByNamespace ( 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 ) ;
2018-02-27 11:25:32 +01:00
} ) ;
}
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 ) ;
} ) ;
}
2015-06-11 15:53:10 +02:00
}
2018-02-27 11:25:32 +01:00
function restartExistingProcessId ( cb ) {
if ( isNaN ( script ) ) return cb ( null ) ;
that . _operate ( 'restartProcessId' , script , opts , function ( err , list ) {
2015-06-11 15:53:10 +02:00
if ( err ) return cb ( err ) ;
2016-06-08 19:21:37 +02:00
Common . printOut ( conf . PREFIX _MSG + 'Process successfully started' ) ;
2015-06-11 15:53:10 +02:00
return cb ( true , list ) ;
} ) ;
}
2015-06-09 19:43:10 +02:00
2018-02-27 11:25:32 +01:00
/**
* Restart a process with the same full path
* Or start it
*/
2018-09-20 13:36:51 +02:00
function restartExistingProcessPathOrStartNew ( cb ) {
2018-02-27 11:25:32 +01:00
that . Client . executeRemote ( 'getMonitorData' , { } , function ( err , procs ) {
if ( err ) return cb ? cb ( new Error ( err ) ) : that . exitCli ( conf . ERROR _EXIT ) ;
2015-12-07 12:10:18 +01:00
2018-02-27 11:25:32 +01:00
var full _path = path . resolve ( that . cwd , script ) ;
var managed _script = null ;
2016-07-03 14:18:03 +02:00
2018-02-27 11:25:32 +01:00
procs . forEach ( function ( proc ) {
if ( proc . pm2 _env . pm _exec _path == full _path &&
2018-09-25 00:07:45 +02:00
proc . pm2 _env . name == app _conf . name )
2018-02-27 11:25:32 +01:00
managed _script = proc ;
} ) ;
2016-07-03 14:18:03 +02:00
2018-02-27 11:25:32 +01:00
if ( managed _script &&
2016-07-03 14:18:03 +02:00
( managed _script . pm2 _env . status == conf . STOPPED _STATUS ||
2018-02-27 11:25:32 +01:00
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 ;
2015-06-09 19:43:10 +02:00
2018-02-27 11:25:32 +01:00
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 ) {
2019-04-26 13:48:16 +02:00
Common . err ( 'Script already launched, add -f option to force re-execution' ) ;
2018-02-27 11:25:32 +01:00
return cb ( new Error ( 'Script already launched' ) ) ;
}
2015-06-09 19:43:10 +02:00
2018-02-27 11:25:32 +01:00
var resolved _paths = null ;
2015-12-07 12:10:18 +01:00
2018-02-27 11:25:32 +01:00
try {
resolved _paths = Common . resolveAppAttributes ( {
cwd : that . cwd ,
pm2 _home : that . pm2 _home
} , app _conf ) ;
} catch ( e ) {
2019-04-26 13:48:16 +02:00
Common . err ( e . message ) ;
2018-02-27 11:25:32 +01:00
return cb ( Common . retErr ( e ) ) ;
}
2015-06-09 19:43:10 +02:00
2018-02-27 11:25:32 +01:00
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 ) ;
2015-06-09 19:43:10 +02:00
2018-02-27 11:25:32 +01:00
if ( ! resolved _paths . env ) resolved _paths . env = { } ;
2016-06-08 19:21:37 +02:00
2018-02-27 11:25:32 +01:00
// Set PM2 HOME in case of child process using PM2 API
resolved _paths . env [ 'PM2_HOME' ] = that . pm2 _home ;
2016-06-08 19:21:37 +02:00
2018-02-27 11:25:32 +01:00
var additional _env = Modularizer . getAdditionalConf ( resolved _paths . name ) ;
util . _extend ( resolved _paths . env , additional _env ) ;
2015-09-01 12:04:36 +02:00
2018-02-27 11:25:32 +01:00
// Is KM linked?
resolved _paths . km _link = that . gl _is _km _linked ;
2017-01-17 14:30:50 +01:00
2018-02-27 11:25:32 +01:00
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 ) ) ;
}
2015-06-09 19:43:10 +02:00
2018-02-27 11:25:32 +01:00
Common . printOut ( conf . PREFIX _MSG + 'Done.' ) ;
return cb ( true , data ) ;
} ) ;
return false ;
2013-10-15 13:11:05 +02:00
} ) ;
2018-02-27 11:25:32 +01:00
}
2017-04-06 23:52:50 +02:00
}
2015-03-01 21:42:21 -05:00
2018-02-27 11:25:32 +01:00
/**
* 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 = { } ;
2019-03-27 16:19:43 +01:00
var staticConf = [ ] ;
2018-02-27 11:25:32 +01:00
var deployConf = { } ;
var apps _info = [ ] ;
var that = this ;
2016-03-25 11:52:40 +01:00
2018-09-23 19:28:13 +02:00
/**
* Get File configuration
*/
2018-02-27 11:25:32 +01:00
if ( typeof ( cb ) === 'undefined' && typeof ( pipe ) === 'function' ) {
cb = pipe ;
}
if ( typeof ( file ) === 'object' ) {
config = file ;
} else if ( pipe === 'pipe' ) {
config = Common . parseConfig ( file , 'pipe' ) ;
2017-04-06 23:52:50 +02:00
} else {
2018-02-27 11:25:32 +01:00
var data = null ;
2017-04-06 23:52:50 +02:00
2018-02-27 12:28:43 +01:00
var isAbsolute = path . isAbsolute ( file )
2018-02-27 11:25:32 +01:00
var file _path = isAbsolute ? file : path . join ( that . cwd , file ) ;
2016-03-25 11:52:40 +01:00
2018-02-27 11:25:32 +01:00
debug ( 'Resolved filepath %s' , file _path ) ;
2015-06-10 12:52:48 +02:00
2018-02-27 11:25:32 +01:00
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 ) ;
}
2015-06-10 12:52:48 +02:00
2018-02-27 11:25:32 +01:00
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 ) ;
}
}
2017-01-29 16:47:47 +01:00
2018-09-23 19:28:13 +02:00
/**
* Alias some optional fields
*/
2018-02-27 11:25:32 +01:00
if ( config . deploy )
deployConf = config . deploy ;
2019-03-27 16:19:43 +01:00
if ( config . static )
staticConf = config . static ;
2018-02-27 11:25:32 +01:00
if ( config . apps )
appConf = config . apps ;
else if ( config . pm2 )
appConf = config . pm2 ;
else
appConf = config ;
if ( ! Array . isArray ( appConf ) )
2018-09-23 19:28:13 +02:00
appConf = [ appConf ] ;
2016-03-15 17:52:32 +01:00
2018-02-27 11:25:32 +01:00
if ( ( appConf = Common . verifyConfs ( appConf ) ) instanceof Error )
return cb ? cb ( appConf ) : that . exitCli ( conf . ERROR _EXIT ) ;
2015-06-10 12:52:48 +02:00
2018-02-27 11:25:32 +01:00
process . env . PM2 _JSON _PROCESSING = true ;
2015-06-10 12:52:48 +02:00
2018-02-27 11:25:32 +01:00
// Get App list
var apps _name = [ ] ;
var proc _list = { } ;
2019-03-27 16:19:43 +01:00
// Add statics to apps
staticConf . forEach ( function ( serve ) {
appConf . push ( {
name : serve . name ? serve . name : ` static-page-server- ${ serve . port } ` ,
script : path . resolve ( _ _dirname , 'API' , 'Serve.js' ) ,
env : {
PM2 _SERVE _PORT : serve . port ,
2019-04-29 08:44:28 +03:00
PM2 _SERVE _HOST : serve . host ,
2019-03-27 16:19:43 +01:00
PM2 _SERVE _PATH : serve . path ,
PM2 _SERVE _SPA : serve . spa ,
PM2 _SERVE _DIRECTORY : serve . directory ,
PM2 _SERVE _BASIC _AUTH : serve . basic _auth !== undefined ,
PM2 _SERVE _BASIC _AUTH _USERNAME : serve . basic _auth ? serve . basic _auth . username : null ,
PM2 _SERVE _BASIC _AUTH _PASSWORD : serve . basic _auth ? serve . basic _auth . password : null ,
2019-03-28 11:27:20 +01:00
PM2 _SERVE _MONITOR : serve . monitor
2019-03-27 16:19:43 +01:00
}
} ) ;
} ) ;
2018-02-27 11:25:32 +01:00
// Here we pick only the field we want from the CLI when starting a JSON
appConf . forEach ( function ( app ) {
2018-06-15 16:59:27 +02:00
if ( ! app . env ) { app . env = { } ; }
app . env . io = app . io ;
2018-02-27 11:25:32 +01:00
// --only <app>
2018-07-12 15:19:03 +02:00
if ( opts . only ) {
var apps = opts . only . split ( /,| / )
if ( apps . indexOf ( app . name ) == - 1 )
return false
}
2019-10-28 13:33:28 +05:30
// Namespace
2020-07-21 13:50:50 -04:00
if ( ! app . namespace ) {
if ( opts . namespace )
app . namespace = opts . namespace ;
else
app . namespace = 'default' ;
}
2018-02-27 11:25:32 +01:00
// --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 ;
2018-09-29 16:40:29 +02:00
if ( opts . install _url )
2019-10-28 13:33:28 +05:30
app . install _url = opts . install _url ;
2018-02-27 11:25:32 +01:00
// --instances <nb>
if ( opts . instances && typeof ( opts . instances ) === 'number' )
app . instances = opts . instances ;
// --uid <user>
if ( opts . uid )
app . uid = opts . uid ;
// --gid <user>
if ( opts . gid )
app . gid = opts . gid ;
// Specific
if ( app . append _env _to _name && opts . env )
app . name += ( '-' + opts . env ) ;
2018-09-25 00:07:45 +02:00
if ( opts . name _prefix && app . name . indexOf ( opts . name _prefix ) == - 1 )
app . name = ` ${ opts . name _prefix } : ${ app . name } `
2018-02-27 11:25:32 +01:00
app . username = Common . getCurrentUsername ( ) ;
apps _name . push ( app . name ) ;
2016-03-15 16:18:25 +01:00
} ) ;
2015-06-10 12:52:48 +02:00
2018-02-27 11:25:32 +01:00
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 ;
} ) ;
/**
* Auto detect application already started
* and act on them depending on action
*/
2018-07-19 09:44:06 -04:00
eachLimit ( Object . keys ( proc _list ) , conf . CONCURRENT _ACTIONS , function ( proc _name , next ) {
2018-02-27 11:25:32 +01:00
// Skip app name (--only option)
if ( apps _name . indexOf ( proc _name ) == - 1 )
return next ( ) ;
2015-06-10 12:52:48 +02:00
2018-02-27 11:25:32 +01:00
if ( ! ( action == 'reloadProcessId' ||
2016-03-15 17:52:32 +01:00
action == 'softReloadProcessId' ||
action == 'restartProcessId' ) )
2018-02-27 11:25:32 +01:00
throw new Error ( 'Wrong action called' ) ;
2015-06-10 12:52:48 +02:00
2018-02-27 11:25:32 +01:00
var apps = appConf . filter ( function ( app ) {
return app . name == proc _name ;
} ) ;
2015-06-10 12:52:48 +02:00
2018-02-27 11:25:32 +01:00
var envs = apps . map ( function ( app ) {
// Binds env_diff to env and returns it.
return Common . mergeEnvironmentVariables ( app , opts . env , deployConf ) ;
} ) ;
2016-10-26 18:07:03 +02:00
2018-02-27 11:25:32 +01:00
// 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 ) ;
} ) ;
2015-06-10 12:52:48 +02:00
2018-02-27 11:25:32 +01:00
// When we are processing JSON, allow to keep the new env by default
env . updateEnv = true ;
2016-10-26 18:07:03 +02:00
2018-02-27 11:25:32 +01:00
// Pass `env` option
that . _operate ( action , proc _name , env , function ( err , ret ) {
if ( err ) Common . printError ( err ) ;
2015-06-10 12:52:48 +02:00
2018-02-27 11:25:32 +01:00
// For return
apps _info = apps _info . concat ( ret ) ;
2016-03-15 18:42:49 +01:00
2018-02-27 11:25:32 +01:00
that . Client . notifyGod ( action , proc _name ) ;
// And Remove from array to spy
apps _name . splice ( apps _name . indexOf ( proc _name ) , 1 ) ;
return next ( ) ;
} ) ;
2016-03-15 17:52:32 +01:00
2018-02-27 11:25:32 +01:00
} , 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 ) ;
} ) ;
2015-06-10 12:52:48 +02:00
} ) ;
2018-02-27 11:25:32 +01:00
return false ;
2015-06-10 12:52:48 +02:00
} ) ;
2016-03-15 16:18:25 +01:00
2018-02-27 11:25:32 +01:00
function startApps ( app _name _to _start , cb ) {
var apps _to _start = [ ] ;
var apps _started = [ ] ;
2018-12-19 14:38:17 +01:00
var apps _errored = [ ] ;
2016-03-15 16:18:25 +01:00
2018-02-27 11:25:32 +01:00
appConf . forEach ( function ( app , i ) {
if ( app _name _to _start . indexOf ( app . name ) != - 1 ) {
apps _to _start . push ( appConf [ i ] ) ;
}
} ) ;
2018-07-19 09:44:06 -04:00
eachLimit ( apps _to _start , conf . CONCURRENT _ACTIONS , function ( app , next ) {
2018-02-27 11:25:32 +01:00
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 ;
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' )
}
try {
resolved _paths = Common . resolveAppAttributes ( {
cwd : that . cwd ,
pm2 _home : that . pm2 _home
} , app ) ;
} catch ( e ) {
2018-12-19 14:38:17 +01:00
apps _errored . push ( e )
2019-06-21 23:15:30 -07:00
Common . err ( ` Error: ${ e . message } ` )
2018-02-27 11:25:32 +01:00
return next ( ) ;
}
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 ;
2016-03-15 16:18:25 +01:00
2018-02-27 11:25:32 +01:00
var additional _env = Modularizer . getAdditionalConf ( resolved _paths . name ) ;
util . _extend ( resolved _paths . env , additional _env ) ;
2016-03-15 16:18:25 +01:00
2018-02-27 11:25:32 +01:00
resolved _paths . env = Common . mergeEnvironmentVariables ( resolved _paths , opts . env , deployConf ) ;
2016-03-15 16:18:25 +01:00
2018-02-27 11:25:32 +01:00
delete resolved _paths . env . current _conf ;
// Is KM linked?
resolved _paths . km _link = that . gl _is _km _linked ;
2018-12-19 15:59:52 +01:00
if ( resolved _paths . wait _ready ) {
Common . warn ( ` App ${ resolved _paths . name } has option 'wait_ready' set, waiting for app to be ready... ` )
}
2018-02-27 11:25:32 +01:00
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 ( ) ;
}
Common . printOut ( conf . PREFIX _MSG + 'App [%s] launched (%d instances)' , data [ 0 ] . pm2 _env . name , data . length ) ;
apps _started = apps _started . concat ( data ) ;
next ( ) ;
} ) ;
} , function ( err ) {
2018-12-19 14:38:17 +01:00
var final _error = err || apps _errored . length > 0 ? apps _errored : null
return cb ? cb ( final _error , apps _started ) : that . speedList ( ) ;
2018-02-27 11:25:32 +01:00
} ) ;
return false ;
}
}
/**
* 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 ;
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 ) ;
2017-01-29 01:22:43 +01:00
}
2016-03-15 16:18:25 +01:00
try {
2018-02-27 11:25:32 +01:00
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 ) ;
2016-03-15 16:18:25 +01:00
}
2018-02-27 11:25:32 +01:00
} 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 ) ;
}
2016-03-15 16:18:25 +01:00
2018-02-27 11:25:32 +01:00
// Backward compatibility
if ( appConf . apps )
appConf = appConf . apps ;
2016-06-08 19:21:37 +02:00
2018-02-27 11:25:32 +01:00
if ( ! Array . isArray ( appConf ) )
appConf = [ appConf ] ;
2016-06-08 19:21:37 +02:00
2018-02-27 11:25:32 +01:00
if ( ( appConf = Common . verifyConfs ( appConf ) ) instanceof Error )
return cb ? cb ( appConf ) : that . exitCli ( conf . ERROR _EXIT ) ;
2016-03-15 16:18:25 +01:00
2018-07-19 09:44:06 -04:00
eachLimit ( appConf , conf . CONCURRENT _ACTIONS , function ( proc , next1 ) {
2018-02-27 11:25:32 +01:00
var name = '' ;
var new _env ;
2016-10-26 18:07:03 +02:00
2018-02-27 11:25:32 +01:00
if ( ! proc . name )
name = path . basename ( proc . script ) ;
else
name = proc . name ;
2016-03-15 16:18:25 +01:00
2018-02-27 11:25:32 +01:00
if ( opts . only && opts . only != name )
return process . nextTick ( next1 ) ;
if ( opts && opts . env )
new _env = Common . mergeEnvironmentVariables ( proc , opts . env ) ;
else
new _env = Common . mergeEnvironmentVariables ( proc ) ;
2017-01-17 14:30:50 +01:00
2018-02-27 11:25:32 +01:00
that . Client . getProcessIdByName ( name , function ( err , ids ) {
2016-03-15 16:18:25 +01:00
if ( err ) {
2018-02-27 11:25:32 +01:00
Common . printError ( err ) ;
return next1 ( ) ;
2017-05-21 00:40:19 +02:00
}
2018-02-27 11:25:32 +01:00
if ( ! ids ) return next1 ( ) ;
2016-03-15 16:18:25 +01:00
2018-07-19 09:44:06 -04:00
eachLimit ( ids , conf . CONCURRENT _ACTIONS , function ( id , next2 ) {
2018-02-27 11:25:32 +01:00
var opts = { } ;
2016-03-15 16:18:25 +01:00
2018-02-27 11:25:32 +01:00
//stopProcessId could accept options to?
if ( action == 'restartProcessId' ) {
opts = { id : id , env : new _env } ;
} else {
opts = id ;
}
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 ) ;
} ) ;
} ) ;
2016-03-15 16:18:25 +01:00
} , function ( err ) {
2018-02-27 11:25:32 +01:00
if ( cb ) return cb ( null , ret _processes ) ;
else return that . speedList ( ) ;
2016-03-15 16:18:25 +01:00
} ) ;
}
2014-06-19 18:53:44 +02:00
2016-03-25 11:52:40 +01:00
2018-02-27 11:25:32 +01:00
/**
* 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
*/
_operate ( action _name , process _name , envs , cb ) {
var that = this ;
var update _env = false ;
var ret = [ ] ;
2016-03-25 11:52:40 +01:00
2018-02-27 11:25:32 +01:00
// Make sure all options exist
if ( ! envs )
envs = { } ;
if ( typeof ( envs ) == 'function' ) {
cb = envs ;
envs = { } ;
2016-03-25 11:52:40 +01:00
}
2014-01-29 13:43:18 +01:00
2018-02-27 11:25:32 +01:00
// Set via env.update (JSON processing)
if ( envs . updateEnv === true )
update _env = true ;
var concurrent _actions = envs . parallel || conf . CONCURRENT _ACTIONS ;
2016-03-25 11:52:40 +01:00
2018-02-27 11:25:32 +01:00
if ( ! process . env . PM2 _JSON _PROCESSING || envs . commands ) {
envs = that . _handleAttributeUpdate ( envs ) ;
}
2014-01-29 13:43:18 +01:00
2018-02-27 11:25:32 +01:00
/**
* Set current updated configuration if not passed
*/
if ( ! envs . current _conf ) {
var _conf = fclone ( envs ) ;
envs = {
current _conf : _conf
}
2014-11-24 14:44:20 +08:00
2018-02-27 11:25:32 +01:00
// Is KM linked?
envs . current _conf . km _link = that . gl _is _km _linked ;
}
2015-09-09 11:51:50 +02:00
2018-02-27 11:25:32 +01:00
/**
* 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 ) ;
2014-01-29 13:43:18 +01:00
2018-12-03 15:03:49 +01:00
if ( ids . length <= 2 )
concurrent _actions = 1 ;
2018-02-27 11:25:32 +01:00
if ( action _name == 'deleteProcessId' )
concurrent _actions = 10 ;
2016-03-02 19:36:06 +01:00
2018-07-19 09:44:06 -04:00
eachLimit ( ids , concurrent _actions , function ( id , next ) {
2018-02-27 11:25:32 +01:00
var opts ;
2016-03-02 19:36:06 +01:00
2018-02-27 11:25:32 +01:00
// These functions need extra param to be passed
if ( action _name == 'restartProcessId' ||
action _name == 'reloadProcessId' ||
action _name == 'softReloadProcessId' ) {
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 ) ;
2014-08-21 18:35:28 +02:00
2018-02-27 11:25:32 +01:00
Object . keys ( envs ) . forEach ( function ( k ) {
new _env [ k ] = envs [ k ] ;
} ) ;
}
else {
new _env = envs ;
}
2014-08-21 18:35:28 +02:00
2018-02-27 11:25:32 +01:00
opts = {
id : id ,
env : new _env
} ;
}
else {
2015-09-28 11:11:34 +02:00
opts = id ;
2015-10-30 23:27:55 +01:00
}
2018-02-27 11:25:32 +01:00
that . Client . executeRemote ( action _name , opts , function ( err , res ) {
2014-08-21 18:35:28 +02:00
if ( err ) {
2018-02-27 11:25:32 +01:00
Common . printError ( conf . PREFIX _MSG _ERR + 'Process %s not found' , id ) ;
2019-06-29 01:43:22 -07:00
return next ( ` Process ${ id } not found ` ) ;
2014-08-21 18:35:28 +02:00
}
2014-09-21 00:39:12 +02:00
2018-02-27 11:25:32 +01:00
if ( action _name == 'restartProcessId' ) {
2016-06-05 12:39:04 +02:00
that . Client . notifyGod ( 'restart' , id ) ;
2018-02-27 11:25:32 +01:00
} else if ( action _name == 'deleteProcessId' ) {
2016-06-05 12:39:04 +02:00
that . Client . notifyGod ( 'delete' , id ) ;
2018-02-27 11:25:32 +01:00
} else if ( action _name == 'stopProcessId' ) {
2016-06-05 12:39:04 +02:00
that . Client . notifyGod ( 'stop' , id ) ;
2018-02-27 11:25:32 +01:00
} else if ( action _name == 'reloadProcessId' ) {
that . Client . notifyGod ( 'reload' , id ) ;
} else if ( action _name == 'softReloadProcessId' ) {
that . Client . notifyGod ( 'graceful reload' , id ) ;
2014-09-21 00:39:12 +02:00
}
2018-02-27 11:25:32 +01:00
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 ) ;
2019-11-18 19:04:07 +01:00
if ( action _name == 'stopProcessId' && proc . pm2 _env && proc . pm2 _env . cron _restart ) {
2019-11-18 15:36:58 +01:00
Common . warn ( ` App ${ chalk . bold ( proc . pm2 _env . name ) } stopped but CRON RESTART is still UP ${ proc . pm2 _env . cron _restart } ` )
}
2018-02-27 11:25:32 +01:00
if ( ! proc . pm2 _env ) return false ;
ret . push ( {
name : proc . pm2 _env . name ,
2019-10-28 13:33:28 +05:30
namespace : proc . pm2 _env . namespace ,
2018-02-27 11:25:32 +01:00
pm _id : proc . pm2 _env . pm _id ,
status : proc . pm2 _env . status ,
restart _time : proc . pm2 _env . restart _time ,
pm2 _env : {
name : proc . pm2 _env . name ,
2019-10-28 13:33:28 +05:30
namespace : proc . pm2 _env . namespace ,
2018-02-27 11:25:32 +01:00
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 ( ) ;
2014-08-21 18:35:28 +02:00
} ) ;
} , function ( err ) {
2018-02-27 11:25:32 +01:00
if ( err ) return cb ? cb ( Common . retErr ( err ) ) : that . exitCli ( conf . ERROR _EXIT ) ;
return cb ? cb ( null , ret ) : that . speedList ( ) ;
2014-08-21 18:35:28 +02:00
} ) ;
2018-02-27 11:25:32 +01:00
}
2014-01-08 17:55:20 +01:00
2018-02-27 11:25:32 +01:00
if ( process _name == 'all' ) {
2018-09-24 22:55:18 +02:00
// When using shortcuts like 'all', do not delete modules
2018-09-25 00:07:45 +02:00
var fn
if ( process . env . PM2 _STATUS == 'stopping' )
that . Client . getAllProcessId ( function ( err , ids ) {
reoperate ( err , ids )
} ) ;
else
that . Client . getAllProcessIdWithoutModules ( function ( err , ids ) {
reoperate ( err , ids )
} ) ;
function reoperate ( err , ids ) {
2018-02-27 11:25:32 +01:00
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 ) ;
2018-09-25 00:07:45 +02:00
}
2018-02-27 11:25:32 +01:00
}
// 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 , '' ) ) ;
2016-10-26 18:07:03 +02:00
2018-02-27 11:25:32 +01:00
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 ) ;
}
} ) ;
2017-07-03 00:44:06 +02:00
2018-02-27 11:25:32 +01:00
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 ) ;
}
2017-01-12 01:18:38 +01:00
2018-02-27 11:25:32 +01:00
return processIds ( found _proc , cb ) ;
} ) ;
2017-01-12 01:34:56 +01:00
}
2018-02-27 11:25:32 +01:00
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 ;
2019-10-28 13:33:28 +05:30
that . Client . getProcessIdByName ( process _name , allow _module _restart , function ( err , ids ) {
2018-02-27 11:25:32 +01:00
if ( err ) {
Common . printError ( err ) ;
return cb ? cb ( Common . retErr ( err ) ) : that . exitCli ( conf . ERROR _EXIT ) ;
}
2019-10-28 13:33:28 +05:30
if ( ids && ids . length > 0 ) {
/**
2018-02-27 11:25:32 +01:00
* Determine if the process to restart is a module
* if yes load configuration variables and merge with the current environment
*/
2019-10-28 13:33:28 +05:30
var additional _env = Modularizer . getAdditionalConf ( process _name ) ;
util . _extend ( envs , additional _env ) ;
return processIds ( ids , cb ) ;
}
2017-01-17 15:25:43 +01:00
2019-10-28 13:33:28 +05:30
that . Client . getProcessIdsByNamespace ( process _name , allow _module _restart , function ( err , ns _process _ids ) {
if ( err ) {
Common . printError ( err ) ;
return cb ? cb ( Common . retErr ( err ) ) : that . exitCli ( conf . ERROR _EXIT ) ;
}
if ( ! ns _process _ids || ns _process _ids . length === 0 ) {
Common . printError ( conf . PREFIX _MSG _ERR + 'Process or Namespace %s not found' , process _name ) ;
return cb ? cb ( new Error ( 'process or namespace not found' ) ) : that . exitCli ( conf . ERROR _EXIT ) ;
}
/**
* Determine if the process to restart is a module
* if yes load configuration variables and merge with the current environment
*/
var ns _additional _env = Modularizer . getAdditionalConf ( process _name ) ;
util . _extend ( envs , ns _additional _env ) ;
return processIds ( ns _process _ids , cb ) ;
} ) ;
2019-10-30 14:41:45 +01:00
} ) ;
2018-02-27 11:25:32 +01:00
} else {
2019-05-29 00:36:34 +02:00
if ( that . pm2 _configuration . docker == "true" ||
that . pm2 _configuration . docker == true ) {
// Docker/Systemd process interaction detection
that . Client . executeRemote ( 'getMonitorData' , { } , ( err , proc _list ) => {
var higher _id = 0
proc _list . forEach ( p => { p . pm _id > higher _id ? higher _id = p . pm _id : null } )
// Is Docker/Systemd
if ( process _name > higher _id )
return DockerMgmt . processCommand ( that , higher _id , process _name , action _name , ( err ) => {
if ( err ) {
Common . printError ( conf . PREFIX _MSG _ERR + ( err . message ? err . message : err ) ) ;
return cb ? cb ( Common . retErr ( err ) ) : that . exitCli ( conf . ERROR _EXIT ) ;
}
2019-05-10 23:26:07 +02:00
2019-05-29 00:36:34 +02:00
return cb ? cb ( null , ret ) : that . speedList ( ) ;
} )
2019-05-06 18:59:37 +02:00
2019-05-29 00:36:34 +02:00
// 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 ) ;
2019-10-30 14:41:45 +01:00
2019-10-28 13:33:28 +05:30
// Check if application name as number is an namespace
that . Client . getProcessIdsByNamespace ( process _name , function ( err , ns _process _ids ) {
if ( ns _process _ids . length > 0 )
return processIds ( ns _process _ids , cb ) ;
// Else operate on pm id
return processIds ( [ process _name ] , cb ) ;
} ) ;
2019-05-29 00:36:34 +02:00
} ) ;
} )
}
else {
2019-05-06 18:59:37 +02:00
// 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 ) ;
2019-10-28 13:33:28 +05:30
// Check if application name as number is an namespace
that . Client . getProcessIdsByNamespace ( process _name , function ( err , ns _process _ids ) {
if ( ns _process _ids . length > 0 )
return processIds ( ns _process _ids , cb ) ;
// Else operate on pm id
return processIds ( [ process _name ] , cb ) ;
} ) ;
2019-05-06 18:59:37 +02:00
} ) ;
2019-05-29 00:36:34 +02:00
}
2018-02-27 11:25:32 +01:00
}
2016-10-26 18:07:03 +02:00
}
2015-09-01 12:04:36 +02:00
2015-02-07 22:37:38 -05:00
/**
2018-02-27 11:25:32 +01:00
* Converts CamelCase Commander.js arguments
* to Underscore
* (nodeArgs -> node_args)
2015-02-07 22:37:38 -05:00
*/
2018-02-27 11:25:32 +01:00
_handleAttributeUpdate ( opts ) {
2018-09-23 19:28:13 +02:00
var conf = Config . filterOptions ( opts ) ;
2018-02-27 11:25:32 +01:00
var that = this ;
2016-07-04 23:59:46 +02:00
2018-02-27 11:25:32 +01:00
if ( typeof ( conf . name ) != 'string' )
delete conf . name ;
2016-03-09 12:16:58 +01:00
2018-02-27 11:25:32 +01:00
var argsIndex = 0 ;
if ( opts . rawArgs && ( argsIndex = opts . rawArgs . indexOf ( '--' ) ) >= 0 ) {
conf . args = opts . rawArgs . slice ( argsIndex + 1 ) ;
}
2014-09-21 00:39:12 +02:00
2018-02-27 11:25:32 +01:00
var appConf = Common . verifyConfs ( conf ) [ 0 ] ;
2014-09-21 00:39:12 +02:00
2018-02-27 11:25:32 +01:00
if ( appConf instanceof Error ) {
Common . printError ( 'Error while transforming CamelCase args to underscore' ) ;
return appConf ;
}
2014-09-21 00:39:12 +02:00
2018-02-27 11:25:32 +01:00
if ( argsIndex == - 1 )
delete appConf . args ;
if ( appConf . name == 'undefined' )
delete appConf . name ;
2016-03-16 12:28:01 +01:00
2018-02-27 11:25:32 +01:00
delete appConf . exec _mode ;
2016-03-17 11:50:05 +01:00
2018-02-27 11:25:32 +01:00
if ( util . isArray ( appConf . watch ) && appConf . watch . length === 0 ) {
if ( ! ~ opts . rawArgs . indexOf ( '--watch' ) )
delete appConf . watch
}
2016-09-15 01:00:20 +02:00
2018-02-27 11:25:32 +01:00
// 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 ;
2016-03-16 12:28:01 +01:00
2018-02-27 11:25:32 +01:00
return appConf ;
2015-12-07 12:10:18 +01:00
}
2014-09-21 00:39:12 +02:00
2018-02-27 11:25:32 +01:00
getProcessIdByName ( name , cb ) {
var that = this ;
this . Client . getProcessIdByName ( name , function ( err , id ) {
2014-09-21 00:39:12 +02:00
if ( err ) {
2015-12-16 14:35:50 +01:00
Common . printError ( err ) ;
2016-06-08 19:21:37 +02:00
return cb ? cb ( Common . retErr ( err ) ) : that . exitCli ( conf . ERROR _EXIT ) ;
2014-09-21 00:39:12 +02:00
}
2018-02-27 11:25:32 +01:00
console . log ( id ) ;
return cb ? cb ( null , id ) : that . exitCli ( conf . SUCCESS _EXIT ) ;
2014-09-21 00:39:12 +02:00
} ) ;
}
2018-02-27 11:25:32 +01:00
/**
* Description
* @method jlist
* @param {} debug
* @return
*/
jlist ( debug ) {
var that = this ;
2017-02-23 22:03:55 +01:00
2017-02-03 15:53:51 +01:00
that . Client . executeRemote ( 'getMonitorData' , { } , function ( err , list ) {
if ( err ) {
2018-02-27 11:25:32 +01:00
Common . printError ( err ) ;
2019-05-06 18:59:37 +02:00
return that . exitCli ( conf . ERROR _EXIT ) ;
2017-02-03 15:53:51 +01:00
}
2018-02-27 11:25:32 +01:00
if ( debug ) {
process . stdout . write ( util . inspect ( list , false , null , false ) ) ;
2014-09-21 00:39:12 +02:00
}
2018-02-27 11:25:32 +01:00
else {
process . stdout . write ( JSON . stringify ( list ) ) ;
2014-09-21 00:39:12 +02:00
}
2018-02-27 11:25:32 +01:00
that . exitCli ( conf . SUCCESS _EXIT ) ;
2015-02-09 17:02:06 -05:00
2016-02-15 11:37:13 +01:00
} ) ;
2014-09-21 00:39:12 +02:00
}
2016-03-09 12:16:58 +01:00
2019-05-06 18:59:37 +02:00
/**
2019-10-22 13:11:03 +02:00
* Display system information
* @method slist
2019-05-06 18:59:37 +02:00
* @return
*/
2019-10-22 13:11:03 +02:00
slist ( tree ) {
2019-05-06 18:59:37 +02:00
this . Client . executeRemote ( 'getSystemData' , { } , ( err , sys _infos ) => {
if ( err ) {
2019-10-30 14:41:45 +01:00
Common . err ( err )
2019-05-06 18:59:37 +02:00
return this . exitCli ( conf . ERROR _EXIT )
}
2019-10-22 13:11:03 +02:00
if ( tree === true ) {
var treeify = require ( './tools/treeify.js' )
console . log ( treeify . asTree ( sys _infos , true ) )
}
else
process . stdout . write ( util . inspect ( sys _infos , false , null , false ) )
2019-05-06 18:59:37 +02:00
this . exitCli ( conf . SUCCESS _EXIT )
} )
}
2018-02-27 11:25:32 +01:00
/**
* Description
* @method speedList
* @return
*/
2020-06-30 10:47:15 +02:00
speedList ( code , apps _acted ) {
2018-02-27 11:25:32 +01:00
var that = this ;
2019-05-01 00:20:37 +02:00
var systemdata = null
2020-06-30 10:47:15 +02:00
var acted = [ ]
2020-08-17 10:48:38 +02:00
if ( ( code != 0 && code != null ) ) {
return that . exitCli ( code ? code : conf . SUCCESS _EXIT ) ;
}
2020-06-30 18:55:56 +02:00
if ( apps _acted && apps _acted . length > 0 ) {
apps _acted . forEach ( proc => {
acted . push ( proc . pm2 _env ? proc . pm2 _env . pm _id : proc . pm _id )
} )
}
2016-05-19 13:27:30 +00:00
2018-02-27 11:25:32 +01:00
// Do nothing if PM2 called programmatically and not called from CLI (also in exitCli)
2020-06-30 15:32:03 +02:00
if ( ( conf . PM2 _PROGRAMMATIC && process . env . PM2 _USAGE != 'CLI' ) )
2020-06-30 10:47:15 +02:00
return false ;
2016-03-09 12:16:58 +01:00
2019-05-01 00:20:37 +02:00
return that . Client . executeRemote ( 'getSystemData' , { } , ( err , sys _infos ) => {
that . Client . executeRemote ( 'getMonitorData' , { } , ( err , proc _list ) => {
doList ( err , proc _list , sys _infos )
} )
} )
2018-06-19 11:57:43 +02:00
2019-05-01 00:20:37 +02:00
function doList ( err , list , sys _infos ) {
2018-02-27 11:25:32 +01:00
if ( err ) {
2018-08-06 14:43:48 +02:00
if ( that . gl _retry == 0 ) {
that . gl _retry += 1 ;
2018-02-27 11:25:32 +01:00
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 ) {
2019-11-04 12:04:05 +01:00
UX . list _min ( list ) ;
2018-02-27 11:25:32 +01:00
}
else if ( commander . miniList && ! commander . silent )
2019-11-04 12:04:05 +01:00
UX . list _min ( list ) ;
2018-02-27 11:25:32 +01:00
else if ( ! commander . silent ) {
if ( that . gl _interact _infos ) {
2019-05-10 22:41:47 +02:00
var dashboard _url = ` https://app.pm2.io/#/r/ ${ that . gl _interact _infos . public _key } `
if ( that . gl _interact _infos . info _node != 'https://root.keymetrics.io' ) {
dashboard _url = ` ${ that . gl _interact _infos . info _node } /#/r/ ${ that . gl _interact _infos . public _key } `
}
2019-04-05 15:40:42 +02:00
Common . printOut ( '%s PM2+ activated | Instance Name: %s | Dash: %s' ,
2018-05-26 19:09:21 +02:00
chalk . green . bold ( '⇆' ) ,
2018-06-25 10:39:16 +02:00
chalk . bold ( that . gl _interact _infos . machine _name ) ,
2019-05-10 22:41:47 +02:00
chalk . bold ( dashboard _url ) )
2018-02-27 11:25:32 +01:00
}
2020-12-09 12:05:54 +01:00
UX . list ( list , sys _infos , commander ) ;
2019-05-07 18:29:23 +02:00
//Common.printOut(chalk.white.italic(' Use `pm2 show <id|name>` to get more details about an app'));
2018-02-27 11:25:32 +01:00
}
2016-03-09 12:16:58 +01:00
2018-02-27 11:25:32 +01:00
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 ) ;
}
2020-08-17 10:48:38 +02:00
// if (process.stdout.isTTY) if looking for start logs
else if ( ! process . env . TRAVIS && process . env . NODE _ENV != 'test' && acted . length > 0 && ( commander . attach === true ) ) {
2020-06-30 18:55:56 +02:00
Common . info ( ` Log streaming apps id: ${ chalk . cyan ( acted . join ( ' ' ) ) } , exit with Ctrl-C or will exit in 10secs ` )
2020-06-30 10:47:15 +02:00
2020-08-17 10:48:38 +02:00
// setTimeout(() => {
// Common.info(`Log streaming exited automatically, run 'pm2 logs' to continue watching logs`)
// return that.exitCli(code ? code : conf.SUCCESS_EXIT);
// }, 10000)
2020-06-30 10:47:15 +02:00
return acted . forEach ( ( proc _name ) => {
that . streamLogs ( proc _name , 0 , false , null , false ) ;
} )
2018-02-27 11:25:32 +01:00
}
else {
return that . exitCli ( code ? code : conf . SUCCESS _EXIT ) ;
}
2018-06-19 11:57:43 +02:00
}
2016-03-12 14:12:26 +01:00
}
2018-02-27 11:25:32 +01:00
/**
* Scale up/down a process
* @method scale
*/
scale ( app _name , number , cb ) {
var that = this ;
2016-06-05 12:39:04 +02:00
2018-02-27 11:25:32 +01:00
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 ) ;
2016-01-28 18:33:31 +01:00
}
2018-02-27 11:25:32 +01:00
function rmProcs ( procs , value , cb ) {
var i = 0 ;
2016-06-05 12:39:04 +02:00
2018-02-27 11:25:32 +01:00
( 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 ) ;
2013-09-28 17:33:46 +02:00
}
2015-06-15 16:45:52 +02:00
2018-02-27 11:25:32 +01:00
function end ( ) {
return cb ? cb ( null , { success : true } ) : that . speedList ( ) ;
2015-06-15 16:45:52 +02:00
}
2015-06-24 15:26:40 +02:00
2018-02-27 11:25:32 +01:00
this . Client . getProcessByName ( app _name , function ( err , procs ) {
if ( err ) {
Common . printError ( err ) ;
return cb ? cb ( Common . retErr ( err ) ) : that . exitCli ( conf . ERROR _EXIT ) ;
}
2016-06-04 14:04:26 +02:00
2018-02-27 11:25:32 +01:00
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 ) ;
}
2016-06-05 12:39:04 +02:00
2018-02-27 11:25:32 +01:00
var proc _number = procs . length ;
2016-07-13 00:56:44 +02:00
2018-02-27 11:25:32 +01:00
if ( typeof ( number ) === 'string' && number . indexOf ( '+' ) >= 0 ) {
number = parseInt ( number , 10 ) ;
return addProcs ( procs [ 0 ] , number , end ) ;
2016-06-04 14:04:26 +02:00
}
2018-02-27 11:25:32 +01:00
else if ( typeof ( number ) === 'string' && number . indexOf ( '-' ) >= 0 ) {
number = parseInt ( number , 10 ) ;
return rmProcs ( procs [ 0 ] , number , end ) ;
2016-06-04 14:04:26 +02:00
}
2018-02-27 11:25:32 +01:00
else {
number = parseInt ( number , 10 ) ;
number = number - proc _number ;
2015-04-21 23:37:46 -04:00
2018-02-27 11:25:32 +01:00
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 ) ;
}
}
} ) ;
2015-04-21 23:37:46 -04:00
}
2018-02-27 11:25:32 +01:00
/**
* Description
* @method describeProcess
* @param {} pm2_id
* @return
*/
describe ( pm2 _id , cb ) {
var that = this ;
2015-04-21 23:37:46 -04:00
2018-02-27 11:25:32 +01:00
var found _proc = [ ] ;
2015-04-21 23:37:46 -04:00
2018-02-27 11:25:32 +01:00
that . Client . executeRemote ( 'getMonitorData' , { } , function ( err , list ) {
if ( err ) {
Common . printError ( 'Error retrieving process list: ' + err ) ;
that . exitCli ( conf . ERROR _EXIT ) ;
2015-04-21 23:37:46 -04:00
}
2018-02-27 11:25:32 +01:00
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 ) ;
}
} ) ;
2014-06-19 18:53:44 +02:00
2018-02-27 11:25:32 +01:00
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 ) ;
}
2014-06-19 18:53:44 +02:00
2018-02-27 11:25:32 +01:00
if ( ! cb ) {
found _proc . forEach ( function ( proc ) {
2019-11-04 12:04:05 +01:00
UX . describe ( proc ) ;
2018-02-27 11:25:32 +01:00
} ) ;
2014-04-13 16:01:40 +08:00
}
2018-02-27 11:25:32 +01:00
return cb ? cb ( null , found _proc ) : that . exitCli ( conf . SUCCESS _EXIT ) ;
2014-04-13 16:01:40 +08:00
} ) ;
2018-02-27 11:25:32 +01:00
}
2014-04-13 16:01:40 +08:00
2018-02-27 11:25:32 +01:00
/**
* API method to perform a deep update of PM2
* @method deepUpdate
*/
deepUpdate ( cb ) {
var that = this ;
2014-06-19 18:53:44 +02:00
2018-02-27 11:25:32 +01:00
Common . printOut ( conf . PREFIX _MSG + 'Updating PM2...' ) ;
2014-06-19 18:53:44 +02:00
2020-04-23 17:33:35 +02:00
var child = sexec ( "npm i -g pm2@latest; pm2 update" ) ;
2018-02-27 11:25:32 +01:00
child . stdout . on ( 'end' , function ( ) {
Common . printOut ( conf . PREFIX _MSG + 'PM2 successfully updated' ) ;
cb ? cb ( null , { success : true } ) : that . exitCli ( conf . SUCCESS _EXIT ) ;
} ) ;
}
2016-03-22 13:29:04 +01:00
} ;
2014-04-13 16:01:40 +08:00
2015-07-29 14:29:43 +02:00
2018-02-27 11:25:32 +01:00
//////////////////////////
// Load all API methods //
//////////////////////////
require ( './API/Extra.js' ) ( API ) ;
require ( './API/Deploy.js' ) ( API ) ;
2018-09-24 22:55:18 +02:00
require ( './API/Modules/index.js' ) ( API ) ;
2018-07-13 18:29:33 +02:00
require ( './API/pm2-plus/link.js' ) ( API ) ;
require ( './API/pm2-plus/process-selector.js' ) ( API ) ;
require ( './API/pm2-plus/helpers.js' ) ( API ) ;
2018-02-27 11:25:32 +01:00
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 ) ;
2015-07-29 14:29:43 +02:00
2018-02-27 10:52:12 +01:00
module . exports = API ;