@underpostnet/underpost 2.96.1 → 2.97.1

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 (51) hide show
  1. package/.dockerignore +1 -2
  2. package/.env.development +0 -3
  3. package/.env.production +0 -3
  4. package/.env.test +0 -3
  5. package/.prettierignore +1 -2
  6. package/README.md +31 -31
  7. package/baremetal/commission-workflows.json +94 -17
  8. package/bin/deploy.js +1 -1
  9. package/cli.md +75 -41
  10. package/conf.js +1 -0
  11. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  12. package/manifests/deployment/dd-test-development/deployment.yaml +4 -4
  13. package/package.json +3 -2
  14. package/packer/scripts/fuse-tar-root +3 -3
  15. package/scripts/disk-clean.sh +128 -187
  16. package/scripts/gpu-diag.sh +2 -2
  17. package/scripts/ip-info.sh +11 -11
  18. package/scripts/ipxe-setup.sh +197 -0
  19. package/scripts/maas-upload-boot-resource.sh +1 -1
  20. package/scripts/nvim.sh +1 -1
  21. package/scripts/packer-setup.sh +13 -13
  22. package/scripts/ports-ls.sh +31 -0
  23. package/scripts/quick-tftp.sh +19 -0
  24. package/scripts/rocky-setup.sh +2 -2
  25. package/scripts/rpmfusion-ffmpeg-setup.sh +4 -4
  26. package/scripts/ssl.sh +7 -7
  27. package/src/api/document/document.controller.js +15 -0
  28. package/src/api/document/document.model.js +44 -1
  29. package/src/api/document/document.router.js +2 -0
  30. package/src/api/document/document.service.js +398 -26
  31. package/src/cli/baremetal.js +2001 -463
  32. package/src/cli/cloud-init.js +354 -231
  33. package/src/cli/cluster.js +51 -53
  34. package/src/cli/db.js +22 -0
  35. package/src/cli/deploy.js +7 -3
  36. package/src/cli/image.js +1 -0
  37. package/src/cli/index.js +40 -37
  38. package/src/cli/lxd.js +3 -3
  39. package/src/cli/run.js +78 -12
  40. package/src/cli/ssh.js +1 -1
  41. package/src/client/components/core/Css.js +16 -2
  42. package/src/client/components/core/Input.js +3 -1
  43. package/src/client/components/core/Modal.js +125 -159
  44. package/src/client/components/core/Panel.js +436 -31
  45. package/src/client/components/core/PanelForm.js +222 -37
  46. package/src/client/components/core/SearchBox.js +801 -0
  47. package/src/client/components/core/Translate.js +11 -0
  48. package/src/client/services/document/document.service.js +42 -0
  49. package/src/index.js +1 -1
  50. package/src/server/dns.js +12 -6
  51. package/src/server/start.js +14 -6
@@ -352,7 +352,7 @@ EOF
352
352
  );
353
353
  shellExec(`sudo mkdir -p /mnt/data`);
354
354
  shellExec(`sudo chmod 777 /mnt/data`);
355
- shellExec(`sudo chown -R root:root /mnt/data`);
355
+ shellExec(`sudo chown -R $(whoami):$(whoami) /mnt/data`);
356
356
  shellExec(`kubectl apply -k ${underpostRoot}/manifests/mysql -n ${options.namespace}`);
357
357
  }
358
358
  if (options.full === true || options.postgresql === true) {
@@ -487,8 +487,8 @@ EOF
487
487
  shellExec(`sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config`);
488
488
 
489
489
  // Enable and start Docker and Kubelet services
490
- shellExec(`sudo systemctl enable --now docker || true`); // Docker might not be needed for K3s
491
- shellExec(`sudo systemctl enable --now kubelet || true`); // Kubelet might not be needed for K3s (K3s uses its own agent)
490
+ shellExec(`sudo systemctl enable --now docker`); // Docker might not be needed for K3s
491
+ shellExec(`sudo systemctl enable --now kubelet`); // Kubelet might not be needed for K3s (K3s uses its own agent)
492
492
 
493
493
  // Configure containerd for SystemdCgroup and explicitly disable SELinux
494
494
  // This is crucial for kubelet/k3s to interact correctly with containerd
@@ -496,9 +496,9 @@ EOF
496
496
  shellExec(`sudo sed -i -e "s/SystemdCgroup = false/SystemdCgroup = true/g" /etc/containerd/config.toml`);
497
497
  // Add a new line to disable SELinux for the runc runtime
498
498
  // shellExec(
499
- // `sudo sed -i '/SystemdCgroup = true/a selinux_disabled = true' /etc/containerd/config.toml || true`,
499
+ // `sudo sed -i '/SystemdCgroup = true/a selinux_disabled = true' /etc/containerd/config.toml`,
500
500
  // );
501
- shellExec(`sudo service docker restart || true`); // Restart docker after containerd config changes
501
+ shellExec(`sudo service docker restart`); // Restart docker after containerd config changes
502
502
  shellExec(`sudo systemctl enable --now containerd.service`);
503
503
  shellExec(`sudo systemctl restart containerd`); // Restart containerd to apply changes
504
504
 
@@ -533,8 +533,8 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
533
533
  shellExec(`${underpostRoot}/scripts/nat-iptables.sh`, { silent: true });
534
534
 
535
535
  // Disable firewalld (common cause of network issues in Kubernetes)
536
- shellExec(`sudo systemctl stop firewalld || true`); // Stop if running
537
- shellExec(`sudo systemctl disable firewalld || true`); // Disable from starting on boot
536
+ shellExec(`sudo systemctl stop firewalld`); // Stop if running
537
+ shellExec(`sudo systemctl disable firewalld`); // Disable from starting on boot
538
538
  },
