@underpostnet/underpost 2.96.0 → 2.97.0

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 (46) 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 +64 -17
  8. package/baremetal/packer-workflows.json +11 -0
  9. package/cli.md +72 -40
  10. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  11. package/manifests/deployment/dd-test-development/deployment.yaml +4 -4
  12. package/package.json +3 -2
  13. package/packer/images/Rocky9Amd64/rocky9.pkr.hcl +6 -2
  14. package/packer/images/Rocky9Arm64/Makefile +69 -0
  15. package/packer/images/Rocky9Arm64/README.md +122 -0
  16. package/packer/images/Rocky9Arm64/http/rocky9.ks.pkrtpl.hcl +114 -0
  17. package/packer/images/Rocky9Arm64/rocky9.pkr.hcl +171 -0
  18. package/scripts/disk-clean.sh +128 -187
  19. package/scripts/ipxe-setup.sh +197 -0
  20. package/scripts/packer-init-vars-file.sh +16 -6
  21. package/scripts/packer-setup.sh +270 -33
  22. package/scripts/ports-ls.sh +31 -0
  23. package/scripts/quick-tftp.sh +19 -0
  24. package/src/api/document/document.controller.js +15 -0
  25. package/src/api/document/document.model.js +14 -0
  26. package/src/api/document/document.router.js +1 -0
  27. package/src/api/document/document.service.js +61 -3
  28. package/src/cli/baremetal.js +1716 -439
  29. package/src/cli/cloud-init.js +354 -231
  30. package/src/cli/cluster.js +1 -1
  31. package/src/cli/db.js +22 -0
  32. package/src/cli/deploy.js +6 -2
  33. package/src/cli/image.js +1 -0
  34. package/src/cli/index.js +40 -36
  35. package/src/cli/run.js +77 -11
  36. package/src/cli/ssh.js +1 -1
  37. package/src/client/components/core/Input.js +3 -1
  38. package/src/client/components/core/Panel.js +161 -15
  39. package/src/client/components/core/PanelForm.js +198 -35
  40. package/src/client/components/core/Translate.js +11 -0
  41. package/src/client/services/document/document.service.js +19 -0
  42. package/src/index.js +2 -1
  43. package/src/server/dns.js +8 -2
  44. package/src/server/start.js +14 -6
  45. package/manifests/mariadb/config.yaml +0 -10
  46. package/manifests/mariadb/secret.yaml +0 -8
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';
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,10 +17,8 @@ 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.')
@@ -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>',
@@ -625,12 +609,32 @@ program
625
609
  '--packer-maas-image-upload',
626
610
  'Uploads an existing MAAS image artifact without rebuilding for the workflow specified by --packer-workflow-id.',
627
611
  )
