underpost 2.8.82 → 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.
Files changed (115) hide show
  1. package/.env.development +1 -0
  2. package/.env.production +1 -0
  3. package/.env.test +1 -0
  4. package/.github/workflows/{ghpkg.yml → ghpkg.ci.yml} +5 -5
  5. package/.github/workflows/{npmpkg.yml → npmpkg.ci.yml} +5 -5
  6. package/.github/workflows/{publish.yml → publish.ci.yml} +1 -1
  7. package/.github/workflows/{pwa-microservices-template.page.yml → pwa-microservices-template-page.cd.yml} +1 -1
  8. package/.github/workflows/{pwa-microservices-template.test.yml → pwa-microservices-template-test.ci.yml} +1 -1
  9. package/.vscode/extensions.json +1 -1
  10. package/.vscode/settings.json +0 -44
  11. package/README.md +62 -2
  12. package/bin/build.js +15 -5
  13. package/bin/deploy.js +42 -92
  14. package/bin/file.js +33 -9
  15. package/bin/vs.js +12 -4
  16. package/cli.md +90 -42
  17. package/conf.js +1 -1
  18. package/docker-compose.yml +1 -1
  19. package/manifests/deployment/dd-template-development/deployment.yaml +2 -2
  20. package/manifests/deployment/tensorflow/tf-gpu-test.yaml +65 -0
  21. package/manifests/maas/device-scan.sh +3 -3
  22. package/manifests/maas/gpu-diag.sh +19 -0
  23. package/manifests/maas/maas-setup.sh +10 -10
  24. package/manifests/maas/snap-clean.sh +26 -0
  25. package/package.json +4 -6
  26. package/src/api/user/user.router.js +24 -1
  27. package/src/api/user/user.service.js +1 -4
  28. package/src/cli/baremetal.js +105 -73
  29. package/src/cli/cloud-init.js +21 -12
  30. package/src/cli/cluster.js +227 -133
  31. package/src/cli/deploy.js +34 -0
  32. package/src/cli/index.js +28 -1
  33. package/src/cli/monitor.js +8 -12
  34. package/src/cli/repository.js +7 -4
  35. package/src/cli/run.js +367 -0
  36. package/src/cli/ssh.js +32 -0
  37. package/src/cli/test.js +1 -1
  38. package/src/client/Default.index.js +7 -3
  39. package/src/client/components/core/Account.js +1 -1
  40. package/src/client/components/core/Chat.js +1 -1
  41. package/src/client/components/core/CommonJs.js +24 -22
  42. package/src/client/components/core/Content.js +1 -5
  43. package/src/client/components/core/Css.js +258 -18
  44. package/src/client/components/core/CssCore.js +8 -8
  45. package/src/client/components/core/Docs.js +14 -61
  46. package/src/client/components/core/DropDown.js +137 -82
  47. package/src/client/components/core/EventsUI.js +92 -5
  48. package/src/client/components/core/LoadingAnimation.js +8 -15
  49. package/src/client/components/core/Modal.js +597 -136
  50. package/src/client/components/core/NotificationManager.js +2 -2
  51. package/src/client/components/core/ObjectLayerEngine.js +638 -0
  52. package/src/client/components/core/Panel.js +158 -34
  53. package/src/client/components/core/PanelForm.js +12 -3
  54. package/src/client/components/core/Recover.js +1 -1
  55. package/src/client/components/core/Router.js +77 -17
  56. package/src/client/components/core/SocketIo.js +3 -3
  57. package/src/client/components/core/Translate.js +6 -2
  58. package/src/client/components/core/VanillaJs.js +0 -3
  59. package/src/client/components/core/Worker.js +3 -1
  60. package/src/client/components/default/CssDefault.js +17 -3
  61. package/src/client/components/default/MenuDefault.js +264 -45
  62. package/src/client/components/default/RoutesDefault.js +6 -12
  63. package/src/client/public/default/android-chrome-144x144.png +0 -0
  64. package/src/client/public/default/android-chrome-192x192.png +0 -0
  65. package/src/client/public/default/android-chrome-256x256.png +0 -0
  66. package/src/client/public/default/android-chrome-36x36.png +0 -0
  67. package/src/client/public/default/android-chrome-48x48.png +0 -0
  68. package/src/client/public/default/android-chrome-72x72.png +0 -0
  69. package/src/client/public/default/android-chrome-96x96.png +0 -0
  70. package/src/client/public/default/apple-touch-icon-114x114-precomposed.png +0 -0
  71. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  72. package/src/client/public/default/apple-touch-icon-120x120-precomposed.png +0 -0
  73. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  74. package/src/client/public/default/apple-touch-icon-144x144-precomposed.png +0 -0
  75. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  76. package/src/client/public/default/apple-touch-icon-152x152-precomposed.png +0 -0
  77. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  78. package/src/client/public/default/apple-touch-icon-180x180-precomposed.png +0 -0
  79. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  80. package/src/client/public/default/apple-touch-icon-57x57-precomposed.png +0 -0
  81. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  82. package/src/client/public/default/apple-touch-icon-60x60-precomposed.png +0 -0
  83. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  84. package/src/client/public/default/apple-touch-icon-72x72-precomposed.png +0 -0
  85. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  86. package/src/client/public/default/apple-touch-icon-76x76-precomposed.png +0 -0
  87. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  88. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  89. package/src/client/public/default/apple-touch-icon.png +0 -0
  90. package/src/client/public/default/assets/background/dark.jpg +0 -0
  91. package/src/client/public/default/assets/background/dark.svg +557 -0
  92. package/src/client/public/default/assets/logo/base-icon.png +0 -0
  93. package/src/client/public/default/assets/logo/underpost.gif +0 -0
  94. package/src/client/public/default/assets/mailer/api-user-check.png +0 -0
  95. package/src/client/public/default/assets/mailer/api-user-invalid-token.png +0 -0
  96. package/src/client/public/default/assets/mailer/api-user-recover.png +0 -0
  97. package/src/client/public/default/favicon-16x16.png +0 -0
  98. package/src/client/public/default/favicon-32x32.png +0 -0
  99. package/src/client/public/default/favicon.ico +0 -0
  100. package/src/client/public/default/mstile-144x144.png +0 -0
  101. package/src/client/public/default/mstile-150x150.png +0 -0
  102. package/src/client/public/default/mstile-310x150.png +0 -0
  103. package/src/client/public/default/mstile-310x310.png +0 -0
  104. package/src/client/public/default/mstile-70x70.png +0 -0
  105. package/src/client/public/default/safari-pinned-tab.svg +24 -0
  106. package/src/client/ssr/body/DefaultSplashScreen.js +2 -2
  107. package/src/index.js +34 -17
  108. package/src/monitor.js +24 -0
  109. package/src/runtime/lampp/Dockerfile +30 -39
  110. package/src/runtime/lampp/Lampp.js +11 -2
  111. package/src/server/client-build-docs.js +205 -0
  112. package/src/server/client-build.js +16 -166
  113. package/src/server/conf.js +18 -8
  114. package/src/server/process.js +16 -19
  115. package/src/server/valkey.js +102 -41
