@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.
- package/.claude/settings.local.json +8 -0
- package/.gitattributes +4 -0
- package/.mocharc.js +14 -0
- package/CHANGELOG.md +2416 -0
- package/CLAUDE.md +84 -0
- package/CONTRIBUTING.md +124 -0
- package/GNU-AGPL-3.0.txt +665 -0
- package/LICENSE +1 -0
- package/README.md +248 -0
- package/bin/zm2 +3 -0
- package/bin/zm2-dev +3 -0
- package/bin/zm2-docker +3 -0
- package/bin/zm2-runtime +3 -0
- package/bin/zm2-windows +3 -0
- package/bin/zm2.ps1 +3 -0
- package/bun.lock +421 -0
- package/constants.js +114 -0
- package/index.js +13 -0
- package/lib/API/Configuration.js +212 -0
- package/lib/API/Containerizer.js +335 -0
- package/lib/API/Dashboard.js +459 -0
- package/lib/API/Deploy.js +117 -0
- package/lib/API/Extra.js +775 -0
- package/lib/API/ExtraMgmt/Docker.js +30 -0
- package/lib/API/Log.js +315 -0
- package/lib/API/LogManagement.js +371 -0
- package/lib/API/Modules/LOCAL.js +122 -0
- package/lib/API/Modules/Modularizer.js +148 -0
- package/lib/API/Modules/NPM.js +445 -0
- package/lib/API/Modules/TAR.js +362 -0
- package/lib/API/Modules/flagExt.js +46 -0
- package/lib/API/Modules/index.js +120 -0
- package/lib/API/Monit.js +247 -0
- package/lib/API/Serve.js +343 -0
- package/lib/API/Startup.js +629 -0
- package/lib/API/UX/helpers.js +213 -0
- package/lib/API/UX/index.js +9 -0
- package/lib/API/UX/pm2-describe.js +193 -0
- package/lib/API/UX/pm2-ls-minimal.js +31 -0
- package/lib/API/UX/pm2-ls.js +483 -0
- package/lib/API/Version.js +382 -0
- package/lib/API/interpreter.json +12 -0
- package/lib/API/pm2-plus/PM2IO.js +372 -0
- package/lib/API/pm2-plus/auth-strategies/CliAuth.js +288 -0
- package/lib/API/pm2-plus/auth-strategies/WebAuth.js +187 -0
- package/lib/API/pm2-plus/helpers.js +97 -0
- package/lib/API/pm2-plus/link.js +126 -0
- package/lib/API/pm2-plus/pres/motd +16 -0
- package/lib/API/pm2-plus/pres/motd.update +26 -0
- package/lib/API/pm2-plus/pres/welcome +28 -0
- package/lib/API/pm2-plus/process-selector.js +52 -0
- package/lib/API/schema.json +379 -0
- package/lib/API.js +1931 -0
- package/lib/Client.js +776 -0
- package/lib/Common.js +911 -0
- package/lib/Configuration.js +304 -0
- package/lib/Daemon.js +456 -0
- package/lib/Event.js +37 -0
- package/lib/God/ActionMethods.js +909 -0
- package/lib/God/ClusterMode.js +97 -0
- package/lib/God/ForkMode.js +297 -0
- package/lib/God/Methods.js +265 -0
- package/lib/God/Reload.js +240 -0
- package/lib/God.js +632 -0
- package/lib/HttpInterface.js +76 -0
- package/lib/ProcessContainer.js +305 -0
- package/lib/ProcessContainerBun.js +360 -0
- package/lib/ProcessContainerFork.js +42 -0
- package/lib/ProcessContainerForkBun.js +33 -0
- package/lib/ProcessUtils.js +55 -0
- package/lib/TreeKill.js +118 -0
- package/lib/Utility.js +430 -0
- package/lib/VersionCheck.js +46 -0
- package/lib/Watcher.js +117 -0
- package/lib/Worker.js +169 -0
- package/lib/binaries/CLI.js +1041 -0
- package/lib/binaries/DevCLI.js +183 -0
- package/lib/binaries/Runtime.js +101 -0
- package/lib/binaries/Runtime4Docker.js +192 -0
- package/lib/completion.js +229 -0
- package/lib/completion.sh +40 -0
- package/lib/motd +36 -0
- package/lib/templates/Dockerfiles/Dockerfile-java.tpl +7 -0
- package/lib/templates/Dockerfiles/Dockerfile-nodejs.tpl +8 -0
- package/lib/templates/Dockerfiles/Dockerfile-ruby.tpl +7 -0
- package/lib/templates/ecosystem-es.tpl +24 -0
- package/lib/templates/ecosystem-simple-es.tpl +8 -0
- package/lib/templates/ecosystem-simple.tpl +6 -0
- package/lib/templates/ecosystem.tpl +22 -0
- package/lib/templates/init-scripts/launchd.tpl +35 -0
- package/lib/templates/init-scripts/openrc.tpl +52 -0
- package/lib/templates/init-scripts/pm2-init-amazon.sh +86 -0
- package/lib/templates/init-scripts/rcd-openbsd.tpl +41 -0
- package/lib/templates/init-scripts/rcd.tpl +44 -0
- package/lib/templates/init-scripts/smf.tpl +43 -0
- package/lib/templates/init-scripts/systemd-online.tpl +22 -0
- package/lib/templates/init-scripts/systemd.tpl +22 -0
- package/lib/templates/init-scripts/upstart.tpl +103 -0
- package/lib/templates/logrotate.d/pm2 +10 -0
- package/lib/templates/sample-apps/http-server/README.md +14 -0
- package/lib/templates/sample-apps/http-server/api.js +9 -0
- package/lib/templates/sample-apps/http-server/ecosystem.config.js +14 -0
- package/lib/templates/sample-apps/http-server/package.json +11 -0
- package/lib/templates/sample-apps/pm2-plus-metrics-actions/README.md +45 -0
- package/lib/templates/sample-apps/pm2-plus-metrics-actions/custom-metrics.js +66 -0
- package/lib/templates/sample-apps/pm2-plus-metrics-actions/ecosystem.config.js +12 -0
- package/lib/templates/sample-apps/pm2-plus-metrics-actions/package.json +11 -0
- package/lib/templates/sample-apps/python-app/README.md +4 -0
- package/lib/templates/sample-apps/python-app/echo.py +7 -0
- package/lib/templates/sample-apps/python-app/ecosystem.config.js +12 -0
- package/lib/templates/sample-apps/python-app/package.json +11 -0
- package/lib/tools/Config.js +248 -0
- package/lib/tools/IsAbsolute.js +20 -0
- package/lib/tools/copydirSync.js +101 -0
- package/lib/tools/deleteFolderRecursive.js +19 -0
- package/lib/tools/find-package-json.js +74 -0
- package/lib/tools/fmt.js +72 -0
- package/lib/tools/isbinaryfile.js +94 -0
- package/lib/tools/json5.js +752 -0
- package/lib/tools/open.js +63 -0
- package/lib/tools/passwd.js +58 -0
- package/lib/tools/promise.min.js +1 -0
- package/lib/tools/sexec.js +55 -0
- package/lib/tools/treeify.js +113 -0
- package/lib/tools/which.js +120 -0
- package/lib/tools/xdg-open +861 -0
- package/package.json +219 -0
- package/paths.js +93 -0
- package/pm2 +11 -0
- package/preinstall.js +24 -0
- package/run.sh +9 -0
- package/types/index.d.ts +722 -0
- package/types/tsconfig.json +14 -0
package/lib/Common.js
ADDED
|
@@ -0,0 +1,911 @@
|
|
|
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
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Common Utilities ONLY USED IN ->CLI<-
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
var fs = require('fs');
|
|
12
|
+
var path = require('path');
|
|
13
|
+
var os = require('os');
|
|
14
|
+
var util = require('util');
|
|
15
|
+
var chalk = require('ansis');
|
|
16
|
+
var fclone = require('fclone');
|
|
17
|
+
var semver = require('semver');
|
|
18
|
+
var dayjs = require('dayjs');
|
|
19
|
+
var execSync = require('child_process').execSync;
|
|
20
|
+
var isBinary = require('./tools/isbinaryfile.js');
|
|
21
|
+
var cst = require('../constants.js');
|
|
22
|
+
var extItps = require('./API/interpreter.json');
|
|
23
|
+
var Config = require('./tools/Config');
|
|
24
|
+
var pkg = require('../package.json');
|
|
25
|
+
var which = require('./tools/which.js');
|
|
26
|
+
var Common = module.exports;
|
|
27
|
+
|
|
28
|
+
function homedir() {
|
|
29
|
+
var env = process.env;
|
|
30
|
+
var home = env.HOME;
|
|
31
|
+
var user = env.LOGNAME || env.USER || env.LNAME || env.USERNAME;
|
|
32
|
+
|
|
33
|
+
if (process.platform === 'win32') {
|
|
34
|
+
return env.USERPROFILE || env.HOMEDRIVE + env.HOMEPATH || home || null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (process.platform === 'darwin') {
|
|
38
|
+
return home || (user ? '/Users/' + user : null);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (process.platform === 'linux') {
|
|
42
|
+
return home || (process.getuid() === 0 ? '/root' : (user ? '/home/' + user : null));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return home || null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function resolveHome(filepath) {
|
|
49
|
+
if (filepath[0] === '~') {
|
|
50
|
+
return path.join(homedir(), filepath.slice(1));
|
|
51
|
+
}
|
|
52
|
+
return filepath;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
Common.determineSilentCLI = function() {
|
|
56
|
+
// pm2 should ignore -s --silent -v if they are after '--'
|
|
57
|
+
var variadicArgsDashesPos = process.argv.indexOf('--');
|
|
58
|
+
var s1opt = process.argv.indexOf('--silent')
|
|
59
|
+
var s2opt = process.argv.indexOf('-s')
|
|
60
|
+
|
|
61
|
+
if (process.env.PM2_SILENT || (variadicArgsDashesPos > -1 &&
|
|
62
|
+
(s1opt != -1 && s1opt < variadicArgsDashesPos) &&
|
|
63
|
+
(s2opt != -1 != s2opt < variadicArgsDashesPos)) ||
|
|
64
|
+
(variadicArgsDashesPos == -1 && (s1opt > -1 || s2opt > -1))) {
|
|
65
|
+
for (var key in console){
|
|
66
|
+
var code = key.charCodeAt(0);
|
|
67
|
+
if (code >= 97 && code <= 122){
|
|
68
|
+
console[key] = function(){};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
process.env.PM2_DISCRETE_MODE = true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
Common.printVersion = function() {
|
|
76
|
+
var variadicArgsDashesPos = process.argv.indexOf('--');
|
|
77
|
+
|
|
78
|
+
if (process.argv.indexOf('-v') > -1 && process.argv.indexOf('-v') < variadicArgsDashesPos) {
|
|
79
|
+
console.log(pkg.version);
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
Common.lockReload = function() {
|
|
85
|
+
try {
|
|
86
|
+
var t1 = fs.readFileSync(cst.PM2_RELOAD_LOCKFILE).toString();
|
|
87
|
+
|
|
88
|
+
// Check if content and if time < 30 return locked
|
|
89
|
+
// Else if content detected (lock file staled), allow and rewritte
|
|
90
|
+
if (t1 && t1 != '') {
|
|
91
|
+
var diff = dayjs().diff(parseInt(t1));
|
|
92
|
+
if (diff < cst.RELOAD_LOCK_TIMEOUT)
|
|
93
|
+
return diff;
|
|
94
|
+
}
|
|
95
|
+
} catch(e) {}
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
// Write latest timestamp
|
|
99
|
+
fs.writeFileSync(cst.PM2_RELOAD_LOCKFILE, dayjs().valueOf().toString());
|
|
100
|
+
return 0;
|
|
101
|
+
} catch(e) {
|
|
102
|
+
console.error(e.message || e);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
Common.unlockReload = function() {
|
|
107
|
+
try {
|
|
108
|
+
fs.writeFileSync(cst.PM2_RELOAD_LOCKFILE, '');
|
|
109
|
+
} catch(e) {
|
|
110
|
+
console.error(e.message || e);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Resolve app paths and replace missing values with defaults.
|
|
116
|
+
* @method prepareAppConf
|
|
117
|
+
* @param app {Object}
|
|
118
|
+
* @param {} cwd
|
|
119
|
+
* @param {} outputter
|
|
120
|
+
* @return app
|
|
121
|
+
*/
|
|
122
|
+
Common.prepareAppConf = function(opts, app) {
|
|
123
|
+
/**
|
|
124
|
+
* Minimum validation
|
|
125
|
+
*/
|
|
126
|
+
if (!app.script)
|
|
127
|
+
return new Error('No script path - aborting');
|
|
128
|
+
|
|
129
|
+
var cwd = null;
|
|
130
|
+
|
|
131
|
+
if (app.cwd) {
|
|
132
|
+
cwd = path.resolve(app.cwd);
|
|
133
|
+
process.env.PWD = app.cwd;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!app.node_args) {
|
|
137
|
+
app.node_args = [];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (app.port && app.env) {
|
|
141
|
+
app.env.PORT = app.port;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// CWD option resolving
|
|
145
|
+
cwd && (cwd[0] != '/') && (cwd = path.resolve(process.cwd(), cwd));
|
|
146
|
+
cwd = cwd || opts.cwd;
|
|
147
|
+
|
|
148
|
+
// Full path script resolution
|
|
149
|
+
app.pm_exec_path = path.resolve(cwd, app.script);
|
|
150
|
+
|
|
151
|
+
// If script does not exist after resolution
|
|
152
|
+
if (!fs.existsSync(app.pm_exec_path)) {
|
|
153
|
+
var ckd;
|
|
154
|
+
// Try resolve command available in $PATH
|
|
155
|
+
if ((ckd = which(app.script))) {
|
|
156
|
+
if (typeof(ckd) !== 'string')
|
|
157
|
+
ckd = ckd.toString();
|
|
158
|
+
app.pm_exec_path = ckd;
|
|
159
|
+
}
|
|
160
|
+
else
|
|
161
|
+
// Throw critical error
|
|
162
|
+
return new Error(`Script not found: ${app.pm_exec_path}`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Auto detect .map file and enable source map support automatically
|
|
167
|
+
*/
|
|
168
|
+
if (app.disable_source_map_support != true) {
|
|
169
|
+
try {
|
|
170
|
+
fs.accessSync(app.pm_exec_path + '.map', fs.constants.R_OK);
|
|
171
|
+
app.source_map_support = true;
|
|
172
|
+
} catch(e) {}
|
|
173
|
+
delete app.disable_source_map_support;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
delete app.script;
|
|
177
|
+
|
|
178
|
+
// Set current env by first adding the process environment and then extending/replacing it
|
|
179
|
+
// with env specified on command-line or JSON file.
|
|
180
|
+
|
|
181
|
+
var env = {};
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Do not copy internal pm2 environment variables if acting on process
|
|
185
|
+
* is made from a programmatic script started by PM2 or if a pm_id is present in env
|
|
186
|
+
*/
|
|
187
|
+
if (cst.PM2_PROGRAMMATIC || process.env.pm_id)
|
|
188
|
+
Common.safeExtend(env, process.env);
|
|
189
|
+
else
|
|
190
|
+
env = process.env;
|
|
191
|
+
|
|
192
|
+
function filterEnv (envObj) {
|
|
193
|
+
if (app.filter_env == true)
|
|
194
|
+
return {}
|
|
195
|
+
|
|
196
|
+
if (typeof app.filter_env === 'string') {
|
|
197
|
+
delete envObj[app.filter_env]
|
|
198
|
+
return envObj
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
var new_env = {};
|
|
202
|
+
var allowedKeys = app.filter_env.reduce((acc, current) =>
|
|
203
|
+
acc.filter( item => !item.includes(current)), Object.keys(envObj))
|
|
204
|
+
allowedKeys.forEach( key => new_env[key] = envObj[key]);
|
|
205
|
+
return new_env
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
app.env = [
|
|
209
|
+
{}, (app.filter_env && app.filter_env.length > 0) ? filterEnv(process.env) : env, app.env || {}
|
|
210
|
+
].reduce(function(e1, e2){
|
|
211
|
+
return Object.assign(e1, e2);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
app.pm_cwd = cwd;
|
|
215
|
+
// Interpreter
|
|
216
|
+
try {
|
|
217
|
+
Common.sink.resolveInterpreter(app);
|
|
218
|
+
} catch(e) {
|
|
219
|
+
return e
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Exec mode and cluster stuff
|
|
223
|
+
Common.sink.determineExecMode(app);
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Scary
|
|
227
|
+
*/
|
|
228
|
+
var formated_app_name = app.name.replace(/[^a-zA-Z0-9\\.\\-]/g, '-');
|
|
229
|
+
|
|
230
|
+
['log', 'out', 'error', 'pid'].forEach(function(f){
|
|
231
|
+
var af = app[f + '_file'], ps, ext = (f == 'pid' ? 'pid':'log'), isStd = !~['log', 'pid'].indexOf(f);
|
|
232
|
+
if (af) af = resolveHome(af);
|
|
233
|
+
|
|
234
|
+
if ((f == 'log' && typeof af == 'boolean' && af) || (f != 'log' && !af)) {
|
|
235
|
+
ps = [cst['DEFAULT_' + ext.toUpperCase() + '_PATH'], formated_app_name + (isStd ? '-' + f : '') + '.' + ext];
|
|
236
|
+
} else if ((f != 'log' || (f == 'log' && af)) && af !== 'NULL' && af !== '/dev/null') {
|
|
237
|
+
ps = [cwd, af];
|
|
238
|
+
|
|
239
|
+
var dir = path.dirname(path.resolve(cwd, af));
|
|
240
|
+
if (!fs.existsSync(dir)) {
|
|
241
|
+
Common.printError(cst.PREFIX_MSG_WARNING + 'Folder does not exist: ' + dir);
|
|
242
|
+
Common.printOut(cst.PREFIX_MSG + 'Creating folder: ' + dir);
|
|
243
|
+
try {
|
|
244
|
+
require('mkdirp').sync(dir);
|
|
245
|
+
} catch (err) {
|
|
246
|
+
Common.printError(cst.PREFIX_MSG_ERR + 'Could not create folder: ' + path.dirname(af));
|
|
247
|
+
throw new Error('Could not create folder');
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
// PM2 paths
|
|
253
|
+
if (af !== 'NULL' && af !== '/dev/null') {
|
|
254
|
+
ps && (app['pm_' + (isStd ? f.substr(0, 3) + '_' : '') + ext + '_path'] = path.resolve.apply(null, ps));
|
|
255
|
+
} else if (path.sep === '\\') {
|
|
256
|
+
app['pm_' + (isStd ? f.substr(0, 3) + '_' : '') + ext + '_path'] = '\\\\.\\NUL';
|
|
257
|
+
} else {
|
|
258
|
+
app['pm_' + (isStd ? f.substr(0, 3) + '_' : '') + ext + '_path'] = '/dev/null';
|
|
259
|
+
}
|
|
260
|
+
delete app[f + '_file'];
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
return app;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Definition of known config file extensions with their type
|
|
268
|
+
*/
|
|
269
|
+
Common.knonwConfigFileExtensions = {
|
|
270
|
+
'.json': 'json',
|
|
271
|
+
'.yml': 'yaml',
|
|
272
|
+
'.yaml': 'yaml',
|
|
273
|
+
'.config.js': 'js',
|
|
274
|
+
'.config.cjs': 'js',
|
|
275
|
+
'.config.mjs': 'mjs'
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Check if filename is a configuration file
|
|
280
|
+
* @param {string} filename
|
|
281
|
+
* @return {mixed} null if not conf file, json or yaml if conf
|
|
282
|
+
*/
|
|
283
|
+
Common.isConfigFile = function (filename) {
|
|
284
|
+
if (typeof (filename) !== 'string')
|
|
285
|
+
return null;
|
|
286
|
+
|
|
287
|
+
for (let extension in Common.knonwConfigFileExtensions) {
|
|
288
|
+
if (filename.indexOf(extension) !== -1) {
|
|
289
|
+
return Common.knonwConfigFileExtensions[extension];
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return null;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
Common.getConfigFileCandidates = function (name) {
|
|
297
|
+
return Object.keys(Common.knonwConfigFileExtensions).map((extension) => name + extension);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Parses a config file like ecosystem.config.js. Supported formats: JS, JSON, JSON5, YAML.
|
|
302
|
+
* @param {string} confString contents of the config file
|
|
303
|
+
* @param {string} filename path to the config file
|
|
304
|
+
* @return {Object} config object
|
|
305
|
+
*/
|
|
306
|
+
Common.parseConfig = function(confObj, filename) {
|
|
307
|
+
var yamljs = require('js-yaml');
|
|
308
|
+
var vm = require('vm');
|
|
309
|
+
|
|
310
|
+
var isConfigFile = Common.isConfigFile(filename);
|
|
311
|
+
|
|
312
|
+
if (!filename ||
|
|
313
|
+
filename == 'pipe' ||
|
|
314
|
+
filename == 'none' ||
|
|
315
|
+
isConfigFile == 'json') {
|
|
316
|
+
var code = '(' + confObj + ')';
|
|
317
|
+
var sandbox = {};
|
|
318
|
+
|
|
319
|
+
return vm.runInThisContext(code, sandbox, {
|
|
320
|
+
filename: path.resolve(filename),
|
|
321
|
+
displayErrors: false,
|
|
322
|
+
timeout: 1000
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
else if (isConfigFile == 'yaml') {
|
|
326
|
+
return yamljs.load(confObj.toString());
|
|
327
|
+
}
|
|
328
|
+
else if (isConfigFile == 'js' || isConfigFile == 'mjs') {
|
|
329
|
+
var confPath = require.resolve(path.resolve(filename));
|
|
330
|
+
delete require.cache[confPath];
|
|
331
|
+
return require(confPath);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
Common.retErr = function(e) {
|
|
336
|
+
if (!e)
|
|
337
|
+
return new Error('Unidentified error');
|
|
338
|
+
if (e instanceof Error)
|
|
339
|
+
return e;
|
|
340
|
+
return new Error(e);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
Common.sink = {};
|
|
344
|
+
|
|
345
|
+
Common.sink.determineCron = function(app) {
|
|
346
|
+
if (app.cron_restart == 0 || app.cron_restart == '0') {
|
|
347
|
+
Common.printOut(cst.PREFIX_MSG + 'disabling cron restart');
|
|
348
|
+
return
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (app.cron_restart) {
|
|
352
|
+
const Croner = require('croner');
|
|
353
|
+
|
|
354
|
+
try {
|
|
355
|
+
Common.printOut(cst.PREFIX_MSG + 'cron restart at ' + app.cron_restart);
|
|
356
|
+
Croner(app.cron_restart);
|
|
357
|
+
} catch(ex) {
|
|
358
|
+
return new Error(`Cron pattern error: ${ex.message}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Handle alias (fork <=> fork_mode, cluster <=> cluster_mode)
|
|
365
|
+
*/
|
|
366
|
+
Common.sink.determineExecMode = function(app) {
|
|
367
|
+
if (app.exec_mode)
|
|
368
|
+
app.exec_mode = app.exec_mode.replace(/^(fork|cluster)$/, '$1_mode');
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Here we put the default exec mode
|
|
372
|
+
*/
|
|
373
|
+
if (!app.exec_mode &&
|
|
374
|
+
(app.instances >= 1 || app.instances === 0 || app.instances === -1) &&
|
|
375
|
+
(app.exec_interpreter.includes('node') === true || app.exec_interpreter.includes('bun') === true)) {
|
|
376
|
+
app.exec_mode = 'cluster_mode';
|
|
377
|
+
} else if (!app.exec_mode) {
|
|
378
|
+
app.exec_mode = 'fork_mode';
|
|
379
|
+
}
|
|
380
|
+
if (typeof app.instances == 'undefined')
|
|
381
|
+
app.instances = 1;
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
var resolveNodeInterpreter = function(app) {
|
|
385
|
+
if (app.exec_mode && app.exec_mode.indexOf('cluster') > -1) {
|
|
386
|
+
Common.printError(cst.PREFIX_MSG_WARNING + chalk.bold.yellow('Choosing the Node.js version in cluster mode is not supported'));
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
var nvm_path = cst.IS_WINDOWS ? process.env.NVM_HOME : process.env.NVM_DIR;
|
|
391
|
+
if (!nvm_path) {
|
|
392
|
+
Common.printError(cst.PREFIX_MSG_ERR + chalk.red('NVM is not available in PATH'));
|
|
393
|
+
Common.printError(cst.PREFIX_MSG_ERR + chalk.red('Fallback to node in PATH'));
|
|
394
|
+
var msg = cst.IS_WINDOWS
|
|
395
|
+
? 'https://github.com/coreybutler/nvm-windows/releases/'
|
|
396
|
+
: '$ curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash';
|
|
397
|
+
Common.printOut(cst.PREFIX_MSG_ERR + chalk.bold('Install NVM:\n' + msg));
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
var node_version = app.exec_interpreter.split('@')[1];
|
|
401
|
+
var path_to_node = cst.IS_WINDOWS
|
|
402
|
+
? '/v' + node_version + '/node.exe'
|
|
403
|
+
: semver.satisfies(node_version, '>= 0.12.0')
|
|
404
|
+
? '/versions/node/v' + node_version + '/bin/node'
|
|
405
|
+
: '/v' + node_version + '/bin/node';
|
|
406
|
+
var nvm_node_path = path.join(nvm_path, path_to_node);
|
|
407
|
+
try {
|
|
408
|
+
fs.accessSync(nvm_node_path);
|
|
409
|
+
} catch(e) {
|
|
410
|
+
Common.printOut(cst.PREFIX_MSG + 'Installing Node v%s', node_version);
|
|
411
|
+
var nvm_bin = path.join(nvm_path, 'nvm.' + (cst.IS_WINDOWS ? 'exe' : 'sh'));
|
|
412
|
+
var nvm_cmd = cst.IS_WINDOWS
|
|
413
|
+
? nvm_bin + ' install ' + node_version
|
|
414
|
+
: '. ' + nvm_bin + ' ; nvm install ' + node_version;
|
|
415
|
+
|
|
416
|
+
Common.printOut(cst.PREFIX_MSG + 'Executing: %s', nvm_cmd);
|
|
417
|
+
|
|
418
|
+
execSync(nvm_cmd, {
|
|
419
|
+
cwd: path.resolve(process.cwd()),
|
|
420
|
+
env: process.env,
|
|
421
|
+
maxBuffer: 20 * 1024 * 1024
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// in order to support both arch, nvm for Windows renames 'node.exe' to:
|
|
425
|
+
// 'node32.exe' for x32 arch
|
|
426
|
+
// 'node64.exe' for x64 arch
|
|
427
|
+
if (cst.IS_WINDOWS)
|
|
428
|
+
nvm_node_path = nvm_node_path.replace(/node/, 'node' + process.arch.slice(1))
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
Common.printOut(cst.PREFIX_MSG + chalk.green.bold('Setting Node to v%s (path=%s)'),
|
|
432
|
+
node_version,
|
|
433
|
+
nvm_node_path);
|
|
434
|
+
|
|
435
|
+
app.exec_interpreter = nvm_node_path;
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Resolve interpreter
|
|
441
|
+
*/
|
|
442
|
+
Common.sink.resolveInterpreter = function(app) {
|
|
443
|
+
var noInterpreter = !app.exec_interpreter;
|
|
444
|
+
var extName = path.extname(app.pm_exec_path);
|
|
445
|
+
var betterInterpreter = extItps[extName];
|
|
446
|
+
|
|
447
|
+
// Bun support
|
|
448
|
+
if (noInterpreter && (extName == '.js' || extName == '.ts') && cst.IS_BUN === true) {
|
|
449
|
+
noInterpreter = false
|
|
450
|
+
app.exec_interpreter = process.execPath;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// No interpreter defined and correspondance in schema hashmap
|
|
454
|
+
if (noInterpreter && betterInterpreter) {
|
|
455
|
+
app.exec_interpreter = betterInterpreter;
|
|
456
|
+
|
|
457
|
+
if (betterInterpreter == "python") {
|
|
458
|
+
if (which('python') == null) {
|
|
459
|
+
if (which('python3') == null)
|
|
460
|
+
Common.printError(cst.PREFIX_MSG_WARNING + chalk.bold.yellow('python and python3 binaries not available in PATH'));
|
|
461
|
+
else
|
|
462
|
+
app.exec_interpreter = 'python3';
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
// Else if no Interpreter detect if process is binary
|
|
467
|
+
else if (noInterpreter) {
|
|
468
|
+
app.exec_interpreter = isBinary(app.pm_exec_path) ? 'none' : process.execPath;
|
|
469
|
+
}
|
|
470
|
+
else if (app.exec_interpreter.indexOf('node@') > -1)
|
|
471
|
+
resolveNodeInterpreter(app);
|
|
472
|
+
|
|
473
|
+
if (app.exec_interpreter.indexOf('python') > -1)
|
|
474
|
+
app.env.PYTHONUNBUFFERED = '1'
|
|
475
|
+
|
|
476
|
+
if (app.exec_interpreter == 'lsc') {
|
|
477
|
+
app.exec_interpreter = path.resolve(__dirname, '../node_modules/.bin/lsc');
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (app.exec_interpreter == 'coffee') {
|
|
481
|
+
app.exec_interpreter = path.resolve(__dirname, '../node_modules/.bin/coffee');
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (app.exec_interpreter != 'none' && which(app.exec_interpreter) == null) {
|
|
485
|
+
// If node is not present
|
|
486
|
+
if (app.exec_interpreter == 'node') {
|
|
487
|
+
Common.warn(`Using builtin node.js version on version ${process.version}`)
|
|
488
|
+
app.exec_interpreter = cst.BUILTIN_NODE_PATH
|
|
489
|
+
}
|
|
490
|
+
else
|
|
491
|
+
throw new Error(`Interpreter ${app.exec_interpreter} is NOT AVAILABLE in PATH. (type 'which ${app.exec_interpreter}' to double check.)`)
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return app;
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
Common.deepCopy = Common.serialize = Common.clone = function(obj) {
|
|
498
|
+
if (obj === null || obj === undefined) return {};
|
|
499
|
+
return fclone(obj);
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
Common.errMod = function(msg) {
|
|
503
|
+
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
|
504
|
+
if (msg instanceof Error)
|
|
505
|
+
return console.error(msg.message);
|
|
506
|
+
return console.error(`${cst.PREFIX_MSG_MOD_ERR}${msg}`);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
Common.err = function(msg) {
|
|
510
|
+
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
|
511
|
+
if (msg instanceof Error)
|
|
512
|
+
return console.error(`${cst.PREFIX_MSG_ERR}${msg.message}`);
|
|
513
|
+
return console.error(`${cst.PREFIX_MSG_ERR}${msg}`);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
Common.printError = function(msg) {
|
|
517
|
+
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
|
518
|
+
if (msg instanceof Error)
|
|
519
|
+
return console.error(msg.message);
|
|
520
|
+
return console.error.apply(console, arguments);
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
Common.log = function(msg) {
|
|
524
|
+
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
|
525
|
+
return console.log(`${cst.PREFIX_MSG}${msg}`);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
Common.info = function(msg) {
|
|
529
|
+
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
|
530
|
+
return console.log(`${cst.PREFIX_MSG_INFO}${msg}`);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
Common.warn = function(msg) {
|
|
534
|
+
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
|
535
|
+
return console.log(`${cst.PREFIX_MSG_WARNING}${msg}`);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
Common.logMod = function(msg) {
|
|
539
|
+
if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
|
540
|
+
return console.log(`${cst.PREFIX_MSG_MOD}${msg}`);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
Common.printOut = function() {
|
|
544
|
+
if (process.env.PM2_SILENT === 'true' || process.env.PM2_PROGRAMMATIC === 'true') return false;
|
|
545
|
+
return console.log.apply(console, arguments);
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Raw extend
|
|
551
|
+
*/
|
|
552
|
+
Common.extend = function(destination, source) {
|
|
553
|
+
if (typeof destination !== 'object') {
|
|
554
|
+
destination = {};
|
|
555
|
+
}
|
|
556
|
+
if (!source || typeof source !== 'object') {
|
|
557
|
+
return destination;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
Object.keys(source).forEach(function(new_key) {
|
|
561
|
+
if (source[new_key] != '[object Object]')
|
|
562
|
+
destination[new_key] = source[new_key];
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
return destination;
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* This is useful when starting script programmatically
|
|
570
|
+
*/
|
|
571
|
+
Common.safeExtend = function(origin, add){
|
|
572
|
+
if (!add || typeof add != 'object') return origin;
|
|
573
|
+
|
|
574
|
+
//Ignore PM2's set environment variables from the nested env
|
|
575
|
+
var keysToIgnore = ['name', 'exec_mode', 'env', 'args', 'pm_cwd', 'exec_interpreter', 'pm_exec_path', 'node_args', 'pm_out_log_path', 'pm_err_log_path', 'pm_pid_path', 'pm_id', 'status', 'pm_uptime', 'created_at', 'windowsHide', 'username', 'merge_logs', 'kill_retry_time', 'prev_restart_delay', 'instance_var', 'unstable_restarts', 'restart_time', 'axm_actions', 'pmx_module', 'command', 'watch', 'filter_env', 'versioning', 'vizion_runing', 'MODULE_DEBUG', 'pmx', 'axm_options', 'created_at', 'watch', 'vizion', 'axm_dynamic', 'axm_monitor', 'instances', 'automation', 'autostart', 'autorestart', 'stop_exit_codes', 'unstable_restart', 'treekill', 'exit_code', 'vizion'];
|
|
576
|
+
|
|
577
|
+
var keys = Object.keys(add);
|
|
578
|
+
var i = keys.length;
|
|
579
|
+
while (i--) {
|
|
580
|
+
//Only copy stuff into the env that we don't have already.
|
|
581
|
+
if(keysToIgnore.indexOf(keys[i]) == -1 && add[keys[i]] != '[object Object]')
|
|
582
|
+
origin[keys[i]] = add[keys[i]];
|
|
583
|
+
}
|
|
584
|
+
return origin;
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Extend the app.env object of with the properties taken from the
|
|
590
|
+
* app.env_[envName] and deploy configuration.
|
|
591
|
+
* Also update current json attributes
|
|
592
|
+
*
|
|
593
|
+
* Used only for Configuration file processing
|
|
594
|
+
*
|
|
595
|
+
* @param {Object} app The app object.
|
|
596
|
+
* @param {string} envName The given environment name.
|
|
597
|
+
* @param {Object} deployConf Deployment configuration object (from JSON file or whatever).
|
|
598
|
+
* @returns {Object} The app.env variables object.
|
|
599
|
+
*/
|
|
600
|
+
Common.mergeEnvironmentVariables = function(app_env, env_name, deploy_conf) {
|
|
601
|
+
var app = fclone(app_env);
|
|
602
|
+
|
|
603
|
+
var new_conf = {
|
|
604
|
+
env : {}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Stringify possible object
|
|
608
|
+
for (var key in app.env) {
|
|
609
|
+
if (typeof app.env[key] == 'object') {
|
|
610
|
+
app.env[key] = JSON.stringify(app.env[key]);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Extra configuration update
|
|
616
|
+
*/
|
|
617
|
+
Object.assign(new_conf, app);
|
|
618
|
+
|
|
619
|
+
if (env_name) {
|
|
620
|
+
// First merge variables from deploy.production.env object as least priority.
|
|
621
|
+
if (deploy_conf && deploy_conf[env_name] && deploy_conf[env_name]['env']) {
|
|
622
|
+
Object.assign(new_conf.env, deploy_conf[env_name]['env']);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
Object.assign(new_conf.env, app.env);
|
|
626
|
+
|
|
627
|
+
// Then, last and highest priority, merge the app.env_production object.
|
|
628
|
+
if ('env_' + env_name in app) {
|
|
629
|
+
Object.assign(new_conf.env, app['env_' + env_name]);
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
Common.printOut(cst.PREFIX_MSG_WARNING + chalk.bold('Environment [%s] is not defined in process file'), env_name);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
delete new_conf.exec_mode
|
|
637
|
+
|
|
638
|
+
var res = {
|
|
639
|
+
current_conf: {}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
Object.assign(res, new_conf.env);
|
|
643
|
+
Object.assign(res.current_conf, new_conf);
|
|
644
|
+
|
|
645
|
+
// #2541 force resolution of node interpreter
|
|
646
|
+
if (app.exec_interpreter &&
|
|
647
|
+
app.exec_interpreter.indexOf('@') > -1) {
|
|
648
|
+
resolveNodeInterpreter(app);
|
|
649
|
+
res.current_conf.exec_interpreter = app.exec_interpreter
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
return res
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* This function will resolve paths, option and environment
|
|
657
|
+
* CALLED before 'prepare' God call (=> PROCESS INITIALIZATION)
|
|
658
|
+
* @method resolveAppAttributes
|
|
659
|
+
* @param {Object} opts
|
|
660
|
+
* @param {Object} opts.cwd
|
|
661
|
+
* @param {Object} opts.pm2_home
|
|
662
|
+
* @param {Object} appConf application configuration
|
|
663
|
+
* @return app
|
|
664
|
+
*/
|
|
665
|
+
Common.resolveAppAttributes = function(opts, conf) {
|
|
666
|
+
var conf_copy = fclone(conf);
|
|
667
|
+
|
|
668
|
+
var app = Common.prepareAppConf(opts, conf_copy);
|
|
669
|
+
if (app instanceof Error) {
|
|
670
|
+
throw new Error(app.message);
|
|
671
|
+
}
|
|
672
|
+
return app;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Verify configurations
|
|
677
|
+
* Called on EVERY Operation (start/restart/reload/stop...)
|
|
678
|
+
* @param {Array} appConfs
|
|
679
|
+
* @returns {Array}
|
|
680
|
+
*/
|
|
681
|
+
Common.verifyConfs = function(appConfs) {
|
|
682
|
+
if (!appConfs || appConfs.length == 0) {
|
|
683
|
+
return [];
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// Make sure it is an Array.
|
|
687
|
+
appConfs = [].concat(appConfs);
|
|
688
|
+
|
|
689
|
+
var verifiedConf = [];
|
|
690
|
+
|
|
691
|
+
for (var i = 0; i < appConfs.length; i++) {
|
|
692
|
+
var app = appConfs[i];
|
|
693
|
+
|
|
694
|
+
if (app.exec_mode)
|
|
695
|
+
app.exec_mode = app.exec_mode.replace(/^(fork|cluster)$/, '$1_mode');
|
|
696
|
+
|
|
697
|
+
// JSON conf: alias cmd to script
|
|
698
|
+
if (app.cmd && !app.script) {
|
|
699
|
+
app.script = app.cmd
|
|
700
|
+
delete app.cmd
|
|
701
|
+
}
|
|
702
|
+
// JSON conf: alias command to script
|
|
703
|
+
if (app.command && !app.script) {
|
|
704
|
+
app.script = app.command
|
|
705
|
+
delete app.command
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
if (!app.env) {
|
|
709
|
+
app.env = {}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// Render an app name if not existing.
|
|
713
|
+
Common.renderApplicationName(app);
|
|
714
|
+
|
|
715
|
+
if (app.execute_command == true) {
|
|
716
|
+
app.exec_mode = 'fork'
|
|
717
|
+
delete app.execute_command
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
app.username = Common.getCurrentUsername();
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* If command is like pm2 start "python xx.py --ok"
|
|
724
|
+
* Then automatically start the script with bash -c and set a name eq to command
|
|
725
|
+
*/
|
|
726
|
+
if (app.script && app.script.indexOf(' ') > -1 && cst.IS_WINDOWS === false) {
|
|
727
|
+
var _script = app.script;
|
|
728
|
+
|
|
729
|
+
if (which('bash')) {
|
|
730
|
+
app.script = 'bash';
|
|
731
|
+
app.args = ['-c', _script];
|
|
732
|
+
if (!app.name) {
|
|
733
|
+
app.name = _script
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
else if (which('sh')) {
|
|
737
|
+
app.script = 'sh';
|
|
738
|
+
app.args = ['-c', _script];
|
|
739
|
+
if (!app.name) {
|
|
740
|
+
app.name = _script
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
else {
|
|
744
|
+
warn('bash or sh not available in $PATH, keeping script as is')
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Add log_date_format by default
|
|
750
|
+
*/
|
|
751
|
+
if (app.time || process.env.ASZ_MODE) {
|
|
752
|
+
app.log_date_format = 'YYYY-MM-DDTHH:mm:ss'
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Checks + Resolve UID/GID
|
|
757
|
+
* comes from pm2 --uid <> --gid <> or --user
|
|
758
|
+
*/
|
|
759
|
+
if (app.uid || app.gid || app.user) {
|
|
760
|
+
// 1/ Check if windows
|
|
761
|
+
if (cst.IS_WINDOWS === true) {
|
|
762
|
+
Common.printError(cst.PREFIX_MSG_ERR + '--uid and --git does not works on windows');
|
|
763
|
+
return new Error('--uid and --git does not works on windows');
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// 2/ Verify that user is root (todo: verify if other has right)
|
|
767
|
+
if (process.env.NODE_ENV != 'test' && process.getuid && process.getuid() !== 0) {
|
|
768
|
+
Common.printError(cst.PREFIX_MSG_ERR + 'To use --uid and --gid please run pm2 as root');
|
|
769
|
+
return new Error('To use UID and GID please run PM2 as root');
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// 3/ Resolve user info via /etc/password
|
|
773
|
+
var passwd = require('./tools/passwd.js')
|
|
774
|
+
var users
|
|
775
|
+
try {
|
|
776
|
+
users = passwd.getUsers()
|
|
777
|
+
} catch(e) {
|
|
778
|
+
Common.printError(e);
|
|
779
|
+
return new Error(e);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
var user_info = users[app.uid || app.user]
|
|
783
|
+
if (!user_info) {
|
|
784
|
+
Common.printError(`${cst.PREFIX_MSG_ERR} User ${app.uid || app.user} cannot be found`);
|
|
785
|
+
return new Error(`${cst.PREFIX_MSG_ERR} User ${app.uid || app.user} cannot be found`);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
app.env.HOME = user_info.homedir
|
|
789
|
+
app.uid = parseInt(user_info.userId)
|
|
790
|
+
|
|
791
|
+
// 4/ Resolve group id if gid is specified
|
|
792
|
+
if (app.gid) {
|
|
793
|
+
var groups
|
|
794
|
+
try {
|
|
795
|
+
groups = passwd.getGroups()
|
|
796
|
+
} catch(e) {
|
|
797
|
+
Common.printError(e);
|
|
798
|
+
return new Error(e);
|
|
799
|
+
}
|
|
800
|
+
var group_info = groups[app.gid]
|
|
801
|
+
if (!group_info) {
|
|
802
|
+
Common.printError(`${cst.PREFIX_MSG_ERR} Group ${app.gid} cannot be found`);
|
|
803
|
+
return new Error(`${cst.PREFIX_MSG_ERR} Group ${app.gid} cannot be found`);
|
|
804
|
+
}
|
|
805
|
+
app.gid = parseInt(group_info.id)
|
|
806
|
+
} else {
|
|
807
|
+
app.gid = parseInt(user_info.groupId)
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* Specific options of PM2.io
|
|
813
|
+
*/
|
|
814
|
+
if (process.env.PM2_DEEP_MONITORING) {
|
|
815
|
+
app.deep_monitoring = true;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
if (app.automation == false) {
|
|
819
|
+
app.pmx = false;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
if (app.disable_trace) {
|
|
823
|
+
app.trace = false
|
|
824
|
+
delete app.disable_trace;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
/**
|
|
828
|
+
* Instances params
|
|
829
|
+
*/
|
|
830
|
+
if (app.instances == 'max') {
|
|
831
|
+
app.instances = 0;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
if (typeof(app.instances) === 'string') {
|
|
835
|
+
app.instances = parseInt(app.instances) || 0;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
if (app.exec_mode != 'cluster_mode' &&
|
|
839
|
+
!app.instances &&
|
|
840
|
+
typeof(app.merge_logs) == 'undefined') {
|
|
841
|
+
app.merge_logs = true;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
var ret;
|
|
845
|
+
|
|
846
|
+
if (app.cron_restart) {
|
|
847
|
+
if ((ret = Common.sink.determineCron(app)) instanceof Error)
|
|
848
|
+
return ret;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Now validation configuration
|
|
853
|
+
*/
|
|
854
|
+
var ret = Config.validateJSON(app);
|
|
855
|
+
if (ret.errors && ret.errors.length > 0){
|
|
856
|
+
ret.errors.forEach(function(err) { warn(err) });
|
|
857
|
+
return new Error(ret.errors);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
verifiedConf.push(ret.config);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
return verifiedConf;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* Get current username
|
|
868
|
+
* Called on EVERY starting app
|
|
869
|
+
*
|
|
870
|
+
* @returns {String}
|
|
871
|
+
*/
|
|
872
|
+
Common.getCurrentUsername = function(){
|
|
873
|
+
var current_user = '';
|
|
874
|
+
|
|
875
|
+
if (os.userInfo) {
|
|
876
|
+
try {
|
|
877
|
+
current_user = os.userInfo().username;
|
|
878
|
+
} catch (err) {
|
|
879
|
+
// For the case of unhandled error for uv_os_get_passwd
|
|
880
|
+
// https://github.com/Unitech/pm2/issues/3184
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
if(current_user === '') {
|
|
885
|
+
current_user = process.env.USER || process.env.LNAME || process.env.USERNAME || process.env.SUDO_USER || process.env.C9_USER || process.env.LOGNAME;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
return current_user;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Render an app name if not existing.
|
|
893
|
+
* @param {Object} conf
|
|
894
|
+
*/
|
|
895
|
+
Common.renderApplicationName = function(conf){
|
|
896
|
+
if (!conf.name && conf.script){
|
|
897
|
+
conf.name = conf.script !== undefined ? path.basename(conf.script) : 'undefined';
|
|
898
|
+
var lastDot = conf.name.lastIndexOf('.');
|
|
899
|
+
if (lastDot > 0){
|
|
900
|
+
conf.name = conf.name.slice(0, lastDot);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* Show warnings
|
|
907
|
+
* @param {String} warning
|
|
908
|
+
*/
|
|
909
|
+
function warn(warning){
|
|
910
|
+
Common.printOut(cst.PREFIX_MSG_WARNING + warning);
|
|
911
|
+
}
|