@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
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
|
|
2
|
+
var Common = require('../Common.js');
|
|
3
|
+
var cst = require('../../constants.js');
|
|
4
|
+
var UX = require('./UX');
|
|
5
|
+
var chalk = require('ansis');
|
|
6
|
+
var Configuration = require('../Configuration.js');
|
|
7
|
+
|
|
8
|
+
module.exports = function(CLI) {
|
|
9
|
+
|
|
10
|
+
CLI.prototype.get = function(key, cb) {
|
|
11
|
+
var that = this;
|
|
12
|
+
|
|
13
|
+
if (!key || key == 'all') {
|
|
14
|
+
displayConf(function(err, data) {
|
|
15
|
+
if (err)
|
|
16
|
+
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
|
17
|
+
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
|
18
|
+
});
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
Configuration.get(key, function(err, data) {
|
|
22
|
+
if (err) {
|
|
23
|
+
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
|
24
|
+
}
|
|
25
|
+
// pm2 conf module-name
|
|
26
|
+
if (key.indexOf(':') === -1 && key.indexOf('.') === -1) {
|
|
27
|
+
displayConf(key, function() {
|
|
28
|
+
console.log('Modules configuration. Copy/Paste line to edit values.')
|
|
29
|
+
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT)
|
|
30
|
+
});
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
// pm2 conf module-name:key
|
|
34
|
+
var module_name, key_name;
|
|
35
|
+
|
|
36
|
+
if (key.indexOf(':') > -1) {
|
|
37
|
+
module_name = key.split(':')[0];
|
|
38
|
+
key_name = key.split(':')[1];
|
|
39
|
+
} else if (key.indexOf('.') > -1) {
|
|
40
|
+
module_name = key.split('.')[0];
|
|
41
|
+
key_name = key.split('.')[1];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Common.printOut('Value for module ' + chalk.blue(module_name), 'key ' + chalk.blue(key_name) + ': ' + chalk.bold.green(data));
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
CLI.prototype.set = function(key, value, cb) {
|
|
52
|
+
var that = this;
|
|
53
|
+
|
|
54
|
+
if (!key) {
|
|
55
|
+
interactiveConfigEdit(function(err) {
|
|
56
|
+
if (err)
|
|
57
|
+
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
|
58
|
+
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
|
59
|
+
});
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Set value
|
|
65
|
+
*/
|
|
66
|
+
Configuration.set(key, value, function(err) {
|
|
67
|
+
if (err)
|
|
68
|
+
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
|
69
|
+
|
|
70
|
+
var values = [];
|
|
71
|
+
|
|
72
|
+
if (key.indexOf('.') > -1)
|
|
73
|
+
values = key.split('.');
|
|
74
|
+
|
|
75
|
+
if (key.indexOf(':') > -1)
|
|
76
|
+
values = key.split(':');
|
|
77
|
+
|
|
78
|
+
if (values && values.length > 1) {
|
|
79
|
+
// The first element is the app name (module_conf.json)
|
|
80
|
+
var app_name = values[0];
|
|
81
|
+
|
|
82
|
+
process.env.PM2_PROGRAMMATIC = 'true';
|
|
83
|
+
that.restart(app_name, {
|
|
84
|
+
updateEnv : true
|
|
85
|
+
}, function(err, data) {
|
|
86
|
+
process.env.PM2_PROGRAMMATIC = 'false';
|
|
87
|
+
if (!err)
|
|
88
|
+
Common.printOut(cst.PREFIX_MSG + 'Module %s restarted', app_name);
|
|
89
|
+
Common.log('Setting changed')
|
|
90
|
+
displayConf(app_name, function() {
|
|
91
|
+
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
displayConf(null, function() {
|
|
97
|
+
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
CLI.prototype.multiset = function(serial, cb) {
|
|
103
|
+
var that = this;
|
|
104
|
+
|
|
105
|
+
Configuration.multiset(serial, function(err, data) {
|
|
106
|
+
if (err)
|
|
107
|
+
return cb ? cb({success:false, err:err}) : that.exitCli(cst.ERROR_EXIT);
|
|
108
|
+
|
|
109
|
+
var values = [];
|
|
110
|
+
var key = serial.match(/(?:[^ "]+|"[^"]*")+/g)[0];
|
|
111
|
+
|
|
112
|
+
if (key.indexOf('.') > -1)
|
|
113
|
+
values = key.split('.');
|
|
114
|
+
|
|
115
|
+
if (key.indexOf(':') > -1)
|
|
116
|
+
values = key.split(':');
|
|
117
|
+
|
|
118
|
+
if (values && values.length > 1) {
|
|
119
|
+
// The first element is the app name (module_conf.json)
|
|
120
|
+
var app_name = values[0];
|
|
121
|
+
|
|
122
|
+
process.env.PM2_PROGRAMMATIC = 'true';
|
|
123
|
+
that.restart(app_name, {
|
|
124
|
+
updateEnv : true
|
|
125
|
+
}, function(err, data) {
|
|
126
|
+
process.env.PM2_PROGRAMMATIC = 'false';
|
|
127
|
+
if (!err)
|
|
128
|
+
Common.printOut(cst.PREFIX_MSG + 'Module %s restarted', app_name);
|
|
129
|
+
displayConf(app_name, function() {
|
|
130
|
+
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT)
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
displayConf(app_name, function() {
|
|
136
|
+
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT)
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
CLI.prototype.unset = function(key, cb) {
|
|
142
|
+
var that = this;
|
|
143
|
+
|
|
144
|
+
Configuration.unset(key, function(err) {
|
|
145
|
+
if (err) {
|
|
146
|
+
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
displayConf(function() { cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT) });
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
CLI.prototype.conf = function(key, value, cb) {
|
|
154
|
+
var that = this;
|
|
155
|
+
|
|
156
|
+
if (typeof(value) === 'function') {
|
|
157
|
+
cb = value;
|
|
158
|
+
value = null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// If key + value = set
|
|
162
|
+
if (key && value) {
|
|
163
|
+
that.set(key, value, function(err) {
|
|
164
|
+
if (err)
|
|
165
|
+
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
|
166
|
+
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// If only key = get
|
|
170
|
+
else if (key) {
|
|
171
|
+
that.get(key, function(err, data) {
|
|
172
|
+
if (err)
|
|
173
|
+
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
|
174
|
+
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
interactiveConfigEdit(function(err) {
|
|
179
|
+
if (err)
|
|
180
|
+
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
|
|
181
|
+
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
function interactiveConfigEdit(cb) {
|
|
189
|
+
UX.helpers.openEditor(cst.PM2_MODULE_CONF_FILE, function(err, data) {
|
|
190
|
+
Common.printOut(chalk.bold('Module configuration (%s) edited.'), cst.PM2_MODULE_CONF_FILE);
|
|
191
|
+
Common.printOut(chalk.bold('To take changes into account, please restart module related.'), cst.PM2_MODULE_CONF_FILE);
|
|
192
|
+
if (err)
|
|
193
|
+
return cb(Common.retErr(err));
|
|
194
|
+
return cb(null, {success:true});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Configuration
|
|
201
|
+
*/
|
|
202
|
+
function displayConf(target_app, cb) {
|
|
203
|
+
if (typeof(target_app) == 'function') {
|
|
204
|
+
cb = target_app;
|
|
205
|
+
target_app = null;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
Configuration.getAll(function(err, data) {
|
|
209
|
+
UX.helpers.dispKeys(data, target_app);
|
|
210
|
+
return cb();
|
|
211
|
+
});
|
|
212
|
+
}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
|
|
2
|
+
var spawn = require('child_process').spawn;
|
|
3
|
+
var exec = require('child_process').exec;
|
|
4
|
+
var chalk = require('ansis');
|
|
5
|
+
var util = require('util');
|
|
6
|
+
var fmt = require('../tools/fmt.js');
|
|
7
|
+
var fs = require('fs');
|
|
8
|
+
var path = require('path');
|
|
9
|
+
var cst = require('../../constants.js');
|
|
10
|
+
var Promise = require('../tools/promise.min.js');
|
|
11
|
+
|
|
12
|
+
function pspawn(cmd) {
|
|
13
|
+
return new Promise(function(resolve, reject) {
|
|
14
|
+
var p_cmd = cmd.split(' ');
|
|
15
|
+
|
|
16
|
+
var install_instance = spawn(p_cmd[0], p_cmd.splice(1, cmd.length), {
|
|
17
|
+
stdio : 'inherit',
|
|
18
|
+
env : process.env,
|
|
19
|
+
shell : true
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
install_instance.on('close', function(code) {
|
|
23
|
+
if (code != 0) {
|
|
24
|
+
console.log(chalk.bold.red('Command failed'));
|
|
25
|
+
return reject(new Error('Bad cmd return'));
|
|
26
|
+
}
|
|
27
|
+
return resolve();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
install_instance.on('error', function (err) {
|
|
31
|
+
return reject(err);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function checkDockerSetup() {
|
|
37
|
+
return new Promise(function(resolve, reject) {
|
|
38
|
+
exec("docker version -f '{{.Client.Version}}'", function(err, stdout, stderr) {
|
|
39
|
+
if (err) {
|
|
40
|
+
console.error(chalk.red.bold('[Docker access] Error while trying to use docker command'));
|
|
41
|
+
if (err.message && err.message.indexOf('Cannot connect to the Docker') > -1) {
|
|
42
|
+
console.log();
|
|
43
|
+
console.log(chalk.blue.bold('[Solution] Setup Docker to be able to be used without sudo rights:'));
|
|
44
|
+
console.log(chalk.bold('$ sudo groupadd docker'));
|
|
45
|
+
console.log(chalk.bold('$ sudo usermod -aG docker $USER'));
|
|
46
|
+
console.log(chalk.bold('Then LOGOUT and LOGIN your Linux session'));
|
|
47
|
+
console.log('Read more: http://bit.ly/29JGdCE');
|
|
48
|
+
}
|
|
49
|
+
return reject(err);
|
|
50
|
+
}
|
|
51
|
+
return resolve();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Switch Dockerfile mode
|
|
58
|
+
* check test/programmatic/containerizer.mocha.js
|
|
59
|
+
*/
|
|
60
|
+
function parseAndSwitch(file_content, main_file, opts) {
|
|
61
|
+
var lines = file_content.split('\n');
|
|
62
|
+
var mode = opts.mode;
|
|
63
|
+
|
|
64
|
+
lines[0] = 'FROM keymetrics/pm2:' + opts.node_version;
|
|
65
|
+
|
|
66
|
+
for (var i = 0; i < lines.length; i++) {
|
|
67
|
+
var line = lines[i];
|
|
68
|
+
|
|
69
|
+
if (['## DISTRIBUTION MODE', '## DEVELOPMENT MODE'].indexOf(line) > -1 ||
|
|
70
|
+
i == lines.length - 1) {
|
|
71
|
+
lines.splice(i, lines.length);
|
|
72
|
+
lines[i] = '## ' + mode.toUpperCase() + ' MODE';
|
|
73
|
+
lines[i + 1] = 'ENV NODE_ENV=' + (mode == 'distribution' ? 'production' : mode);
|
|
74
|
+
|
|
75
|
+
if (mode == 'distribution') {
|
|
76
|
+
lines[i + 2] = 'COPY . /var/app';
|
|
77
|
+
lines[i + 3] = 'CMD ["pm2-docker", "' + main_file + '", "--env", "production"]';
|
|
78
|
+
}
|
|
79
|
+
if (mode == 'development') {
|
|
80
|
+
lines[i + 2] = 'CMD ["pm2-dev", "' + main_file + '", "--env", "development"]';
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
lines = lines.join('\n');
|
|
86
|
+
return lines;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Replace ENV, COPY and CMD depending on the mode
|
|
91
|
+
* @param {String} docker_filepath Dockerfile absolute path
|
|
92
|
+
* @param {String} main_file Main file to start in container
|
|
93
|
+
* @param {String} mode Mode to switch the Dockerfile
|
|
94
|
+
*/
|
|
95
|
+
function switchDockerFile(docker_filepath, main_file, opts) {
|
|
96
|
+
return new Promise(function(resolve, reject) {
|
|
97
|
+
var data = fs.readFileSync(docker_filepath, 'utf8').toString();
|
|
98
|
+
|
|
99
|
+
if (['distribution', 'development'].indexOf(opts.mode) == -1)
|
|
100
|
+
return reject(new Error('Unknown mode'));
|
|
101
|
+
|
|
102
|
+
var lines = parseAndSwitch(data, main_file, opts)
|
|
103
|
+
fs.writeFile(docker_filepath, lines, function(err) {
|
|
104
|
+
if (err) return reject(err);
|
|
105
|
+
resolve({
|
|
106
|
+
Dockerfile_path : docker_filepath,
|
|
107
|
+
Dockerfile : lines,
|
|
108
|
+
CMD : ''
|
|
109
|
+
});
|
|
110
|
+
})
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Generate sample Dockerfile (lib/templates/Dockerfiles)
|
|
116
|
+
* @param {String} docker_filepath Dockerfile absolute path
|
|
117
|
+
* @param {String} main_file Main file to start in container
|
|
118
|
+
* @param {String} mode Mode to switch the Dockerfile
|
|
119
|
+
*/
|
|
120
|
+
function generateDockerfile(docker_filepath, main_file, opts) {
|
|
121
|
+
return new Promise(function(resolve, reject) {
|
|
122
|
+
var tpl_file = path.join(cst.TEMPLATE_FOLDER, cst.DOCKERFILE_NODEJS);
|
|
123
|
+
var template = fs.readFileSync(tpl_file, {encoding: 'utf8'});
|
|
124
|
+
var CMD;
|
|
125
|
+
|
|
126
|
+
template = parseAndSwitch(template, main_file, opts);
|
|
127
|
+
|
|
128
|
+
fs.writeFile(docker_filepath, template, function(err) {
|
|
129
|
+
if (err) return reject(err);
|
|
130
|
+
resolve({
|
|
131
|
+
Dockerfile_path : docker_filepath,
|
|
132
|
+
Dockerfile : template,
|
|
133
|
+
CMD : CMD
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function handleExit(CLI, opts, mode) {
|
|
140
|
+
process.on('SIGINT', function() {
|
|
141
|
+
CLI.disconnect();
|
|
142
|
+
|
|
143
|
+
if (mode != 'distribution')
|
|
144
|
+
return false;
|
|
145
|
+
|
|
146
|
+
exec('docker ps -lq', function(err, stdout, stderr) {
|
|
147
|
+
if (err) {
|
|
148
|
+
console.error(err);
|
|
149
|
+
}
|
|
150
|
+
require('vizion').analyze({folder : process.cwd()}, function recur_path(err, meta){
|
|
151
|
+
if (!err && meta.revision) {
|
|
152
|
+
var commit_id = util.format('#%s(%s) %s',
|
|
153
|
+
meta.branch,
|
|
154
|
+
meta.revision.slice(0, 5),
|
|
155
|
+
meta.comment);
|
|
156
|
+
|
|
157
|
+
console.log(chalk.bold.magenta('$ docker commit -m "%s" %s %s'),
|
|
158
|
+
commit_id,
|
|
159
|
+
stdout.replace('\n', ''),
|
|
160
|
+
opts.imageName);
|
|
161
|
+
}
|
|
162
|
+
else
|
|
163
|
+
console.log(chalk.bold.magenta('$ docker commit %s %s'), stdout.replace('\n', ''), opts.imageName);
|
|
164
|
+
|
|
165
|
+
console.log(chalk.bold.magenta('$ docker push %s'), opts.imageName);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
module.exports = function(CLI) {
|
|
172
|
+
CLI.prototype.generateDockerfile = function(script, opts) {
|
|
173
|
+
var docker_filepath = path.join(process.cwd(), 'Dockerfile');
|
|
174
|
+
var that = this;
|
|
175
|
+
|
|
176
|
+
fs.stat(docker_filepath, function(err, stat) {
|
|
177
|
+
if (err || opts.force == true) {
|
|
178
|
+
generateDockerfile(docker_filepath, script, {
|
|
179
|
+
mode : 'development'
|
|
180
|
+
})
|
|
181
|
+
.then(function() {
|
|
182
|
+
console.log(chalk.bold('New Dockerfile generated in current folder'));
|
|
183
|
+
console.log(chalk.bold('You can now run\n$ pm2 docker:dev <file|config>'));
|
|
184
|
+
return that.exitCli(cst.SUCCESS_EXIT);
|
|
185
|
+
});
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
console.log(chalk.red.bold('Dockerfile already exists in this folder, use --force if you want to replace it'));
|
|
189
|
+
that.exitCli(cst.ERROR_EXIT);
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
CLI.prototype.dockerMode = function(script, opts, mode) {
|
|
194
|
+
var promptly = require('promptly');
|
|
195
|
+
var self = this;
|
|
196
|
+
handleExit(self, opts, mode);
|
|
197
|
+
|
|
198
|
+
if (mode == 'distribution' && !opts.imageName) {
|
|
199
|
+
console.error(chalk.bold.red('--image-name [name] option is missing'));
|
|
200
|
+
return self.exitCli(cst.ERROR_EXIT);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
var template;
|
|
204
|
+
var app_path, main_script;
|
|
205
|
+
var image_name;
|
|
206
|
+
var node_version = opts.nodeVersion ? opts.nodeVersion.split('.')[0] : 'latest';
|
|
207
|
+
|
|
208
|
+
image_name = opts.imageName || require('crypto').randomBytes(6).toString('hex');
|
|
209
|
+
|
|
210
|
+
if (script.indexOf('/') > -1) {
|
|
211
|
+
app_path = path.join(process.cwd(), path.dirname(script));
|
|
212
|
+
main_script = path.basename(script);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
app_path = process.cwd();
|
|
216
|
+
main_script = script;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
checkDockerSetup()
|
|
220
|
+
.then(function() {
|
|
221
|
+
/////////////////////////
|
|
222
|
+
// Generate Dockerfile //
|
|
223
|
+
/////////////////////////
|
|
224
|
+
return new Promise(function(resolve, reject) {
|
|
225
|
+
var docker_filepath = path.join(process.cwd(), 'Dockerfile');
|
|
226
|
+
|
|
227
|
+
fs.stat(docker_filepath, function(err, stat) {
|
|
228
|
+
if (err) {
|
|
229
|
+
// Dockerfile does not exist, generate one
|
|
230
|
+
// console.log(chalk.blue.bold('Generating new Dockerfile'));
|
|
231
|
+
if (opts.force == true) {
|
|
232
|
+
return resolve(generateDockerfile(docker_filepath, main_script, {
|
|
233
|
+
node_version : node_version,
|
|
234
|
+
mode : mode
|
|
235
|
+
}));
|
|
236
|
+
}
|
|
237
|
+
if (opts.dockerdaemon)
|
|
238
|
+
return resolve(generateDockerfile(docker_filepath, main_script, {
|
|
239
|
+
node_version : node_version,
|
|
240
|
+
mode : mode
|
|
241
|
+
}));
|
|
242
|
+
promptly.prompt('No Dockerfile in current directory, ok to generate a new one? (y/n)', function(err, value) {
|
|
243
|
+
if (value == 'y')
|
|
244
|
+
return resolve(generateDockerfile(docker_filepath, main_script, {
|
|
245
|
+
node_version : node_version,
|
|
246
|
+
mode : mode
|
|
247
|
+
}));
|
|
248
|
+
else
|
|
249
|
+
return self.exitCli(cst.SUCCESS_EXIT);
|
|
250
|
+
});
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
return resolve(switchDockerFile(docker_filepath, main_script, {
|
|
254
|
+
node_version : node_version,
|
|
255
|
+
mode : mode
|
|
256
|
+
}));
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
})
|
|
260
|
+
.then(function(_template) {
|
|
261
|
+
template = _template;
|
|
262
|
+
return Promise.resolve();
|
|
263
|
+
})
|
|
264
|
+
.then(function() {
|
|
265
|
+
//////////////////
|
|
266
|
+
// Docker build //
|
|
267
|
+
//////////////////
|
|
268
|
+
|
|
269
|
+
var docker_build = util.format('docker build -t %s -f %s',
|
|
270
|
+
image_name,
|
|
271
|
+
template.Dockerfile_path);
|
|
272
|
+
|
|
273
|
+
if (opts.fresh == true)
|
|
274
|
+
docker_build += ' --no-cache';
|
|
275
|
+
docker_build += ' .';
|
|
276
|
+
|
|
277
|
+
console.log();
|
|
278
|
+
fmt.sep();
|
|
279
|
+
fmt.title('Building Boot System');
|
|
280
|
+
fmt.field('Type', chalk.cyan.bold('Docker'));
|
|
281
|
+
fmt.field('Mode', mode);
|
|
282
|
+
fmt.field('Image name', image_name);
|
|
283
|
+
fmt.field('Docker build command', docker_build);
|
|
284
|
+
fmt.field('Dockerfile path', template.Dockerfile_path);
|
|
285
|
+
fmt.sep();
|
|
286
|
+
|
|
287
|
+
return pspawn(docker_build);
|
|
288
|
+
})
|
|
289
|
+
.then(function() {
|
|
290
|
+
////////////////
|
|
291
|
+
// Docker run //
|
|
292
|
+
////////////////
|
|
293
|
+
|
|
294
|
+
var docker_run = 'docker run --net host';
|
|
295
|
+
|
|
296
|
+
if (opts.dockerdaemon == true)
|
|
297
|
+
docker_run += ' -d';
|
|
298
|
+
if (mode != 'distribution')
|
|
299
|
+
docker_run += util.format(' -v %s:/var/app -v /var/app/node_modules', app_path);
|
|
300
|
+
docker_run += ' ' + image_name;
|
|
301
|
+
var dockerfile_parsed = template.Dockerfile.split('\n');
|
|
302
|
+
var base_image = dockerfile_parsed[0];
|
|
303
|
+
var run_cmd = dockerfile_parsed[dockerfile_parsed.length - 1];
|
|
304
|
+
|
|
305
|
+
console.log();
|
|
306
|
+
fmt.sep();
|
|
307
|
+
fmt.title('Booting');
|
|
308
|
+
fmt.field('Type', chalk.cyan.bold('Docker'));
|
|
309
|
+
fmt.field('Mode', mode);
|
|
310
|
+
fmt.field('Base Image', base_image);
|
|
311
|
+
fmt.field('Image Name', image_name);
|
|
312
|
+
fmt.field('Docker Command', docker_run);
|
|
313
|
+
fmt.field('RUN Command', run_cmd);
|
|
314
|
+
fmt.field('CWD', app_path);
|
|
315
|
+
fmt.sep();
|
|
316
|
+
return pspawn(docker_run);
|
|
317
|
+
})
|
|
318
|
+
.then(function() {
|
|
319
|
+
console.log(chalk.blue.bold('>>> Leaving Docker instance uuid=%s'), image_name);
|
|
320
|
+
self.disconnect();
|
|
321
|
+
return Promise.resolve();
|
|
322
|
+
})
|
|
323
|
+
.catch(function(err) {
|
|
324
|
+
console.log();
|
|
325
|
+
console.log(chalk.gray('Raw error=', err.message));
|
|
326
|
+
self.disconnect();
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
module.exports.generateDockerfile = generateDockerfile;
|
|
334
|
+
module.exports.parseAndSwitch = parseAndSwitch;
|
|
335
|
+
module.exports.switchDockerFile = switchDockerFile;
|