@underpostnet/underpost 2.99.1 → 2.99.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.development +0 -3
- package/.env.production +1 -3
- package/.env.test +0 -3
- package/LICENSE +1 -1
- package/README.md +30 -30
- package/baremetal/commission-workflows.json +52 -0
- package/bin/deploy.js +101 -47
- package/cli.md +47 -43
- package/examples/static-page/README.md +55 -378
- package/examples/static-page/ssr-components/CustomPage.js +1 -13
- package/jsconfig.json +4 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/manifests/deployment/playwright/deployment.yaml +52 -0
- package/package.json +2 -2
- package/scripts/disk-devices.sh +13 -0
- package/scripts/rocky-pwa.sh +2 -2
- package/scripts/ssl.sh +12 -6
- package/src/api/user/user.model.js +1 -0
- package/src/cli/baremetal.js +576 -176
- package/src/cli/cloud-init.js +97 -79
- package/src/cli/deploy.js +6 -24
- package/src/cli/env.js +4 -1
- package/src/cli/image.js +7 -40
- package/src/cli/index.js +37 -7
- package/src/cli/repository.js +3 -1
- package/src/cli/run.js +109 -92
- package/src/cli/secrets.js +0 -34
- package/src/cli/static.js +0 -26
- package/src/cli/test.js +13 -1
- package/src/client/components/core/Polyhedron.js +896 -7
- package/src/client/components/core/Translate.js +4 -0
- package/src/client/services/default/default.management.js +12 -2
- package/src/index.js +27 -1
- package/src/runtime/express/Express.js +3 -3
- package/src/server/conf.js +6 -4
- package/src/server/logger.js +33 -31
- package/src/server/process.js +27 -2
- package/src/server/proxy.js +4 -6
- package/src/server/tls.js +30 -25
- package/examples/static-page/QUICK-REFERENCE.md +0 -481
- package/examples/static-page/STATIC-GENERATOR-GUIDE.md +0 -757
package/src/cli/cloud-init.js
CHANGED
|
@@ -261,6 +261,12 @@ curl -X POST \\
|
|
|
261
261
|
* @param {boolean} params.ubuntuToolsBuild - Flag to determine if Ubuntu tools should be built.
|
|
262
262
|
* @param {string} [params.bootcmd] - Optional custom commands to run during boot.
|
|
263
263
|
* @param {string} [params.runcmd] - Optional custom commands to run during first boot.
|
|
264
|
+
* @param {object} [params.write_files] - Optional array of files to write during cloud-init, each with path, permissions, owner, and content.
|
|
265
|
+
* @param {string} [params.write_files[].path] - The file path where the content will be written on the target machine.
|
|
266
|
+
* @param {string} [params.write_files[].permissions] - The file permissions to set for the written file (e.g., '0644').
|
|
267
|
+
* @param {string} [params.write_files[].owner] - The owner of the written file (e.g., 'root:root').
|
|
268
|
+
* @param {string} [params.write_files[].content] - The content to write into the file.
|
|
269
|
+
* @param {boolean} [params.write_files[].defer] - Whether to defer writing the file until the 'final' stage of cloud-init.
|
|
264
270
|
* @param {object} [authCredentials={}] - Optional MAAS authentication credentials.
|
|
265
271
|
* @returns {object} The generated cloud-init configuration content.
|
|
266
272
|
* @memberof UnderpostCloudInit
|
|
@@ -278,6 +284,15 @@ curl -X POST \\
|
|
|
278
284
|
ubuntuToolsBuild,
|
|
279
285
|
bootcmd: bootcmdParam,
|
|
280
286
|
runcmd: runcmdParam,
|
|
287
|
+
write_files = [
|
|
288
|
+
{
|
|
289
|
+
path: '',
|
|
290
|
+
permissions: '',
|
|
291
|
+
owner: '',
|
|
292
|
+
content: '',
|
|
293
|
+
defer: false,
|
|
294
|
+
},
|
|
295
|
+
],
|
|
281
296
|
},
|
|
282
297
|
authCredentials = { consumer_key: '', consumer_secret: '', token_key: '', token_secret: '' },
|
|
283
298
|
) {
|
|
@@ -305,6 +320,7 @@ curl -X POST \\
|
|
|
305
320
|
let runcmd = [
|
|
306
321
|
'echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"',
|
|
307
322
|
'echo "Init runcmd"',
|
|
323
|
+
'systemctl enable --now ssh',
|
|
308
324
|
'echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"',
|
|
309
325
|
];
|
|
310
326
|
|
|
@@ -334,12 +350,14 @@ curl -X POST \\
|
|
|
334
350
|
name: process.env.MAAS_ADMIN_USERNAME,
|
|
335
351
|
sudo: ['ALL=(ALL) NOPASSWD:ALL'],
|
|
336
352
|
shell: '/bin/bash',
|
|
337
|
-
lock_passwd:
|
|
353
|
+
lock_passwd: true,
|
|
338
354
|
groups: 'sudo,users,admin,wheel,lxd',
|
|
339
|
-
plain_text_passwd: process.env.MAAS_ADMIN_USERNAME,
|
|
355
|
+
// plain_text_passwd: process.env.MAAS_ADMIN_USERNAME,
|
|
340
356
|
ssh_authorized_keys: [fs.readFileSync(`/home/dd/engine/engine-private/deploy/id_rsa.pub`, 'utf8')],
|
|
341
357
|
},
|
|
342
358
|
],
|
|
359
|
+
disable_root: true,
|
|
360
|
+
ssh_pwauth: false,
|
|
343
361
|
timezone,
|
|
344
362
|
ntp: {
|
|
345
363
|
enabled: true,
|
|
@@ -360,6 +378,7 @@ curl -X POST \\
|
|
|
360
378
|
'smartmontools',
|
|
361
379
|
'net-tools',
|
|
362
380
|
'util-linux',
|
|
381
|
+
'openssh-server',
|
|
363
382
|
],
|
|
364
383
|
resize_rootfs: false,
|
|
365
384
|
growpart: { mode: 'off' },
|
|
@@ -380,7 +399,7 @@ curl -X POST \\
|
|
|
380
399
|
final_message: '====== Cloud init finished ======',
|
|
381
400
|
bootcmd,
|
|
382
401
|
runcmd,
|
|
383
|
-
|
|
402
|
+
write_files,
|
|
384
403
|
preserve_hostname: false,
|
|
385
404
|
cloud_init_modules: [
|
|
386
405
|
// minimal for commissioning
|
|
@@ -394,37 +413,37 @@ curl -X POST \\
|
|
|
394
413
|
'ssh', // enable/configure SSH for temporary access
|
|
395
414
|
|
|
396
415
|
// optional modules (commented out by default)
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
416
|
+
'migrator',
|
|
417
|
+
'seed_random',
|
|
418
|
+
'growpart',
|
|
419
|
+
'resizefs',
|
|
420
|
+
'users-groups',
|
|
402
421
|
],
|
|
403
422
|
cloud_config_modules: [
|
|
404
423
|
// minimal so MAAS can run commissioning scripts
|
|
405
424
|
'runcmd', // commissioning / final script execution
|
|
406
425
|
'mounts', // mount devices during commissioning if needed
|
|
407
|
-
|
|
426
|
+
'ntp', // optional — enable if you want time sync
|
|
408
427
|
|
|
409
428
|
// typically not required for basic commissioning (commented)
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
429
|
+
'emit_upstart',
|
|
430
|
+
'disk_setup',
|
|
431
|
+
'ssh-import-id',
|
|
432
|
+
'locale',
|
|
433
|
+
'set-passwords',
|
|
434
|
+
'grub-dpkg',
|
|
435
|
+
'apt-pipelining',
|
|
436
|
+
'apt-configure',
|
|
437
|
+
'package-update-upgrade-install', // heavy; do NOT enable by default
|
|
438
|
+
'landscape',
|
|
439
|
+
'timezone',
|
|
440
|
+
'puppet',
|
|
441
|
+
'chef',
|
|
442
|
+
'salt-minion',
|
|
443
|
+
'mcollective',
|
|
444
|
+
'disable-ec2-metadata',
|
|
445
|
+
'byobu',
|
|
446
|
+
'ssh-import-id', // duplicate in original list
|
|
428
447
|
],
|
|
429
448
|
cloud_final_modules: [
|
|
430
449
|
// minimal suggestions so final scripts run and node reports status
|
|
@@ -432,64 +451,19 @@ curl -X POST \\
|
|
|
432
451
|
'final-message', // useful for logs/reporting
|
|
433
452
|
|
|
434
453
|
// optional / commented
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
454
|
+
'rightscale_userdata',
|
|
455
|
+
'scripts-vendor',
|
|
456
|
+
'scripts-per-once',
|
|
457
|
+
'scripts-user',
|
|
458
|
+
'ssh-authkey-fingerprints',
|
|
459
|
+
'keys-to-console',
|
|
460
|
+
'power-state-change', // use carefully (can poweroff/reboot)
|
|
442
461
|
],
|
|
443
462
|
});
|
|
444
463
|
|
|
445
464
|
return { cloudConfigSrc };
|
|
446
465
|
},
|
|
447
466
|
|
|
448
|
-
/**
|
|
449
|
-
* @method authCredentialsFactory
|
|
450
|
-
* @description Retrieves MAAS API key credentials from the MAAS CLI.
|
|
451
|
-
* This method parses the output of `maas apikey` to extract the consumer key,
|
|
452
|
-
* consumer secret, token key, and token secret.
|
|
453
|
-
* @returns {object} An object containing the MAAS authentication credentials.
|
|
454
|
-
* @memberof UnderpostCloudInit
|
|
455
|
-
* @throws {Error} If the MAAS API key format is invalid.
|
|
456
|
-
*/
|
|
457
|
-
authCredentialsFactory() {
|
|
458
|
-
// Expected formats:
|
|
459
|
-
// <consumer_key>:<consumer_token>:<secret> (older format)
|
|
460
|
-
// <consumer_key>:<consumer_secret>:<token_key>:<token_secret> (newer format)
|
|
461
|
-
// Commands used to generate API keys:
|
|
462
|
-
// maas apikey --with-names --username ${process.env.MAAS_ADMIN_USERNAME}
|
|
463
|
-
// maas ${process.env.MAAS_ADMIN_USERNAME} account create-authorisation-token
|
|
464
|
-
// maas apikey --generate --username ${process.env.MAAS_ADMIN_USERNAME}
|
|
465
|
-
// Reference: https://github.com/CanonicalLtd/maas-docs/issues/647
|
|
466
|
-
|
|
467
|
-
const parts = shellExec(`maas apikey --with-names --username ${process.env.MAAS_ADMIN_USERNAME}`, {
|
|
468
|
-
stdout: true,
|
|
469
|
-
})
|
|
470
|
-
.trim()
|
|
471
|
-
.split(`\n`)[0] // Take only the first line of output.
|
|
472
|
-
.split(':'); // Split by colon to get individual parts.
|
|
473
|
-
|
|
474
|
-
let consumer_key, consumer_secret, token_key, token_secret;
|
|
475
|
-
|
|
476
|
-
// Determine the format of the API key and assign parts accordingly.
|
|
477
|
-
if (parts.length === 4) {
|
|
478
|
-
[consumer_key, consumer_secret, token_key, token_secret] = parts;
|
|
479
|
-
} else if (parts.length === 3) {
|
|
480
|
-
// Handle older 3-part format, setting consumer_secret as empty.
|
|
481
|
-
[consumer_key, token_key, token_secret] = parts;
|
|
482
|
-
consumer_secret = '""';
|
|
483
|
-
token_secret = token_secret.split(' MAAS consumer')[0].trim(); // Clean up token secret.
|
|
484
|
-
} else {
|
|
485
|
-
// Throw an error if the format is not recognized.
|
|
486
|
-
throw new Error('Invalid token format');
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
logger.info('Maas api token generated', { consumer_key, consumer_secret, token_key, token_secret });
|
|
490
|
-
return { consumer_key, consumer_secret, token_key, token_secret };
|
|
491
|
-
},
|
|
492
|
-
|
|
493
467
|
/**
|
|
494
468
|
* @method generateCloudConfig
|
|
495
469
|
* @description Generates a generic cloud-init configuration string.
|
|
@@ -518,6 +492,7 @@ curl -X POST \\
|
|
|
518
492
|
growpart,
|
|
519
493
|
network,
|
|
520
494
|
runcmd,
|
|
495
|
+
write_files,
|
|
521
496
|
final_message,
|
|
522
497
|
bootcmd,
|
|
523
498
|
disable_root,
|
|
@@ -645,6 +620,21 @@ curl -X POST \\
|
|
|
645
620
|
runcmd.forEach((cmd) => yaml.push(` - ${cmd}`));
|
|
646
621
|
}
|
|
647
622
|
|
|
623
|
+
if (write_files) {
|
|
624
|
+
yaml.push('write_files:');
|
|
625
|
+
write_files.forEach((file) => {
|
|
626
|
+
yaml.push(` - path: ${file.path}`);
|
|
627
|
+
if (file.encoding) yaml.push(` encoding: ${file.encoding}`);
|
|
628
|
+
if (file.owner) yaml.push(` owner: ${file.owner}`);
|
|
629
|
+
if (file.permissions) yaml.push(` permissions: '${file.permissions}'`);
|
|
630
|
+
if (file.defer) yaml.push(` defer: ${file.defer}`);
|
|
631
|
+
if (file.content) {
|
|
632
|
+
yaml.push(` content: |`);
|
|
633
|
+
file.content.split('\n').forEach((line) => yaml.push(` ${line}`));
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
|
|
648
638
|
if (final_message) yaml.push(`final_message: "${final_message}"`);
|
|
649
639
|
|
|
650
640
|
if (bootcmd) {
|
|
@@ -669,6 +659,34 @@ curl -X POST \\
|
|
|
669
659
|
}
|
|
670
660
|
|
|
671
661
|
return yaml.join('\n');
|
|
662
|
+
} /**
|
|
663
|
+
* @method kernelParamsFactory
|
|
664
|
+
* @description Generates the kernel parameters for the target machine's bootloader configuration,
|
|
665
|
+
* including the necessary parameters to enable cloud-init with a specific configuration URL and logging settings.
|
|
666
|
+
* @param {array} cmd - The existing array of kernel parameters to which cloud-init parameters will be appended.
|
|
667
|
+
* @param {object} options - Options for generating kernel parameters.
|
|
668
|
+
* @param {string} options.ipDhcpServer - The IP address of the DHCP server.
|
|
669
|
+
* @param {object} [options.machine] - The machine information, including system_id for constructing the cloud-init configuration URL.
|
|
670
|
+
* @param {string} [options.machine.system_id] - The unique identifier of the machine, used to fetch the correct cloud-init preseed configuration from MAAS.
|
|
671
|
+
* @return {array} The modified array of kernel parameters with cloud-init parameters included.
|
|
672
|
+
* @memberof UnderpostCloudInit
|
|
673
|
+
*/,
|
|
674
|
+
kernelParamsFactory(
|
|
675
|
+
macAddress,
|
|
676
|
+
cmd = [],
|
|
677
|
+
options = {
|
|
678
|
+
ipDhcpServer: '',
|
|
679
|
+
bootstrapHttpServerPort: 8888,
|
|
680
|
+
hostname: '',
|
|
681
|
+
machine: {
|
|
682
|
+
system_id: '',
|
|
683
|
+
},
|
|
684
|
+
authCredentials: { consumer_key: '', consumer_secret: '', token_key: '', token_secret: '' },
|
|
685
|
+
},
|
|
686
|
+
) {
|
|
687
|
+
const { ipDhcpServer, bootstrapHttpServerPort, hostname } = options;
|
|
688
|
+
const cloudConfigUrl = `http://${ipDhcpServer}:${bootstrapHttpServerPort}/${hostname}/cloud-init/user-data`;
|
|
689
|
+
return cmd.concat([`cloud-config-url=${cloudConfigUrl}`]);
|
|
672
690
|
},
|
|
673
691
|
};
|
|
674
692
|
}
|
package/src/cli/deploy.js
CHANGED
|
@@ -698,30 +698,12 @@ EOF`);
|
|
|
698
698
|
* @memberof UnderpostDeploy
|
|
699
699
|
*/
|
|
700
700
|
existsContainerFile({ podName, path }) {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
}).trim(),
|
|
708
|
-
);
|
|
709
|
-
const isFolder = JSON.parse(
|
|
710
|
-
shellExec(`docker exec ${podName} sh -c 'test -d "$1" && echo true || echo false' sh ${path}`, {
|
|
711
|
-
stdout: true,
|
|
712
|
-
disableLog: true,
|
|
713
|
-
silent: true,
|
|
714
|
-
}).trim(),
|
|
715
|
-
);
|
|
716
|
-
return isFolder || isFile;
|
|
717
|
-
}
|
|
718
|
-
return JSON.parse(
|
|
719
|
-
shellExec(`kubectl exec ${podName} -- test -f ${path} && echo "true" || echo "false"`, {
|
|
720
|
-
stdout: true,
|
|
721
|
-
disableLog: true,
|
|
722
|
-
silent: true,
|
|
723
|
-
}).trim(),
|
|
724
|
-
);
|
|
701
|
+
const result = shellExec(`kubectl exec ${podName} -- test -f ${path} && echo "true" || echo "false"`, {
|
|
702
|
+
stdout: true,
|
|
703
|
+
disableLog: true,
|
|
704
|
+
silent: true,
|
|
705
|
+
}).trim();
|
|
706
|
+
return result === 'true';
|
|
725
707
|
},
|
|
726
708
|
/**
|
|
727
709
|
* Checks the status of a deployment.
|
package/src/cli/env.js
CHANGED
|
@@ -8,6 +8,7 @@ import { getNpmRootPath, writeEnv } from '../server/conf.js';
|
|
|
8
8
|
import fs from 'fs-extra';
|
|
9
9
|
import { loggerFactory } from '../server/logger.js';
|
|
10
10
|
import dotenv from 'dotenv';
|
|
11
|
+
import { pbcopy } from '../server/process.js';
|
|
11
12
|
|
|
12
13
|
dotenv.config();
|
|
13
14
|
|
|
@@ -72,9 +73,10 @@ class UnderpostRootEnv {
|
|
|
72
73
|
* @param {object} options - Options for getting the environment variable.
|
|
73
74
|
* @param {boolean} [options.plain=false] - If true, returns the environment variable value as a string.
|
|
74
75
|
* @param {boolean} [options.disableLog=false] - If true, disables logging of the environment variable value.
|
|
76
|
+
* @param {boolean} [options.copy=false] - If true, copies the environment variable value to the clipboard.
|
|
75
77
|
* @memberof UnderpostEnv
|
|
76
78
|
*/
|
|
77
|
-
get(key, value, options = { plain: false, disableLog: false }) {
|
|
79
|
+
get(key, value, options = { plain: false, disableLog: false, copy: false }) {
|
|
78
80
|
const exeRootPath = `${getNpmRootPath()}/underpost`;
|
|
79
81
|
const envPath = `${exeRootPath}/.env`;
|
|
80
82
|
if (!fs.existsSync(envPath)) {
|
|
@@ -84,6 +86,7 @@ class UnderpostRootEnv {
|
|
|
84
86
|
const env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
85
87
|
if (!options.disableLog)
|
|
86
88
|
options?.plain === true ? console.log(env[key]) : logger.info(`${key}(${typeof env[key]})`, env[key]);
|
|
89
|
+
if (options.copy === true) pbcopy(env[key]);
|
|
87
90
|
return env[key];
|
|
88
91
|
},
|
|
89
92
|
/**
|
package/src/cli/image.js
CHANGED
|
@@ -8,7 +8,7 @@ import fs from 'fs-extra';
|
|
|
8
8
|
import dotenv from 'dotenv';
|
|
9
9
|
import { loggerFactory } from '../server/logger.js';
|
|
10
10
|
import Underpost from '../index.js';
|
|
11
|
-
import { getUnderpostRootPath } from '../server/conf.js';
|
|
11
|
+
import { getNpmRootPath, getUnderpostRootPath } from '../server/conf.js';
|
|
12
12
|
import { shellExec } from '../server/process.js';
|
|
13
13
|
|
|
14
14
|
dotenv.config();
|
|
@@ -32,7 +32,7 @@ class UnderpostImage {
|
|
|
32
32
|
* @param {boolean} [options.kind=false] - If true, load image into Kind cluster.
|
|
33
33
|
* @param {boolean} [options.kubeadm=false] - If true, load image into Kubeadm cluster.
|
|
34
34
|
* @param {boolean} [options.k3s=false] - If true, load image into K3s cluster.
|
|
35
|
-
* @param {string} [options.path=
|
|
35
|
+
* @param {string} [options.path=''] - Path to the Dockerfile context.
|
|
36
36
|
* @param {boolean} [options.dev=false] - If true, use development mode.
|
|
37
37
|
* @param {string} [options.version=''] - Version tag for the image.
|
|
38
38
|
* @param {string} [options.imageName=''] - Custom name for the image.
|
|
@@ -43,7 +43,7 @@ class UnderpostImage {
|
|
|
43
43
|
kind: false,
|
|
44
44
|
kubeadm: false,
|
|
45
45
|
k3s: false,
|
|
46
|
-
path:
|
|
46
|
+
path: '',
|
|
47
47
|
dev: false,
|
|
48
48
|
version: '',
|
|
49
49
|
imageName: '',
|
|
@@ -79,8 +79,6 @@ class UnderpostImage {
|
|
|
79
79
|
* @param {boolean} [options.kind=false] - If true, load the image archive into a Kind cluster.
|
|
80
80
|
* @param {boolean} [options.kubeadm=false] - If true, load the image archive into a Kubeadm cluster (uses 'ctr').
|
|
81
81
|
* @param {boolean} [options.k3s=false] - If true, load the image archive into a K3s cluster (uses 'k3s ctr').
|
|
82
|
-
* @param {boolean} [options.secrets=false] - If true, load secrets from the .env file for the build.
|
|
83
|
-
* @param {string} [options.secretsPath=''] - Custom path to the .env file for secrets.
|
|
84
82
|
* @param {boolean} [options.reset=false] - If true, perform a no-cache build.
|
|
85
83
|
* @param {boolean} [options.dev=false] - If true, use development mode.
|
|
86
84
|
* @memberof UnderpostImage
|
|
@@ -96,27 +94,11 @@ class UnderpostImage {
|
|
|
96
94
|
kind: false,
|
|
97
95
|
kubeadm: false,
|
|
98
96
|
k3s: false,
|
|
99
|
-
secrets: false,
|
|
100
|
-
secretsPath: '',
|
|
101
97
|
reset: false,
|
|
102
98
|
dev: false,
|
|
103
99
|
},
|
|
104
100
|
) {
|
|
105
|
-
let {
|
|
106
|
-
path,
|
|
107
|
-
imageName,
|
|
108
|
-
version,
|
|
109
|
-
imagePath,
|
|
110
|
-
dockerfileName,
|
|
111
|
-
podmanSave,
|
|
112
|
-
secrets,
|
|
113
|
-
secretsPath,
|
|
114
|
-
kind,
|
|
115
|
-
kubeadm,
|
|
116
|
-
k3s,
|
|
117
|
-
reset,
|
|
118
|
-
dev,
|
|
119
|
-
} = options;
|
|
101
|
+
let { path, imageName, version, imagePath, dockerfileName, podmanSave, kind, kubeadm, k3s, reset, dev } = options;
|
|
120
102
|
if (!path) path = '.';
|
|
121
103
|
if (!imageName) imageName = `rockylinux9-underpost:${Underpost.version}`;
|
|
122
104
|
if (!imagePath) imagePath = '.';
|
|
@@ -126,29 +108,14 @@ class UnderpostImage {
|
|
|
126
108
|
if (imagePath && typeof imagePath === 'string' && !fs.existsSync(imagePath))
|
|
127
109
|
fs.mkdirSync(imagePath, { recursive: true });
|
|
128
110
|
const tarFile = `${imagePath}/${imageName.replace(':', '_')}.tar`;
|
|
129
|
-
let secretsInput = ' ';
|
|
130
|
-
let secretDockerInput = '';
|
|
131
111
|
let cache = '';
|
|
132
|
-
if (secrets === true) {
|
|
133
|
-
const envObj = dotenv.parse(
|
|
134
|
-
fs.readFileSync(
|
|
135
|
-
secretsPath && typeof secretsPath === 'string' ? secretsPath : `${getNpmRootPath()}/underpost/.env`,
|
|
136
|
-
'utf8',
|
|
137
|
-
),
|
|
138
|
-
);
|
|
139
|
-
for (const key of Object.keys(envObj)) {
|
|
140
|
-
secretsInput += ` && export ${key}="${envObj[key]}" `; // Example: $(cat gitlab-token.txt)
|
|
141
|
-
secretDockerInput += ` --secret id=${key},env=${key} \ `;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
112
|
if (reset === true) cache += ' --rm --no-cache';
|
|
145
|
-
if (path
|
|
113
|
+
if (path)
|
|
146
114
|
shellExec(
|
|
147
|
-
`cd ${path}
|
|
115
|
+
`cd ${path} && sudo podman build -f ./${
|
|
148
116
|
dockerfileName && typeof dockerfileName === 'string' ? dockerfileName : 'Dockerfile'
|
|
149
|
-
} -t ${imageName} --pull=never --cap-add=CAP_AUDIT_WRITE${cache}
|
|
117
|
+
} -t ${imageName} --pull=never --cap-add=CAP_AUDIT_WRITE${cache} --network host`,
|
|
150
118
|
);
|
|
151
|
-
|
|
152
119
|
if (podmanSave === true) {
|
|
153
120
|
if (fs.existsSync(tarFile)) fs.removeSync(tarFile);
|
|
154
121
|
shellExec(`podman save -o ${tarFile} ${podManImg}`);
|
package/src/cli/index.js
CHANGED
|
@@ -138,9 +138,6 @@ program
|
|
|
138
138
|
.option('--head-components <paths>', 'Comma-separated SSR head component paths.')
|
|
139
139
|
.option('--body-components <paths>', 'Comma-separated SSR body component paths.')
|
|
140
140
|
|
|
141
|
-
.option('--deploy-id <deploy-id>', 'Build static assets for a specific deployment ID.')
|
|
142
|
-
.option('--build', 'Triggers the static build process for the specified deployment ID.')
|
|
143
|
-
.option('--build-host <build-host>', 'Sets a custom build host for static documents or assets.')
|
|
144
141
|
.option('--build-path <build-path>', 'Sets a custom build path for static documents or assets.')
|
|
145
142
|
.option('--env <env>', 'Sets the environment for the static build (e.g., "development", "production").')
|
|
146
143
|
.option('--minify', 'Minify HTML output (default: true for production).')
|
|
@@ -165,6 +162,7 @@ program
|
|
|
165
162
|
.option('--filter <keyword>', 'Filters the list by matching key or value (only for list operation).')
|
|
166
163
|
.option('--deploy-id <deploy-id>', 'Sets the deployment configuration ID for the operation context.')
|
|
167
164
|
.option('--build', 'Sets the build context for the operation.')
|
|
165
|
+
.option('--copy', 'Copies the configuration value to the clipboard (only for get operation).')
|
|
168
166
|
.description(`Manages Underpost configurations using various operators.`)
|
|
169
167
|
.action((...args) => Underpost.env[args[0]](args[1], args[2], args[3]));
|
|
170
168
|
|
|
@@ -320,8 +318,6 @@ program
|
|
|
320
318
|
.option('--kubeadm', 'Set kubeadm cluster env image context management.')
|
|
321
319
|
.option('--k3s', 'Set k3s cluster env image context management.')
|
|
322
320
|
.option('--node-name', 'Set node name for kubeadm or k3s cluster env image context management.')
|
|
323
|
-
.option('--secrets', 'Includes Dockerfile environment secrets during the build.')
|
|
324
|
-
.option('--secrets-path [secrets-path]', 'Specifies a custom path for Dockerfile environment secrets.')
|
|
325
321
|
.option('--reset', 'Performs a build without using the cache.')
|
|
326
322
|
.option('--dev', 'Use development mode.')
|
|
327
323
|
.option('--pull-dockerhub <dockerhub-image>', 'Sets a custom Docker Hub image for base image pulls.')
|
|
@@ -557,6 +553,20 @@ program
|
|
|
557
553
|
.option('--retry-count <count>', 'Sets HTTPProxy per-route retry count (e.g., 3).')
|
|
558
554
|
.option('--retry-per-try-timeout <duration>', 'Sets HTTPProxy retry per-try timeout (e.g., "150ms").')
|
|
559
555
|
.option('--disable-private-conf-update', 'Disables updates to private configuration during execution.')
|
|
556
|
+
.option('--logs', 'Streams logs during the runner execution.')
|
|
557
|
+
.option('--monitor-status <status>', 'Sets the status to monitor for pod/resource (default: "Running").')
|
|
558
|
+
.option(
|
|
559
|
+
'--monitor-status-kind-type <kind-type>',
|
|
560
|
+
'Sets the Kubernetes resource kind type to monitor (default: "pods").',
|
|
561
|
+
)
|
|
562
|
+
.option(
|
|
563
|
+
'--monitor-status-delta-ms <milliseconds>',
|
|
564
|
+
'Sets the polling interval in milliseconds for status monitoring (default: 1000).',
|
|
565
|
+
)
|
|
566
|
+
.option(
|
|
567
|
+
'--monitor-status-max-attempts <attempts>',
|
|
568
|
+
'Sets the maximum number of status check attempts (default: 600).',
|
|
569
|
+
)
|
|
560
570
|
.description('Runs specified scripts using various runners.')
|
|
561
571
|
.action(Underpost.run.callback);
|
|
562
572
|
|
|
@@ -596,7 +606,13 @@ program
|
|
|
596
606
|
.action(Underpost.lxd.callback);
|
|
597
607
|
|
|
598
608
|
program
|
|
599
|
-
.command('baremetal [workflow-id]
|
|
609
|
+
.command('baremetal [workflow-id]')
|
|
610
|
+
.option('--ip-address <ip-address>', 'The IP address of the control server or the local machine.')
|
|
611
|
+
.option('--hostname <hostname>', 'The hostname of the target baremetal machine.')
|
|
612
|
+
.option('--ip-file-server <ip-file-server>', 'The IP address of the file server (NFS/TFTP).')
|
|
613
|
+
.option('--ip-config <ip-config>', 'IP configuration string for the baremetal machine.')
|
|
614
|
+
.option('--netmask <netmask>', 'Netmask of network.')
|
|
615
|
+
.option('--dns-server <dns-server>', 'DNS server IP address.')
|
|
600
616
|
.option('--control-server-install', 'Installs the baremetal control server.')
|
|
601
617
|
.option('--control-server-uninstall', 'Uninstalls the baremetal control server.')
|
|
602
618
|
.option('--control-server-restart', 'Restarts the baremetal control server.')
|
|
@@ -609,6 +625,10 @@ program
|
|
|
609
625
|
)
|
|
610
626
|
.option('--ipxe', 'Chainloads iPXE to normalize identity before commissioning.')
|
|
611
627
|
.option('--ipxe-rebuild', 'Forces rebuild of iPXE binary with embedded boot script.')
|
|
628
|
+
.option(
|
|
629
|
+
'--ipxe-build-iso <iso-path>',
|
|
630
|
+
'Builds a standalone iPXE ISO with embedded script for the specified workflow ID.',
|
|
631
|
+
)
|
|
612
632
|
.option('--install-packer', 'Installs Packer CLI.')
|
|
613
633
|
.option(
|
|
614
634
|
'--packer-maas-image-template <template-path>',
|
|
@@ -652,7 +672,17 @@ program
|
|
|
652
672
|
.option('--rocky-tools-test', 'Tests rocky linux tools in chroot environment.')
|
|
653
673
|
.option('--bootcmd <bootcmd-list>', 'Comma-separated list of boot commands to execute.')
|
|
654
674
|
.option('--runcmd <runcmd-list>', 'Comma-separated list of run commands to execute.')
|
|
655
|
-
.option(
|
|
675
|
+
.option(
|
|
676
|
+
'--logs <log-id>',
|
|
677
|
+
`Displays logs for log id: ${[
|
|
678
|
+
'dhcp',
|
|
679
|
+
'dhcp-lease',
|
|
680
|
+
'dhcp-lan',
|
|
681
|
+
'cloud-init',
|
|
682
|
+
'cloud-init-machine',
|
|
683
|
+
'cloud-init-config',
|
|
684
|
+
]}`,
|
|
685
|
+
)
|
|
656
686
|
.option('--dev', 'Sets the development context environment for baremetal operations.')
|
|
657
687
|
.option('--ls', 'Lists available boot resources and machines.')
|
|
658
688
|
.description(
|
package/src/cli/repository.js
CHANGED
|
@@ -152,6 +152,7 @@ class UnderpostRepository {
|
|
|
152
152
|
.map((commitData, i) => `${i === 0 ? '' : ' && '}git ${diffCmd} ${commitData.hash}`)
|
|
153
153
|
.join('');
|
|
154
154
|
if (history[0]) {
|
|
155
|
+
let index = history.length;
|
|
155
156
|
for (const commit of history) {
|
|
156
157
|
console.log(
|
|
157
158
|
shellExec(`git show -s --format=%ci ${commit.hash}`, {
|
|
@@ -160,7 +161,8 @@ class UnderpostRepository {
|
|
|
160
161
|
disableLog: true,
|
|
161
162
|
}).trim().green,
|
|
162
163
|
);
|
|
163
|
-
console.log(commit.hash.yellow, commit.message);
|
|
164
|
+
console.log(`${index}`.magenta, commit.hash.yellow, commit.message);
|
|
165
|
+
index--;
|
|
164
166
|
console.log(
|
|
165
167
|
shellExec(`git show --name-status --pretty="" ${commit.hash}`, {
|
|
166
168
|
stdout: true,
|