underpost 2.8.84 → 2.8.85
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.development +1 -0
- package/.env.production +1 -0
- package/.env.test +1 -0
- package/.github/workflows/{ghpkg.yml → ghpkg.ci.yml} +1 -1
- package/.github/workflows/{npmpkg.yml → npmpkg.ci.yml} +1 -1
- package/.github/workflows/{publish.yml → publish.ci.yml} +1 -1
- package/.github/workflows/{pwa-microservices-template.page.yml → pwa-microservices-template-page.cd.yml} +1 -1
- package/.github/workflows/{pwa-microservices-template.test.yml → pwa-microservices-template-test.ci.yml} +1 -1
- package/.vscode/settings.json +0 -1
- package/README.md +45 -2
- package/bin/build.js +15 -5
- package/bin/deploy.js +17 -82
- package/bin/file.js +15 -8
- package/cli.md +65 -44
- package/conf.js +1 -1
- package/docker-compose.yml +1 -1
- package/manifests/deployment/dd-template-development/deployment.yaml +2 -2
- package/manifests/maas/gpu-diag.sh +1 -1
- package/package.json +4 -6
- package/src/api/user/user.router.js +24 -1
- package/src/api/user/user.service.js +1 -4
- package/src/cli/cluster.js +42 -27
- package/src/cli/deploy.js +20 -0
- package/src/cli/index.js +9 -0
- package/src/cli/monitor.js +8 -12
- package/src/cli/run.js +111 -6
- package/src/cli/ssh.js +32 -0
- package/src/client/Default.index.js +7 -3
- package/src/client/components/core/Account.js +1 -1
- package/src/client/components/core/Chat.js +1 -1
- package/src/client/components/core/CommonJs.js +24 -22
- package/src/client/components/core/Content.js +1 -5
- package/src/client/components/core/Css.js +258 -18
- package/src/client/components/core/CssCore.js +8 -8
- package/src/client/components/core/Docs.js +14 -61
- package/src/client/components/core/DropDown.js +137 -82
- package/src/client/components/core/EventsUI.js +92 -5
- package/src/client/components/core/LoadingAnimation.js +8 -15
- package/src/client/components/core/Modal.js +597 -136
- package/src/client/components/core/NotificationManager.js +2 -2
- package/src/client/components/core/ObjectLayerEngine.js +638 -0
- package/src/client/components/core/Panel.js +158 -34
- package/src/client/components/core/PanelForm.js +12 -3
- package/src/client/components/core/Recover.js +1 -1
- package/src/client/components/core/Router.js +77 -17
- package/src/client/components/core/SocketIo.js +3 -3
- package/src/client/components/core/Translate.js +6 -2
- package/src/client/components/core/VanillaJs.js +0 -3
- package/src/client/components/core/Worker.js +3 -1
- package/src/client/components/default/CssDefault.js +17 -3
- package/src/client/components/default/MenuDefault.js +264 -45
- package/src/client/components/default/RoutesDefault.js +6 -12
- package/src/client/public/default/android-chrome-144x144.png +0 -0
- package/src/client/public/default/android-chrome-192x192.png +0 -0
- package/src/client/public/default/android-chrome-256x256.png +0 -0
- package/src/client/public/default/android-chrome-36x36.png +0 -0
- package/src/client/public/default/android-chrome-48x48.png +0 -0
- package/src/client/public/default/android-chrome-72x72.png +0 -0
- package/src/client/public/default/android-chrome-96x96.png +0 -0
- package/src/client/public/default/apple-touch-icon-114x114-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
- package/src/client/public/default/apple-touch-icon-120x120-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
- package/src/client/public/default/apple-touch-icon-144x144-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
- package/src/client/public/default/apple-touch-icon-152x152-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
- package/src/client/public/default/apple-touch-icon-180x180-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
- package/src/client/public/default/apple-touch-icon-57x57-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
- package/src/client/public/default/apple-touch-icon-60x60-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
- package/src/client/public/default/apple-touch-icon-72x72-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
- package/src/client/public/default/apple-touch-icon-76x76-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
- package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon.png +0 -0
- package/src/client/public/default/assets/background/dark.jpg +0 -0
- package/src/client/public/default/assets/background/dark.svg +557 -0
- package/src/client/public/default/assets/logo/base-icon.png +0 -0
- package/src/client/public/default/assets/logo/underpost.gif +0 -0
- package/src/client/public/default/assets/mailer/api-user-check.png +0 -0
- package/src/client/public/default/assets/mailer/api-user-invalid-token.png +0 -0
- package/src/client/public/default/assets/mailer/api-user-recover.png +0 -0
- package/src/client/public/default/favicon-16x16.png +0 -0
- package/src/client/public/default/favicon-32x32.png +0 -0
- package/src/client/public/default/favicon.ico +0 -0
- package/src/client/public/default/mstile-144x144.png +0 -0
- package/src/client/public/default/mstile-150x150.png +0 -0
- package/src/client/public/default/mstile-310x150.png +0 -0
- package/src/client/public/default/mstile-310x310.png +0 -0
- package/src/client/public/default/mstile-70x70.png +0 -0
- package/src/client/public/default/safari-pinned-tab.svg +24 -0
- package/src/client/ssr/body/DefaultSplashScreen.js +2 -2
- package/src/index.js +9 -1
- package/src/monitor.js +24 -0
- package/src/runtime/lampp/Dockerfile +30 -39
- package/src/runtime/lampp/Lampp.js +11 -2
- package/src/server/client-build-docs.js +205 -0
- package/src/server/client-build.js +16 -166
- package/src/server/conf.js +12 -5
- package/src/server/valkey.js +102 -41
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { authMiddleware } from '../../server/auth.js';
|
|
1
|
+
import { authMiddleware, hashPassword } from '../../server/auth.js';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import { loggerFactory } from '../../server/logger.js';
|
|
4
4
|
import { UserController } from './user.controller.js';
|
|
5
5
|
import express from 'express';
|
|
6
|
+
import { DataBaseProvider } from '../../db/DataBaseProvider.js';
|
|
6
7
|
|
|
7
8
|
const logger = loggerFactory(import.meta);
|
|
8
9
|
|
|
@@ -10,6 +11,28 @@ const UserRouter = (options) => {
|
|
|
10
11
|
const router = express.Router();
|
|
11
12
|
|
|
12
13
|
(async () => {
|
|
14
|
+
const models = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models;
|
|
15
|
+
if (models.User) {
|
|
16
|
+
try {
|
|
17
|
+
const adminUser = await models.User.findOne({ role: 'admin' });
|
|
18
|
+
if (!adminUser) {
|
|
19
|
+
const defaultPassword = process.env.DEFAULT_ADMIN_PASSWORD || 'changethis';
|
|
20
|
+
const hashedPassword = hashPassword(defaultPassword);
|
|
21
|
+
|
|
22
|
+
const result = await models.User.create({
|
|
23
|
+
username: 'admin',
|
|
24
|
+
email: process.env.DEFAULT_ADMIN_EMAIL || 'admin@' + options.host,
|
|
25
|
+
password: hashedPassword,
|
|
26
|
+
role: 'admin',
|
|
27
|
+
emailConfirmed: true,
|
|
28
|
+
publicKey: [],
|
|
29
|
+
});
|
|
30
|
+
logger.warn('Default admin user created. Please change the default password immediately!', result._doc);
|
|
31
|
+
}
|
|
32
|
+
} catch (error) {
|
|
33
|
+
logger.error('Error checking/creating admin user:', error);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
13
36
|
options.png = {
|
|
14
37
|
buffer: {
|
|
15
38
|
'invalid-token': fs.readFileSync(`./src/client/public/default/assets/mailer/api-user-invalid-token.png`),
|
|
@@ -444,7 +444,7 @@ const UserService = {
|
|
|
444
444
|
_id: user._id,
|
|
445
445
|
}).select(UserDto.select.get());
|
|
446
446
|
} else throw new Error('invalid token');
|
|
447
|
-
}
|
|
447
|
+
} else delete req.body.password;
|
|
448
448
|
|
|
449
449
|
switch (req.params.id) {
|
|
450
450
|
default: {
|
|
@@ -453,9 +453,6 @@ const UserService = {
|
|
|
453
453
|
});
|
|
454
454
|
switch (user.role) {
|
|
455
455
|
case 'admin': {
|
|
456
|
-
if (req.body.password !== undefined && req.body.password !== user.password)
|
|
457
|
-
req.body.password = await hashPassword(req.body.password);
|
|
458
|
-
else delete req.body.password;
|
|
459
456
|
return await User.findByIdAndUpdate(req.params.id, req.body, {
|
|
460
457
|
runValidators: true,
|
|
461
458
|
});
|
package/src/cli/cluster.js
CHANGED
|
@@ -19,6 +19,7 @@ class UnderpostCluster {
|
|
|
19
19
|
* @param {object} [options] - Configuration options for cluster initialization.
|
|
20
20
|
* @param {boolean} [options.mongodb=false] - Deploy MongoDB.
|
|
21
21
|
* @param {boolean} [options.mongodb4=false] - Deploy MongoDB 4.4.
|
|
22
|
+
* @param {String} [options.mongoDbHost=''] - Set custom mongo db host
|
|
22
23
|
* @param {boolean} [options.mariadb=false] - Deploy MariaDB.
|
|
23
24
|
* @param {boolean} [options.mysql=false] - Deploy MySQL.
|
|
24
25
|
* @param {boolean} [options.postgresql=false] - Deploy PostgreSQL.
|
|
@@ -48,6 +49,7 @@ class UnderpostCluster {
|
|
|
48
49
|
options = {
|
|
49
50
|
mongodb: false,
|
|
50
51
|
mongodb4: false,
|
|
52
|
+
mongoDbHost: '',
|
|
51
53
|
mariadb: false,
|
|
52
54
|
mysql: false,
|
|
53
55
|
postgresql: false,
|
|
@@ -260,17 +262,18 @@ class UnderpostCluster {
|
|
|
260
262
|
|
|
261
263
|
if (options.full === true || options.valkey === true) {
|
|
262
264
|
if (options.pullImage === true) {
|
|
263
|
-
shellExec(`
|
|
264
|
-
|
|
265
|
-
if (!options.kubeadm && !options.k3s)
|
|
265
|
+
// shellExec(`sudo podman pull valkey/valkey:latest`);
|
|
266
|
+
if (!options.kubeadm && !options.k3s) {
|
|
266
267
|
// Only load if not kubeadm/k3s (Kind needs it)
|
|
268
|
+
shellExec(`docker pull valkey/valkey:latest`);
|
|
267
269
|
shellExec(`sudo kind load docker-image valkey/valkey:latest`);
|
|
268
|
-
else if (options.kubeadm || options.k3s)
|
|
270
|
+
} else if (options.kubeadm || options.k3s)
|
|
269
271
|
// For kubeadm/k3s, ensure it's available for containerd
|
|
270
272
|
shellExec(`sudo crictl pull valkey/valkey:latest`);
|
|
271
273
|
}
|
|
272
274
|
shellExec(`kubectl delete statefulset valkey-service --ignore-not-found`);
|
|
273
275
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/valkey`);
|
|
276
|
+
await UnderpostTest.API.statusMonitor('valkey-service', 'Running', 'pods', 1000, 60);
|
|
274
277
|
}
|
|
275
278
|
if (options.full === true || options.mariadb === true) {
|
|
276
279
|
shellExec(
|
|
@@ -279,18 +282,16 @@ class UnderpostCluster {
|
|
|
279
282
|
shellExec(`kubectl delete statefulset mariadb-statefulset --ignore-not-found`);
|
|
280
283
|
|
|
281
284
|
if (options.pullImage === true) {
|
|
282
|
-
shellExec(`
|
|
283
|
-
|
|
284
|
-
if (!options.kubeadm && !options.k3s)
|
|
285
|
+
// shellExec(`sudo podman pull mariadb:latest`);
|
|
286
|
+
if (!options.kubeadm && !options.k3s) {
|
|
285
287
|
// Only load if not kubeadm/k3s (Kind needs it)
|
|
288
|
+
shellExec(`docker pull mariadb:latest`);
|
|
286
289
|
shellExec(`sudo kind load docker-image mariadb:latest`);
|
|
287
|
-
else if (options.kubeadm || options.k3s)
|
|
290
|
+
} else if (options.kubeadm || options.k3s)
|
|
288
291
|
// For kubeadm/k3s, ensure it's available for containerd
|
|
289
292
|
shellExec(`sudo crictl pull mariadb:latest`);
|
|
290
293
|
}
|
|
291
|
-
|
|
292
|
-
// This storage class is specific to kubeadm setup
|
|
293
|
-
shellExec(`kubectl apply -f ${underpostRoot}/manifests/mariadb/storage-class.yaml`);
|
|
294
|
+
shellExec(`kubectl apply -f ${underpostRoot}/manifests/mariadb/storage-class.yaml`);
|
|
294
295
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mariadb`);
|
|
295
296
|
}
|
|
296
297
|
if (options.full === true || options.mysql === true) {
|
|
@@ -304,11 +305,11 @@ class UnderpostCluster {
|
|
|
304
305
|
}
|
|
305
306
|
if (options.full === true || options.postgresql === true) {
|
|
306
307
|
if (options.pullImage === true) {
|
|
307
|
-
|
|
308
|
-
if (!options.kubeadm && !options.k3s)
|
|
308
|
+
if (!options.kubeadm && !options.k3s) {
|
|
309
309
|
// Only load if not kubeadm/k3s (Kind needs it)
|
|
310
|
+
shellExec(`docker pull postgres:latest`);
|
|
310
311
|
shellExec(`sudo kind load docker-image postgres:latest`);
|
|
311
|
-
else if (options.kubeadm || options.k3s)
|
|
312
|
+
} else if (options.kubeadm || options.k3s)
|
|
312
313
|
// For kubeadm/k3s, ensure it's available for containerd
|
|
313
314
|
shellExec(`sudo crictl pull postgres:latest`);
|
|
314
315
|
}
|
|
@@ -319,11 +320,11 @@ class UnderpostCluster {
|
|
|
319
320
|
}
|
|
320
321
|
if (options.mongodb4 === true) {
|
|
321
322
|
if (options.pullImage === true) {
|
|
322
|
-
|
|
323
|
-
if (!options.kubeadm && !options.k3s)
|
|
323
|
+
if (!options.kubeadm && !options.k3s) {
|
|
324
324
|
// Only load if not kubeadm/k3s (Kind needs it)
|
|
325
|
+
shellExec(`docker pull mongo:4.4`);
|
|
325
326
|
shellExec(`sudo kind load docker-image mongo:4.4`);
|
|
326
|
-
else if (options.kubeadm || options.k3s)
|
|
327
|
+
} else if (options.kubeadm || options.k3s)
|
|
327
328
|
// For kubeadm/k3s, ensure it's available for containerd
|
|
328
329
|
shellExec(`sudo crictl pull mongo:4.4`);
|
|
329
330
|
}
|
|
@@ -334,9 +335,10 @@ class UnderpostCluster {
|
|
|
334
335
|
const successInstance = await UnderpostTest.API.statusMonitor(deploymentName);
|
|
335
336
|
|
|
336
337
|
if (successInstance) {
|
|
338
|
+
if (!options.mongoDbHost) options.mongoDbHost = 'mongodb-service';
|
|
337
339
|
const mongoConfig = {
|
|
338
340
|
_id: 'rs0',
|
|
339
|
-
members: [{ _id: 0, host:
|
|
341
|
+
members: [{ _id: 0, host: `${options.mongoDbHost}:27017` }],
|
|
340
342
|
};
|
|
341
343
|
|
|
342
344
|
const [pod] = UnderpostDeploy.API.get(deploymentName);
|
|
@@ -348,11 +350,11 @@ class UnderpostCluster {
|
|
|
348
350
|
}
|
|
349
351
|
} else if (options.full === true || options.mongodb === true) {
|
|
350
352
|
if (options.pullImage === true) {
|
|
351
|
-
|
|
352
|
-
if (!options.kubeadm && !options.k3s)
|
|
353
|
+
if (!options.kubeadm && !options.k3s) {
|
|
353
354
|
// Only load if not kubeadm/k3s (Kind needs it)
|
|
355
|
+
shellExec(`docker pull mongo:latest`);
|
|
354
356
|
shellExec(`sudo kind load docker-image mongo:latest`);
|
|
355
|
-
else if (options.kubeadm || options.k3s)
|
|
357
|
+
} else if (options.kubeadm || options.k3s)
|
|
356
358
|
// For kubeadm/k3s, ensure it's available for containerd
|
|
357
359
|
shellExec(`sudo crictl pull mongo:latest`);
|
|
358
360
|
}
|
|
@@ -363,19 +365,26 @@ class UnderpostCluster {
|
|
|
363
365
|
`sudo kubectl create secret generic mongodb-secret --from-file=username=/home/dd/engine/engine-private/mongodb-username --from-file=password=/home/dd/engine/engine-private/mongodb-password --dry-run=client -o yaml | kubectl apply -f -`,
|
|
364
366
|
);
|
|
365
367
|
shellExec(`kubectl delete statefulset mongodb --ignore-not-found`);
|
|
366
|
-
|
|
367
|
-
// This storage class is specific to kubeadm setup
|
|
368
|
-
shellExec(`kubectl apply -f ${underpostRoot}/manifests/mongodb/storage-class.yaml`);
|
|
368
|
+
shellExec(`kubectl apply -f ${underpostRoot}/manifests/mongodb/storage-class.yaml`);
|
|
369
369
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mongodb`);
|
|
370
370
|
|
|
371
|
-
const successInstance = await UnderpostTest.API.statusMonitor('mongodb-
|
|
371
|
+
const successInstance = await UnderpostTest.API.statusMonitor('mongodb-0', 'Running', 'pods', 1000, 60 * 10);
|
|
372
372
|
|
|
373
373
|
if (successInstance) {
|
|
374
|
+
if (!options.mongoDbHost) options.mongoDbHost = 'mongodb-service';
|
|
374
375
|
const mongoConfig = {
|
|
375
376
|
_id: 'rs0',
|
|
376
377
|
members: [
|
|
377
|
-
{
|
|
378
|
-
|
|
378
|
+
{
|
|
379
|
+
_id: 0,
|
|
380
|
+
host: `${options.mongoDbHost === 'mongodb-service' ? 'mongodb-0.' : ''}${options.mongoDbHost}:27017`,
|
|
381
|
+
priority: 1,
|
|
382
|
+
},
|
|
383
|
+
// {
|
|
384
|
+
// _id: 1,
|
|
385
|
+
// host: `${options.mongoDbHost === 'mongodb-service' ? 'mongodb-1.' : ''}${options.mongoDbHost}:27017`,
|
|
386
|
+
// priority: 1,
|
|
387
|
+
// },
|
|
379
388
|
],
|
|
380
389
|
};
|
|
381
390
|
|
|
@@ -467,6 +476,12 @@ net.bridge.bridge-nf-call-arptables = 1
|
|
|
467
476
|
net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
468
477
|
{ silent: true },
|
|
469
478
|
);
|
|
479
|
+
|
|
480
|
+
// Increase inotify limits
|
|
481
|
+
shellExec(`sudo sysctl -w fs.inotify.max_user_watches=2099999999`);
|
|
482
|
+
shellExec(`sudo sysctl -w fs.inotify.max_user_instances=2099999999`);
|
|
483
|
+
shellExec(`sudo sysctl -w fs.inotify.max_queued_events=2099999999`);
|
|
484
|
+
|
|
470
485
|
// shellExec(`sudo sysctl --system`); // Apply sysctl changes immediately
|
|
471
486
|
// Apply NAT iptables rules.
|
|
472
487
|
shellExec(`${underpostRoot}/manifests/maas/nat-iptables.sh`, { silent: true });
|
package/src/cli/deploy.js
CHANGED
|
@@ -528,6 +528,26 @@ node bin/deploy build-full-client ${deployId}
|
|
|
528
528
|
}).trim(),
|
|
529
529
|
);
|
|
530
530
|
},
|
|
531
|
+
checkDeploymentReadyStatus(deployId, env, traffic, ignoresNames = []) {
|
|
532
|
+
const cmd = `underpost config get container-status`;
|
|
533
|
+
const pods = UnderpostDeploy.API.get(`${deployId}-${env}-${traffic}`);
|
|
534
|
+
const readyPods = [];
|
|
535
|
+
const notReadyPods = [];
|
|
536
|
+
for (const pod of pods) {
|
|
537
|
+
const { NAME } = pod;
|
|
538
|
+
if (ignoresNames && ignoresNames.find((t) => NAME.trim().toLowerCase().match(t.trim().toLowerCase()))) continue;
|
|
539
|
+
if (
|
|
540
|
+
shellExec(`sudo kubectl exec -i ${NAME} -- sh -c "${cmd}"`, { stdout: true }).match(
|
|
541
|
+
`${deployId}-${env}-running-deployment`,
|
|
542
|
+
)
|
|
543
|
+
) {
|
|
544
|
+
readyPods.push(pod);
|
|
545
|
+
} else {
|
|
546
|
+
notReadyPods.push(pod);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return { ready: notReadyPods.length === 0, notReadyPods, readyPods };
|
|
550
|
+
},
|
|
531
551
|
};
|
|
532
552
|
}
|
|
533
553
|
|
package/src/cli/index.js
CHANGED
|
@@ -112,6 +112,7 @@ program
|
|
|
112
112
|
.option('--mariadb', 'Initializes the cluster with a MariaDB statefulset.')
|
|
113
113
|
.option('--mysql', 'Initializes the cluster with a MySQL statefulset.')
|
|
114
114
|
.option('--mongodb', 'Initializes the cluster with a MongoDB statefulset.')
|
|
115
|
+
.option('--mongo-db-host <host>', 'Set custom mongo db host')
|
|
115
116
|
.option('--postgresql', 'Initializes the cluster with a PostgreSQL statefulset.')
|
|
116
117
|
.option('--mongodb4', 'Initializes the cluster with a MongoDB 4.4 service.')
|
|
117
118
|
.option('--valkey', 'Initializes the cluster with a Valkey service.')
|
|
@@ -315,6 +316,13 @@ program
|
|
|
315
316
|
.description('Manages health server monitoring for specified deployments.')
|
|
316
317
|
.action(Underpost.monitor.callback);
|
|
317
318
|
|
|
319
|
+
// 'ssh' command: SSH management
|
|
320
|
+
program
|
|
321
|
+
.command('ssh')
|
|
322
|
+
.option('--generate', 'Generates new ssh credential and stores it in current private keys file storage.')
|
|
323
|
+
.description('Import and start ssh server and client based on current default deployment ID.')
|
|
324
|
+
.action(Underpost.ssh.callback);
|
|
325
|
+
|
|
318
326
|
// 'run' command: Run a script
|
|
319
327
|
program
|
|
320
328
|
.command('run')
|
|
@@ -326,6 +334,7 @@ program
|
|
|
326
334
|
.option('--pod-name <pod-name>', 'Optional: Specifies the pod name for test execution.')
|
|
327
335
|
.option('--volume-host-path <volume-host-path>', 'Optional: Specifies the volume host path for test execution.')
|
|
328
336
|
.option('--volume-mount-path <volume-mount-path>', 'Optional: Specifies the volume mount path for test execution.')
|
|
337
|
+
.option('--volume-type <volume-type>', 'Optional: Specifies the volume type for test execution.')
|
|
329
338
|
.option('--image-name <image-name>', 'Optional: Specifies the image name for test execution.')
|
|
330
339
|
.option('--container-name <container-name>', 'Optional: Specifies the container name for test execution.')
|
|
331
340
|
.option('--namespace <namespace>', 'Optional: Specifies the namespace for test execution.')
|
package/src/cli/monitor.js
CHANGED
|
@@ -173,19 +173,15 @@ class UnderpostMonitor {
|
|
|
173
173
|
monitorTrafficName = undefined;
|
|
174
174
|
monitorPodName = undefined;
|
|
175
175
|
}
|
|
176
|
-
const cmd = `underpost config get container-status`;
|
|
177
176
|
const checkDeploymentReadyStatus = () => {
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
monitorPodName = NAME;
|
|
187
|
-
monitorTrafficName = `${traffic}`;
|
|
188
|
-
}
|
|
177
|
+
const { ready, notReadyPods, readyPods } = UnderpostDeploy.API.checkDeploymentReadyStatus(
|
|
178
|
+
deployId,
|
|
179
|
+
env,
|
|
180
|
+
traffic,
|
|
181
|
+
);
|
|
182
|
+
if (ready) {
|
|
183
|
+
monitorPodName = readyPods[0].NAME;
|
|
184
|
+
monitorTrafficName = `${traffic}`;
|
|
189
185
|
}
|
|
190
186
|
};
|
|
191
187
|
if (!monitorPodName) {
|
package/src/cli/run.js
CHANGED
|
@@ -6,6 +6,7 @@ import UnderpostTest from './test.js';
|
|
|
6
6
|
import fs from 'fs-extra';
|
|
7
7
|
import { range, setPad, timer } from '../client/components/core/CommonJs.js';
|
|
8
8
|
import UnderpostDeploy from './deploy.js';
|
|
9
|
+
import UnderpostRootEnv from './env.js';
|
|
9
10
|
|
|
10
11
|
const logger = loggerFactory(import.meta);
|
|
11
12
|
|
|
@@ -64,6 +65,41 @@ class UnderpostRun {
|
|
|
64
65
|
shellExec(`kubectl delete pod tf-gpu-test-pod`);
|
|
65
66
|
shellExec(`kubectl apply -f ${underpostRoot}/manifests/deployment/tensorflow/tf-gpu-test.yaml`);
|
|
66
67
|
},
|
|
68
|
+
'dev-cluster': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
69
|
+
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
70
|
+
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --reset`);
|
|
71
|
+
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''}`);
|
|
72
|
+
shellExec(
|
|
73
|
+
`${baseCommand} cluster${options.dev ? ' --dev' : ''} --mongodb --mongo-db-host ${'127.0.0.1'} --pull-image`,
|
|
74
|
+
);
|
|
75
|
+
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --valkey --pull-image`);
|
|
76
|
+
shellExec(`${baseCommand} deploy --expose mongo`, { async: true });
|
|
77
|
+
shellExec(`${baseCommand} deploy --expose valkey`, { async: true });
|
|
78
|
+
},
|
|
79
|
+
'cyberia-ide': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
80
|
+
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
81
|
+
shellExec(`${baseCommand} run ide /home/dd/cyberia-server`);
|
|
82
|
+
shellExec(`${baseCommand} run ide /home/dd/cyberia-client`);
|
|
83
|
+
},
|
|
84
|
+
'engine-ide': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
85
|
+
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
86
|
+
shellExec(`${baseCommand} run ide /home/dd/engine`);
|
|
87
|
+
shellExec(`${baseCommand} run ide /home/dd/engine/engine-private`);
|
|
88
|
+
},
|
|
89
|
+
'template-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
90
|
+
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
91
|
+
shellCd('/home/dd/engine');
|
|
92
|
+
shellExec(`git reset`);
|
|
93
|
+
shellExec(`${baseCommand} cmt . --empty ci package-pwa-microservices-template`);
|
|
94
|
+
shellExec(`${baseCommand} push . underpostnet/engine`);
|
|
95
|
+
},
|
|
96
|
+
'ssh-deploy': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
97
|
+
const baseCommand = options.dev || true ? 'node bin' : 'underpost';
|
|
98
|
+
shellCd('/home/dd/engine');
|
|
99
|
+
shellExec(`git reset`);
|
|
100
|
+
shellExec(`${baseCommand} cmt . --empty cd ssh-${path}`);
|
|
101
|
+
shellExec(`${baseCommand} push . underpostnet/engine`);
|
|
102
|
+
},
|
|
67
103
|
ide: (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
68
104
|
const { underpostRoot } = options;
|
|
69
105
|
shellExec(`node ${underpostRoot}/bin/vs ${path}`);
|
|
@@ -141,6 +177,66 @@ class UnderpostRun {
|
|
|
141
177
|
};
|
|
142
178
|
_monitor();
|
|
143
179
|
},
|
|
180
|
+
'db-client': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
181
|
+
const { underpostRoot } = options;
|
|
182
|
+
shellExec(`kubectl apply -k ${underpostRoot}/manifests/deployment/adminer/.`);
|
|
183
|
+
},
|
|
184
|
+
cluster: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
185
|
+
const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
|
|
186
|
+
const env = 'production';
|
|
187
|
+
shellCd(`/home/dd/engine`);
|
|
188
|
+
shellExec(`underpost cluster --reset`);
|
|
189
|
+
await timer(5000);
|
|
190
|
+
shellExec(`underpost cluster --kubeadm`);
|
|
191
|
+
await timer(5000);
|
|
192
|
+
shellExec(`underpost dockerfile-pull-base-images --path /home/dd/engine/src/runtime/lampp --kubeadm-load`);
|
|
193
|
+
await timer(5000);
|
|
194
|
+
shellExec(`underpost cluster --kubeadm --pull-image --mongodb`);
|
|
195
|
+
await timer(5000);
|
|
196
|
+
shellExec(`underpost cluster --kubeadm --pull-image --mariadb`);
|
|
197
|
+
await timer(5000);
|
|
198
|
+
for (const deployId of deployList) {
|
|
199
|
+
shellExec(`underpost db ${deployId} --import --git`);
|
|
200
|
+
}
|
|
201
|
+
await timer(5000);
|
|
202
|
+
shellExec(`underpost cluster --kubeadm --pull-image --valkey`);
|
|
203
|
+
await timer(5000);
|
|
204
|
+
shellExec(`underpost cluster --kubeadm --contour`);
|
|
205
|
+
await timer(5000);
|
|
206
|
+
shellExec(`underpost cluster --kubeadm --cert-manager`);
|
|
207
|
+
for (const deployId of deployList) {
|
|
208
|
+
shellExec(`underpost deploy ${deployId} ${env} --kubeadm --cert`);
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
deploy: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
212
|
+
const deployId = path;
|
|
213
|
+
const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
|
|
214
|
+
const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
|
|
215
|
+
const env = 'production';
|
|
216
|
+
const ignorePods = UnderpostDeploy.API.get(`${deployId}-${env}-${targetTraffic}`).map((p) => p.NAME);
|
|
217
|
+
shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${targetTraffic}`);
|
|
218
|
+
|
|
219
|
+
let secondsElapsed = 0;
|
|
220
|
+
logger.info('Deployment init', { deployId, env, targetTraffic });
|
|
221
|
+
|
|
222
|
+
while (!UnderpostDeploy.API.checkDeploymentReadyStatus(deployId, env, targetTraffic, ignorePods).ready) {
|
|
223
|
+
await timer(1000);
|
|
224
|
+
secondsElapsed++;
|
|
225
|
+
logger.info(`Deployment in progress, seconds elapsed: ${secondsElapsed}`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
logger.info(`Deployment ready, seconds elapsed: ${secondsElapsed}`);
|
|
229
|
+
|
|
230
|
+
UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, targetTraffic);
|
|
231
|
+
|
|
232
|
+
shellExec(
|
|
233
|
+
`node bin deploy --info-router --build-manifest --traffic ${targetTraffic} --replicas ${
|
|
234
|
+
options.replicas ? options.replicas : 1
|
|
235
|
+
} ${deployId} ${env}`,
|
|
236
|
+
);
|
|
237
|
+
shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
|
|
238
|
+
shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${currentTraffic}`);
|
|
239
|
+
},
|
|
144
240
|
'tf-vae-test': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
145
241
|
const { underpostRoot } = options;
|
|
146
242
|
const podName = 'tf-vae-test';
|
|
@@ -187,6 +283,12 @@ class UnderpostRun {
|
|
|
187
283
|
const volumeHostPath = options.volumeHostPath || path;
|
|
188
284
|
const enableVolumeMount = volumeHostPath && volumeMountPath;
|
|
189
285
|
|
|
286
|
+
if (options.volumeType === 'dev') options.volumeType = 'FileOrCreate';
|
|
287
|
+
const volumeType =
|
|
288
|
+
options.volumeType || (enableVolumeMount && fs.statSync(volumeHostPath).isDirectory()) ? 'Directory' : 'File';
|
|
289
|
+
|
|
290
|
+
const envs = UnderpostRootEnv.API.list();
|
|
291
|
+
|
|
190
292
|
const cmd = `kubectl apply -f - <<EOF
|
|
191
293
|
apiVersion: v1
|
|
192
294
|
kind: Pod
|
|
@@ -210,16 +312,19 @@ ${
|
|
|
210
312
|
${args.map((arg) => ` ${arg}`).join('\n')}`
|
|
211
313
|
: ''
|
|
212
314
|
}
|
|
213
|
-
${
|
|
315
|
+
${`${
|
|
214
316
|
gpuEnable
|
|
215
317
|
? ` resources:
|
|
216
318
|
limits:
|
|
217
319
|
nvidia.com/gpu: '1'
|
|
218
|
-
|
|
219
|
-
- name: NVIDIA_VISIBLE_DEVICES
|
|
220
|
-
value: all`
|
|
320
|
+
`
|
|
221
321
|
: ''
|
|
222
|
-
}
|
|
322
|
+
} env:
|
|
323
|
+
${Object.keys(envs)
|
|
324
|
+
.map((key) => ({ key, value: typeof envs[key] === 'number' ? envs[key] : `"${envs[key]}"` }))
|
|
325
|
+
.concat(gpuEnable ? [{ key: 'NVIDIA_VISIBLE_DEVICES', value: 'all' }] : [])
|
|
326
|
+
.map((env) => ` - name: ${env.key}\n value: ${env.value}`)
|
|
327
|
+
.join('\n')}`}
|
|
223
328
|
${
|
|
224
329
|
enableVolumeMount
|
|
225
330
|
? `
|
|
@@ -230,7 +335,7 @@ ${
|
|
|
230
335
|
- name: ${volumeName}
|
|
231
336
|
hostPath:
|
|
232
337
|
path: ${volumeHostPath}
|
|
233
|
-
type: ${
|
|
338
|
+
type: ${volumeType}`
|
|
234
339
|
: ''
|
|
235
340
|
}
|
|
236
341
|
EOF`;
|
package/src/cli/ssh.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getNpmRootPath } from '../server/conf.js';
|
|
2
|
+
import { shellExec } from '../server/process.js';
|
|
3
|
+
|
|
4
|
+
class UnderpostSSH {
|
|
5
|
+
static API = {
|
|
6
|
+
/**
|
|
7
|
+
* @method callback
|
|
8
|
+
* @param {object} options
|
|
9
|
+
* @param {boolean} options.generate - Generates new ssh credential and stores it in current private keys file storage.
|
|
10
|
+
* @description Import and start ssh server and client based on current default deployment ID.
|
|
11
|
+
*/
|
|
12
|
+
callback: async (
|
|
13
|
+
options = {
|
|
14
|
+
generate: false,
|
|
15
|
+
},
|
|
16
|
+
) => {
|
|
17
|
+
// only import + start
|
|
18
|
+
// node bin/deploy ssh root@<host> <password> import
|
|
19
|
+
|
|
20
|
+
// generate + import + start
|
|
21
|
+
// node bin/deploy ssh root@<host> <password>
|
|
22
|
+
|
|
23
|
+
shellExec(
|
|
24
|
+
`node bin/deploy ssh root@${process.env.DEFAULT_DEPLOY_HOST} ${process.env.DEFAULT_DEPLOY_PASSWORD ?? `''`}${
|
|
25
|
+
options.generate === true ? '' : ' import'
|
|
26
|
+
}`,
|
|
27
|
+
);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default UnderpostSSH;
|
|
@@ -16,21 +16,25 @@ import { SocketIo } from './components/core/SocketIo.js';
|
|
|
16
16
|
import { SocketIoDefault } from './components/default/SocketIoDefault.js';
|
|
17
17
|
import { ElementsDefault } from './components/default/ElementsDefault.js';
|
|
18
18
|
import { Scroll } from './components/core/Scroll.js';
|
|
19
|
+
import { CssDefaultDark, CssDefaultLight } from './components/default/CssDefault.js';
|
|
19
20
|
|
|
20
21
|
const htmlMainBody = async () => {
|
|
21
|
-
return html`<span
|
|
22
|
+
return html`<span>Hello World!!</span>`;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
window.onload = () =>
|
|
25
26
|
Worker.instance({
|
|
26
27
|
router: RouterDefault,
|
|
27
28
|
render: async () => {
|
|
28
|
-
await Css.loadThemes();
|
|
29
|
+
await Css.loadThemes([CssDefaultLight, CssDefaultDark]);
|
|
29
30
|
await TranslateCore.Init();
|
|
30
31
|
await TranslateDefault.Init();
|
|
31
32
|
await Responsive.Init();
|
|
32
33
|
await MenuDefault.Render({ htmlMainBody });
|
|
33
|
-
await SocketIo.Init({
|
|
34
|
+
await SocketIo.Init({
|
|
35
|
+
channels: ElementsDefault.Data,
|
|
36
|
+
path: `/`,
|
|
37
|
+
});
|
|
34
38
|
await SocketIoDefault.Init();
|
|
35
39
|
await LogInDefault();
|
|
36
40
|
await LogOutDefault();
|
|
@@ -44,7 +44,7 @@ const Account = {
|
|
|
44
44
|
{ model: 'email', id: `account-email`, rules: [{ type: 'isEmpty' }, { type: 'isEmail' }] },
|
|
45
45
|
{
|
|
46
46
|
model: 'password',
|
|
47
|
-
defaultValue: '
|
|
47
|
+
defaultValue: '#Changethis123',
|
|
48
48
|
id: `account-password`,
|
|
49
49
|
rules: [{ type: 'isStrongPassword' }],
|
|
50
50
|
},
|
|
@@ -822,70 +822,72 @@ const generateRandomPasswordSelection = (length) => {
|
|
|
822
822
|
|
|
823
823
|
const commitData = {
|
|
824
824
|
feat: {
|
|
825
|
-
description: '
|
|
825
|
+
description: 'New feature or enhancement (frontend, backend, API, or UX)',
|
|
826
826
|
title: 'Features',
|
|
827
827
|
emoji: '✨',
|
|
828
828
|
},
|
|
829
829
|
fix: {
|
|
830
|
-
description: '
|
|
830
|
+
description: 'Fix a bug',
|
|
831
831
|
title: 'Bug Fixes',
|
|
832
832
|
emoji: '🐛',
|
|
833
833
|
},
|
|
834
834
|
docs: {
|
|
835
|
-
description: 'Documentation
|
|
835
|
+
description: 'Documentation changes',
|
|
836
836
|
title: 'Documentation',
|
|
837
837
|
emoji: '📚',
|
|
838
838
|
},
|
|
839
839
|
style: {
|
|
840
|
-
description:
|
|
841
|
-
'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)',
|
|
840
|
+
description: 'Formatting, whitespace, semicolons, code style',
|
|
842
841
|
title: 'Styles',
|
|
843
842
|
emoji: '💎',
|
|
844
843
|
},
|
|
845
844
|
refactor: {
|
|
846
|
-
description: '
|
|
845
|
+
description: 'Code refactor.',
|
|
847
846
|
title: 'Code Refactoring',
|
|
848
847
|
emoji: '📦',
|
|
849
848
|
},
|
|
850
849
|
perf: {
|
|
851
|
-
description: '
|
|
850
|
+
description: 'Performance improvements across the stack.',
|
|
852
851
|
title: 'Performance Improvements',
|
|
853
852
|
emoji: '⚡️',
|
|
854
853
|
},
|
|
854
|
+
ci: {
|
|
855
|
+
description: 'CI pipeline changes (GitHub Actions, runners, caching)',
|
|
856
|
+
title: 'Continuous Integration',
|
|
857
|
+
emoji: '⚙️',
|
|
858
|
+
},
|
|
855
859
|
cd: {
|
|
856
|
-
description:
|
|
857
|
-
'Changes to our Continuous Delivery configuration files and scripts (example scopes: Jenkins, Spinnaker, ArgoCD)',
|
|
860
|
+
description: 'CD / deployment changes (Remote ssh deployment scripts)',
|
|
858
861
|
title: 'Continuous Delivery',
|
|
859
862
|
emoji: '🚀',
|
|
860
863
|
},
|
|
861
|
-
|
|
862
|
-
description: '
|
|
863
|
-
title: '
|
|
864
|
-
emoji: '
|
|
864
|
+
infra: {
|
|
865
|
+
description: 'Infrastructure changes (MAAS, LXD, cloud infra, networking, provisioning).',
|
|
866
|
+
title: 'Infrastructure',
|
|
867
|
+
emoji: '🏗️',
|
|
865
868
|
},
|
|
866
869
|
build: {
|
|
867
|
-
description: '
|
|
870
|
+
description: 'Build system or dependency changes (tooling, bundler, build scripts).',
|
|
868
871
|
title: 'Builds',
|
|
869
872
|
emoji: '🛠',
|
|
870
873
|
},
|
|
871
|
-
|
|
872
|
-
description:
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
emoji: '⚙️',
|
|
874
|
+
test: {
|
|
875
|
+
description: 'Unit or integration tests added/updated, test helpers, flake fixes.',
|
|
876
|
+
title: 'Tests',
|
|
877
|
+
emoji: '🚨',
|
|
876
878
|
},
|
|
877
879
|
chore: {
|
|
878
|
-
description: "Other changes that don't modify src or
|
|
880
|
+
description: "Other changes that don't modify src or tests (automation, housekeeping).",
|
|
879
881
|
title: 'Chores',
|
|
880
882
|
emoji: '♻️',
|
|
881
883
|
},
|
|
882
884
|
revert: {
|
|
883
|
-
description: '
|
|
885
|
+
description: 'Revert a previous commit or change.',
|
|
884
886
|
title: 'Reverts',
|
|
885
887
|
emoji: '🗑',
|
|
886
888
|
},
|
|
887
889
|
backup: {
|
|
888
|
-
description: '
|
|
890
|
+
description: 'Backups, snapshotting, restore scripts, or backup docs.',
|
|
889
891
|
title: 'Backups',
|
|
890
892
|
emoji: '💾',
|
|
891
893
|
},
|