ActionMethods.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. /**
  2. * Copyright 2013-2022 the PM2 project authors. All rights reserved.
  3. * Use of this source code is governed by a license that
  4. * can be found in the LICENSE file.
  5. */
  6. 'use strict';
  7. /**
  8. * @file ActionMethod like restart, stop, monitor... are here
  9. * @author Alexandre Strzelewicz <as@unitech.io>
  10. * @project PM2
  11. */
  12. var fs = require('fs');
  13. var path = require('path');
  14. var eachLimit = require('async/eachLimit');
  15. var os = require('os');
  16. var p = path;
  17. var cst = require('../../constants.js');
  18. var pkg = require('../../package.json');
  19. var pidusage = require('pidusage');
  20. var util = require('util');
  21. var debug = require('debug')('pm2:ActionMethod');
  22. var Utility = require('../Utility');
  23. /**
  24. * Description
  25. * @method exports
  26. * @param {} God
  27. * @return
  28. */
  29. module.exports = function(God) {
  30. /**
  31. * Description
  32. * @method getMonitorData
  33. * @param {} env
  34. * @param {} cb
  35. * @return
  36. */
  37. God.getMonitorData = function getMonitorData(env, cb) {
  38. var processes = God.getFormatedProcesses();
  39. var pids = processes.filter(filterBadProcess)
  40. .map(function(pro, i) {
  41. var pid = getProcessId(pro)
  42. return pid;
  43. })
  44. // No pids, return empty statistics
  45. if (pids.length === 0) {
  46. return cb(null, processes.map(function(pro) {
  47. pro['monit'] = {
  48. memory : 0,
  49. cpu : 0
  50. };
  51. return pro
  52. }))
  53. }
  54. pidusage(pids, function retPidUsage(err, statistics) {
  55. // Just log, we'll set empty statistics
  56. if (err) {
  57. console.error('Error caught while calling pidusage');
  58. console.error(err);
  59. return cb(null, processes.map(function(pro) {
  60. pro['monit'] = {
  61. memory : 0,
  62. cpu : 0
  63. };
  64. return pro
  65. }))
  66. }
  67. if (!statistics) {
  68. console.error('Statistics is not defined!')
  69. return cb(null, processes.map(function(pro) {
  70. pro['monit'] = {
  71. memory : 0,
  72. cpu : 0
  73. };
  74. return pro
  75. }))
  76. }
  77. processes = processes.map(function(pro) {
  78. if (filterBadProcess(pro) === false) {
  79. pro['monit'] = {
  80. memory : 0,
  81. cpu : 0
  82. };
  83. return pro;
  84. }
  85. var pid = getProcessId(pro);
  86. var stat = statistics[pid];
  87. if (!stat) {
  88. pro['monit'] = {
  89. memory : 0,
  90. cpu : 0
  91. };
  92. return pro;
  93. }
  94. pro['monit'] = {
  95. memory: stat.memory,
  96. cpu: Math.round(stat.cpu * 10) / 10
  97. };
  98. return pro;
  99. });
  100. cb(null, processes);
  101. });
  102. };
  103. /**
  104. * Description
  105. * @method dumpProcessList
  106. * @param {} cb
  107. * @return
  108. */
  109. God.dumpProcessList = function(cb) {
  110. var process_list = [];
  111. var apps = Utility.clone(God.getFormatedProcesses());
  112. var that = this;
  113. // Don't override the actual dump file if process list is empty
  114. // unless user explicitely did `pm2 dump`.
  115. // This often happens when PM2 crashed, we don't want to override
  116. // the dump file with an empty list of process.
  117. if (!apps[0]) {
  118. debug('[PM2] Did not override dump file because list of processes is empty');
  119. return cb(null, {success:true, process_list: process_list});
  120. }
  121. function fin(err) {
  122. // try to fix issues with empty dump file
  123. // like #3485
  124. if (process_list.length === 0) {
  125. // fix : if no dump file, no process, only module and after pm2 update
  126. if (!fs.existsSync(cst.DUMP_FILE_PATH) && typeof that.clearDump === 'function') {
  127. that.clearDump(function(){});
  128. }
  129. // if no process in list don't modify dump file
  130. // process list should not be empty
  131. return cb(null, {success:true, process_list: process_list});
  132. }
  133. // Back up dump file
  134. try {
  135. if (fs.existsSync(cst.DUMP_FILE_PATH)) {
  136. fs.writeFileSync(cst.DUMP_BACKUP_FILE_PATH, fs.readFileSync(cst.DUMP_FILE_PATH));
  137. }
  138. } catch (e) {
  139. console.error(e.stack || e);
  140. }
  141. // Overwrite dump file, delete if broken
  142. try {
  143. fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify(process_list));
  144. } catch (e) {
  145. console.error(e.stack || e);
  146. try {
  147. // try to backup file
  148. if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
  149. fs.writeFileSync(cst.DUMP_FILE_PATH, fs.readFileSync(cst.DUMP_BACKUP_FILE_PATH));
  150. }
  151. } catch (e) {
  152. // don't keep broken file
  153. fs.unlinkSync(cst.DUMP_FILE_PATH);
  154. console.error(e.stack || e);
  155. }
  156. }
  157. return cb(null, {success:true, process_list: process_list});
  158. }
  159. function saveProc(apps) {
  160. if (!apps[0])
  161. return fin(null);
  162. delete apps[0].pm2_env.instances;
  163. delete apps[0].pm2_env.pm_id;
  164. // Do not dump modules
  165. if (!apps[0].pm2_env.pmx_module)
  166. process_list.push(apps[0].pm2_env);
  167. apps.shift();
  168. return saveProc(apps);
  169. }
  170. saveProc(apps);
  171. };
  172. /**
  173. * Description
  174. * @method ping
  175. * @param {} env
  176. * @param {} cb
  177. * @return CallExpression
  178. */
  179. God.ping = function(env, cb) {
  180. return cb(null, {msg : 'pong'});
  181. };
  182. /**
  183. * Description
  184. * @method notifyKillPM2
  185. */
  186. God.notifyKillPM2 = function() {
  187. God.pm2_being_killed = true;
  188. };
  189. /**
  190. * Duplicate a process
  191. * @method duplicateProcessId
  192. * @param {} id
  193. * @param {} cb
  194. * @return CallExpression
  195. */
  196. God.duplicateProcessId = function(id, cb) {
  197. if (!(id in God.clusters_db))
  198. return cb(God.logAndGenerateError(id + ' id unknown'), {});
  199. if (!God.clusters_db[id] || !God.clusters_db[id].pm2_env)
  200. return cb(God.logAndGenerateError('Error when getting proc || proc.pm2_env'), {});
  201. var proc = Utility.clone(God.clusters_db[id].pm2_env);
  202. delete proc.created_at;
  203. delete proc.pm_id;
  204. delete proc.unique_id;
  205. // generate a new unique id for new process
  206. proc.unique_id = Utility.generateUUID()
  207. God.injectVariables(proc, function inject (_err, proc) {
  208. return God.executeApp(Utility.clone(proc), function (err, clu) {
  209. if (err) return cb(err);
  210. God.notify('start', clu, true);
  211. return cb(err, Utility.clone(clu));
  212. });
  213. });
  214. };
  215. /**
  216. * Start a stopped process by ID
  217. * @method startProcessId
  218. * @param {} id
  219. * @param {} cb
  220. * @return CallExpression
  221. */
  222. God.startProcessId = function(id, cb) {
  223. if (!(id in God.clusters_db))
  224. return cb(God.logAndGenerateError(id + ' id unknown'), {});
  225. var proc = God.clusters_db[id];
  226. if (proc.pm2_env.status == cst.ONLINE_STATUS)
  227. return cb(God.logAndGenerateError('process already online'), {});
  228. if (proc.pm2_env.status == cst.LAUNCHING_STATUS)
  229. return cb(God.logAndGenerateError('process already started'), {});
  230. if (proc.process && proc.process.pid)
  231. return cb(God.logAndGenerateError('Process with pid ' + proc.process.pid + ' already exists'), {});
  232. return God.executeApp(God.clusters_db[id].pm2_env, function(err, proc) {
  233. return cb(err, Utility.clone(proc));
  234. });
  235. };
  236. /**
  237. * Stop a process and set it on state 'stopped'
  238. * @method stopProcessId
  239. * @param {} id
  240. * @param {} cb
  241. * @return Literal
  242. */
  243. God.stopProcessId = function(id, cb) {
  244. if (typeof id == 'object' && 'id' in id)
  245. id = id.id;
  246. if (!(id in God.clusters_db))
  247. return cb(God.logAndGenerateError(id + ' : id unknown'), {});
  248. var proc = God.clusters_db[id];
  249. //clear time-out restart task
  250. clearTimeout(proc.pm2_env.restart_task);
  251. if (proc.pm2_env.status == cst.STOPPED_STATUS) {
  252. proc.process.pid = 0;
  253. return cb(null, God.getFormatedProcess(id));
  254. }
  255. // state == 'none' means that the process is not online yet
  256. if (proc.state && proc.state === 'none')
  257. return setTimeout(function() { God.stopProcessId(id, cb); }, 250);
  258. console.log('Stopping app:%s id:%s', proc.pm2_env.name, proc.pm2_env.pm_id);
  259. proc.pm2_env.status = cst.STOPPING_STATUS;
  260. if (!proc.process.pid) {
  261. console.error('app=%s id=%d does not have a pid', proc.pm2_env.name, proc.pm2_env.pm_id);
  262. proc.pm2_env.status = cst.STOPPED_STATUS;
  263. return cb(null, { error : true, message : 'could not kill process w/o pid'});
  264. }
  265. God.killProcess(proc.process.pid, proc.pm2_env, function(err) {
  266. proc.pm2_env.status = cst.STOPPED_STATUS;
  267. God.notify('exit', proc);
  268. if (err && err.type && err.type === 'timeout') {
  269. console.error('app=%s id=%d pid=%s could not be stopped',
  270. proc.pm2_env.name,
  271. proc.pm2_env.pm_id,
  272. proc.process.pid);
  273. proc.pm2_env.status = cst.ERRORED_STATUS;
  274. return cb(null, God.getFormatedProcess(id));
  275. }
  276. if (proc.pm2_env.pm_id.toString().indexOf('_old_') !== 0) {
  277. try {
  278. fs.unlinkSync(proc.pm2_env.pm_pid_path);
  279. } catch (e) {}
  280. }
  281. if (proc.pm2_env.axm_actions) proc.pm2_env.axm_actions = [];
  282. if (proc.pm2_env.axm_monitor) proc.pm2_env.axm_monitor = {};
  283. proc.process.pid = 0;
  284. return cb(null, God.getFormatedProcess(id));
  285. });
  286. };
  287. God.resetMetaProcessId = function(id, cb) {
  288. if (!(id in God.clusters_db))
  289. return cb(God.logAndGenerateError(id + ' id unknown'), {});
  290. if (!God.clusters_db[id] || !God.clusters_db[id].pm2_env)
  291. return cb(God.logAndGenerateError('Error when getting proc || proc.pm2_env'), {});
  292. God.clusters_db[id].pm2_env.created_at = Utility.getDate();
  293. God.clusters_db[id].pm2_env.unstable_restarts = 0;
  294. God.clusters_db[id].pm2_env.restart_time = 0;
  295. return cb(null, God.getFormatedProcesses());
  296. };
  297. /**
  298. * Delete a process by id
  299. * It will stop it and remove it from the database
  300. * @method deleteProcessId
  301. * @param {} id
  302. * @param {} cb
  303. * @return Literal
  304. */
  305. God.deleteProcessId = function(id, cb) {
  306. God.deleteCron(id);
  307. God.stopProcessId(id, function(err, proc) {
  308. if (err) return cb(God.logAndGenerateError(err), {});
  309. // ! transform to slow object
  310. delete God.clusters_db[id];
  311. if (Object.keys(God.clusters_db).length == 0)
  312. God.next_id = 0;
  313. return cb(null, proc);
  314. });
  315. return false;
  316. };
  317. /**
  318. * Restart a process ID
  319. * If the process is online it will not put it on state stopped
  320. * but directly kill it and let God restart it
  321. * @method restartProcessId
  322. * @param {} id
  323. * @param {} cb
  324. * @return Literal
  325. */
  326. God.restartProcessId = function(opts, cb) {
  327. var id = opts.id;
  328. var env = opts.env || {};
  329. if (typeof(id) === 'undefined')
  330. return cb(God.logAndGenerateError('opts.id not passed to restartProcessId', opts));
  331. if (!(id in God.clusters_db))
  332. return cb(God.logAndGenerateError('God db process id unknown'), {});
  333. var proc = God.clusters_db[id];
  334. God.resetState(proc.pm2_env);
  335. God.deleteCron(id);
  336. /**
  337. * Merge new application configuration on restart
  338. * Same system in reloadProcessId and softReloadProcessId
  339. */
  340. Utility.extend(proc.pm2_env.env, env);
  341. Utility.extendExtraConfig(proc, opts);
  342. if (God.pm2_being_killed) {
  343. return cb(God.logAndGenerateError('[RestartProcessId] PM2 is being killed, stopping restart procedure...'));
  344. }
  345. if (proc.pm2_env.status === cst.ONLINE_STATUS || proc.pm2_env.status === cst.LAUNCHING_STATUS) {
  346. God.stopProcessId(id, function(err) {
  347. if (God.pm2_being_killed)
  348. return cb(God.logAndGenerateError('[RestartProcessId] PM2 is being killed, stopping restart procedure...'));
  349. proc.pm2_env.restart_time += 1;
  350. return God.startProcessId(id, cb);
  351. });
  352. return false;
  353. }
  354. else {
  355. debug('[restart] process not online, starting it');
  356. return God.startProcessId(id, cb);
  357. }
  358. };
  359. /**
  360. * Restart all process by name
  361. * @method restartProcessName
  362. * @param {} name
  363. * @param {} cb
  364. * @return Literal
  365. */
  366. God.restartProcessName = function(name, cb) {
  367. var processes = God.findByName(name);
  368. if (processes && processes.length === 0)
  369. return cb(God.logAndGenerateError('Unknown process'), {});
  370. eachLimit(processes, cst.CONCURRENT_ACTIONS, function(proc, next) {
  371. if (God.pm2_being_killed)
  372. return next('[Watch] PM2 is being killed, stopping restart procedure...');
  373. if (proc.pm2_env.status === cst.ONLINE_STATUS)
  374. return God.restartProcessId({id:proc.pm2_env.pm_id}, next);
  375. else if (proc.pm2_env.status !== cst.STOPPING_STATUS
  376. && proc.pm2_env.status !== cst.LAUNCHING_STATUS)
  377. return God.startProcessId(proc.pm2_env.pm_id, next);
  378. else
  379. return next(util.format('[Watch] Process name %s is being stopped so I won\'t restart it', name));
  380. }, function(err) {
  381. if (err) return cb(God.logAndGenerateError(err));
  382. return cb(null, God.getFormatedProcesses());
  383. });
  384. return false;
  385. };
  386. /**
  387. * Send system signal to process id
  388. * @method sendSignalToProcessId
  389. * @param {} opts
  390. * @param {} cb
  391. * @return CallExpression
  392. */
  393. God.sendSignalToProcessId = function(opts, cb) {
  394. var id = opts.process_id;
  395. var signal = opts.signal;
  396. if (!(id in God.clusters_db))
  397. return cb(God.logAndGenerateError(id + ' id unknown'), {});
  398. var proc = God.clusters_db[id];
  399. //God.notify('send signal ' + signal, proc, true);
  400. try {
  401. process.kill(God.clusters_db[id].process.pid, signal);
  402. } catch(e) {
  403. return cb(God.logAndGenerateError('Error when sending signal (signal unknown)'), {});
  404. }
  405. return cb(null, God.getFormatedProcesses());
  406. };
  407. /**
  408. * Send system signal to all processes by name
  409. * @method sendSignalToProcessName
  410. * @param {} opts
  411. * @param {} cb
  412. * @return
  413. */
  414. God.sendSignalToProcessName = function(opts, cb) {
  415. var processes = God.findByName(opts.process_name);
  416. var signal = opts.signal;
  417. if (processes && processes.length === 0)
  418. return cb(God.logAndGenerateError('Unknown process name'), {});
  419. eachLimit(processes, cst.CONCURRENT_ACTIONS, function(proc, next) {
  420. if (proc.pm2_env.status == cst.ONLINE_STATUS || proc.pm2_env.status == cst.LAUNCHING_STATUS) {
  421. try {
  422. process.kill(proc.process.pid, signal);
  423. } catch(e) {
  424. return next(e);
  425. }
  426. }
  427. return setTimeout(next, 200);
  428. }, function(err) {
  429. if (err) return cb(God.logAndGenerateError(err), {});
  430. return cb(null, God.getFormatedProcesses());
  431. });
  432. };
  433. /**
  434. * Stop watching daemon
  435. * @method stopWatch
  436. * @param {} method
  437. * @param {} value
  438. * @param {} fn
  439. * @return
  440. */
  441. God.stopWatch = function(method, value, fn) {
  442. var env = null;
  443. if (method == 'stopAll' || method == 'deleteAll') {
  444. var processes = God.getFormatedProcesses();
  445. processes.forEach(function(proc) {
  446. God.clusters_db[proc.pm_id].pm2_env.watch = false;
  447. God.watch.disable(proc.pm2_env);
  448. });
  449. } else {
  450. if (method.indexOf('ProcessId') !== -1) {
  451. env = God.clusters_db[value];
  452. } else if (method.indexOf('ProcessName') !== -1) {
  453. env = God.clusters_db[God.findByName(value)];
  454. }
  455. if (env) {
  456. God.watch.disable(env.pm2_env);
  457. env.pm2_env.watch = false;
  458. }
  459. }
  460. return fn(null, {success:true});
  461. };
  462. /**
  463. * Toggle watching daemon
  464. * @method toggleWatch
  465. * @param {String} method
  466. * @param {Object} application environment, should include id
  467. * @param {Function} callback
  468. */
  469. God.toggleWatch = function(method, value, fn) {
  470. var env = null;
  471. if (method == 'restartProcessId') {
  472. env = God.clusters_db[value.id];
  473. } else if(method == 'restartProcessName') {
  474. env = God.clusters_db[God.findByName(value)];
  475. }
  476. if (env) {
  477. env.pm2_env.watch = !env.pm2_env.watch;
  478. if (env.pm2_env.watch)
  479. God.watch.enable(env.pm2_env);
  480. else
  481. God.watch.disable(env.pm2_env);
  482. }
  483. return fn(null, {success:true});
  484. };
  485. /**
  486. * Start Watch
  487. * @method startWatch
  488. * @param {String} method
  489. * @param {Object} application environment, should include id
  490. * @param {Function} callback
  491. */
  492. God.startWatch = function(method, value, fn) {
  493. var env = null;
  494. if (method == 'restartProcessId') {
  495. env = God.clusters_db[value.id];
  496. } else if(method == 'restartProcessName') {
  497. env = God.clusters_db[God.findByName(value)];
  498. }
  499. if (env) {
  500. if (env.pm2_env.watch)
  501. return fn(null, {success:true, notrestarted:true});
  502. God.watch.enable(env.pm2_env);
  503. //env.pm2_env.env.watch = true;
  504. env.pm2_env.watch = true;
  505. }
  506. return fn(null, {success:true});
  507. };
  508. /**
  509. * Description
  510. * @method reloadLogs
  511. * @param {} opts
  512. * @param {} cb
  513. * @return CallExpression
  514. */
  515. God.reloadLogs = function(opts, cb) {
  516. console.log('Reloading logs...');
  517. var processIds = Object.keys(God.clusters_db);
  518. processIds.forEach(function (id) {
  519. var cluster = God.clusters_db[id];
  520. console.log('Reloading logs for process id %d', id);
  521. if (cluster && cluster.pm2_env) {
  522. // Cluster mode
  523. if (cluster.send && cluster.pm2_env.exec_mode == 'cluster_mode') {
  524. try {
  525. cluster.send({
  526. type:'log:reload'
  527. });
  528. } catch(e) {
  529. console.error(e.message || e);
  530. }
  531. }
  532. // Fork mode
  533. else if (cluster._reloadLogs) {
  534. cluster._reloadLogs(function(err) {
  535. if (err) God.logAndGenerateError(err);
  536. });
  537. }
  538. }
  539. });
  540. return cb(null, {});
  541. };
  542. /**
  543. * Send Line To Stdin
  544. * @method sendLineToStdin
  545. * @param Object packet
  546. * @param String pm_id Process ID
  547. * @param String line Line to send to process stdin
  548. */
  549. God.sendLineToStdin = function(packet, cb) {
  550. if (typeof(packet.pm_id) == 'undefined' || !packet.line)
  551. return cb(God.logAndGenerateError('pm_id or line field missing'), {});
  552. var pm_id = packet.pm_id;
  553. var line = packet.line;
  554. var proc = God.clusters_db[pm_id];
  555. if (!proc)
  556. return cb(God.logAndGenerateError('Process with ID <' + pm_id + '> unknown.'), {});
  557. if (proc.pm2_env.exec_mode == 'cluster_mode')
  558. return cb(God.logAndGenerateError('Cannot send line to processes in cluster mode'), {});
  559. if (proc.pm2_env.status != cst.ONLINE_STATUS && proc.pm2_env.status != cst.LAUNCHING_STATUS)
  560. return cb(God.logAndGenerateError('Process with ID <' + pm_id + '> offline.'), {});
  561. try {
  562. proc.stdin.write(line, function() {
  563. return cb(null, {
  564. pm_id : pm_id,
  565. line : line
  566. });
  567. });
  568. } catch(e) {
  569. return cb(God.logAndGenerateError(e), {});
  570. }
  571. }
  572. /**
  573. * @param {object} packet
  574. * @param {function} cb
  575. */
  576. God.sendDataToProcessId = function(packet, cb) {
  577. if (typeof(packet.id) == 'undefined' ||
  578. typeof(packet.data) == 'undefined' ||
  579. !packet.topic)
  580. return cb(God.logAndGenerateError('ID, DATA or TOPIC field is missing'), {});
  581. var pm_id = packet.id;
  582. var data = packet.data;
  583. var proc = God.clusters_db[pm_id];
  584. if (!proc)
  585. return cb(God.logAndGenerateError('Process with ID <' + pm_id + '> unknown.'), {});
  586. if (proc.pm2_env.status != cst.ONLINE_STATUS && proc.pm2_env.status != cst.LAUNCHING_STATUS)
  587. return cb(God.logAndGenerateError('Process with ID <' + pm_id + '> offline.'), {});
  588. try {
  589. proc.send(packet);
  590. }
  591. catch(e) {
  592. return cb(God.logAndGenerateError(e), {});
  593. }
  594. return cb(null, {
  595. success: true,
  596. data : packet
  597. });
  598. };
  599. /**
  600. * Send Message to Process by id or name
  601. * @method msgProcess
  602. * @param {} cmd
  603. * @param {} cb
  604. * @return Literal
  605. */
  606. God.msgProcess = function(cmd, cb) {
  607. if ('id' in cmd) {
  608. var id = cmd.id;
  609. if (!(id in God.clusters_db))
  610. return cb(God.logAndGenerateError(id + ' id unknown'), {});
  611. var proc = God.clusters_db[id];
  612. var action_exist = false;
  613. proc.pm2_env.axm_actions.forEach(function(action) {
  614. if (action.action_name == cmd.msg) {
  615. action_exist = true;
  616. // Reset output buffer
  617. action.output = [];
  618. }
  619. });
  620. if (action_exist == false) {
  621. return cb(God.logAndGenerateError('Action doesn\'t exist ' + cmd.msg + ' for ' + proc.pm2_env.name), {});
  622. }
  623. if (proc.pm2_env.status == cst.ONLINE_STATUS || proc.pm2_env.status == cst.LAUNCHING_STATUS) {
  624. /*
  625. * Send message
  626. */
  627. if (cmd.opts == null && !cmd.uuid)
  628. proc.send(cmd.msg);
  629. else
  630. proc.send(cmd);
  631. return cb(null, { process_count : 1, success : true });
  632. }
  633. else
  634. return cb(God.logAndGenerateError(id + ' : id offline'), {});
  635. }
  636. else if ('name' in cmd) {
  637. /*
  638. * As names are not unique in case of cluster, this
  639. * will send msg to all process matching 'name'
  640. */
  641. var name = cmd.name;
  642. var arr = Object.keys(God.clusters_db);
  643. var sent = 0;
  644. (function ex(arr) {
  645. if (arr[0] == null || !arr) {
  646. return cb(null, {
  647. process_count : sent,
  648. success : true
  649. });
  650. }
  651. var id = arr[0];
  652. if (!God.clusters_db[id] || !God.clusters_db[id].pm2_env) {
  653. arr.shift();
  654. return ex(arr);
  655. }
  656. var proc_env = God.clusters_db[id].pm2_env;
  657. const isActionAvailable = proc_env.axm_actions.find(action => action.action_name === cmd.msg) !== undefined
  658. // if action doesn't exist for this app
  659. // try with the next one
  660. if (isActionAvailable === false) {
  661. arr.shift();
  662. return ex(arr);
  663. }
  664. if ((p.basename(proc_env.pm_exec_path) == name ||
  665. proc_env.name == name ||
  666. proc_env.namespace == name ||
  667. name == 'all') &&
  668. (proc_env.status == cst.ONLINE_STATUS ||
  669. proc_env.status == cst.LAUNCHING_STATUS)) {
  670. proc_env.axm_actions.forEach(function(action) {
  671. if (action.action_name == cmd.msg) {
  672. action_exist = true;
  673. }
  674. });
  675. if (action_exist == false || proc_env.axm_actions.length == 0) {
  676. arr.shift();
  677. return ex(arr);
  678. }
  679. if (cmd.opts == null)
  680. God.clusters_db[id].send(cmd.msg);
  681. else
  682. God.clusters_db[id].send(cmd);
  683. sent++;
  684. arr.shift();
  685. return ex(arr);
  686. }
  687. else {
  688. arr.shift();
  689. return ex(arr);
  690. }
  691. return false;
  692. })(arr);
  693. }
  694. else return cb(God.logAndGenerateError('method requires name or id field'), {});
  695. return false;
  696. };
  697. /**
  698. * Description
  699. * @method getVersion
  700. * @param {} env
  701. * @param {} cb
  702. * @return CallExpression
  703. */
  704. God.getVersion = function(env, cb) {
  705. process.nextTick(function() {
  706. return cb(null, pkg.version);
  707. });
  708. };
  709. God.monitor = function Monitor(pm_id, cb) {
  710. if (!God.clusters_db[pm_id] || !God.clusters_db[pm_id].pm2_env)
  711. return cb(new Error('Unknown pm_id'));
  712. God.clusters_db[pm_id].pm2_env._km_monitored = true;
  713. return cb(null, { success : true, pm_id : pm_id });
  714. }
  715. God.unmonitor = function Monitor(pm_id, cb) {
  716. if (!God.clusters_db[pm_id] || !God.clusters_db[pm_id].pm2_env)
  717. return cb(new Error('Unknown pm_id'));
  718. God.clusters_db[pm_id].pm2_env._km_monitored = false;
  719. return cb(null, { success : true, pm_id : pm_id });
  720. }
  721. God.getReport = function(arg, cb) {
  722. var report = {
  723. pm2_version : pkg.version,
  724. node_version : 'N/A',
  725. node_path : process.env['_'] || 'not found',
  726. argv0 : process.argv0,
  727. argv : process.argv,
  728. user : process.env.USER,
  729. uid : (cst.IS_WINDOWS === false && process.geteuid) ? process.geteuid() : 'N/A',
  730. gid : (cst.IS_WINDOWS === false && process.getegid) ? process.getegid() : 'N/A',
  731. env : process.env,
  732. managed_apps : Object.keys(God.clusters_db).length,
  733. started_at : God.started_at
  734. };
  735. if (process.versions && process.versions.node) {
  736. report.node_version = process.versions.node;
  737. }
  738. process.nextTick(function() {
  739. return cb(null, report);
  740. });
  741. };
  742. };
  743. function filterBadProcess(pro) {
  744. if (pro.pm2_env.status !== cst.ONLINE_STATUS) {
  745. return false;
  746. }
  747. if (pro.pm2_env.axm_options && pro.pm2_env.axm_options.pid) {
  748. if (isNaN(pro.pm2_env.axm_options.pid)) {
  749. return false;
  750. }
  751. }
  752. return true;
  753. }
  754. function getProcessId(pro) {
  755. var pid = pro.pid
  756. if (pro.pm2_env.axm_options && pro.pm2_env.axm_options.pid) {
  757. pid = pro.pm2_env.axm_options.pid;
  758. }
  759. return pid
  760. }