underpost 2.8.885 → 2.8.886
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/.env.production +3 -0
- package/.github/workflows/ghpkg.ci.yml +1 -1
- package/.github/workflows/npmpkg.ci.yml +1 -1
- package/.github/workflows/publish.ci.yml +5 -5
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -1
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/CHANGELOG.md +145 -1
- package/Dockerfile +1 -1
- package/README.md +3 -3
- package/bin/build.js +18 -9
- package/bin/deploy.js +93 -187
- package/cli.md +2 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +54 -54
- package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
- package/manifests/lxd/underpost-setup.sh +5 -5
- package/package.json +3 -3
- package/scripts/ssl.sh +164 -0
- package/src/cli/baremetal.js +7 -7
- package/src/cli/cloud-init.js +1 -1
- package/src/cli/cluster.js +10 -3
- package/src/cli/cron.js +1 -1
- package/src/cli/db.js +1 -1
- package/src/cli/deploy.js +33 -1
- package/src/cli/fs.js +2 -2
- package/src/cli/image.js +7 -0
- package/src/cli/monitor.js +33 -1
- package/src/cli/run.js +315 -51
- package/src/cli/script.js +32 -0
- package/src/cli/secrets.js +34 -0
- package/src/cli/test.js +42 -1
- package/src/client/components/core/Css.js +0 -8
- package/src/client/components/core/windowGetDimensions.js +229 -162
- package/src/index.js +2 -2
- package/src/mailer/MailerProvider.js +1 -0
- package/src/runtime/express/Express.js +12 -4
- package/src/runtime/lampp/Dockerfile +1 -1
- package/src/server/backup.js +20 -0
- package/src/server/client-build-live.js +12 -10
- package/src/server/client-build.js +136 -91
- package/src/server/client-dev-server.js +16 -2
- package/src/server/client-icons.js +19 -0
- package/src/server/conf.js +470 -60
- package/src/server/dns.js +184 -42
- package/src/server/downloader.js +65 -24
- package/src/server/object-layer.js +260 -162
- package/src/server/peer.js +2 -8
- package/src/server/proxy.js +93 -76
- package/src/server/runtime.js +15 -16
- package/src/server/ssr.js +4 -4
- package/src/server/tls.js +251 -0
- package/src/server/valkey.js +11 -10
- package/src/ws/IoInterface.js +2 -1
- package/src/ws/IoServer.js +2 -1
- package/src/ws/core/core.ws.connection.js +1 -1
- package/src/ws/core/core.ws.emit.js +1 -1
- package/src/ws/core/core.ws.server.js +1 -1
- package/manifests/maas/lxd-preseed.yaml +0 -32
- package/src/server/ssl.js +0 -108
- /package/{manifests/maas → scripts}/device-scan.sh +0 -0
- /package/{manifests/maas → scripts}/gpu-diag.sh +0 -0
- /package/{manifests/maas → scripts}/maas-setup.sh +0 -0
- /package/{manifests/maas → scripts}/nat-iptables.sh +0 -0
- /package/{manifests/maas → scripts}/nvim.sh +0 -0
- /package/{manifests/maas → scripts}/snap-clean.sh +0 -0
- /package/{manifests/maas → scripts}/ssh-cluster-info.sh +0 -0
package/src/cli/run.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description The main entry point for the Underpost CLI applications.
|
|
3
|
+
* @module src/cli/run.js
|
|
4
|
+
* @namespace UnderpostRun
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import { daemonProcess, getTerminalPid, openTerminal, pbcopy, shellCd, shellExec } from '../server/process.js';
|
|
2
|
-
import
|
|
3
|
-
import { getNpmRootPath } from '../server/conf.js';
|
|
8
|
+
import { getNpmRootPath, isDeployRunnerContext } from '../server/conf.js';
|
|
4
9
|
import { actionInitLog, loggerFactory } from '../server/logger.js';
|
|
5
10
|
import UnderpostTest from './test.js';
|
|
6
11
|
import fs from 'fs-extra';
|
|
@@ -12,7 +17,33 @@ import os from 'os';
|
|
|
12
17
|
|
|
13
18
|
const logger = loggerFactory(import.meta);
|
|
14
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @class UnderpostRun
|
|
22
|
+
* @description Manages the execution of various CLI commands and operations.
|
|
23
|
+
* This class provides a set of static methods to perform different tasks
|
|
24
|
+
* such as running tests, deploying applications, managing environment variables,
|
|
25
|
+
* and more. It also includes a default option configuration and a collection of
|
|
26
|
+
* runners for executing specific commands.
|
|
27
|
+
* @memberof UnderpostRun
|
|
28
|
+
*/
|
|
15
29
|
class UnderpostRun {
|
|
30
|
+
/**
|
|
31
|
+
* @static
|
|
32
|
+
* @description Default options for the UnderpostRun class.
|
|
33
|
+
* @type {Object}
|
|
34
|
+
* @property {boolean} dev - Whether to run in development mode.
|
|
35
|
+
* @property {string} podName - The name of the pod to run.
|
|
36
|
+
* @property {string} volumeHostPath - The host path for the volume.
|
|
37
|
+
* @property {string} volumeMountPath - The mount path for the volume.
|
|
38
|
+
* @property {string} imageName - The name of the image to run.
|
|
39
|
+
* @property {string} containerName - The name of the container to run.
|
|
40
|
+
* @property {string} namespace - The namespace to run in.
|
|
41
|
+
* @property {boolean} build - Whether to build the image.
|
|
42
|
+
* @property {number} replicas - The number of replicas to run.
|
|
43
|
+
* @property {boolean} k3s - Whether to run in k3s mode.
|
|
44
|
+
* @property {boolean} kubeadm - Whether to run in kubeadm mode.
|
|
45
|
+
* @memberof UnderpostRun
|
|
46
|
+
*/
|
|
16
47
|
static DEFAULT_OPTION = {
|
|
17
48
|
dev: false,
|
|
18
49
|
podName: '',
|
|
@@ -26,7 +57,20 @@ class UnderpostRun {
|
|
|
26
57
|
k3s: false,
|
|
27
58
|
kubeadm: false,
|
|
28
59
|
};
|
|
60
|
+
/**
|
|
61
|
+
* @static
|
|
62
|
+
* @description Collection of runners for executing specific commands.
|
|
63
|
+
* @type {Object}
|
|
64
|
+
* @memberof UnderpostRun
|
|
65
|
+
*/
|
|
29
66
|
static RUNNERS = {
|
|
67
|
+
/**
|
|
68
|
+
* @method spark-template
|
|
69
|
+
* @description Creates a new Spark template project using `sbt new` in `/home/dd/spark-template`, initializes a Git repository, and runs `replace_params.sh` and `build.sh`.
|
|
70
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
71
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
72
|
+
* @memberof UnderpostRun
|
|
73
|
+
*/
|
|
30
74
|
'spark-template': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
31
75
|
const dir = '/home/dd/spark-template';
|
|
32
76
|
shellExec(`sudo rm -rf ${dir}`);
|
|
@@ -47,12 +91,33 @@ class UnderpostRun {
|
|
|
47
91
|
|
|
48
92
|
shellCd('/home/dd/engine');
|
|
49
93
|
},
|
|
94
|
+
/**
|
|
95
|
+
* @method rmi
|
|
96
|
+
* @description Forces the removal of all local Podman images (`podman rmi $(podman images -qa) --force`).
|
|
97
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
98
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
99
|
+
* @memberof UnderpostRun
|
|
100
|
+
*/
|
|
50
101
|
rmi: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
51
102
|
shellExec(`podman rmi $(podman images -qa) --force`);
|
|
52
103
|
},
|
|
104
|
+
/**
|
|
105
|
+
* @method kill
|
|
106
|
+
* @description Kills the process running on the specified port by finding its PID using `lsof -t -i:${path}`.
|
|
107
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the port number).
|
|
108
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
109
|
+
* @memberof UnderpostRun
|
|
110
|
+
*/
|
|
53
111
|
kill: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
54
112
|
shellExec(`sudo kill -9 $(lsof -t -i:${path})`);
|
|
55
113
|
},
|
|
114
|
+
/**
|
|
115
|
+
* @method secret
|
|
116
|
+
* @description Creates an Underpost secret named 'underpost' from a file, defaulting to `/home/dd/engine/engine-private/conf/dd-cron/.env.production` if no path is provided.
|
|
117
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the optional path to the secret file).
|
|
118
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
119
|
+
* @memberof UnderpostRun
|
|
120
|
+
*/
|
|
56
121
|
secret: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
57
122
|
shellExec(
|
|
58
123
|
`underpost secret underpost --create-from-file ${
|
|
@@ -60,20 +125,48 @@ class UnderpostRun {
|
|
|
60
125
|
}`,
|
|
61
126
|
);
|
|
62
127
|
},
|
|
128
|
+
/**
|
|
129
|
+
* @method underpost-config
|
|
130
|
+
* @description Calls `UnderpostDeploy.API.configMap` to create a Kubernetes ConfigMap, defaulting to the 'production' environment.
|
|
131
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the optional configuration name/environment).
|
|
132
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
133
|
+
* @memberof UnderpostRun
|
|
134
|
+
*/
|
|
63
135
|
'underpost-config': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
64
136
|
UnderpostDeploy.API.configMap(path ?? 'production');
|
|
65
137
|
},
|
|
138
|
+
/**
|
|
139
|
+
* @method gpu-env
|
|
140
|
+
* @description Sets up a dedicated GPU development environment cluster, resetting and then setting up the cluster with `--dedicated-gpu` and monitoring the pods.
|
|
141
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
142
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
143
|
+
* @memberof UnderpostRun
|
|
144
|
+
*/
|
|
66
145
|
'gpu-env': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
67
146
|
shellExec(
|
|
68
147
|
`node bin cluster --dev --reset && node bin cluster --dev --dedicated-gpu --kubeadm && kubectl get pods --all-namespaces -o wide -w`,
|
|
69
148
|
);
|
|
70
149
|
},
|
|
150
|
+
/**
|
|
151
|
+
* @method tf-gpu-test
|
|
152
|
+
* @description Deletes existing `tf-gpu-test-script` ConfigMap and `tf-gpu-test-pod`, and applies the test manifest from `manifests/deployment/tensorflow/tf-gpu-test.yaml`.
|
|
153
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
154
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
155
|
+
* @memberof UnderpostRun
|
|
156
|
+
*/
|
|
71
157
|
'tf-gpu-test': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
72
158
|
const { underpostRoot } = options;
|
|
73
159
|
shellExec(`kubectl delete configmap tf-gpu-test-script`);
|
|
74
160
|
shellExec(`kubectl delete pod tf-gpu-test-pod`);
|
|
75
161
|
shellExec(`kubectl apply -f ${underpostRoot}/manifests/deployment/tensorflow/tf-gpu-test.yaml`);
|
|
76
162
|
},
|
|
163
|
+
/**
|
|
164
|
+
* @method dev-cluster
|
|
165
|
+
* @description Resets and deploys a full development cluster including MongoDB, Valkey, exposes services, and updates `/etc/hosts` for local access.
|
|
166
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
167
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
168
|
+
* @memberof UnderpostRun
|
|
169
|
+
*/
|
|
77
170
|
'dev-cluster': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
78
171
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
79
172
|
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --reset`);
|
|
@@ -92,21 +185,64 @@ class UnderpostRun {
|
|
|
92
185
|
logger.info(hostListenResult.renderHosts);
|
|
93
186
|
}
|
|
94
187
|
},
|
|
188
|
+
/**
|
|
189
|
+
* @method ssh-cluster-info
|
|
190
|
+
* @description Executes the `ssh-cluster-info.sh` script to display cluster connection information.
|
|
191
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
192
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
193
|
+
* @memberof UnderpostRun
|
|
194
|
+
*/
|
|
95
195
|
'ssh-cluster-info': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
96
196
|
const { underpostRoot } = options;
|
|
97
|
-
shellExec(`chmod +x ${underpostRoot}/
|
|
98
|
-
shellExec(`${underpostRoot}/
|
|
197
|
+
shellExec(`chmod +x ${underpostRoot}/scripts/ssh-cluster-info.sh`);
|
|
198
|
+
shellExec(`${underpostRoot}/scripts/ssh-cluster-info.sh`);
|
|
99
199
|
},
|
|
200
|
+
/**
|
|
201
|
+
* @method cyberia-ide
|
|
202
|
+
* @description Starts the development environment (IDE) for both `cyberia-server` and `cyberia-client` repositories.
|
|
203
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
204
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
205
|
+
* @memberof UnderpostRun
|
|
206
|
+
*/
|
|
100
207
|
'cyberia-ide': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
101
208
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
102
209
|
shellExec(`${baseCommand} run ide /home/dd/cyberia-server`);
|
|
103
210
|
shellExec(`${baseCommand} run ide /home/dd/cyberia-client`);
|
|
104
211
|
},
|
|
212
|
+
/**
|
|
213
|
+
* @method engine-ide
|
|
214
|
+
* @description Starts the development environment (IDE) for the `engine` and `engine-private` repositories.
|
|
215
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
216
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
217
|
+
* @memberof UnderpostRun
|
|
218
|
+
*/
|
|
105
219
|
'engine-ide': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
106
220
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
107
221
|
shellExec(`${baseCommand} run ide /home/dd/engine`);
|
|
108
222
|
shellExec(`${baseCommand} run ide /home/dd/engine/engine-private`);
|
|
109
223
|
},
|
|
224
|
+
/**
|
|
225
|
+
* @method cluster-build
|
|
226
|
+
* @description Build configuration for cluster deployment.
|
|
227
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
228
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
229
|
+
* @memberof UnderpostRun
|
|
230
|
+
*/
|
|
231
|
+
'cluster-build': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
232
|
+
shellExec(`node bin run clean`);
|
|
233
|
+
shellExec(`node bin run --dev sync-replica template-deploy`);
|
|
234
|
+
shellExec(`node bin run sync-replica template-deploy`);
|
|
235
|
+
shellExec(`node bin env clean`);
|
|
236
|
+
shellExec(`git add . && underpost cmt . build cluster-build`);
|
|
237
|
+
shellExec(`cd engine-private && git add . && underpost cmt . build cluster-build`);
|
|
238
|
+
},
|
|
239
|
+
/**
|
|
240
|
+
* @method template-deploy
|
|
241
|
+
* @description Cleans up, pushes `engine-private` and `engine` repositories with a commit tag `ci package-pwa-microservices-template`.
|
|
242
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
243
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
244
|
+
* @memberof UnderpostRun
|
|
245
|
+
*/
|
|
110
246
|
'template-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
111
247
|
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
112
248
|
shellExec(`${baseCommand} run clean`);
|
|
@@ -116,16 +252,37 @@ class UnderpostRun {
|
|
|
116
252
|
shellExec(`${baseCommand} cmt . --empty ci package-pwa-microservices-template`);
|
|
117
253
|
shellExec(`${baseCommand} push . ${process.env.GITHUB_USERNAME}/engine`);
|
|
118
254
|
},
|
|
255
|
+
/**
|
|
256
|
+
* @method clean
|
|
257
|
+
* @description Changes directory to the provided path (defaulting to `/home/dd/engine`) and runs `node bin/deploy clean-core-repo`.
|
|
258
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the optional directory path).
|
|
259
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
260
|
+
* @memberof UnderpostRun
|
|
261
|
+
*/
|
|
119
262
|
clean: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
120
263
|
shellCd(path ?? `/home/dd/engine`);
|
|
121
264
|
shellExec(`node bin/deploy clean-core-repo`);
|
|
122
265
|
},
|
|
266
|
+
/**
|
|
267
|
+
* @method pull
|
|
268
|
+
* @description Cleans the core repository and pulls the latest content for `engine` and `engine-private` repositories from the remote.
|
|
269
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
270
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
271
|
+
* @memberof UnderpostRun
|
|
272
|
+
*/
|
|
123
273
|
pull: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
124
274
|
shellCd(`/home/dd/engine`);
|
|
125
275
|
shellExec(`node bin/deploy clean-core-repo`);
|
|
126
276
|
shellExec(`underpost pull . ${process.env.GITHUB_USERNAME}/engine`);
|
|
127
277
|
shellExec(`underpost pull ./engine-private ${process.env.GITHUB_USERNAME}/engine-private`);
|
|
128
278
|
},
|
|
279
|
+
/**
|
|
280
|
+
* @method release-deploy
|
|
281
|
+
* @description Executes deployment (`underpost run deploy`) for all deployment IDs listed in `./engine-private/deploy/dd.router`.
|
|
282
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
283
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
284
|
+
* @memberof UnderpostRun
|
|
285
|
+
*/
|
|
129
286
|
'release-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
130
287
|
actionInitLog();
|
|
131
288
|
shellExec(`underpost --version`);
|
|
@@ -135,6 +292,13 @@ class UnderpostRun {
|
|
|
135
292
|
shellExec(`underpost run deploy ${deployId}`, { async: true });
|
|
136
293
|
}
|
|
137
294
|
},
|
|
295
|
+
/**
|
|
296
|
+
* @method ssh-deploy
|
|
297
|
+
* @description Performs a Git reset, commits with a message `cd ssh-${path}`, and pushes the `engine` repository, likely triggering an SSH-based CD pipeline.
|
|
298
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the deployment identifier for the commit message).
|
|
299
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
300
|
+
* @memberof UnderpostRun
|
|
301
|
+
*/
|
|
138
302
|
'ssh-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
139
303
|
actionInitLog();
|
|
140
304
|
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
@@ -143,31 +307,53 @@ class UnderpostRun {
|
|
|
143
307
|
shellExec(`${baseCommand} cmt . --empty cd ssh-${path}`);
|
|
144
308
|
shellExec(`${baseCommand} push . ${process.env.GITHUB_USERNAME}/engine`);
|
|
145
309
|
},
|
|
310
|
+
/**
|
|
311
|
+
* @method ide
|
|
312
|
+
* @description Opens a Visual Studio Code (VS Code) session for the specified path using `node ${underpostRoot}/bin/vs ${path}`.
|
|
313
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the path to the directory to open in the IDE).
|
|
314
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
315
|
+
* @memberof UnderpostRun
|
|
316
|
+
*/
|
|
146
317
|
ide: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
147
318
|
const { underpostRoot } = options;
|
|
148
319
|
shellExec(`node ${underpostRoot}/bin/vs ${path}`);
|
|
149
320
|
},
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
},
|
|
160
|
-
sync: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
321
|
+
/**
|
|
322
|
+
* @method sync
|
|
323
|
+
* @description Cleans up, and then runs a deployment synchronization command (`underpost deploy --kubeadm --build-manifest --sync...`) using parameters parsed from `path` (deployId, replicas, versions, image, node).
|
|
324
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as a comma-separated string containing deploy parameters).
|
|
325
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
326
|
+
* @memberof UnderpostRun
|
|
327
|
+
*/
|
|
328
|
+
sync: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
329
|
+
// Dev usage: node bin run --dev --build sync dd-default
|
|
161
330
|
const env = options.dev ? 'development' : 'production';
|
|
162
331
|
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
163
|
-
|
|
164
|
-
|
|
332
|
+
const defaultPath = [
|
|
333
|
+
'dd-default',
|
|
334
|
+
1,
|
|
335
|
+
``,
|
|
336
|
+
``,
|
|
337
|
+
options.dev || !isDeployRunnerContext(path, options) ? 'kind-control-plane' : os.hostname(),
|
|
338
|
+
];
|
|
165
339
|
let [deployId, replicas, versions, image, node] = path ? path.split(',') : defaultPath;
|
|
166
340
|
deployId = deployId ?? defaultPath[0];
|
|
167
341
|
replicas = replicas ?? defaultPath[1];
|
|
168
342
|
versions = versions ?? defaultPath[2];
|
|
169
343
|
image = image ?? defaultPath[3];
|
|
170
344
|
node = node ?? defaultPath[4];
|
|
345
|
+
|
|
346
|
+
if (isDeployRunnerContext(path, options)) {
|
|
347
|
+
const { validVersion } = UnderpostRepository.API.privateConfUpdate(deployId);
|
|
348
|
+
if (!validVersion) throw new Error('Version mismatch');
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const currentTraffic = isDeployRunnerContext(path, options)
|
|
352
|
+
? UnderpostDeploy.API.getCurrentTraffic(deployId)
|
|
353
|
+
: '';
|
|
354
|
+
let targetTraffic = currentTraffic ? (currentTraffic === 'blue' ? 'green' : 'blue') : '';
|
|
355
|
+
if (targetTraffic) versions = targetTraffic;
|
|
356
|
+
|
|
171
357
|
shellExec(
|
|
172
358
|
`${baseCommand} deploy --kubeadm --build-manifest --sync --info-router --replicas ${
|
|
173
359
|
replicas ?? 1
|
|
@@ -175,11 +361,31 @@ class UnderpostRun {
|
|
|
175
361
|
versions ? ` --versions ${versions.replaceAll('+', ',')}` : ''
|
|
176
362
|
} dd ${env}`,
|
|
177
363
|
);
|
|
178
|
-
|
|
364
|
+
|
|
365
|
+
if (isDeployRunnerContext(path, options)) {
|
|
366
|
+
shellExec(`${baseCommand} deploy --kubeadm ${deployId} ${env}`);
|
|
367
|
+
if (!targetTraffic) targetTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
|
|
368
|
+
await UnderpostDeploy.API.monitorReadyRunner(deployId, env, targetTraffic);
|
|
369
|
+
UnderpostDeploy.API.switchTraffic(deployId, env, targetTraffic);
|
|
370
|
+
} else logger.info('current traffic', UnderpostDeploy.API.getCurrentTraffic(deployId));
|
|
179
371
|
},
|
|
372
|
+
/**
|
|
373
|
+
* @method ls-deployments
|
|
374
|
+
* @description Retrieves and logs a table of Kubernetes deployments using `UnderpostDeploy.API.get`.
|
|
375
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as an optional deployment name filter).
|
|
376
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
377
|
+
* @memberof UnderpostRun
|
|
378
|
+
*/
|
|
180
379
|
'ls-deployments': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
181
380
|
console.table(await UnderpostDeploy.API.get(path, 'deployments'));
|
|
182
381
|
},
|
|
382
|
+
/**
|
|
383
|
+
* @method monitor
|
|
384
|
+
* @description Monitors a specific pod (identified by `path`) for the existence of a file (`/await`), and performs conditional actions (like file copying and opening Firefox) when the file is removed.
|
|
385
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the name of the pod to monitor).
|
|
386
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
387
|
+
* @memberof UnderpostRun
|
|
388
|
+
*/
|
|
183
389
|
monitor: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
184
390
|
const pid = getTerminalPid();
|
|
185
391
|
logger.info('monitor pid', pid);
|
|
@@ -253,6 +459,13 @@ class UnderpostRun {
|
|
|
253
459
|
};
|
|
254
460
|
_monitor();
|
|
255
461
|
},
|
|
462
|
+
/**
|
|
463
|
+
* @method db-client
|
|
464
|
+
* @description Deploys and exposes the Adminer database client application (using `adminer:4.7.6-standalone` image) on the cluster.
|
|
465
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
466
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
467
|
+
* @memberof UnderpostRun
|
|
468
|
+
*/
|
|
256
469
|
'db-client': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
257
470
|
const { underpostRoot } = options;
|
|
258
471
|
|
|
@@ -274,6 +487,13 @@ class UnderpostRun {
|
|
|
274
487
|
shellExec(`underpost deploy --expose adminer`);
|
|
275
488
|
}
|
|
276
489
|
},
|
|
490
|
+
/**
|
|
491
|
+
* @method promote
|
|
492
|
+
* @description Switches traffic between blue/green deployments for a specified deployment ID(s) (uses `dd.router` for 'dd', or a specific ID).
|
|
493
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as a comma-separated string: `deployId,env,replicas`).
|
|
494
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
495
|
+
* @memberof UnderpostRun
|
|
496
|
+
*/
|
|
277
497
|
promote: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
278
498
|
let [inputDeployId, inputEnv, inputReplicas] = path.split(',');
|
|
279
499
|
if (!inputEnv) inputEnv = 'production';
|
|
@@ -290,7 +510,13 @@ class UnderpostRun {
|
|
|
290
510
|
UnderpostDeploy.API.switchTraffic(inputDeployId, inputEnv, targetTraffic, inputReplicas);
|
|
291
511
|
}
|
|
292
512
|
},
|
|
293
|
-
|
|
513
|
+
/**
|
|
514
|
+
* @method metrics
|
|
515
|
+
* @description Deploys Prometheus and Grafana for metrics monitoring, targeting the hosts defined in the deployment configuration files.
|
|
516
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
517
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
518
|
+
* @memberof UnderpostRun
|
|
519
|
+
*/
|
|
294
520
|
metrics: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
295
521
|
const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
|
|
296
522
|
let hosts = [];
|
|
@@ -301,7 +527,13 @@ class UnderpostRun {
|
|
|
301
527
|
shellExec(`node bin cluster --prom ${hosts.join(',')}`);
|
|
302
528
|
shellExec(`node bin cluster --grafana`);
|
|
303
529
|
},
|
|
304
|
-
|
|
530
|
+
/**
|
|
531
|
+
* @method cluster
|
|
532
|
+
* @description Deploys a full production-ready Kubernetes cluster environment including MongoDB, MariaDB, Valkey, Contour (Ingress), and Cert-Manager, and deploys all services.
|
|
533
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
534
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
535
|
+
* @memberof UnderpostRun
|
|
536
|
+
*/
|
|
305
537
|
cluster: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
306
538
|
const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
|
|
307
539
|
const env = 'production';
|
|
@@ -329,50 +561,65 @@ class UnderpostRun {
|
|
|
329
561
|
shellExec(`underpost deploy ${deployId} ${env} --kubeadm --cert`);
|
|
330
562
|
}
|
|
331
563
|
},
|
|
564
|
+
/**
|
|
565
|
+
* @method deploy
|
|
566
|
+
* @description Deploys a specified service (identified by `path`) using blue/green strategy, monitors its status, and switches traffic upon readiness.
|
|
567
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the deployment ID to deploy).
|
|
568
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
569
|
+
* @memberof UnderpostRun
|
|
570
|
+
*/
|
|
332
571
|
deploy: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
333
572
|
const deployId = path;
|
|
334
|
-
const { validVersion
|
|
573
|
+
const { validVersion } = UnderpostRepository.API.privateConfUpdate(deployId);
|
|
335
574
|
if (!validVersion) throw new Error('Version mismatch');
|
|
336
575
|
const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
|
|
337
576
|
const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
|
|
338
577
|
const env = 'production';
|
|
339
578
|
const ignorePods = UnderpostDeploy.API.get(`${deployId}-${env}-${targetTraffic}`).map((p) => p.NAME);
|
|
340
579
|
|
|
341
|
-
|
|
342
|
-
// deployId, replicas, versions, image, node
|
|
343
|
-
shellExec(
|
|
344
|
-
`node bin run sync ${deployId},${options.replicas ?? 1},${targetTraffic},${
|
|
345
|
-
options.imageName ?? `localhost/rockylinux9-underpost:${deployVersion}`
|
|
346
|
-
},${os.hostname()}`,
|
|
347
|
-
);
|
|
348
|
-
} else shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${targetTraffic}`);
|
|
580
|
+
shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${targetTraffic}`);
|
|
349
581
|
|
|
350
|
-
|
|
351
|
-
const checkStatusIterationMsDelay = 1000;
|
|
352
|
-
const iteratorTag = `[${deployId}-${env}-${targetTraffic}]`;
|
|
353
|
-
logger.info('Deployment init', { deployId, env, targetTraffic, checkStatusIterationMsDelay });
|
|
354
|
-
const minReadyOk = 3;
|
|
355
|
-
let readyOk = 0;
|
|
356
|
-
|
|
357
|
-
while (readyOk < minReadyOk) {
|
|
358
|
-
const ready = UnderpostDeploy.API.checkDeploymentReadyStatus(deployId, env, targetTraffic, ignorePods).ready;
|
|
359
|
-
if (ready === true) {
|
|
360
|
-
readyOk++;
|
|
361
|
-
logger.info(`${iteratorTag} | Deployment ready. Verification number: ${readyOk}`);
|
|
362
|
-
}
|
|
363
|
-
await timer(checkStatusIterationMsDelay);
|
|
364
|
-
checkStatusIteration++;
|
|
365
|
-
logger.info(
|
|
366
|
-
`${iteratorTag} | Deployment in progress... | Delay number check iterations: ${checkStatusIteration}`,
|
|
367
|
-
);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
logger.info(`${iteratorTag} | Deployment ready. | Total delay number check iterations: ${checkStatusIteration}`);
|
|
582
|
+
await UnderpostDeploy.API.monitorReadyRunner(deployId, env, targetTraffic, ignorePods);
|
|
371
583
|
|
|
372
584
|
UnderpostDeploy.API.switchTraffic(deployId, env, targetTraffic);
|
|
585
|
+
},
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* @method sync-replica
|
|
589
|
+
* @description Syncs a replica for the dd.router
|
|
590
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
591
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
592
|
+
* @memberof UnderpostRun
|
|
593
|
+
*/
|
|
594
|
+
'sync-replica': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
595
|
+
const env = options.dev ? 'development' : 'production';
|
|
596
|
+
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
373
597
|
|
|
374
|
-
|
|
598
|
+
for (let deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',')) {
|
|
599
|
+
deployId = deployId.trim();
|
|
600
|
+
const _path = '/single-replica';
|
|
601
|
+
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
602
|
+
shellExec(`${baseCommand} env ${deployId} ${env}`);
|
|
603
|
+
for (const host of Object.keys(confServer)) {
|
|
604
|
+
if (!(_path in confServer[host])) continue;
|
|
605
|
+
shellExec(`node bin/deploy build-single-replica ${deployId} ${host} ${_path}`);
|
|
606
|
+
shellExec(`node bin/deploy build-full-client ${deployId}`);
|
|
607
|
+
const node = options.dev || !isDeployRunnerContext(path, options) ? 'kind-control-plane' : os.hostname();
|
|
608
|
+
// deployId, replicas, versions, image, node
|
|
609
|
+
let defaultPath = [deployId, 1, ``, ``, node];
|
|
610
|
+
shellExec(`${baseCommand} run${options.dev === true ? ' --dev' : ''} --build sync ${defaultPath}`);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
if (isDeployRunnerContext(path, options)) shellExec(`${baseCommand} run promote ${path} production`);
|
|
375
614
|
},
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* @method tf-vae-test
|
|
618
|
+
* @description Creates and runs a job pod (`tf-vae-test`) that installs TensorFlow dependencies, clones the TensorFlow docs, and runs the CVAE tutorial script, with a terminal monitor attached.
|
|
619
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
620
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
621
|
+
* @memberof UnderpostRun
|
|
622
|
+
*/
|
|
376
623
|
'tf-vae-test': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
377
624
|
const { underpostRoot } = options;
|
|
378
625
|
const podName = 'tf-vae-test';
|
|
@@ -406,6 +653,13 @@ class UnderpostRun {
|
|
|
406
653
|
],
|
|
407
654
|
});
|
|
408
655
|
},
|
|
656
|
+
/**
|
|
657
|
+
* @method deploy-job
|
|
658
|
+
* @description Creates and applies a custom Kubernetes Pod manifest (Job) for running arbitrary commands inside a container image (defaulting to a TensorFlow/NVIDIA image).
|
|
659
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the optional script path or job argument).
|
|
660
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
661
|
+
* @memberof UnderpostRun
|
|
662
|
+
*/
|
|
409
663
|
'deploy-job': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
410
664
|
const podName = options.podName || 'deploy-job';
|
|
411
665
|
const volumeName = `${podName}-volume`;
|
|
@@ -485,7 +739,17 @@ EOF`;
|
|
|
485
739
|
}
|
|
486
740
|
},
|
|
487
741
|
};
|
|
742
|
+
|
|
488
743
|
static API = {
|
|
744
|
+
/**
|
|
745
|
+
* @method callback
|
|
746
|
+
* @description Initiates the execution of a specified CLI command (runner) with the given input value (`path`) and processed options.
|
|
747
|
+
* @param {string} runner - The name of the runner to execute.
|
|
748
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
749
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
750
|
+
* @memberof UnderpostRun
|
|
751
|
+
* @returns {Promise<any>} The result of the callback execution.
|
|
752
|
+
*/
|
|
489
753
|
async callback(runner, path, options = UnderpostRun.DEFAULT_OPTION) {
|
|
490
754
|
const npmRoot = getNpmRootPath();
|
|
491
755
|
const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
|
package/src/cli/script.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Script module for managing the execution of scripts.
|
|
3
|
+
* @module src/cli/script.js
|
|
4
|
+
* @namespace UnderpostScript
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import { getNpmRootPath } from '../server/conf.js';
|
|
2
8
|
import { loggerFactory } from '../server/logger.js';
|
|
3
9
|
import { shellExec } from '../server/process.js';
|
|
@@ -6,14 +12,34 @@ import UnderpostDeploy from './deploy.js';
|
|
|
6
12
|
|
|
7
13
|
const logger = loggerFactory(import.meta);
|
|
8
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @class UnderpostScript
|
|
17
|
+
* @description Manages the execution of scripts.
|
|
18
|
+
* @memberof UnderpostScript
|
|
19
|
+
*/
|
|
9
20
|
class UnderpostScript {
|
|
10
21
|
static API = {
|
|
22
|
+
/**
|
|
23
|
+
* @method set
|
|
24
|
+
* @description Sets a script in the package.json file.
|
|
25
|
+
* @param {string} key - The key for the script.
|
|
26
|
+
* @param {string} value - The value for the script.
|
|
27
|
+
* @memberof UnderpostScript
|
|
28
|
+
*/
|
|
11
29
|
set(key, value) {
|
|
12
30
|
const npmRoot = `${getNpmRootPath()}/underpost`;
|
|
13
31
|
const packageJson = JSON.parse(fs.readFileSync(`${npmRoot}/package.json`, 'utf8'));
|
|
14
32
|
packageJson.scripts[key] = value;
|
|
15
33
|
fs.writeFileSync(`${npmRoot}/package.json`, JSON.stringify(packageJson, null, 4));
|
|
16
34
|
},
|
|
35
|
+
/**
|
|
36
|
+
* @method run
|
|
37
|
+
* @description Runs a script.
|
|
38
|
+
* @param {string} key - The key for the script.
|
|
39
|
+
* @param {string} value - The value for the script.
|
|
40
|
+
* @param {object} options - The options for the script.
|
|
41
|
+
* @memberof UnderpostScript
|
|
42
|
+
*/
|
|
17
43
|
run(key, value, options) {
|
|
18
44
|
const npmRoot = `${getNpmRootPath()}/underpost`;
|
|
19
45
|
const packageJson = JSON.parse(fs.readFileSync(`${npmRoot}/package.json`, 'utf8'));
|
|
@@ -41,6 +67,12 @@ class UnderpostScript {
|
|
|
41
67
|
}
|
|
42
68
|
shellExec(`cd ${npmRoot} && npm run ${key}`);
|
|
43
69
|
},
|
|
70
|
+
/**
|
|
71
|
+
* @method get
|
|
72
|
+
* @description Gets a script from the package.json file.
|
|
73
|
+
* @param {string} key - The key for the script.
|
|
74
|
+
* @memberof UnderpostScript
|
|
75
|
+
*/
|
|
44
76
|
get(key) {
|
|
45
77
|
const npmRoot = `${getNpmRootPath()}/underpost`;
|
|
46
78
|
const packageJson = JSON.parse(fs.readFileSync(`${npmRoot}/package.json`, 'utf8'));
|
package/src/cli/secrets.js
CHANGED
|
@@ -1,14 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secrets module for managing the secrets of the application.
|
|
3
|
+
* @module src/cli/secrets.js
|
|
4
|
+
* @namespace UnderpostSecret
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import dotenv from 'dotenv';
|
|
2
8
|
import { shellExec } from '../server/process.js';
|
|
3
9
|
import fs from 'fs-extra';
|
|
4
10
|
import UnderpostRootEnv from './env.js';
|
|
5
11
|
|
|
12
|
+
dotenv.config();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @class UnderpostSecret
|
|
16
|
+
* @description Manages the secrets of the application.
|
|
17
|
+
* @memberof UnderpostSecret
|
|
18
|
+
*/
|
|
6
19
|
class UnderpostSecret {
|
|
7
20
|
static API = {
|
|
21
|
+
/**
|
|
22
|
+
* @method docker
|
|
23
|
+
* @description Manages the secrets of the application.
|
|
24
|
+
* @memberof UnderpostSecret
|
|
25
|
+
*/
|
|
8
26
|
docker: {
|
|
27
|
+
/**
|
|
28
|
+
* @method init
|
|
29
|
+
* @description Initializes the docker secrets.
|
|
30
|
+
* @memberof UnderpostSecret
|
|
31
|
+
*/
|
|
9
32
|
init() {
|
|
10
33
|
shellExec(`docker swarm init`);
|
|
11
34
|
},
|
|
35
|
+
/**
|
|
36
|
+
* @method createFromEnvFile
|
|
37
|
+
* @description Creates a secret from an env file.
|
|
38
|
+
* @param {string} envPath - The path to the env file.
|
|
39
|
+
* @memberof UnderpostSecret
|
|
40
|
+
*/
|
|
12
41
|
createFromEnvFile(envPath) {
|
|
13
42
|
const envObj = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
14
43
|
for (const key of Object.keys(envObj)) {
|
|
@@ -23,6 +52,11 @@ class UnderpostSecret {
|
|
|
23
52
|
shellExec(`docker secret ls`);
|
|
24
53
|
},
|
|
25
54
|
},
|
|
55
|
+
/**
|
|
56
|
+
* @method underpost
|
|
57
|
+
* @description Manages the secrets of the application.
|
|
58
|
+
* @memberof UnderpostSecret
|
|
59
|
+
*/
|
|
26
60
|
underpost: {
|
|
27
61
|
createFromEnvFile(envPath) {
|
|
28
62
|
const envObj = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|