@zappinginc/zm2 6.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/.gitattributes +4 -0
  3. package/.mocharc.js +14 -0
  4. package/CHANGELOG.md +2416 -0
  5. package/CLAUDE.md +84 -0
  6. package/CONTRIBUTING.md +124 -0
  7. package/GNU-AGPL-3.0.txt +665 -0
  8. package/LICENSE +1 -0
  9. package/README.md +248 -0
  10. package/bin/zm2 +3 -0
  11. package/bin/zm2-dev +3 -0
  12. package/bin/zm2-docker +3 -0
  13. package/bin/zm2-runtime +3 -0
  14. package/bin/zm2-windows +3 -0
  15. package/bin/zm2.ps1 +3 -0
  16. package/bun.lock +421 -0
  17. package/constants.js +114 -0
  18. package/index.js +13 -0
  19. package/lib/API/Configuration.js +212 -0
  20. package/lib/API/Containerizer.js +335 -0
  21. package/lib/API/Dashboard.js +459 -0
  22. package/lib/API/Deploy.js +117 -0
  23. package/lib/API/Extra.js +775 -0
  24. package/lib/API/ExtraMgmt/Docker.js +30 -0
  25. package/lib/API/Log.js +315 -0
  26. package/lib/API/LogManagement.js +371 -0
  27. package/lib/API/Modules/LOCAL.js +122 -0
  28. package/lib/API/Modules/Modularizer.js +148 -0
  29. package/lib/API/Modules/NPM.js +445 -0
  30. package/lib/API/Modules/TAR.js +362 -0
  31. package/lib/API/Modules/flagExt.js +46 -0
  32. package/lib/API/Modules/index.js +120 -0
  33. package/lib/API/Monit.js +247 -0
  34. package/lib/API/Serve.js +343 -0
  35. package/lib/API/Startup.js +629 -0
  36. package/lib/API/UX/helpers.js +213 -0
  37. package/lib/API/UX/index.js +9 -0
  38. package/lib/API/UX/pm2-describe.js +193 -0
  39. package/lib/API/UX/pm2-ls-minimal.js +31 -0
  40. package/lib/API/UX/pm2-ls.js +483 -0
  41. package/lib/API/Version.js +382 -0
  42. package/lib/API/interpreter.json +12 -0
  43. package/lib/API/pm2-plus/PM2IO.js +372 -0
  44. package/lib/API/pm2-plus/auth-strategies/CliAuth.js +288 -0
  45. package/lib/API/pm2-plus/auth-strategies/WebAuth.js +187 -0
  46. package/lib/API/pm2-plus/helpers.js +97 -0
  47. package/lib/API/pm2-plus/link.js +126 -0
  48. package/lib/API/pm2-plus/pres/motd +16 -0
  49. package/lib/API/pm2-plus/pres/motd.update +26 -0
  50. package/lib/API/pm2-plus/pres/welcome +28 -0
  51. package/lib/API/pm2-plus/process-selector.js +52 -0
  52. package/lib/API/schema.json +379 -0
  53. package/lib/API.js +1931 -0
  54. package/lib/Client.js +776 -0
  55. package/lib/Common.js +911 -0
  56. package/lib/Configuration.js +304 -0
  57. package/lib/Daemon.js +456 -0
  58. package/lib/Event.js +37 -0
  59. package/lib/God/ActionMethods.js +909 -0
  60. package/lib/God/ClusterMode.js +97 -0
  61. package/lib/God/ForkMode.js +297 -0
  62. package/lib/God/Methods.js +265 -0
  63. package/lib/God/Reload.js +240 -0
  64. package/lib/God.js +632 -0
  65. package/lib/HttpInterface.js +76 -0
  66. package/lib/ProcessContainer.js +305 -0
  67. package/lib/ProcessContainerBun.js +360 -0
  68. package/lib/ProcessContainerFork.js +42 -0
  69. package/lib/ProcessContainerForkBun.js +33 -0
  70. package/lib/ProcessUtils.js +55 -0
  71. package/lib/TreeKill.js +118 -0
  72. package/lib/Utility.js +430 -0
  73. package/lib/VersionCheck.js +46 -0
  74. package/lib/Watcher.js +117 -0
  75. package/lib/Worker.js +169 -0
  76. package/lib/binaries/CLI.js +1041 -0
  77. package/lib/binaries/DevCLI.js +183 -0
  78. package/lib/binaries/Runtime.js +101 -0
  79. package/lib/binaries/Runtime4Docker.js +192 -0
  80. package/lib/completion.js +229 -0
  81. package/lib/completion.sh +40 -0
  82. package/lib/motd +36 -0
  83. package/lib/templates/Dockerfiles/Dockerfile-java.tpl +7 -0
  84. package/lib/templates/Dockerfiles/Dockerfile-nodejs.tpl +8 -0
  85. package/lib/templates/Dockerfiles/Dockerfile-ruby.tpl +7 -0
  86. package/lib/templates/ecosystem-es.tpl +24 -0
  87. package/lib/templates/ecosystem-simple-es.tpl +8 -0
  88. package/lib/templates/ecosystem-simple.tpl +6 -0
  89. package/lib/templates/ecosystem.tpl +22 -0
  90. package/lib/templates/init-scripts/launchd.tpl +35 -0
  91. package/lib/templates/init-scripts/openrc.tpl +52 -0
  92. package/lib/templates/init-scripts/pm2-init-amazon.sh +86 -0
  93. package/lib/templates/init-scripts/rcd-openbsd.tpl +41 -0
  94. package/lib/templates/init-scripts/rcd.tpl +44 -0
  95. package/lib/templates/init-scripts/smf.tpl +43 -0
  96. package/lib/templates/init-scripts/systemd-online.tpl +22 -0
  97. package/lib/templates/init-scripts/systemd.tpl +22 -0
  98. package/lib/templates/init-scripts/upstart.tpl +103 -0
  99. package/lib/templates/logrotate.d/pm2 +10 -0
  100. package/lib/templates/sample-apps/http-server/README.md +14 -0
  101. package/lib/templates/sample-apps/http-server/api.js +9 -0
  102. package/lib/templates/sample-apps/http-server/ecosystem.config.js +14 -0
  103. package/lib/templates/sample-apps/http-server/package.json +11 -0
  104. package/lib/templates/sample-apps/pm2-plus-metrics-actions/README.md +45 -0
  105. package/lib/templates/sample-apps/pm2-plus-metrics-actions/custom-metrics.js +66 -0
  106. package/lib/templates/sample-apps/pm2-plus-metrics-actions/ecosystem.config.js +12 -0
  107. package/lib/templates/sample-apps/pm2-plus-metrics-actions/package.json +11 -0
  108. package/lib/templates/sample-apps/python-app/README.md +4 -0
  109. package/lib/templates/sample-apps/python-app/echo.py +7 -0
  110. package/lib/templates/sample-apps/python-app/ecosystem.config.js +12 -0
  111. package/lib/templates/sample-apps/python-app/package.json +11 -0
  112. package/lib/tools/Config.js +248 -0
  113. package/lib/tools/IsAbsolute.js +20 -0
  114. package/lib/tools/copydirSync.js +101 -0
  115. package/lib/tools/deleteFolderRecursive.js +19 -0
  116. package/lib/tools/find-package-json.js +74 -0
  117. package/lib/tools/fmt.js +72 -0
  118. package/lib/tools/isbinaryfile.js +94 -0
  119. package/lib/tools/json5.js +752 -0
  120. package/lib/tools/open.js +63 -0
  121. package/lib/tools/passwd.js +58 -0
  122. package/lib/tools/promise.min.js +1 -0
  123. package/lib/tools/sexec.js +55 -0
  124. package/lib/tools/treeify.js +113 -0
  125. package/lib/tools/which.js +120 -0
  126. package/lib/tools/xdg-open +861 -0
  127. package/package.json +219 -0
  128. package/paths.js +93 -0
  129. package/pm2 +11 -0
  130. package/preinstall.js +24 -0
  131. package/run.sh +9 -0
  132. package/types/index.d.ts +722 -0
  133. package/types/tsconfig.json +14 -0
@@ -0,0 +1,909 @@
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
+
14
+ var fs = require('fs');
15
+ var path = require('path');
16
+ var eachLimit = require('async/eachLimit');
17
+ var os = require('os');
18
+ var p = path;
19
+ var cst = require('../../constants.js');
20
+ var pkg = require('../../package.json');
21
+ var pidusage = require('pidusage');
22
+ var util = require('util');
23
+ var debug = require('debug')('zm2:ActionMethod');
24
+ var Utility = require('../Utility');
25
+
26
+ /**
27
+ * Description
28
+ * @method exports
29
+ * @param {} God
30
+ * @return
31
+ */
32
+ module.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
+
887
+ function 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
+
901
+ function 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
+ }