539
539
 
540
540
  /**
@@ -563,7 +563,7 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
563
563
  } else if (clusterType === 'kind') {
564
564
  // For Kind, the kubeconfig is usually merged automatically or can be explicitly exported
565
565
  // This command ensures it's merged into the default kubeconfig
566
- shellExec(`kind get kubeconfig > ~/.kube/config || true`);
566
+ shellExec(`kind get kubeconfig > ~/.kube/config`);
567
567
  shellExec(`sudo -E chown $(id -u):$(id -g) ~/.kube/config`);
568
568
  } else {
569
569
  logger.warn('No specific kubeconfig path defined for this cluster type, or it is managed automatically.');
@@ -622,7 +622,7 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
622
622
  if (pv.spec.hostPath && pv.spec.hostPath.path) {
623
623
  const hostPath = pv.spec.hostPath.path;
624
624
  logger.info(`Removing data from host path for PV '${pv.metadata.name}': ${hostPath}`);
625
- shellExec(`sudo rm -rf ${hostPath}/* || true`);
625
+ shellExec(`sudo rm -rf ${hostPath}/*`);
626
626
  }
627
627
  }
628
628
  } else {
@@ -637,52 +637,52 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
637
637
  // Enable SELinux permissive mode and restore file contexts.
638
638
  logger.info('Phase 2/7: Stopping services and fixing SELinux...');
639
639
  logger.info(' -> Ensuring SELinux is in permissive mode...');
640
- shellExec(`sudo setenforce 0 || true`);
641
- shellExec(`sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config || true`);
640
+ shellExec(`sudo setenforce 0`);
641
+ shellExec(`sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config`);
642
642
  logger.info(' -> Restoring SELinux contexts for container data directories...');
643
643
  // The 'restorecon' command corrects file system security contexts.
644
- shellExec(`sudo restorecon -Rv /var/lib/containerd || true`);
645
- shellExec(`sudo restorecon -Rv /var/lib/kubelet || true`);
644
+ shellExec(`sudo restorecon -Rv /var/lib/containerd`);
645
+ shellExec(`sudo restorecon -Rv /var/lib/kubelet`);
646
646
 
647
647
  logger.info(' -> Stopping kubelet, docker, and podman services...');
648
- shellExec('sudo systemctl stop kubelet || true');
649
- shellExec('sudo systemctl stop docker || true');
650
- shellExec('sudo systemctl stop podman || true');
648
+ shellExec('sudo systemctl stop kubelet');
649
+ shellExec('sudo systemctl stop docker');
650
+ shellExec('sudo systemctl stop podman');
651
651
  // Safely unmount pod filesystems to avoid errors.
652
- shellExec('sudo umount -f /var/lib/kubelet/pods/*/* || true');
652
+ shellExec('sudo umount -f /var/lib/kubelet/pods/*/*');
653
653
 
654
654
  // Phase 3: Execute official uninstallation commands
655
655
  logger.info('Phase 3/7: Executing official reset and uninstallation commands...');
656
656
  logger.info(' -> Executing kubeadm reset...');
657
- shellExec('sudo kubeadm reset --force || true');
657
+ shellExec('sudo kubeadm reset --force');
658
658
  logger.info(' -> Executing K3s uninstallation script if it exists...');
659
- shellExec('sudo /usr/local/bin/k3s-uninstall.sh || true');
659
+ shellExec('sudo /usr/local/bin/k3s-uninstall.sh');
660
660
  logger.info(' -> Deleting Kind clusters...');
661
- shellExec('kind get clusters | xargs -r -t -n1 kind delete cluster || true');
661
+ shellExec('kind get clusters | xargs -r -t -n1 kind delete cluster');
662
662
 
663
663
  // Phase 4: File system cleanup
664
664
  logger.info('Phase 4/7: Cleaning up remaining file system artifacts...');
665
665
  // Remove any leftover configurations and data.
666
- shellExec('sudo rm -rf /etc/kubernetes/* || true');
667
- shellExec('sudo rm -rf /etc/cni/net.d/* || true');
668
- shellExec('sudo rm -rf /var/lib/kubelet/* || true');
669
- shellExec('sudo rm -rf /var/lib/cni/* || true');
670
- shellExec('sudo rm -rf /var/lib/docker/* || true');
671
- shellExec('sudo rm -rf /var/lib/containerd/* || true');
672
- shellExec('sudo rm -rf /var/lib/containers/storage/* || true');
666
+ shellExec('sudo rm -rf /etc/kubernetes/*');
667
+ shellExec('sudo rm -rf /etc/cni/net.d/*');
668
+ shellExec('sudo rm -rf /var/lib/kubelet/*');
669
+ shellExec('sudo rm -rf /var/lib/cni/*');
670
+ shellExec('sudo rm -rf /var/lib/docker/*');
671
+ shellExec('sudo rm -rf /var/lib/containerd/*');
672
+ shellExec('sudo rm -rf /var/lib/containers/storage/*');
673
673
  // Clean up the current user's kubeconfig.
