@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,629 @@
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
+ var chalk = require('ansis');
7
+ var path = require('path');
8
+ var fs = require('fs');
9
+ var forEachLimit = require('async/forEachLimit');
10
+ var eachLimit = require('async/eachLimit');
11
+ var Common = require('../Common.js');
12
+ var cst = require('../../constants.js');
13
+ var util = require('util');
14
+ var tmpPath = require('os').tmpdir;
15
+ var which = require('../tools/which.js');
16
+ var sexec = require('../tools/sexec')
17
+ module.exports = function(CLI) {
18
+ /**
19
+ * If command is launched without root right
20
+ * Display helper
21
+ */
22
+ function isNotRoot(startup_mode, platform, opts, cb) {
23
+ Common.printOut(`${cst.PREFIX_MSG}To ${startup_mode} the Startup Script, copy/paste the following command:`);
24
+
25
+ let pm2_bin_path = require.main.filename
26
+
27
+ if (pm2_bin_path.includes('/lib/binaries/CLI.js') === true) {
28
+ pm2_bin_path = pm2_bin_path.replace('/lib/binaries/CLI.js', '/bin/zm2')
29
+ }
30
+
31
+ if (opts.user) {
32
+ console.log('sudo env PATH=$PATH:' + path.dirname(process.execPath) + ' zm2 ' + opts.args[1].name() + ' ' + platform + ' -u ' + opts.user + ' --hp ' + process.env.HOME);
33
+ return cb(new Error('You have to run this with elevated rights'));
34
+ }
35
+ return sexec('whoami', {silent: true}, function(err, stdout, stderr) {
36
+ console.log('sudo env PATH=$PATH:' + path.dirname(process.execPath) + ' ' + pm2_bin_path + ' ' + opts.args[1].name() + ' ' + platform + ' -u ' + stdout.trim() + ' --hp ' + process.env.HOME);
37
+ return cb(new Error('You have to run this with elevated rights'));
38
+ });
39
+ }
40
+
41
+ /**
42
+ * Detect running init system
43
+ */
44
+ function detectInitSystem() {
45
+ var hash_map = {
46
+ 'systemctl' : 'systemd',
47
+ 'update-rc.d': 'upstart',
48
+ 'chkconfig' : 'systemv',
49
+ 'rc-update' : 'openrc',
50
+ 'launchctl' : 'launchd',
51
+ 'sysrc' : 'rcd',
52
+ 'rcctl' : 'rcd-openbsd',
53
+ 'svcadm' : 'smf'
54
+ };
55
+ var init_systems = Object.keys(hash_map);
56
+
57
+ for (var i = 0; i < init_systems.length; i++) {
58
+ if (which(init_systems[i]) != null) {
59
+ break;
60
+ }
61
+ }
62
+
63
+ if (i >= init_systems.length) {
64
+ Common.printError(cst.PREFIX_MSG_ERR + 'Init system not found');
65
+ return null;
66
+ }
67
+ Common.printOut(cst.PREFIX_MSG + 'Init System found: ' + chalk.bold(hash_map[init_systems[i]]));
68
+ return hash_map[init_systems[i]];
69
+ }
70
+
71
+ CLI.prototype.uninstallStartup = function(platform, opts, cb) {
72
+ var commands;
73
+ var that = this;
74
+ var actual_platform = detectInitSystem();
75
+ var user = opts.user || process.env.USER || process.env.LOGNAME; // Use LOGNAME on Solaris-like systems
76
+ var service_name = (opts.serviceName || 'zm2-' + user);
77
+ var openrc_service_name = 'zm2';
78
+ var launchd_service_name = (opts.serviceName || 'zm2.' + user);
79
+
80
+ if (!platform)
81
+ platform = actual_platform;
82
+ else if (actual_platform && actual_platform !== platform) {
83
+ Common.printOut('-----------------------------------------------------------')
84
+ Common.printOut(' ZM2 detected ' + actual_platform + ' but you precised ' + platform)
85
+ Common.printOut(' Please verify that your choice is indeed your init system')
86
+ Common.printOut(' If you arent sure, just run : zm2 startup')
87
+ Common.printOut('-----------------------------------------------------------')
88
+ }
89
+ if (platform === null)
90
+ throw new Error('Init system not found')
91
+
92
+ if (!cb) {
93
+ cb = function(err, data) {
94
+ if (err)
95
+ return that.exitCli(cst.ERROR_EXIT);
96
+ return that.exitCli(cst.SUCCESS_EXIT);
97
+ }
98
+ }
99
+
100
+ if (process.getuid() != 0) {
101
+ return isNotRoot('unsetup', platform, opts, cb);
102
+ }
103
+
104
+ if (fs.existsSync('/etc/init.d/zm2-init.sh')) {
105
+ platform = 'oldsystem';
106
+ }
107
+
108
+ switch(platform) {
109
+ case 'systemd':
110
+ commands = [
111
+ 'systemctl stop ' + service_name,
112
+ 'systemctl disable ' + service_name,
113
+ 'rm /etc/systemd/system/' + service_name + '.service'
114
+ ];
115
+ break;
116
+ case 'systemv':
117
+ commands = [
118
+ 'chkconfig ' + service_name + ' off',
119
+ 'rm /etc/init.d/' + service_name
120
+ ];
121
+ break;
122
+ case 'oldsystem':
123
+ Common.printOut(cst.PREFIX_MSG + 'Disabling and deleting old startup system');
124
+ commands = [
125
+ 'update-rc.d zm2-init.sh disable',
126
+ 'update-rc.d -f zm2-init.sh remove',
127
+ 'rm /etc/init.d/zm2-init.sh'
128
+ ];
129
+ break;
130
+ case 'openrc':
131
+ service_name = openrc_service_name;
132
+ commands = [
133
+ '/etc/init.d/' + service_name + ' stop',
134
+ 'rc-update delete ' + service_name + ' default',
135
+ 'rm /etc/init.d/' + service_name
136
+ ];
137
+ break;
138
+ case 'upstart':
139
+ commands = [
140
+ 'update-rc.d ' + service_name + ' disable',
141
+ 'update-rc.d -f ' + service_name + ' remove',
142
+ 'rm /etc/init.d/' + service_name
143
+ ];
144
+ break;
145
+ case 'launchd':
146
+ var destination = path.join(process.env.HOME, 'Library/LaunchAgents/' + launchd_service_name + '.plist');
147
+ commands = [
148
+ 'launchctl remove ' + launchd_service_name + ' || true',
149
+ 'rm ' + destination
150
+ ];
151
+ break;
152
+ case 'rcd':
153
+ service_name = (opts.serviceName || 'zm2_' + user);
154
+ commands = [
155
+ '/usr/local/etc/rc.d/' + service_name + ' stop',
156
+ 'sysrc -x ' + service_name + '_enable',
157
+ 'rm /usr/local/etc/rc.d/' + service_name
158
+ ];
159
+ break;
160
+ case 'rcd-openbsd':
161
+ service_name = (opts.serviceName || 'zm2_' + user);
162
+ var destination = path.join('/etc/rc.d', service_name);
163
+ commands = [
164
+ 'rcctl stop ' + service_name,
165
+ 'rcctl disable ' + service_name,
166
+ 'rm ' + destination
167
+ ];
168
+ break;
169
+ case 'smf':
170
+ service_name = (opts.serviceName || 'zm2_' + user);
171
+ commands = [
172
+ 'svcadm disable ' + service_name,
173
+ 'svccfg delete -f ' + service_name
174
+ ]
175
+ };
176
+
177
+ sexec(commands.join('&& '), function(code, stdout, stderr) {
178
+ Common.printOut(stdout);
179
+ Common.printOut(stderr);
180
+ if (code == 0) {
181
+ Common.printOut(cst.PREFIX_MSG + chalk.bold('Init file disabled.'));
182
+ } else {
183
+ Common.printOut(cst.ERROR_MSG + chalk.bold('Return code : ' + code));
184
+ }
185
+
186
+ cb(null, {
187
+ commands : commands,
188
+ platform : platform
189
+ });
190
+ });
191
+ };
192
+
193
+ /**
194
+ * Startup script generation
195
+ * @method startup
196
+ * @param {string} platform type (centos|redhat|amazon|gentoo|systemd|smf)
197
+ */
198
+ CLI.prototype.startup = function(platform, opts, cb) {
199
+ var that = this;
200
+ var actual_platform = detectInitSystem();
201
+ var user = (opts.user || process.env.USER || process.env.LOGNAME); // Use LOGNAME on Solaris-like systems
202
+ var service_name = (opts.serviceName || 'zm2-' + user);
203
+ var openrc_service_name = 'zm2';
204
+ var launchd_service_name = (opts.serviceName || 'zm2.' + user);
205
+
206
+ if (!platform)
207
+ platform = actual_platform;
208
+ else if (actual_platform && actual_platform !== platform) {
209
+ Common.printOut('-----------------------------------------------------------')
210
+ Common.printOut(' ZM2 detected ' + actual_platform + ' but you precised ' + platform)
211
+ Common.printOut(' Please verify that your choice is indeed your init system')
212
+ Common.printOut(' If you arent sure, just run : zm2 startup')
213
+ Common.printOut('-----------------------------------------------------------')
214
+ }
215
+ if (platform == null)
216
+ throw new Error('Init system not found');
217
+
218
+ if (!cb) {
219
+ cb = function(err, data) {
220
+ if (err)
221
+ return that.exitCli(cst.ERROR_EXIT);
222
+ return that.exitCli(cst.SUCCESS_EXIT);
223
+ }
224
+ }
225
+
226
+ if (process.getuid() != 0) {
227
+ return isNotRoot('setup', platform, opts, cb);
228
+ }
229
+
230
+ var destination;
231
+ var commands;
232
+ var template;
233
+
234
+ function getTemplate(type) {
235
+ return fs.readFileSync(path.join(__dirname, '..', 'templates/init-scripts', type + '.tpl'), {encoding: 'utf8'});
236
+ }
237
+
238
+ switch(platform) {
239
+ case 'ubuntu':
240
+ case 'centos':
241
+ case 'arch':
242
+ case 'oracle':
243
+ case 'systemd':
244
+ if (opts.waitIp)
245
+ template = getTemplate('systemd-online');
246
+ else
247
+ template = getTemplate('systemd');
248
+ destination = '/etc/systemd/system/' + service_name + '.service';
249
+ commands = [
250
+ 'systemctl enable ' + service_name
251
+ ];
252
+ break;
253
+ case 'ubuntu14':
254
+ case 'ubuntu12':
255
+ case 'upstart':
256
+ template = getTemplate('upstart');
257
+ destination = '/etc/init.d/' + service_name;
258
+ commands = [
259
+ 'chmod +x ' + destination,
260
+ 'mkdir -p /var/lock/subsys',
261
+ 'touch /var/lock/subsys/' + service_name,
262
+ 'update-rc.d ' + service_name + ' defaults'
263
+ ];
264
+ break;
265
+ case 'systemv':
266
+ case 'amazon':
267
+ case 'centos6':
268
+ template = getTemplate('upstart');
269
+ destination = '/etc/init.d/' + service_name;
270
+ commands = [
271
+ 'chmod +x ' + destination,
272
+ 'mkdir -p /var/lock/subsys',
273
+ 'touch /var/lock/subsys/' + service_name,
274
+ 'chkconfig --add ' + service_name,
275
+ 'chkconfig ' + service_name + ' on',
276
+ 'initctl list'
277
+ ];
278
+ break;
279
+ case 'macos':
280
+ case 'darwin':
281
+ case 'launchd':
282
+ template = getTemplate('launchd');
283
+ destination = path.join(process.env.HOME, 'Library/LaunchAgents/' + launchd_service_name + '.plist');
284
+ commands = [
285
+ 'mkdir -p ' + path.join(process.env.HOME, 'Library/LaunchAgents'),
286
+ 'launchctl load -w ' + destination
287
+ ]
288
+ break;
289
+ case 'freebsd':
290
+ case 'rcd':
291
+ template = getTemplate('rcd');
292
+ service_name = (opts.serviceName || 'zm2_' + user);
293
+ destination = '/usr/local/etc/rc.d/' + service_name;
294
+ commands = [
295
+ 'chmod 755 ' + destination,
296
+ 'sysrc ' + service_name + '_enable=YES'
297
+ ];
298
+ break;
299
+ case 'openbsd':
300
+ case 'rcd-openbsd':
301
+ template = getTemplate('rcd-openbsd');
302
+ service_name = (opts.serviceName || 'zm2_' + user);
303
+ destination = path.join('/etc/rc.d/', service_name);
304
+ commands = [
305
+ 'chmod 755 ' + destination,
306
+ 'rcctl enable ' + service_name,
307
+ 'rcctl start ' + service_name
308
+ ];
309
+ break;
310
+ case 'openrc':
311
+ template = getTemplate('openrc');
312
+ service_name = openrc_service_name;
313
+ destination = '/etc/init.d/' + service_name;
314
+ commands = [
315
+ 'chmod +x ' + destination,
316
+ 'rc-update add ' + service_name + ' default'
317
+ ];
318
+ break;
319
+ case 'smf':
320
+ case 'sunos':
321
+ case 'solaris':
322
+ template = getTemplate('smf');
323
+ service_name = (opts.serviceName || 'zm2_' + user);
324
+ destination = path.join(tmpPath(), service_name + '.xml');
325
+ commands = [
326
+ 'svccfg import ' + destination,
327
+ 'svcadm enable ' + service_name
328
+ ];
329
+ break;
330
+ default:
331
+ throw new Error('Unknown platform / init system name');
332
+ }
333
+
334
+ /**
335
+ * 4# Replace template variable value
336
+ */
337
+ var envPath
338
+
339
+ if (cst.HAS_NODE_EMBEDDED == true)
340
+ envPath = util.format('%s:%s', process.env.PATH || '', path.dirname(process.execPath))
341
+ else if (new RegExp(path.dirname(process.execPath)).test(process.env.PATH))
342
+ envPath = process.env.PATH
343
+ else
344
+ envPath = util.format('%s:%s', process.env.PATH || '', path.dirname(process.execPath))
345
+
346
+ let pm2_bin_path = require.main.filename
347
+
348
+ if (pm2_bin_path.includes('/lib/binaries/CLI.js') === true) {
349
+ pm2_bin_path = pm2_bin_path.replace('/lib/binaries/CLI.js', '/bin/zm2')
350
+ }
351
+
352
+ template = template.replace(/%PM2_PATH%/g, pm2_bin_path)
353
+ .replace(/%NODE_PATH%/g, envPath)
354
+ .replace(/%USER%/g, user)
355
+ .replace(/%HOME_PATH%/g, opts.hp ? path.resolve(opts.hp, '.pm2') : cst.PM2_ROOT_PATH)
356
+ .replace(/%SERVICE_NAME%/g, service_name);
357
+
358
+ Common.printOut(chalk.bold('Platform'), platform);
359
+ Common.printOut(chalk.bold('Template'));
360
+ Common.printOut(template);
361
+ Common.printOut(chalk.bold('Target path'));
362
+ Common.printOut(destination);
363
+ Common.printOut(chalk.bold('Command list'));
364
+ Common.printOut(commands);
365
+
366
+ Common.printOut(cst.PREFIX_MSG + 'Writing init configuration in ' + destination);
367
+ try {
368
+ fs.writeFileSync(destination, template);
369
+ } catch (e) {
370
+ console.error(cst.PREFIX_MSG_ERR + 'Failure when trying to write startup script');
371
+ console.error(e.message || e);
372
+ return cb(e);
373
+ }
374
+
375
+ Common.printOut(cst.PREFIX_MSG + 'Making script booting at startup...');
376
+
377
+ forEachLimit(commands, 1, function(command, next) {
378
+ Common.printOut(cst.PREFIX_MSG + '[-] Executing: %s...', chalk.bold(command));
379
+
380
+ sexec(command, function(code, stdout, stderr) {
381
+ if (code === 0) {
382
+ Common.printOut(cst.PREFIX_MSG + chalk.bold('[v] Command successfully executed.'));
383
+ return next();
384
+ } else {
385
+ Common.printOut(chalk.red('[ERROR] Exit code : ' + code))
386
+ return next(new Error(command + ' failed, see error above.'));
387
+ }
388
+ })
389
+
390
+ }, function(err) {
391
+ if (err) {
392
+ console.error(cst.PREFIX_MSG_ERR + (err.message || err));
393
+ return cb(err);
394
+ }
395
+ Common.printOut(chalk.bold.blue('+---------------------------------------+'));
396
+ Common.printOut(chalk.bold.blue((cst.PREFIX_MSG + 'Freeze a process list on reboot via:' )));
397
+ Common.printOut(chalk.bold('$ zm2 save'));
398
+ Common.printOut('');
399
+ Common.printOut(chalk.bold.blue(cst.PREFIX_MSG + 'Remove init script via:'));
400
+ Common.printOut(chalk.bold('$ zm2 unstartup ' + platform));
401
+
402
+ return cb(null, {
403
+ destination : destination,
404
+ template : template
405
+ });
406
+ });
407
+ };
408
+
409
+ /**
410
+ * DISABLED FEATURE
411
+ * KEEPING METHOD FOR BACKWARD COMPAT
412
+ */
413
+ CLI.prototype.autodump = function(cb) {
414
+ return cb()
415
+ }
416
+
417
+ /**
418
+ * Dump current processes managed by pm2 into DUMP_FILE_PATH file
419
+ * @method dump
420
+ * @param {} cb
421
+ * @return
422
+ */
423
+ CLI.prototype.dump = function(force, cb) {
424
+ var env_arr = [];
425
+ var that = this;
426
+
427
+ if (typeof(force) === 'function') {
428
+ cb = force
429
+ force = false
430
+ }
431
+
432
+ if (!cb)
433
+ Common.printOut(cst.PREFIX_MSG + 'Saving current process list...');
434
+
435
+ that.Client.executeRemote('getMonitorData', {}, function(err, list) {
436
+ if (err) {
437
+ Common.printError('Error retrieving process list: ' + err);
438
+ return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
439
+ }
440
+
441
+ /**
442
+ * Description
443
+ * @method fin
444
+ * @param {} err
445
+ * @return
446
+ */
447
+ function fin(err) {
448
+
449
+ // try to fix issues with empty dump file
450
+ // like #3485
451
+ if (!force && env_arr.length === 0 && !process.env.FORCE) {
452
+
453
+ // fix : if no dump file, no process, only module and after pm2 update
454
+ if (!fs.existsSync(cst.DUMP_FILE_PATH)) {
455
+ that.clearDump(function(){});
456
+ }
457
+
458
+ // if no process in list don't modify dump file
459
+ // process list should not be empty
460
+ if (cb) {
461
+ return cb(new Error('Process list empty, cannot save empty list'));
462
+ } else {
463
+ Common.printOut(cst.PREFIX_MSG_WARNING + 'ZM2 is not managing any process, skipping save...');
464
+ Common.printOut(cst.PREFIX_MSG_WARNING + 'To force saving use: zm2 save --force');
465
+ that.exitCli(cst.SUCCESS_EXIT);
466
+ return;
467
+ }
468
+ }
469
+
470
+ // Back up dump file
471
+ try {
472
+ if (fs.existsSync(cst.DUMP_FILE_PATH)) {
473
+ fs.writeFileSync(cst.DUMP_BACKUP_FILE_PATH, fs.readFileSync(cst.DUMP_FILE_PATH));
474
+ }
475
+ } catch (e) {
476
+ console.error(e.stack || e);
477
+ Common.printOut(cst.PREFIX_MSG_ERR + 'Failed to back up dump file in %s', cst.DUMP_BACKUP_FILE_PATH);
478
+ }
479
+
480
+ // Overwrite dump file, delete if broken and exit
481
+ try {
482
+ fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify(env_arr, '', 2));
483
+ } catch (e) {
484
+ console.error(e.stack || e);
485
+ try {
486
+ // try to backup file
487
+ if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
488
+ fs.writeFileSync(cst.DUMP_FILE_PATH, fs.readFileSync(cst.DUMP_BACKUP_FILE_PATH));
489
+ }
490
+ } catch (e) {
491
+ // don't keep broken file
492
+ fs.unlinkSync(cst.DUMP_FILE_PATH);
493
+ console.error(e.stack || e);
494
+ }
495
+ Common.printOut(cst.PREFIX_MSG_ERR + 'Failed to save dump file in %s', cst.DUMP_FILE_PATH);
496
+ return that.exitCli(cst.ERROR_EXIT);
497
+ }
498
+ if (cb) return cb(null, {success:true});
499
+
500
+ Common.printOut(cst.PREFIX_MSG + 'Successfully saved in %s', cst.DUMP_FILE_PATH);
501
+ return that.exitCli(cst.SUCCESS_EXIT);
502
+ }
503
+
504
+ (function ex(apps) {
505
+ if (!apps[0]) return fin(null);
506
+ delete apps[0].pm2_env.instances;
507
+ delete apps[0].pm2_env.pm_id;
508
+ delete apps[0].pm2_env.prev_restart_delay;
509
+ if (!apps[0].pm2_env.pmx_module)
510
+ env_arr.push(apps[0].pm2_env);
511
+ apps.shift();
512
+ return ex(apps);
513
+ })(list);
514
+ });
515
+ };
516
+
517
+ /**
518
+ * Remove DUMP_FILE_PATH file and DUMP_BACKUP_FILE_PATH file
519
+ * @method dump
520
+ * @param {} cb
521
+ * @return
522
+ */
523
+ CLI.prototype.clearDump = function(cb) {
524
+ fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify([]));
525
+
526
+ if(cb && typeof cb === 'function') return cb();
527
+
528
+ Common.printOut(cst.PREFIX_MSG + 'Successfully created %s', cst.DUMP_FILE_PATH);
529
+ return this.exitCli(cst.SUCCESS_EXIT);
530
+ };
531
+
532
+ /**
533
+ * Resurrect processes
534
+ * @method resurrect
535
+ * @param {} cb
536
+ * @return
537
+ */
538
+ CLI.prototype.resurrect = function(cb) {
539
+ var apps = {};
540
+ var that = this;
541
+
542
+ var processes;
543
+
544
+ function readDumpFile(dumpFilePath) {
545
+ Common.printOut(cst.PREFIX_MSG + 'Restoring processes located in %s', dumpFilePath);
546
+ try {
547
+ var apps = fs.readFileSync(dumpFilePath);
548
+ } catch (e) {
549
+ Common.printError(cst.PREFIX_MSG_ERR + 'Failed to read dump file in %s', dumpFilePath);
550
+ throw e;
551
+ }
552
+
553
+ return apps;
554
+ }
555
+
556
+ function parseDumpFile(dumpFilePath, apps) {
557
+ try {
558
+ var processes = Common.parseConfig(apps, 'none');
559
+ } catch (e) {
560
+ Common.printError(cst.PREFIX_MSG_ERR + 'Failed to parse dump file in %s', dumpFilePath);
561
+ try {
562
+ fs.unlinkSync(dumpFilePath);
563
+ } catch (e) {
564
+ console.error(e.stack || e);
565
+ }
566
+ throw e;
567
+ }
568
+
569
+ return processes;
570
+ }
571
+
572
+ // Read dump file, fall back to backup, delete if broken
573
+ try {
574
+ apps = readDumpFile(cst.DUMP_FILE_PATH);
575
+ processes = parseDumpFile(cst.DUMP_FILE_PATH, apps);
576
+ } catch(e) {
577
+ try {
578
+ apps = readDumpFile(cst.DUMP_BACKUP_FILE_PATH);
579
+ processes = parseDumpFile(cst.DUMP_BACKUP_FILE_PATH, apps);
580
+ } catch(e) {
581
+ Common.printError(cst.PREFIX_MSG_ERR + 'No processes saved; DUMP file doesn\'t exist');
582
+ // if (cb) return cb(Common.retErr(e));
583
+ // else return that.exitCli(cst.ERROR_EXIT);
584
+ return that.speedList();
585
+ }
586
+ }
587
+
588
+ that.Client.executeRemote('getMonitorData', {}, function(err, list) {
589
+ if (err) {
590
+ Common.printError(err);
591
+ return that.exitCli(1);
592
+ }
593
+
594
+ var current = [];
595
+ var target = [];
596
+
597
+ list.forEach(function(app) {
598
+ if (!current[app.name])
599
+ current[app.name] = 0;
600
+ current[app.name]++;
601
+ });
602
+
603
+ processes.forEach(function(app) {
604
+ if (!target[app.name])
605
+ target[app.name] = 0;
606
+ target[app.name]++;
607
+ });
608
+
609
+ var tostart = Object.keys(target).filter(function(i) {
610
+ return Object.keys(current).indexOf(i) < 0;
611
+ })
612
+
613
+ eachLimit(processes, cst.CONCURRENT_ACTIONS, function(app, next) {
614
+ if (tostart.indexOf(app.name) == -1)
615
+ return next();
616
+ that.Client.executeRemote('prepare', app, function(err, dt) {
617
+ if (err)
618
+ Common.printError(err);
619
+ else
620
+ Common.printOut(cst.PREFIX_MSG + 'Process %s restored', app.pm_exec_path);
621
+ next();
622
+ });
623
+ }, function(err) {
624
+ return cb ? cb(null, apps) : that.speedList();
625
+ });
626
+ });
627
+ };
628
+
629
+ }