UNPKG

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