674
- shellExec('rm -rf $HOME/.kube || true');
674
+ shellExec('rm -rf $HOME/.kube');
675
675
 
676
676
  // Phase 5: Host network cleanup
677
677
  logger.info('Phase 5/7: Cleaning up host network configurations...');
678
678
  // Remove iptables rules and CNI network interfaces.
679
- shellExec('sudo iptables -F || true');
680
- shellExec('sudo iptables -t nat -F || true');
679
+ shellExec('sudo iptables -F');
680
+ shellExec('sudo iptables -t nat -F');
681
681
  // Restore iptables rules
682
682
  shellExec(`chmod +x ${options.underpostRoot}/scripts/nat-iptables.sh`);
683
683
  shellExec(`${options.underpostRoot}/scripts/nat-iptables.sh`, { silent: true });
684
- shellExec('sudo ip link del cni0 || true');
685
- shellExec('sudo ip link del flannel.1 || true');
684
+ shellExec('sudo ip link del cni0');
685
+ shellExec('sudo ip link del flannel.1');
686
686
 
687
687
  logger.info('Phase 6/7: Clean up images');
688
688
  shellExec(`podman rmi $(podman images -qa) --force`);
@@ -792,51 +792,49 @@ EOF`);
792
792
 
793
793
  // Remove Kind
794
794
  console.log('Removing Kind...');
795
- shellExec(`sudo rm -f /bin/kind || true`);
795
+ shellExec(`sudo rm -f /bin/kind`);
796
796
 
797
797
  // Remove Helm
798
798
  console.log('Removing Helm...');
799
- shellExec(`sudo rm -f /usr/local/bin/helm || true`);
800
- shellExec(`sudo rm -f /usr/local/bin/helm.sh || true`); // clean up the install script if it exists
799
+ shellExec(`sudo rm -f /usr/local/bin/helm`);
800
+ shellExec(`sudo rm -f /usr/local/bin/helm.sh`); // clean up the install script if it exists
801
801
 
802
802
  // Remove Docker and its dependencies
803
803
  console.log('Removing Docker, containerd, and related packages...');
804
- shellExec(
805
- `sudo dnf -y remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin || true`,
806
- );
804
+ shellExec(`sudo dnf -y remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin`);
807
805
 
808
806
  // Remove Podman
809
807
  console.log('Removing Podman...');
810
- shellExec(`sudo dnf -y remove podman || true`);
808
+ shellExec(`sudo dnf -y remove podman`);
811
809
 
812
810
  // Remove Kubeadm, Kubelet, and Kubectl
813
811
  console.log('Removing Kubernetes tools...');
814
- shellExec(`sudo yum remove -y kubelet kubeadm kubectl || true`);
812
+ shellExec(`sudo yum remove -y kubelet kubeadm kubectl`);
815
813
 
816
814
  // Remove Kubernetes repo file
817
815
  console.log('Removing Kubernetes repository configuration...');
818
- shellExec(`sudo rm -f /etc/yum.repos.d/kubernetes.repo || true`);
816
+ shellExec(`sudo rm -f /etc/yum.repos.d/kubernetes.repo`);
819
817
 
820
818
  // Clean up Kubeadm config and data directories
821
819
  console.log('Cleaning up Kubernetes configuration directories...');
822
- shellExec(`sudo rm -rf /etc/kubernetes/pki || true`);
823
- shellExec(`sudo rm -rf ~/.kube || true`);
820
+ shellExec(`sudo rm -rf /etc/kubernetes/pki`);
821
+ shellExec(`sudo rm -rf ~/.kube`);
824
822
 
825
823
  // Stop and disable services
826
824
  console.log('Stopping and disabling services...');
827
- shellExec(`sudo systemctl stop docker.service || true`);
828
- shellExec(`sudo systemctl disable docker.service || true`);
829
- shellExec(`sudo systemctl stop containerd.service || true`);
830
- shellExec(`sudo systemctl disable containerd.service || true`);
831
- shellExec(`sudo systemctl stop kubelet.service || true`);
832
- shellExec(`sudo systemctl disable kubelet.service || true`);
825
+ shellExec(`sudo systemctl stop docker.service`);
826
+ shellExec(`sudo systemctl disable docker.service`);
827
+ shellExec(`sudo systemctl stop containerd.service`);
828
+ shellExec(`sudo systemctl disable containerd.service`);
829
+ shellExec(`sudo systemctl stop kubelet.service`);
830
+ shellExec(`sudo systemctl disable kubelet.service`);
833
831
 
834
832
  // Clean up config files
835
833
  console.log('Removing host configuration files...');
836
- shellExec(`sudo rm -f /etc/containerd/config.toml || true`);
837
- shellExec(`sudo rm -f /etc/sysctl.d/k8s.conf || true`);
838
- shellExec(`sudo rm -f /etc/sysctl.d/99-k8s-ipforward.conf || true`);
839
- shellExec(`sudo rm -f /etc/sysctl.d/99-k8s.conf || true`);
834
+ shellExec(`sudo rm -f /etc/containerd/config.toml`);
835
+ shellExec(`sudo rm -f /etc/sysctl.d/k8s.conf`);
836
+ shellExec(`sudo rm -f /etc/sysctl.d/99-k8s-ipforward.conf`);
837
+ shellExec(`sudo rm -f /etc/sysctl.d/99-k8s.conf`);
840
838
 
841
839
  // Restore SELinux to enforcing
842
840
  console.log('Restoring SELinux to enforcing mode...');
package/src/cli/db.js CHANGED
@@ -725,8 +725,14 @@ class UnderpostDB {
725
725
  * @param {string} [options.paths=''] - Comma-separated list of paths to filter databases
726
726
  * @param {boolean} [options.allPods=false] - Whether to target all pods in deployment
727
727
  * @param {boolean} [options.primaryPod=false] - Whether to target MongoDB primary pod only
728
+ * @param {string} [options.primaryPodEnsure=''] - Pod name to ensure MongoDB primary pod is running
728
729
  * @param {boolean} [options.stats=false] - Whether to display database statistics
729
730
  * @param {number} [options.macroRollbackExport=1] - Number of commits to rollback in macro export
731
+ * @param {boolean} [options.forceClone=false] - Whether to force re-clone Git repository
732
+ * @param {boolean} [options.dev=false] - Development mode flag
733
+ * @param {boolean} [options.k3s=false] - k3s cluster flag
734
+ * @param {boolean} [options.kubeadm=false] - kubeadm cluster flag
735
+ * @param {boolean} [options.kind=false] - kind cluster flag
730
736
  * @returns {Promise<void>} Resolves when operation is complete
731
737
  * @memberof UnderpostDB
732
738
  */
@@ -746,9 +752,14 @@ class UnderpostDB {
746
752
  paths: '',
747
753
  allPods: false,
748
754
  primaryPod: false,
755
+ primaryPodEnsure: '',
749
756
  stats: false,
750
757
  macroRollbackExport: 1,
751
758
  forceClone: false,
759
+ dev: false,
760
+ k3s: false,
761
+ kubeadm: false,
762
+ kind: false,
752
763
  },
753
764
  ) {
754
765
  const newBackupTimestamp = new Date().getTime();
@@ -763,6 +774,17 @@ class UnderpostDB {
763
774
  export: options.export,
764
775
  });
765
776
 
777
+ if (options.primaryPodEnsure) {
778
+ const primaryPodName = UnderpostDB.API.getMongoPrimaryPodName({ namespace, podName: options.primaryPodEnsure });
779
+ if (!primaryPodName) {
780
+ const baseCommand = options.dev ? 'node bin' : 'underpost';
781
+ const baseClusterCommand = options.dev ? ' --dev' : '';
782
+ let clusterFlag = options.k3s ? ' --k3s' : options.kubeadm ? ' --kubeadm' : '';
783
+ shellExec(`${baseCommand} cluster${baseClusterCommand}${clusterFlag} --mongodb`);
784
+ }
785
+ return;
786
+ }
787
+
766
788
  // Track processed repositories to avoid duplicate Git operations
767
789
  const processedRepos = new Set();
768
790
  // Track processed host+path combinations to avoid duplicates
package/src/cli/deploy.js CHANGED
@@ -106,12 +106,13 @@ class UnderpostDeploy {
106
106
  * @memberof UnderpostDeploy
107
107
  */
108
108
  deploymentYamlPartsFactory({ deployId, env, suffix, resources, replicas, image, namespace, volumes, cmd }) {
109
+ const baseCommand = env === 'development' ? 'node bin' : 'underpost';
109
110
  if (!cmd)
110
111
  cmd = [
111
112
  `npm install -g npm@11.2.0`,
112
113
  `npm install -g underpost`,
113
- `underpost secret underpost --create-from-file /etc/config/.env.${env}`,
114
- `underpost start --build --run ${deployId} ${env}`,
114
+ `${baseCommand} secret underpost --create-from-file /etc/config/.env.${env}`,
115
+ `${baseCommand} start --build --run ${deployId} ${env}`,
115
116
  ];
116
117
  const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
117
118
  if (!volumes)
@@ -221,6 +222,7 @@ ${UnderpostDeploy.API.deploymentYamlPartsFactory({
221
222
  replicas,
222
223
  image,
223
224
  namespace: options.namespace,
225
+ cmd: options.cmd ? options.cmd.split(',').map((c) => c.trim()) : undefined,
224
226
  }).replace('{{ports}}', buildKindPorts(fromPort, toPort))}
225
227
  `;