@@ -1,6 +1,7 @@
1
1
  import { getNpmRootPath } from '../server/conf.js';
2
2
  import { loggerFactory } from '../server/logger.js';
3
3
  import { shellExec } from '../server/process.js';
4
+ import UnderpostBaremetal from './baremetal.js';
4
5
  import UnderpostDeploy from './deploy.js';
5
6
  import UnderpostTest from './test.js';
6
7
  import os from 'os';
@@ -18,6 +19,7 @@ class UnderpostCluster {
18
19
  * @param {object} [options] - Configuration options for cluster initialization.
19
20
  * @param {boolean} [options.mongodb=false] - Deploy MongoDB.
20
21
  * @param {boolean} [options.mongodb4=false] - Deploy MongoDB 4.4.
22
+ * @param {String} [options.mongoDbHost=''] - Set custom mongo db host
21
23
  * @param {boolean} [options.mariadb=false] - Deploy MariaDB.
22
24
  * @param {boolean} [options.mysql=false] - Deploy MySQL.
23
25
  * @param {boolean} [options.postgresql=false] - Deploy PostgreSQL.
@@ -37,6 +39,7 @@ class UnderpostCluster {
37
39
  * @param {boolean} [options.kubeadm=false] - Initialize the cluster using Kubeadm.
38
40
  * @param {boolean} [options.k3s=false] - Initialize the cluster using K3s.
39
41
  * @param {boolean} [options.initHost=false] - Perform initial host setup (install Docker, Podman, Kind, Kubeadm, Helm).
42
+ * @param {boolean} [options.uninstallHost=false] - Uninstall all host components.
40
43
  * @param {boolean} [options.config=false] - Apply general host configuration (SELinux, containerd, sysctl, firewalld).
41
44
  * @param {boolean} [options.worker=false] - Configure as a worker node (for Kubeadm or K3s join).
42
45
  * @param {boolean} [options.chown=false] - Set up kubectl configuration for the current user.
@@ -46,6 +49,7 @@ class UnderpostCluster {
46
49
  options = {
47
50
  mongodb: false,
48
51
  mongodb4: false,
52
+ mongoDbHost: '',
49
53
  mariadb: false,
50
54
  mysql: false,
51
55
  postgresql: false,
@@ -65,6 +69,7 @@ class UnderpostCluster {
65
69
  kubeadm: false,
66
70
  k3s: false,
67
71
  initHost: false,
72
+ uninstallHost: false,
68
73
  config: false,
69
74
  worker: false,
70
75
  chown: false,
@@ -73,6 +78,9 @@ class UnderpostCluster {
73
78
  // Handles initial host setup (installing docker, podman, kind, kubeadm, helm)
74
79
  if (options.initHost === true) return UnderpostCluster.API.initHost();
75
80
 
81
+ // Handles initial host setup (installing docker, podman, kind, kubeadm, helm)
82
+ if (options.uninstallHost === true) return UnderpostCluster.API.uninstallHost();
83
+
76
84
  // Applies general host configuration (SELinux, containerd, sysctl)
77
85
  if (options.config === true) return UnderpostCluster.API.config();
78
86
 
@@ -126,7 +134,7 @@ class UnderpostCluster {
126
134
  }
127
135
 
128
136
  // Reset Kubernetes cluster components (Kind/Kubeadm/K3s) and container runtimes
129
- if (options.reset === true) return await UnderpostCluster.API.reset();
137
+ if (options.reset === true) return await UnderpostCluster.API.safeReset({ underpostRoot });
130
138
 
131
139
  // Check if a cluster (Kind, Kubeadm, or K3s) is already initialized
132
140
  const alreadyKubeadmCluster = UnderpostDeploy.API.get('calico-kube-controllers')[0];
@@ -138,6 +146,7 @@ class UnderpostCluster {
138
146
  // This block handles the initial setup of the Kubernetes cluster (control plane or worker).
139
147
  // It prevents re-initialization if a cluster is already detected.
140
148
  if (!options.worker && !alreadyKubeadmCluster && !alreadyKindCluster && !alreadyK3sCluster) {
149
+ UnderpostCluster.API.config();
141
150
  if (options.k3s === true) {
142
151
  logger.info('Initializing K3s control plane...');
143
152
  // Install K3s
@@ -253,17 +262,18 @@ class UnderpostCluster {
253
262
 
254
263
  if (options.full === true || options.valkey === true) {
255
264
  if (options.pullImage === true) {
256
- shellExec(`docker pull valkey/valkey:latest`);
257
- shellExec(`sudo podman pull valkey/valkey:latest`);
258
- if (!options.kubeadm && !options.k3s)
265
+ // shellExec(`sudo podman pull valkey/valkey:latest`);
266
+ if (!options.kubeadm && !options.k3s) {
259
267
  // Only load if not kubeadm/k3s (Kind needs it)
268
+ shellExec(`docker pull valkey/valkey:latest`);
260
269
  shellExec(`sudo kind load docker-image valkey/valkey:latest`);
261
- else if (options.kubeadm || options.k3s)
270
+ } else if (options.kubeadm || options.k3s)
262
271
  // For kubeadm/k3s, ensure it's available for containerd
263
272
  shellExec(`sudo crictl pull valkey/valkey:latest`);
264
273
  }
265
274
  shellExec(`kubectl delete statefulset valkey-service --ignore-not-found`);
266
275
  shellExec(`kubectl apply -k ${underpostRoot}/manifests/valkey`);
276
+ await UnderpostTest.API.statusMonitor('valkey-service', 'Running', 'pods', 1000, 60);
267
277
  }
268
278
  if (options.full === true || options.mariadb === true) {
269
279
  shellExec(
@@ -272,18 +282,16 @@ class UnderpostCluster {
272
282
  shellExec(`kubectl delete statefulset mariadb-statefulset --ignore-not-found`);
273
283
 
274
284
  if (options.pullImage === true) {
275
- shellExec(`docker pull mariadb:latest`);
276
- shellExec(`sudo podman pull mariadb:latest`);
277
- if (!options.kubeadm && !options.k3s)
285
+ // shellExec(`sudo podman pull mariadb:latest`);
286
+ if (!options.kubeadm && !options.k3s) {
278
287
  // Only load if not kubeadm/k3s (Kind needs it)
288
+ shellExec(`docker pull mariadb:latest`);
279
289
  shellExec(`sudo kind load docker-image mariadb:latest`);
280
- else if (options.kubeadm || options.k3s)
290
+ } else if (options.kubeadm || options.k3s)
281
291
  // For kubeadm/k3s, ensure it's available for containerd
282
292
  shellExec(`sudo crictl pull mariadb:latest`);
283
293
  }
284
- if (options.kubeadm === true)
285
- // This storage class is specific to kubeadm setup
286
- shellExec(`kubectl apply -f ${underpostRoot}/manifests/mariadb/storage-class.yaml`);
294
+ shellExec(`kubectl apply -f ${underpostRoot}/manifests/mariadb/storage-class.yaml`);
287
295
  shellExec(`kubectl apply -k ${underpostRoot}/manifests/mariadb`);
288
296
  }
289
297
  if (options.full === true || options.mysql === true) {
@@ -297,11 +305,11 @@ class UnderpostCluster {
297
305
  }
298
306
  if (options.full === true || options.postgresql === true) {
299
307
  if (options.pullImage === true) {
300
- shellExec(`docker pull postgres:latest`);
301
- if (!options.kubeadm && !options.k3s)
308
+ if (!options.kubeadm && !options.k3s) {
302
309
  // Only load if not kubeadm/k3s (Kind needs it)
310
+ shellExec(`docker pull postgres:latest`);
303
311
  shellExec(`sudo kind load docker-image postgres:latest`);
304
- else if (options.kubeadm || options.k3s)
312
+ } else if (options.kubeadm || options.k3s)
305
313
  // For kubeadm/k3s, ensure it's available for containerd
306
314
  shellExec(`sudo crictl pull postgres:latest`);
307
315
  }
@@ -312,11 +320,11 @@ class UnderpostCluster {
312
320
  }
313
321
  if (options.mongodb4 === true) {
314
322
  if (options.pullImage === true) {
315
- shellExec(`docker pull mongo:4.4`);
316
- if (!options.kubeadm && !options.k3s)
323
+ if (!options.kubeadm && !options.k3s) {
317
324
  // Only load if not kubeadm/k3s (Kind needs it)
325
+ shellExec(`docker pull mongo:4.4`);
318
326
  shellExec(`sudo kind load docker-image mongo:4.4`);
319
- else if (options.kubeadm || options.k3s)
327
+ } else if (options.kubeadm || options.k3s)
320
328
  // For kubeadm/k3s, ensure it's available for containerd
321
329
  shellExec(`sudo crictl pull mongo:4.4`);
322
330
  }
@@ -327,9 +335,10 @@ class UnderpostCluster {
327
335
  const successInstance = await UnderpostTest.API.statusMonitor(deploymentName);
328
336
 
329
337
  if (successInstance) {
338
+ if (!options.mongoDbHost) options.mongoDbHost = 'mongodb-service';
330
339
  const mongoConfig = {
331
340
  _id: 'rs0',
332
- members: [{ _id: 0, host: 'mongodb-service:27017' }],
341
+ members: [{ _id: 0, host: `${options.mongoDbHost}:27017` }],
333
342
  };
334
343
 
335
344
  const [pod] = UnderpostDeploy.API.get(deploymentName);
@@ -341,11 +350,11 @@ class UnderpostCluster {
341
350
  }
342
351
  } else if (options.full === true || options.mongodb === true) {
343
352
  if (options.pullImage === true) {
344
- shellExec(`docker pull mongo:latest`);
345
- if (!options.kubeadm && !options.k3s)
353
+ if (!options.kubeadm && !options.k3s) {
346
354
  // Only load if not kubeadm/k3s (Kind needs it)
355
+ shellExec(`docker pull mongo:latest`);
347
356
  shellExec(`sudo kind load docker-image mongo:latest`);
348
- else if (options.kubeadm || options.k3s)
357
+ } else if (options.kubeadm || options.k3s)
349
358
  // For kubeadm/k3s, ensure it's available for containerd
350
359
  shellExec(`sudo crictl pull mongo:latest`);
351
360
  }
@@ -356,19 +365,26 @@ class UnderpostCluster {
356
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 -`,
357
366
  );
358
367
  shellExec(`kubectl delete statefulset mongodb --ignore-not-found`);
359
- if (options.kubeadm === true)
360
- // This storage class is specific to kubeadm setup
361
- shellExec(`kubectl apply -f ${underpostRoot}/manifests/mongodb/storage-class.yaml`);
368
+ shellExec(`kubectl apply -f ${underpostRoot}/manifests/mongodb/storage-class.yaml`);
362
369
  shellExec(`kubectl apply -k ${underpostRoot}/manifests/mongodb`);
363
370
 
364
- const successInstance = await UnderpostTest.API.statusMonitor('mongodb-1');
371
+ const successInstance = await UnderpostTest.API.statusMonitor('mongodb-0', 'Running', 'pods', 1000, 60 * 10);
365
372
 
366
373
  if (successInstance) {
374
+ if (!options.mongoDbHost) options.mongoDbHost = 'mongodb-service';
367
375
  const mongoConfig = {
368
376
  _id: 'rs0',
369
377
  members: [
370
- { _id: 0, host: 'mongodb-0.mongodb-service:27017', priority: 1 },
371
- { _id: 1, host: 'mongodb-1.mongodb-service:27017', priority: 1 },
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
+ // },
372
388
  ],
373
389
  };
374
390
 
@@ -415,8 +431,10 @@ class UnderpostCluster {
415
431
  * This method ensures proper SELinux, Docker, Containerd, and Sysctl settings
416
432
  * are applied for a healthy Kubernetes environment. It explicitly avoids
417
433
  * iptables flushing commands to prevent conflicts with Kubernetes' own network management.
434
+ * @param {string} underpostRoot - The root directory of the underpost project.
418
435
  */
419
- config() {
436
+ config(options = { underpostRoot: '.' }) {
437
+ const { underpostRoot } = options;
420
438
  console.log('Applying host configuration: SELinux, Docker, Containerd, and Sysctl settings.');
421
439
  // Disable SELinux (permissive mode)
422
440
  shellExec(`sudo setenforce 0`);
@@ -426,10 +444,14 @@ class UnderpostCluster {
426
444
  shellExec(`sudo systemctl enable --now docker || true`); // Docker might not be needed for K3s
427
445
  shellExec(`sudo systemctl enable --now kubelet || true`); // Kubelet might not be needed for K3s (K3s uses its own agent)
428
446
 
429
- // Configure containerd for SystemdCgroup
447
+ // Configure containerd for SystemdCgroup and explicitly disable SELinux
430
448
  // This is crucial for kubelet/k3s to interact correctly with containerd
431
449
  shellExec(`containerd config default | sudo tee /etc/containerd/config.toml > /dev/null`);
432
450
  shellExec(`sudo sed -i -e "s/SystemdCgroup = false/SystemdCgroup = true/g" /etc/containerd/config.toml`);
451
+ // Add a new line to disable SELinux for the runc runtime
452
+ // shellExec(
453
+ // `sudo sed -i '/SystemdCgroup = true/a selinux_disabled = true' /etc/containerd/config.toml || true`,
454
+ // );
433
455
  shellExec(`sudo service docker restart || true`); // Restart docker after containerd config changes
434
456
  shellExec(`sudo systemctl enable --now containerd.service`);
435
457
  shellExec(`sudo systemctl restart containerd`); // Restart containerd to apply changes
@@ -447,11 +469,22 @@ class UnderpostCluster {
447
469
  `/etc/sysctl.d/99-k8s-ipforward.conf`,
448
470
  `/etc/sysctl.d/99-k8s.conf`,
449
471
  ])
450
- shellExec(`echo 'net.bridge.bridge-nf-call-iptables = 1
472
+ shellExec(
473
+ `echo 'net.bridge.bridge-nf-call-iptables = 1
451
474
  net.bridge.bridge-nf-call-ip6tables = 1
452
475
  net.bridge.bridge-nf-call-arptables = 1
453
- net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`);
454
- shellExec(`sudo sysctl --system`); // Apply sysctl changes immediately
476
+ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
477
+ { silent: true },
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
+
485
+ // shellExec(`sudo sysctl --system`); // Apply sysctl changes immediately
486
+ // Apply NAT iptables rules.
487
+ shellExec(`${underpostRoot}/manifests/maas/nat-iptables.sh`, { silent: true });
455
488
 
456
489
  // Disable firewalld (common cause of network issues in Kubernetes)
457
490
  shellExec(`sudo systemctl stop firewalld || true`); // Stop if running
@@ -492,22 +525,40 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`);
492
525
  },
493
526
 
494
527
  /**
495
- * @method reset
496
- * @description Performs a comprehensive reset of Kubernetes and container environments.
497
- * This function is for cleaning up a node, reverting changes made by 'kubeadm init', 'kubeadm join', or 'k3s install'.
498
- * It includes deleting Kind clusters, resetting kubeadm, removing CNI configs,
499
- * cleaning Docker and Podman data, persistent volumes, and resetting kubelet components.
500
- * It avoids aggressive iptables flushing that would break host connectivity, relying on kube-proxy's
501
- * control loop to eventually clean up rules if the cluster is not re-initialized.
528
+ * @method safeReset
529
+ * @description Performs a complete reset of the Kubernetes cluster and its container environments.
530
+ * This version focuses on correcting persistent permission errors (such as 'permission denied'
531
+ * in coredns) by restoring SELinux security contexts and safely cleaning up cluster artifacts.
532
+ * @param {object} [options] - Configuration options for the reset.
533
+ * @param {string} [options.underpostRoot] - The root path of the underpost project.
502
534
  */
503
- async reset() {
504
- logger.info('Starting comprehensive reset of Kubernetes and container environments...');
535
+ async safeReset(options = { underpostRoot: '.' }) {
536
+ logger.info('Starting a safe and comprehensive reset of Kubernetes and container environments...');
505
537
 
506
538
  try {
507
- // Phase 1: Pre-reset Kubernetes Cleanup (while API server is still up)
508
- logger.info('Phase 1/6: Cleaning up Kubernetes resources (PVCs, PVs) while API server is accessible...');
539
+ // Phase 0: Truncate large logs under /var/log to free up immediate space
540
+ logger.info('Phase 0/7: Truncating large log files under /var/log...');
541
+ try {
542
+ const cleanPath = `/var/log/`;
543
+ const largeLogsFiles = shellExec(
544
+ `sudo du -sh ${cleanPath}* | awk '{if ($1 ~ /G$/ && ($1+0) > 1) print}' | sort -rh`,
545
+ {
546
+ stdout: true,
547
+ },
548
+ );
549
+ for (const pathLog of largeLogsFiles
550
+ .split(`\n`)
551
+ .map((p) => p.split(cleanPath)[1])
552
+ .filter((p) => p)) {
553
+ shellExec(`sudo rm -rf ${cleanPath}${pathLog}`);
554
+ }
555
+ } catch (err) {
556
+ logger.warn(` -> Error truncating log files: ${err.message}. Continuing with reset.`);
557
+ }
509
558
 
510
- // Get all Persistent Volumes and identify their host paths for data deletion.
559
+ // Phase 1: Clean up Persistent Volumes with hostPath
560
+ // This targets data created by Kubernetes Persistent Volumes that use hostPath.
561
+ logger.info('Phase 1/7: Cleaning Kubernetes hostPath volumes...');
511
562
  try {
512
563
  const pvListJson = shellExec(`kubectl get pv -o json || echo '{"items":[]}'`, { stdout: true, silent: true });
513
564
  const pvList = JSON.parse(pvListJson);
@@ -527,60 +578,66 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`);
527
578
  } catch (error) {
528
579
  logger.error('Failed to clean up Persistent Volumes:', error);
529
580
  }
530
-
531
- // Phase 2: Stop Kubelet/K3s agent and remove CNI configuration
532
- logger.info('Phase 2/6: Stopping Kubelet/K3s agent and removing CNI configurations...');
533
- shellExec(`sudo systemctl stop kubelet || true`); // Stop kubelet if it's running (kubeadm)
534
- shellExec(`sudo /usr/local/bin/k3s-uninstall.sh || true`); // Run K3s uninstall script if it exists
535
-
536
- // CNI plugins use /etc/cni/net.d to store their configuration.
581
+ // Phase 2: Restore SELinux and stop services
582
+ // This is critical for fixing the 'permission denied' error you experienced.
583
+ // Enable SELinux permissive mode and restore file contexts.
584
+ logger.info('Phase 2/7: Stopping services and fixing SELinux...');
585
+ logger.info(' -> Ensuring SELinux is in permissive mode...');
586
+ shellExec(`sudo setenforce 0 || true`);
587
+ shellExec(`sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config || true`);
588
+ logger.info(' -> Restoring SELinux contexts for container data directories...');
589
+ // The 'restorecon' command corrects file system security contexts.
590
+ shellExec(`sudo restorecon -Rv /var/lib/containerd || true`);
591
+ shellExec(`sudo restorecon -Rv /var/lib/kubelet || true`);
592
+
593
+ logger.info(' -> Stopping kubelet, docker, and podman services...');
594
+ shellExec('sudo systemctl stop kubelet || true');
595
+ shellExec('sudo systemctl stop docker || true');
596
+ shellExec('sudo systemctl stop podman || true');
597
+ // Safely unmount pod filesystems to avoid errors.
598
+ shellExec('sudo umount -f /var/lib/kubelet/pods/*/* || true');
599
+
600
+ // Phase 3: Execute official uninstallation commands
601
+ logger.info('Phase 3/7: Executing official reset and uninstallation commands...');
602
+ logger.info(' -> Executing kubeadm reset...');
603
+ shellExec('sudo kubeadm reset --force || true');
604
+ logger.info(' -> Executing K3s uninstallation script if it exists...');
605
+ shellExec('sudo /usr/local/bin/k3s-uninstall.sh || true');
606
+ logger.info(' -> Deleting Kind clusters...');
607
+ shellExec('kind get clusters | xargs -r -t -n1 kind delete cluster || true');
608
+
609
+ // Phase 4: File system cleanup
610
+ logger.info('Phase 4/7: Cleaning up remaining file system artifacts...');
611
+ // Remove any leftover configurations and data.
612
+ shellExec('sudo rm -rf /etc/kubernetes/* || true');
537
613
  shellExec('sudo rm -rf /etc/cni/net.d/* || true');
538
-
539
- // Phase 3: Kind Cluster Cleanup
540
- logger.info('Phase 3/6: Cleaning up Kind clusters...');
541
- shellExec(`kind get clusters | xargs -r -t -n1 kind delete cluster || true`);
542
-
543
- // Phase 4: Kubeadm Reset (if applicable)
544
- logger.info('Phase 4/6: Performing kubeadm reset (if applicable)...');
545
- shellExec(`sudo kubeadm reset --force || true`); // Use || true to prevent script from failing if kubeadm is not installed
546
-
547
- // Phase 5: Post-reset File System Cleanup (Local Storage, Kubeconfig)
548
- logger.info('Phase 5/6: Cleaning up local storage provisioner data and kubeconfig...');
614
+ shellExec('sudo rm -rf /var/lib/kubelet/* || true');
615
+ shellExec('sudo rm -rf /var/lib/cni/* || true');
616
+ shellExec('sudo rm -rf /var/lib/docker/* || true');
617
+ shellExec('sudo rm -rf /var/lib/containerd/* || true');
618
+ shellExec('sudo rm -rf /var/lib/containers/storage/* || true');
619
+ // Clean up the current user's kubeconfig.
549
620
  shellExec('rm -rf $HOME/.kube || true');
550
- shellExec(`sudo rm -rf /opt/local-path-provisioner/* || true`);
551
-
552
- // Phase 6: Container Runtime Cleanup (Docker and Podman)
553
- logger.info('Phase 6/6: Cleaning up Docker and Podman data...');
554
- shellExec('sudo docker system prune -a -f || true');
555
- shellExec('sudo service docker stop || true');
556
- shellExec(`sudo rm -rf /var/lib/containers/storage/* || true`);
557
- shellExec(`sudo rm -rf /var/lib/docker/volumes/* || true`);
558
- shellExec(`sudo rm -rf /var/lib/docker~/* || true`);
559
- shellExec(`sudo rm -rf /home/containers/storage/* || true`);
560
- shellExec(`sudo rm -rf /home/docker/* || true`);
561
- shellExec('sudo mkdir -p /home/docker || true');
562
- shellExec('sudo chmod 777 /home/docker || true');
563
- shellExec('sudo ln -sf /home/docker /var/lib/docker || true');
564
-
565
- shellExec(`sudo podman system prune -a -f || true`);
566
- shellExec(`sudo podman system prune --all --volumes --force || true`);
567
- shellExec(`sudo podman system prune --external --force || true`);
568
- shellExec(`sudo mkdir -p /home/containers/storage || true`);
569
- shellExec('sudo chmod 0711 /home/containers/storage || true');
570
- shellExec(
571
- `sudo sed -i -e "s@/var/lib/containers/storage@/home/containers/storage@g" /etc/containers/storage.conf || true`,
572
- );
573
- shellExec(`sudo podman system reset -f || true`);
574
-
575
- // Final Kubelet and System Cleanup (after all other operations)
576
- logger.info('Finalizing Kubelet and system file cleanup...');
577
- shellExec(`sudo rm -rf /etc/kubernetes/* || true`);
578
- shellExec(`sudo rm -rf /var/lib/kubelet/* || true`);
579
- shellExec(`sudo rm -rf /root/.local/share/Trash/files/* || true`);
580
- shellExec(`sudo systemctl daemon-reload`);
581
- shellExec(`sudo systemctl start kubelet || true`); // Attempt to start kubelet; might fail if fully reset
582
621
 
583
- logger.info('Comprehensive reset completed successfully.');
622
+ // Phase 5: Host network cleanup
623
+ logger.info('Phase 5/7: Cleaning up host network configurations...');
624
+ // Remove iptables rules and CNI network interfaces.
625
+ shellExec('sudo iptables -F || true');
626
+ shellExec('sudo iptables -t nat -F || true');
627
+ // Restore iptables rules
628
+ shellExec(`chmod +x ${options.underpostRoot}/manifests/maas/nat-iptables.sh`);
629
+ shellExec(`${options.underpostRoot}/manifests/maas/nat-iptables.sh`, { silent: true });
630
+ shellExec('sudo ip link del cni0 || true');
631
+ shellExec('sudo ip link del flannel.1 || true');
632
+
633
+ logger.info('Phase 6/7: Clean up images');
634
+ shellExec(`podman rmi $(podman images -qa) --force`);
635
+
636
+ // Phase 6: Reload daemon and finalize
637
+ logger.info('Phase 7/7: Reloading the system daemon and finalizing...');
638
+ // shellExec('sudo systemctl daemon-reload');
639
+ UnderpostCluster.API.config();
640
+ logger.info('Safe and complete reset finished. The system is ready for a new cluster initialization.');
584
641
  } catch (error) {
585
642
  logger.error(`Error during reset: ${error.message}`);
586
643
  console.error(error);
@@ -623,51 +680,24 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`);
623
680
  },
624
681
  /**
625
682
  * @method initHost
626
- * @description Installs essential host-level prerequisites for Kubernetes,
627
- * including Docker, Podman, Kind, Kubeadm, and Helm.
628
- *
629
- * Quick-Start Guide for K3s Installation:
630
- * This guide will help you quickly launch a cluster with default options. Make sure your nodes meet the requirements before proceeding.
631
- * Consult the Installation page for greater detail on installing and configuring K3s.
632
- * For information on how K3s components work together, refer to the Architecture page.
633
- * If you are new to Kubernetes, the official Kubernetes docs have great tutorials covering basics that all cluster administrators should be familiar with.
634
- *
635
- * Install Script:
636
- * K3s provides an installation script that is a convenient way to install it as a service on systemd or openrc based systems. This script is available at https://get.k3s.io. To install K3s using this method, just run:
637
- * curl -sfL https://get.k3s.io | sh -
638
- *
639
- * After running this installation:
640
- * - The K3s service will be configured to automatically restart after node reboots or if the process crashes or is killed
641
- * - Additional utilities will be installed, including kubectl, crictl, ctr, k3s-killall.sh, and k3s-uninstall.sh
642
- * - A kubeconfig file will be written to /etc/rancher/k3s/k3s.yaml and the kubectl installed by K3s will automatically use it
643
- *
644
- * A single-node server installation is a fully-functional Kubernetes cluster, including all the datastore, control-plane, kubelet, and container runtime components necessary to host workload pods. It is not necessary to add additional server or agents nodes, but you may want to do so to add additional capacity or redundancy to your cluster.
645
- *
646
- * To install additional agent nodes and add them to the cluster, run the installation script with the K3S_URL and K3S_TOKEN environment variables. Here is an example showing how to join an agent:
647
- * curl -sfL https://get.k3s.io | K3S_URL=https://myserver:6443 K3S_TOKEN=mynodetoken sh -
648
- *
649
- * Setting the K3S_URL parameter causes the installer to configure K3s as an agent, instead of a server. The K3s agent will register with the K3s server listening at the supplied URL. The value to use for K3S_TOKEN is stored at /var/lib/rancher/k3s/server/node-token on your server node.
650
- *
651
- * Note: Each machine must have a unique hostname. If your machines do not have unique hostnames, pass the K3S_NODE_NAME environment variable and provide a value with a valid and unique hostname for each node.
652
- * If you are interested in having more server nodes, see the High Availability Embedded etcd and High Availability External DB pages for more information.
683
+ * @description Installs essential host-level prerequisites for Kubernetes (Docker, Podman, Kind, Kubeadm, Helm).
653
684
  */
654
685
  initHost() {
655
- console.log(
656
- 'Installing essential host-level prerequisites for Kubernetes (Docker, Podman, Kind, Kubeadm, Helm) and providing K3s Quick-Start Guide information...',
657
- );
658
- // Install docker
659
- shellExec(`sudo dnf -y install dnf-plugins-core`);
686
+ const archData = UnderpostBaremetal.API.getHostArch();
687
+ logger.info('Installing essential host-level prerequisites for Kubernetes...', archData);
688
+ // Install Docker and its dependencies
689
+ shellExec(`sudo dnf -y install dnf-plugins-core dbus-x11`);
660
690
  shellExec(`sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo`);
661
691
  shellExec(`sudo dnf -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin`);
662
692
 
663
- // Install podman
693
+ // Install Podman
664
694
  shellExec(`sudo dnf -y install podman`);
665
695
 
666
- // Install kind
667
- shellExec(`[ $(uname -m) = aarch64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.29.0/kind-linux-arm64
696
+ // Install Kind (Kubernetes in Docker)
697
+ shellExec(`[ $(uname -m) = ${archData.name} ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.29.0/kind-linux-${archData.alias}
668
698
  chmod +x ./kind
669
699
  sudo mv ./kind /bin/kind`);
670
- // Install kubeadm, kubelet, kubectl (these are also useful for K3s for kubectl command)
700
+ // Install Kubernetes tools: Kubeadm, Kubelet, and Kubectl
671
701
  shellExec(`cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
672
702
  [kubernetes]
673
703
  name=Kubernetes
@@ -679,14 +709,78 @@ exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
679
709
  EOF`);
680
710
  shellExec(`sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes`);
681
711
 
682
- // Install helm
712
+ // Install Helm
683
713
  shellExec(`curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3`);
684
714
  shellExec(`chmod 700 get_helm.sh`);
685
715
  shellExec(`./get_helm.sh`);
686
716
  shellExec(`chmod +x /usr/local/bin/helm`);
687
717
  shellExec(`sudo mv /usr/local/bin/helm /bin/helm`);
718
+ shellExec(`sudo rm -rf get_helm.sh`);
688
719
  console.log('Host prerequisites installed successfully.');
689
720
  },
721
+ /**
722
+ * @method uninstallHost
723
+ * @description Uninstalls all host components installed by initHost.
724
+ * This includes Docker, Podman, Kind, Kubeadm, Kubelet, Kubectl, and Helm.
725
+ */
726
+ uninstallHost() {
727
+ console.log('Uninstalling host components: Docker, Podman, Kind, Kubeadm, Kubelet, Kubectl, Helm.');
728
+
729
+ // Remove Kind
730
+ console.log('Removing Kind...');
731
+ shellExec(`sudo rm -f /bin/kind || true`);
732
+
733
+ // Remove Helm
734
+ console.log('Removing Helm...');
735
+ shellExec(`sudo rm -f /usr/local/bin/helm || true`);
736
+ shellExec(`sudo rm -f /usr/local/bin/helm.sh || true`); // clean up the install script if it exists
737
+
738
+ // Remove Docker and its dependencies
739
+ console.log('Removing Docker, containerd, and related packages...');
740
+ shellExec(
741
+ `sudo dnf -y remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin || true`,
742
+ );
743
+
744
+ // Remove Podman
745
+ console.log('Removing Podman...');
746
+ shellExec(`sudo dnf -y remove podman || true`);
747
+
748
+ // Remove Kubeadm, Kubelet, and Kubectl
749
+ console.log('Removing Kubernetes tools...');
750
+ shellExec(`sudo yum remove -y kubelet kubeadm kubectl || true`);
751
+
752
+ // Remove Kubernetes repo file
753
+ console.log('Removing Kubernetes repository configuration...');
754
+ shellExec(`sudo rm -f /etc/yum.repos.d/kubernetes.repo || true`);
755
+
756
+ // Clean up Kubeadm config and data directories
757
+ console.log('Cleaning up Kubernetes configuration directories...');
758
+ shellExec(`sudo rm -rf /etc/kubernetes/pki || true`);
759
+ shellExec(`sudo rm -rf ~/.kube || true`);
760
+
761
+ // Stop and disable services
762
+ console.log('Stopping and disabling services...');
763
+ shellExec(`sudo systemctl stop docker.service || true`);
764
+ shellExec(`sudo systemctl disable docker.service || true`);
765
+ shellExec(`sudo systemctl stop containerd.service || true`);
766
+ shellExec(`sudo systemctl disable containerd.service || true`);
767
+ shellExec(`sudo systemctl stop kubelet.service || true`);
768
+ shellExec(`sudo systemctl disable kubelet.service || true`);
769
+
770
+ // Clean up config files
771
+ console.log('Removing host configuration files...');
772
+ shellExec(`sudo rm -f /etc/containerd/config.toml || true`);
773
+ shellExec(`sudo rm -f /etc/sysctl.d/k8s.conf || true`);
774
+ shellExec(`sudo rm -f /etc/sysctl.d/99-k8s-ipforward.conf || true`);
775
+ shellExec(`sudo rm -f /etc/sysctl.d/99-k8s.conf || true`);
776
+
777
+ // Restore SELinux to enforcing
778
+ console.log('Restoring SELinux to enforcing mode...');
779
+ // shellExec(`sudo setenforce 1`);
780
+ // shellExec(`sudo sed -i 's/^SELINUX=permissive$/SELINUX=enforcing/' /etc/selinux/config`);
781
+
782
+ console.log('Uninstall process completed.');
783
+ },
690
784
  };
691
785
  }
692
786
  export default UnderpostCluster;
package/src/cli/deploy.js CHANGED
@@ -296,6 +296,11 @@ kind: StatefulSet
296
296
  metadata:
297
297
  name: ...
298
298
  EOF
299
+
300
+ https://org.ngc.nvidia.com/setup/api-keys
301
+ docker login nvcr.io
302
+ Username: $oauthtoken
303
+ Password: <Your Key>
299
304
  `);
300
305
  if (deployList === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`))
301
306
  deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
@@ -514,6 +519,35 @@ node bin/deploy build-full-client ${deployId}
514
519
  logger.error(error, error.stack);
515
520
  }
516
521
  },
522
+ existsContainerFile({ podName, path }) {
523
+ return JSON.parse(
524
+ shellExec(`kubectl exec ${podName} -- test -f ${path} && echo "true" || echo "false"`, {
525
+ stdout: true,
526
+ disableLog: true,
527
+ silent: true,
528
+ }).trim(),
529
+ );
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
+ },
517
551
  };
518
552
  }
519
553