612
+ .option(
613
+ '--packer-maas-image-cached',
614
+ 'Continue last build without removing artifacts (used with --packer-maas-image-build).',
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.')
628
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.')
629
628
  .option('--nfs-build', 'Builds an NFS root filesystem for a workflow id config architecture using QEMU emulation.')
630
629
  .option('--nfs-mount', 'Mounts the NFS root filesystem for a workflow id config architecture.')
631
630
  .option('--nfs-unmount', 'Unmounts the NFS root filesystem for a workflow id config architecture.')
632
631
  .option('--nfs-sh', 'Copies QEMU emulation root entrypoint shell command to the clipboard.')
632
+ .option('--cloud-init', 'Sets the kernel parameters and sets the necessary seed users on the HTTP server.')
633
633
  .option('--cloud-init-update', 'Updates cloud init for a workflow id config architecture.')
634
+ .option('--ubuntu-tools-build', 'Builds ubuntu tools for chroot environment.')
635
+ .option('--ubuntu-tools-test', 'Tests ubuntu tools in chroot environment.')
636
+ .option('--bootcmd <bootcmd-list>', 'Comma-separated list of boot commands to execute.')
637
+ .option('--runcmd <runcmd-list>', 'Comma-separated list of run commands to execute.')
634
638
  .option('--logs <log-id>', 'Displays logs for log id: dhcp, cloud, machine, cloud-config.')
635
639
  .option('--dev', 'Sets the development context environment for baremetal operations.')
636
640
  .option('--ls', 'Lists available boot resources and machines.')
package/src/cli/run.js CHANGED
@@ -57,6 +57,7 @@ class UnderpostRun {
57
57
  * @property {boolean} force - Whether to force the operation.
58
58
  * @property {boolean} reset - Whether to reset the operation.
59
59
  * @property {boolean} tls - Whether to use TLS.
60
+ * @property {string} cmd - The command to run in the container.
60
61
  * @property {string} tty - The TTY option for the container.
61
62
  * @property {string} stdin - The stdin option for the container.
62
63
  * @property {string} restartPolicy - The restart policy for the container.
@@ -87,6 +88,7 @@ class UnderpostRun {
87
88
  * @property {string} deployId - The deployment ID.
88
89
  * @property {string} instanceId - The instance ID.
89
90
  * @property {string} user - The user to run as.
91
+ * @property {string} pid - The process ID.
90
92
  * @memberof UnderpostRun
91
93
  */
92
94
  static DEFAULT_OPTION = {
@@ -104,6 +106,7 @@ class UnderpostRun {
104
106
  force: false,
105
107
  reset: false,
106
108
  tls: false,
109
+ cmd: '',
107
110
  tty: '',
108
111
  stdin: '',
109
112
  restartPolicy: '',
@@ -134,6 +137,7 @@ class UnderpostRun {
134
137
  deployId: '',
135
138
  instanceId: '',
136
139
  user: '',
140
+ pid: '',
137
141
  };
138
142
  /**
139
143
  * @static
@@ -187,6 +191,7 @@ class UnderpostRun {
187
191
  * @memberof UnderpostRun
188
192
  */
189
193
  kill: (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
194
+ if (options.pid) return shellExec(`sudo kill -9 ${options.pid}`);
190
195
  for (const _path of path.split(',')) {
191
196
  if (_path.split('+')[1]) {
192
197
  let [port, sumPortOffSet] = _path.split('+');
@@ -564,7 +569,7 @@ class UnderpostRun {
564
569
  const currentTraffic = isDeployRunnerContext(path, options)
565
570
  ? UnderpostDeploy.API.getCurrentTraffic(deployId, { namespace: options.namespace })
566
571
  : '';
567
- let targetTraffic = currentTraffic ? (currentTraffic === 'blue' ? 'green' : 'blue') : '';
572
+ let targetTraffic = currentTraffic ? (currentTraffic === 'blue' ? 'green' : 'blue') : 'green';
568
573
  if (targetTraffic) versions = targetTraffic;
569
574
 
570
575
  shellExec(
@@ -574,8 +579,13 @@ class UnderpostRun {
574
579
  );
575
580
 
576
581
  if (isDeployRunnerContext(path, options)) {
582
+ const cmdString = options.cmd
583
+ ? ` --cmd ${options.cmd.find((c) => c.match('"')) ? `"${options.cmd}"` : `'${options.cmd}'`}`
584
+ : '';
577
585
  shellExec(
578
- `${baseCommand} deploy --kubeadm --disable-update-proxy ${deployId} ${env} --versions ${versions}${options.namespace ? ` --namespace ${options.namespace}` : ''}`,
586
+ `${baseCommand} deploy --kubeadm${cmdString} --replicas ${
587
+ replicas
588
+ } --disable-update-proxy ${deployId} ${env} --versions ${versions}${options.namespace ? ` --namespace ${options.namespace}` : ''}`,
579
589
  );
580
590
  if (!targetTraffic)
581
591
  targetTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId, { namespace: options.namespace });
@@ -1157,6 +1167,7 @@ EOF
1157
1167
  * @memberof UnderpostRun
1158
1168
  */
1159
1169
  cluster: async (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
1170
+ const { underpostRoot } = options;
1160
1171
  const env = options.dev ? 'development' : 'production';
1161
1172
  const baseCommand = options.dev ? 'node bin' : 'underpost';
1162
1173
  const baseClusterCommand = options.dev ? ' --dev' : '';
@@ -1166,12 +1177,16 @@ EOF
1166
1177
  await timer(5000);
1167
1178
  shellExec(`${baseCommand} cluster${baseClusterCommand} --${clusterType}`);
1168
1179
  await timer(5000);
1169
- let [runtimeImage, deployList] = path.split(',')
1170
- ? path.split(',')
1171
- : ['express', fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').replaceAll(',', '+')];
1180
+ let [runtimeImage, deployList] =
1181
+ path && path.trim() && path.split(',')
1182
+ ? path.split(',')
1183
+ : [
1184
+ 'express',
1185
+ fs.readFileSync(`${underpostRoot}/engine-private/deploy/dd.router`, 'utf8').replaceAll(',', '+'),
1186
+ ];
1172
1187
  shellExec(
1173
- `${baseCommand} image${baseClusterCommand}${
1174
- runtimeImage ? ` --pull-base --path /home/dd/engine/src/runtime/${runtimeImage}` : ''
1188
+ `${baseCommand} image${baseClusterCommand} --build ${
1189
+ runtimeImage ? ` --pull-base --path ${underpostRoot}/src/runtime/${runtimeImage}` : ''
1175
1190
  } --${clusterType}`,
1176
1191
  );
1177
1192
  if (!deployList) {
@@ -1246,7 +1261,7 @@ EOF
1246
1261
  'disk-clean': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
1247
1262
  const { underpostRoot } = options;
1248
1263
  shellExec(`chmod +x ${underpostRoot}/scripts/disk-clean.sh`);
1249
- shellExec(`./scripts/disk-clean.sh --yes --aggressive`);
1264
+ shellExec(`./scripts/disk-clean.sh`);
1250
1265
  },
1251
1266
 
1252
1267
  /**
@@ -1405,7 +1420,7 @@ EOF
1405
1420
  shellExec(
1406
1421
  `${baseCommand} deploy${options.dev ? '' : ' --kubeadm'}${options.devProxyPortOffset ? ' --disable-deployment-proxy' : ''} --disable-update-deployment ${deployId} ${env} --versions ${versions}`,
1407
1422
  );
1408
- } else logger.error('Mongo Express deployment failed');
1423
+ } else logger.error(`Service pod ${podToMonitor} failed to start in time.`);
1409
1424
  if (options.etcHosts === true) {
1410
1425
  const hostListenResult = UnderpostDeploy.API.etcHostFactory([host]);
1411
1426
  logger.info(hostListenResult.renderHosts);
@@ -1447,6 +1462,32 @@ EOF
1447
1462
  console.log(result);
1448
1463
  },
1449
1464
 
1465
+ /**
1466
+ * @method ps
1467
+ * @description Displays running processes that match a specified path or keyword.
1468
+ * @param {string} path - The input value, identifier, or path for the operation (used as a keyword to filter processes).
1469
+ * @param {Object} options - The default underpost runner options for customizing workflow
1470
+ * @memberof UnderpostRun
1471
+ */
1472
+ ps: async (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
1473
+ const out = shellExec(`ps aux${path ? `| grep '${path}' | grep -v grep` : ''}`, {
1474
+ stdout: true,
1475
+ silent: true,
1476
+ });
1477
+ console.log(path ? out.replaceAll(path, path.bgYellow.black.bold) : out);
1478
+ },
1479
+
1480
+ /**
1481
+ * @method ptls
1482
+ * @description Set on ~/.bashrc alias: ports <port> Command to list listening ports that match the given keyword.
1483
+ * @param {string} path - The input value, identifier, or path for the operation (used as a keyword to filter listening ports).
1484
+ * @param {Object} options - The default underpost runner options for customizing workflow
1485
+ * @memberof UnderpostRun
1486
+ */
1487
+ ptls: async (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
1488
+ shellExec(`chmod +x ${options.underpostRoot}/scripts/ports-ls.sh`);
1489
+ shellExec(`${options.underpostRoot}/scripts/ports-ls.sh`);
1490
+ },
1450
1491
  /**
1451
1492
  * @method release-cmt
1452
1493
  * @description Commits and pushes a new release for the `engine` repository with a message indicating the new version.
@@ -1462,6 +1503,31 @@ EOF
1462
1503
  shellExec(`underpost push . ${process.env.GITHUB_USERNAME}/engine`, { silent: true });
1463
1504
  },
1464
1505
 
1506
+ /**
1507
+ * @method deploy-test
1508
+ * @description Deploys a test deployment (`dd-test`) in either development or production mode, setting up necessary secrets and starting the deployment.
1509
+ * @param {string} path - The input value, identifier, or path for the operation (used as the deployment ID).
1510
+ * @param {Object} options - The default underpost runner options for customizing workflow
1511
+ * @memberof UnderpostRun
1512
+ */
1513
+ 'deploy-test': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
1514
+ // Note: use recomendation empty deploy cluster: node bin --dev cluster
1515
+ const env = options.dev ? 'development' : 'production';
1516
+ const baseCommand = options.dev ? 'node bin' : 'underpost';
1517
+ const baseClusterCommand = options.dev ? ' --dev' : '';
1518
+ const inputs = path ? path.split(',') : [];
1519
+ const deployId = inputs[0] ? inputs[0] : 'dd-test';
1520
+ const cmd = options.cmd
1521
+ ? options.cmd
1522
+ : [
1523
+ `npm install -g npm@11.2.0`,
1524
+ `npm install -g underpost`,
1525
+ `${baseCommand} secret underpost --create-from-file /etc/config/.env.${env}`,
1526
+ `${baseCommand} start --build --run ${deployId} ${env} --underpost-quickly-install`,
1527
+ ];
1528
+ shellExec(`node bin run sync${baseClusterCommand} --cron-jobs none dd-test --cmd "${cmd}"`);
1529
+ },
1530
+
1465
1531
  /**
1466
1532
  * @method sync-replica
1467
1533
  * @description Syncs a replica for the dd.router
@@ -1597,7 +1663,7 @@ ${hostNetwork ? ` hostNetwork: ${hostNetwork}` : ''}
1597
1663
  imagePullPolicy: ${imagePullPolicy}
1598
1664
  tty: ${tty}
1599
1665
  stdin: ${stdin}
1600
- command: ${JSON.stringify(options.command ? options.command : ['/bin/bash', '-c'])}
1666
+ command: ${JSON.stringify(options.cmd ? options.cmd : ['/bin/bash', '-c'])}
1601
1667
  ${
1602
1668
  args.length > 0
1603
1669
  ? ` args:
@@ -1649,7 +1715,7 @@ EOF`;
1649
1715
  try {
1650
1716
  const npmRoot = getNpmRootPath();
1651
1717
  const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
1652
- if (options.command) options.command = options.command.split(',');
1718
+ if (options.cmd) options.cmd = options.cmd.split(',');
1653
1719
  if (options.args) options.args = options.args.split(',');
1654
1720
  if (!options.underpostRoot) options.underpostRoot = underpostRoot;
1655
1721
  if (!options.namespace) options.namespace = 'default';
package/src/cli/ssh.js CHANGED
@@ -280,7 +280,7 @@ EOF`);
280
280
  options.password = confNode.users[options.user].password;
281
281
  logger.info(`Using saved password for user ${options.user}`);
282
282
  }
283
- options.port = confNode.users[options.user].port || options.port;
283
+ options.port = options.port || confNode.users[options.user].port || 22;
284
284
  }
285
285
  }
286
286
 
@@ -162,7 +162,9 @@ const Input = {
162
162
  break;
163
163
  }
164
164
  case 'md':
165
- RichText.Tokens[inputData.id].easyMDE.value('');
165
+ setTimeout(() => {
166
+ RichText.Tokens[inputData.id].easyMDE.value('');
167
+ });
166
168
  continue;
167
169
  break;
168
170
  case 'checkbox':