226
228
  }
@@ -389,6 +391,7 @@ spec:
389
391
  * @param {string} [options.namespace] - Kubernetes namespace for the deployment.
390
392
  * @param {string} [options.kindType] - Type of Kubernetes resource to retrieve information for.
391
393
  * @param {number} [options.port] - Port number for exposing the deployment.
394
+ * @param {string} [options.cmd] - Custom initialization command for deploymentYamlPartsFactory (comma-separated commands).
392
395
  * @returns {Promise<void>} - Promise that resolves when the deployment process is complete.
393
396
  * @memberof UnderpostDeploy
394
397
  */
@@ -420,6 +423,7 @@ spec:
420
423
  namespace: '',
421
424
  kindType: '',
422
425
  port: 0,
426
+ cmd: '',
423
427
  },
424
428
  ) {
425
429
  const namespace = options.namespace ? options.namespace : 'default';
@@ -757,7 +761,7 @@ EOF`);
757
761
  // shellExec(`docker cp ${volume.volumeMountPath} kind-worker:${rootVolumeHostPath}`);
758
762
  shellExec(`tar -C ${volume.volumeMountPath} -c . | docker cp - kind-worker:${rootVolumeHostPath}`);
759
763
  shellExec(
760
- `docker exec -i kind-worker bash -c "chown -R 1000:1000 ${rootVolumeHostPath} || true; chmod -R 755 ${rootVolumeHostPath}"`,
764
+ `docker exec -i kind-worker bash -c "chown -R 1000:1000 ${rootVolumeHostPath}; chmod -R 755 ${rootVolumeHostPath}"`,
761
765
  );
762
766
  }
763
767
  shellExec(`kubectl delete pvc ${pvcId} -n ${namespace} --ignore-not-found`);
package/src/cli/image.js CHANGED
@@ -119,6 +119,7 @@ class UnderpostImage {
119
119
  } = options;
120
120
  if (!path) path = '.';
121
121
  if (!imageName) imageName = `rockylinux9-underpost:${Underpost.version}`;
122
+ if (!imagePath) imagePath = '.';
122
123
  if (!version) version = 'latest';
123
124
  version = imageName && imageName.match(':') ? '' : `:${version}`;
124
125
  const podManImg = `localhost/${imageName}${version}`;
package/src/cli/index.js CHANGED
@@ -10,7 +10,6 @@ import UnderpostRun from './run.js';
10
10
  import Dns from '../server/dns.js';
11
11
  import UnderpostStatic from './static.js';
12
12
 
13
- // Load environment variables from .env file
14
13
  const underpostRootPath = getUnderpostRootPath();
15
14
  fs.existsSync(`${underpostRootPath}/.env`)
16
15
  ? dotenv.config({ path: `${underpostRootPath}/.env`, override: true })
@@ -18,14 +17,12 @@ fs.existsSync(`${underpostRootPath}/.env`)
18
17
 
19
18
  const program = new Command();
20
19
 
21
- // Set up the main program information
22
20
  program.name('underpost').description(`underpost ci/cd cli ${Underpost.version}`).version(Underpost.version);
23
21
 
24
- // 'new' command: Create a new project
25
22
  program
26
23
  .command('new')
27
24
  .argument('[app-name]', 'The name of the new project.')
28
- .option('--deploy-id <deploy-id>', 'Crete deploy ID conf env files')
25
+ .option('--deploy-id <deploy-id>', 'Create deploy ID conf env files')
29
26
  .option('--sub-conf <sub-conf>', 'Create sub conf env files')
30
27
  .option('--cluster', 'Create deploy ID cluster files and sync to current cluster')
31
28
  .option('--build-repos', 'Create deploy ID repositories')
@@ -39,7 +36,6 @@ program
39
36
  .description('Initializes a new Underpost project, service, or configuration.')
40
37
  .action(Underpost.repo.new);
41
38
 
42
- // 'start' command: Start application servers, build pipelines, or services
43
39
  program
44
40
  .command('start')
45
41
  .argument('<deploy-id>', 'The unique identifier for the deployment configuration.')
@@ -49,10 +45,10 @@ program
49
45
  )
50
46
  .option('--run', 'Starts application servers and monitors their health.')
51
47
  .option('--build', 'Triggers the client-side application build process.')
48
+ .option('--underpost-quickly-install', 'Uses Underpost Quickly Install for dependency installation.')
52
49
  .action(Underpost.start.callback)
53
50
  .description('Initiates application servers, build pipelines, or other defined services based on the deployment ID.');
54
51
 
55
- // 'clone' command: Clone a GitHub repository
56
52
  program
57
53
  .command('clone')
58
54
  .argument(`<uri>`, 'The URI of the GitHub repository (e.g., "username/repository").')
@@ -61,7 +57,6 @@ program
61
57
  .description('Clones a specified GitHub repository into the current directory.')
62
58
  .action(Underpost.repo.clone);
63
59
 
64
- // 'pull' command: Pull updates from a GitHub repository
65
60
  program
66
61
  .command('pull')
67
62
  .argument('<path>', 'The absolute or relative directory path where the repository is located.')
@@ -70,7 +65,6 @@ program
70
65
  .option('-g8', 'Uses the g8 repository extension for pulling.')
71
66
  .action(Underpost.repo.pull);
72
67
 
73
- // 'cmt' command: Commit changes to a GitHub repository
74
68
  program
75
69
  .command('cmt')
76
70
  .argument('[path]', 'The absolute or relative directory path of the repository.')
@@ -92,7 +86,6 @@ program
92
86
  .description('Manages commits to a GitHub repository, supporting various commit types and options.')
93
87
  .action(Underpost.repo.commit);
94
88
 
95
- // 'push' command: Push changes to a GitHub repository
96
89
  program
97
90
  .command('push')
98
91
  .argument('<path>', 'The absolute or relative directory path of the repository.')
@@ -102,7 +95,6 @@ program
102
95
  .description('Pushes committed changes from a local repository to a remote GitHub repository.')
103
96
  .action(Underpost.repo.push);
104
97
 
105
- // 'env' command: Manage environment variables
106
98
  program
107
99
  .command('env')
108
100
  .argument(
@@ -122,7 +114,6 @@ program
122
114
  loadConf(deployId, subConf);
123
115
  });
124
116
 
125
- // 'static' command: Manage static configurations
126
117
  program
127
118
  .command('static')
128
119
  .option('--page <ssr-component-path>', 'Build custom static pages.')
@@ -139,21 +130,17 @@ program
139
130
  .option('--locale <locale>', 'Page locale (default: en-US).')
140
131
  .option('--site-name <name>', 'Site name for Open Graph.')
141
132
 
142
- // Script and style options
143
133
  .option('--head-scripts <paths>', 'Comma-separated paths to scripts for head section.')
144
134
  .option('--body-scripts <paths>', 'Comma-separated paths to scripts for body section.')
145
135
  .option('--styles <paths>', 'Comma-separated paths to stylesheets.')
146
136
 
147
- // Icon options
148
137
  .option('--favicon <path>', 'Favicon path.')
149
138
  .option('--apple-touch-icon <path>', 'Apple touch icon path.')
150
139
  .option('--manifest <path>', 'Web manifest path.')
151
140
 
152
- // Component options
153
141
  .option('--head-components <paths>', 'Comma-separated SSR head component paths.')
154
142
  .option('--body-components <paths>', 'Comma-separated SSR body component paths.')
155
143
 
156
- // Build options
157
144
  .option('--deploy-id <deploy-id>', 'Build static assets for a specific deployment ID.')
158
145
  .option('--build', 'Triggers the static build process for the specified deployment ID.')
159
146
  .option('--build-host <build-host>', 'Sets a custom build host for static documents or assets.')
@@ -162,11 +149,9 @@ program
162
149
  .option('--minify', 'Minify HTML output (default: true for production).')
163
150
  .option('--no-minify', 'Disable HTML minification.')
164
151
 
165
- // Config file options
166
152
  .option('--config-file <path>', 'Path to JSON configuration file.')
167
153
  .option('--generate-config [path]', 'Generate a template configuration file.')
168
154
 
169
- // Other options
170
155
  .option('--lang <lang>', 'HTML lang attribute (default: en).')
171
156
  .option('--dir <dir>', 'HTML dir attribute (default: ltr).')
172
157
  .option('--dev', 'Sets the development cli context')
@@ -174,7 +159,6 @@ program
174
159
  .description(`Manages static build of page, bundles, and documentation with comprehensive customization options.`)
175
160
  .action(UnderpostStatic.API.callback);
176
161
 
177
- // 'config' command: Manage Underpost configurations
178
162
  program
179
163
  .command('config')
180
164
  .argument('operator', `The configuration operation to perform. Options: ${Object.keys(Underpost.env).join(', ')}.`)
@@ -185,7 +169,6 @@ program
185
169
  .description(`Manages Underpost configurations using various operators.`)
186
170
  .action((...args) => Underpost.env[args[0]](args[1], args[2], args[3]));
187
171
 
188
- // 'root' command: Get npm root path
189
172
  program
190
173
  .command('root')
191
174
  .description('Displays the root path of the npm installation.')
@@ -194,6 +177,7 @@ program
194
177
  program
195
178
  .command('ip')
196
179
  .argument('[ips]', 'Optional args comma-separated list of IP to process.')
180
+ .option('--dhcp', 'Fetches and displays the current Dynamic Host Configuration Protocol server IP address.')
197
181
  .option('--copy', 'Copies the IP addresses to the clipboard.')
198
182
  .option('--ban-ingress-add', 'Adds IP addresses to banned ingress list.')
199
183
  .option('--ban-ingress-remove', 'Removes IP addresses from banned ingress list.')
@@ -208,7 +192,6 @@ program
208
192
  .description('Displays the current public machine IP addresses.')
209
193
  .action(Dns.ipDispatcher);
210
194
 
211
- // 'cluster' command: Manage Kubernetes clusters
212
195
  program
213
196
  .command('cluster')
214
197
  .argument('[pod-name]', 'Optional: Filters information by a specific pod name.')
@@ -257,7 +240,6 @@ program
257
240
  .action(Underpost.cluster.init)
258
241
  .description('Manages Kubernetes clusters, defaulting to Kind cluster initialization.');
259
242
 
260
- // 'deploy' command: Manage deployments
261
243
  program
262
244
  .command('deploy')
263
245
  .argument('[deploy-list]', 'A comma-separated list of deployment IDs (e.g., "default-a,default-b").')
@@ -295,10 +277,10 @@ program
295
277
  .option('--namespace <namespace>', 'Kubernetes namespace for deployment operations (defaults to "default").')
296
278
  .option('--kind-type <kind-type>', 'Specifies the Kind cluster type for deployment operations.')
297
279
  .option('--port <port>', 'Sets up port forwarding from local to remote ports.')
280
+ .option('--cmd <cmd>', 'Custom initialization command for deployment (comma-separated commands).')
298
281
  .description('Manages application deployments, defaulting to deploying development pods.')
299
282
  .action(Underpost.deploy.callback);
300
283
 
301
- // 'secret' command: Manage secrets
302
284
  program
303
285
  .command('secret')
304
286
  .argument('<platform>', `The secret management platform. Options: ${Object.keys(Underpost.secret).join(', ')}.`)
@@ -312,7 +294,6 @@ program
312
294
  if (args[1].init) return Underpost.secret[args[0]].init();
313
295
  });
314
296
 
315
- // 'image'
316
297
  program
317
298
  .command('image')
318
299
  .option(
@@ -348,7 +329,6 @@ program
348
329
  Underpost.image.pullDockerHubImage({ ...options, dockerhubImage: options.pullDockerhub });
349
330
  });
350
331
 
351
- // 'install' command: Fast import npm dependencies
352
332
  program
353
333
  .command('install')
354
334
  .description('Quickly imports Underpost npm dependencies by copying them.')
@@ -356,10 +336,9 @@ program
356
336
  fs.copySync(`${underpostRootPath}/node_modules`, './node_modules');
357
337
  });
358
338
 
359
- // 'db' command: Manage databases
360
339
  program
361
340
  .command('db')
362
- .argument('<deploy-list>', 'A comma-separated list of deployment IDs (e.g., "default-a,default-b").')
341
+ .argument('[deploy-list]', 'A comma-separated list of deployment IDs (e.g., "default-a,default-b").')
363
342
  .option('--import', 'Imports container backups from specified repositories.')
364
343
  .option('--export', 'Exports container backups to specified repositories.')
365
344
  .option(
@@ -368,6 +347,7 @@ program
368
347
  )
369
348
  .option('--all-pods', 'Target all matching pods instead of just the first one.')
370
349
  .option('--primary-pod', 'Automatically detect and use MongoDB primary pod (MongoDB only).')
350
+ .option('--primary-pod-ensure <pod-name>', 'Ensure setup of MongoDB replica set primary pod before operations.')
371
351
  .option('--stats', 'Display database statistics (collection/table names with document/row counts).')
372
352
  .option('--collections <collections>', 'Comma-separated list of database collections to operate on.')
373
353
  .option('--out-path <out-path>', 'Specifies a custom output path for backups.')
@@ -382,6 +362,10 @@ program
382
362
  '--macro-rollback-export <n-commits-reset>',
383
363
  'Exports a macro rollback script that reverts the last n commits (Git integration required).',
384
364
  )
365
+ .option('--dev', 'Sets the development cli context')
366
+ .option('--kubeadm', 'Enables the kubeadm context for database operations.')
367
+ .option('--kind', 'Enables the kind context for database operations.')
368
+ .option('--k3s', 'Enables the k3s context for database operations.')
385
369
  .description(
386
370
  'Manages database operations with support for MariaDB and MongoDB, including import/export, multi-pod targeting, and Git integration.',
387
371
  )
@@ -401,7 +385,6 @@ program
401
385
  .description('Manages cluster metadata operations, including import and export.')
402
386
  .action(Underpost.db.clusterMetadataBackupCallback);
403
387
 
404
- // 'script' command: Execute scripts
405
388
  program
406
389
  .command('script')
407
390
  .argument('operator', `The script operation to perform. Options: ${Object.keys(Underpost.script).join(', ')}.`)
@@ -416,7 +399,6 @@ program
416
399
  )
417
400
  .action((...args) => Underpost.script[args[0]](args[1], args[2], args[3]));
418
401
 
419
- // 'cron' command: Manage cron jobs
420
402
  program
421
403
  .command('cron')
422
404
  .argument('[deploy-list]', 'A comma-separated list of deployment IDs (e.g., "default-a,default-b").')
@@ -432,7 +414,6 @@ program
432
414
  .description('Manages cron jobs, including initialization, execution, and configuration updates.')
433
415
  .action(Underpost.cron.callback);
434
416
 
435
- // 'fs' command: File storage management
436
417
  program
437
418
  .command('fs')
438
419
  .argument('[path]', 'The absolute or relative directory path for file operations.')
@@ -446,7 +427,6 @@ program
446
427
  .description('Manages file storage, defaulting to file upload operations.')
447
428
  .action(Underpost.fs.callback);
448
429
 
449
- // 'test' command: Manage tests
450
430
  program
451
431
  .command('test')
452
432
  .argument('[deploy-list]', 'A comma-separated list of deployment IDs (e.g., "default-a,default-b").')
@@ -459,7 +439,6 @@ program
459
439
  .option('--kind-type <kind-type>', 'Optional: Specifies the Kind cluster type for tests.')
460
440
  .action(Underpost.test.callback);
461
441
 
462
- // 'monitor' command: Monitor health server
463
442
  program
464
443
  .command('monitor')
465
444
  .argument('<deploy-id>', 'The deployment configuration ID to monitor.')
@@ -477,7 +456,6 @@ program
477
456
  .description('Manages health server monitoring for specified deployments.')
478
457
  .action(Underpost.monitor.callback);
479
458
 
480
- // 'ssh' command: SSH management
481
459
  program
482
460
  .command('ssh')
483
461
  .option('--deploy-id <deploy-id>', 'Sets deploy id context for ssh operations.')
@@ -503,12 +481,11 @@ program
503
481
  .option('--copy', 'Copies the connection URI to clipboard.')
504
482
  .action(Underpost.ssh.callback);
505
483
 
506
- // 'run' command: Run a script
507
484
  program
508
485
  .command('run')
509
486
  .argument('<runner-id>', `The runner ID to run. Options: ${Object.keys(UnderpostRun.RUNNERS).join(', ')}.`)
510
487
  .argument('[path]', 'The input value, identifier, or path for the operation.')
511
- .option('--command <command-array>', 'Array of commands to run.')
488
+ .option('--cmd <command-list>', 'Comma-separated list of commands to execute.')
512
489
  .option('--args <args-array>', 'Array of arguments to pass to the command.')
513
490
  .option('--dev', 'Sets the development context environment for the script.')
514
491
  .option('--build', 'Set builder context runner')
@@ -565,10 +542,10 @@ program
565
542
  .option('--user <user>', 'Sets user context for the runner execution.')
566
543
  .option('--hosts <hosts>', 'Comma-separated list of hosts for the runner execution.')
567
544
  .option('--instance-id <instance-id>', 'Sets instance id context for the runner execution.')
545
+ .option('--pid <process-id>', 'Sets process id context for the runner execution.')
568
546
  .description('Runs specified scripts using various runners.')
569
547
  .action(UnderpostRun.API.callback);
570
548
 
571
- // 'lxd' command: LXD management
572
549
  program
573
550
  .command('lxd')
574
551
  .option('--init', 'Initializes LXD on the current machine.')
@@ -604,13 +581,20 @@ program
604
581
  .description('Manages LXD containers and virtual machines.')
605
582
  .action(UnderpostLxd.API.callback);
606
583
 
607
- // 'baremetal' command: Baremetal server management
608
584
  program
609
- .command('baremetal [workflow-id] [hostname] [ip-address]')
585
+ .command('baremetal [workflow-id] [ip-address] [hostname] [ip-file-server] [ip-config] [netmask] [dns-server]')
610
586
  .option('--control-server-install', 'Installs the baremetal control server.')
611
587
  .option('--control-server-uninstall', 'Uninstalls the baremetal control server.')
588
+ .option('--control-server-restart', 'Restarts the baremetal control server.')
612
589
  .option('--control-server-db-install', 'Installs up the database for the baremetal control server.')
613
590
  .option('--control-server-db-uninstall', 'Uninstalls the database for the baremetal control server.')
591
+ .option('--create-machine', 'Creates a new baremetal machine entry in the database.')
592
+ .option(
593
+ '--mac <mac>',
594
+ 'Specifies the MAC address for baremetal machine operations. Use "random" for random MAC, "hardware" to use device\'s actual MAC (no spoofing), or specify a MAC address.',
595
+ )
596
+ .option('--ipxe', 'Chainloads iPXE to normalize identity before commissioning.')
597
+ .option('--ipxe-rebuild', 'Forces rebuild of iPXE binary with embedded boot script.')
614
598
  .option('--install-packer', 'Installs Packer CLI.')
615
599
  .option(
616
600
  '--packer-maas-image-template <template-path>',
@@ -629,12 +613,31 @@ program
629
613
  '--packer-maas-image-cached',
630
614
  'Continue last build without removing artifacts (used with --packer-maas-image-build).',
631
615
  )
616
+ .option('--remove-machines <system-ids>', 'Removes baremetal machines by comma-separated system IDs, or use "all"')
617
+ .option('--clear-discovered', 'Clears all discovered baremetal machines from the database.')
632
618
  .option('--commission', 'Init workflow for commissioning a physical machine.')
619
+ .option(
620
+ '--bootstrap-http-server-path <path>',
621
+ 'Sets a custom bootstrap HTTP server path for baremetal commissioning.',
622
+ )
623
+ .option(
624
+ '--bootstrap-http-server-port <port>',
625
+ 'Sets a custom bootstrap HTTP server port for baremetal commissioning.',
626
+ )
627
+ .option('--iso-url <url>', 'Uses a custom ISO URL for baremetal machine commissioning.')
633
628
  .option('--nfs-build', 'Builds an NFS root filesystem for a workflow id config architecture using QEMU emulation.')
634
629
  .option('--nfs-mount', 'Mounts the NFS root filesystem for a workflow id config architecture.')
635
630
  .option('--nfs-unmount', 'Unmounts the NFS root filesystem for a workflow id config architecture.')
631
+ .option('--nfs-build-server', 'Builds the NFS server for a workflow id config architecture.')
636
632
  .option('--nfs-sh', 'Copies QEMU emulation root entrypoint shell command to the clipboard.')
633
+ .option('--cloud-init', 'Sets the kernel parameters and sets the necessary seed users on the HTTP server.')
637
634
  .option('--cloud-init-update', 'Updates cloud init for a workflow id config architecture.')
635
+ .option('--ubuntu-tools-build', 'Builds ubuntu tools for chroot environment.')
636
+ .option('--ubuntu-tools-test', 'Tests ubuntu tools in chroot environment.')
637
+ .option('--rocky-tools-build', 'Builds rocky linux tools for chroot environment.')
638
+ .option('--rocky-tools-test', 'Tests rocky linux tools in chroot environment.')
639
+ .option('--bootcmd <bootcmd-list>', 'Comma-separated list of boot commands to execute.')
640
+ .option('--runcmd <runcmd-list>', 'Comma-separated list of run commands to execute.')
638
641
  .option('--logs <log-id>', 'Displays logs for log id: dhcp, cloud, machine, cloud-config.')
639
642
  .option('--dev', 'Sets the development context environment for baremetal operations.')
640
643
  .option('--ls', 'Lists available boot resources and machines.')