underpost 3.2.10 → 3.2.12
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/.vscode/extensions.json +9 -9
- package/.vscode/settings.json +12 -1
- package/CHANGELOG.md +92 -1
- package/CLI-HELP.md +80 -26
- package/README.md +6 -10
- package/bin/build.js +9 -6
- package/bin/build.template.js +187 -0
- package/bin/deploy.js +29 -18
- package/conf.js +1 -4
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/manifests/lxd/lxd-admin-profile.yaml +12 -3
- package/manifests/mongodb-4.4/headless-service.yaml +10 -0
- package/manifests/mongodb-4.4/kustomization.yaml +3 -1
- package/manifests/mongodb-4.4/mongodb-nodeport.yaml +17 -0
- package/manifests/mongodb-4.4/pv-pvc.yaml +10 -14
- package/manifests/mongodb-4.4/statefulset.yaml +79 -0
- package/manifests/mongodb-4.4/storage-class.yaml +9 -0
- package/manifests/valkey/statefulset.yaml +1 -1
- package/manifests/valkey/valkey-nodeport.yaml +17 -0
- package/package.json +3 -3
- package/scripts/ipxe-setup.sh +52 -49
- package/scripts/k3s-node-setup.sh +84 -68
- package/scripts/lxd-vm-setup.sh +193 -8
- package/scripts/maas-nat-firewalld.sh +145 -0
- package/src/cli/baremetal.js +115 -93
- package/src/cli/cluster.js +548 -221
- package/src/cli/deploy.js +131 -166
- package/src/cli/fs.js +11 -3
- package/src/cli/index.js +75 -17
- package/src/cli/lxd.js +1034 -240
- package/src/cli/monitor.js +9 -3
- package/src/cli/release.js +72 -36
- package/src/cli/repository.js +10 -16
- package/src/cli/run.js +72 -55
- package/src/cli/secrets.js +11 -2
- package/src/client/components/core/Auth.js +4 -3
- package/src/client/components/core/ClientEvents.js +76 -0
- package/src/client/components/core/EventBus.js +4 -0
- package/src/client/components/core/Modal.js +82 -41
- package/src/db/DataBaseProvider.js +9 -9
- package/src/db/mariadb/MariaDB.js +2 -1
- package/src/db/mongo/MongoBootstrap.js +592 -522
- package/src/db/mongo/MongooseDB.js +19 -15
- package/src/index.js +1 -1
- package/src/server/conf.js +67 -19
- package/src/server/proxy.js +9 -2
- package/src/server/start.js +8 -4
- package/src/server/valkey.js +2 -0
- package/bin/file.js +0 -220
- package/bin/vs.js +0 -74
- package/bin/zed.js +0 -84
package/src/cli/baremetal.js
CHANGED
|
@@ -27,6 +27,13 @@ const logger = loggerFactory(import.meta);
|
|
|
27
27
|
* and system provisioning for different architectures.
|
|
28
28
|
*/
|
|
29
29
|
class UnderpostBaremetal {
|
|
30
|
+
// NFSv3 RPC ports. Single source of truth shared by the firewall/export setup
|
|
31
|
+
// (rebuildNfsServer) and the kernel `nfsroot=` mount options so the client mount and the
|
|
32
|
+
// opened firewall ports always agree.
|
|
33
|
+
// rpc.statd rejects identical listen and outgoing ports (exit 255 "Listening and outgoing ports cannot be the same!").
|
|
34
|
+
// statd=32765 (listen), statdOutgoing=32766 (SM_NOTIFY source port) is the standard split.
|
|
35
|
+
static NFS_V3_PORTS = { mountd: 20048, statd: 32765, statdOutgoing: 32766, lockd: 32803 };
|
|
36
|
+
|
|
30
37
|
static API = {
|
|
31
38
|
/**
|
|
32
39
|
* @method callback
|
|
@@ -498,10 +505,13 @@ rm -rf ${artifacts.join(' ')}`);
|
|
|
498
505
|
|
|
499
506
|
// Handle control server installation.
|
|
500
507
|
if (options.controlServerInstall === true) {
|
|
501
|
-
// Ensure
|
|
508
|
+
// Ensure the MAAS setup script is executable and then run it.
|
|
502
509
|
shellExec(`chmod +x ${underpostRoot}/scripts/maas-setup.sh`);
|
|
503
|
-
|
|
510
|
+
if (!fs.existsSync(`${process.env.HOME}/.ssh/id_rsa.pub`)) shellExec(`node bin ssh --generate`);
|
|
504
511
|
shellExec(`${underpostRoot}/scripts/maas-setup.sh`);
|
|
512
|
+
// Install GRUB modules into the NFS root filesystem to
|
|
513
|
+
// ensure the necessary files are present for bootloader installation later.
|
|
514
|
+
Underpost.baremetal.installGrubModules();
|
|
505
515
|
return;
|
|
506
516
|
}
|
|
507
517
|
|
|
@@ -601,7 +611,7 @@ rm -rf ${artifacts.join(' ')}`);
|
|
|
601
611
|
}
|
|
602
612
|
|
|
603
613
|
// Create a podman container to extract QEMU static binaries.
|
|
604
|
-
shellExec(`sudo podman create --name extract multiarch/qemu-user-static`);
|
|
614
|
+
shellExec(`sudo podman create --name extract docker.io/multiarch/qemu-user-static`);
|
|
605
615
|
shellExec(`podman ps -a`); // List all podman containers for verification.
|
|
606
616
|
|
|
607
617
|
// If cross-architecture, copy the QEMU static binary into the chroot.
|
|
@@ -917,9 +927,6 @@ rm -rf ${artifacts.join(' ')}`);
|
|
|
917
927
|
isoUrl: workflowsConfig[workflowId].isoUrl,
|
|
918
928
|
});
|
|
919
929
|
|
|
920
|
-
// Set up iptables rules for NAT and port forwarding to enable network connectivity for the baremetal machines.
|
|
921
|
-
shellExec(`${underpostRoot}/scripts/nat-iptables.sh`, { silent: true });
|
|
922
|
-
|
|
923
930
|
// Start HTTP bootstrap server if commissioning or if ISO URL is used (for ISO-based workflows).
|
|
924
931
|
if (options.bootstrapHttpServerRun || options.commission) {
|
|
925
932
|
Underpost.baremetal.httpBootstrapServerRunnerFactory({
|
|
@@ -933,7 +940,7 @@ rm -rf ${artifacts.join(' ')}`);
|
|
|
933
940
|
});
|
|
934
941
|
}
|
|
935
942
|
|
|
936
|
-
// Rebuild NFS
|
|
943
|
+
// Rebuild NFS exports and the matching MAAS/firewalld host configuration.
|
|
937
944
|
if (
|
|
938
945
|
(options.nfsBuildServer === true || options.commission === true) &&
|
|
939
946
|
(workflowsConfig[workflowId].type === 'iso-nfs' ||
|
|
@@ -943,6 +950,7 @@ rm -rf ${artifacts.join(' ')}`);
|
|
|
943
950
|
Underpost.baremetal.rebuildNfsServer({
|
|
944
951
|
nfsHostPath,
|
|
945
952
|
nfsReset: options.nfsReset,
|
|
953
|
+
underpostRoot,
|
|
946
954
|
});
|
|
947
955
|
|
|
948
956
|
// Handle commissioning tasks
|
|
@@ -1399,7 +1407,9 @@ rm -rf ${artifacts.join(' ')}`);
|
|
|
1399
1407
|
shellExec(`mkdir -p ${mountPoint}`);
|
|
1400
1408
|
|
|
1401
1409
|
// Ensure mount point is not already mounted
|
|
1402
|
-
shellExec(`sudo umount ${mountPoint}
|
|
1410
|
+
shellExec(`sudo umount ${mountPoint}`, {
|
|
1411
|
+
silentOnError: true, // Ignore errors if not mounted
|
|
1412
|
+
});
|
|
1403
1413
|
|
|
1404
1414
|
try {
|
|
1405
1415
|
// Mount the ISO
|
|
@@ -2342,39 +2352,36 @@ fi
|
|
|
2342
2352
|
// Determine OS family from osIdLike
|
|
2343
2353
|
const { isDebianBased, isRhelBased } = Underpost.baremetal.getFamilyBaseOs(options.osIdLike);
|
|
2344
2354
|
|
|
2345
|
-
const
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
}`;
|
|
2373
|
-
|
|
2374
|
-
const
|
|
2375
|
-
nfsOptions ? `,${nfsOptions}` : ''
|
|
2376
|
-
}`;
|
|
2377
|
-
|
|
2355
|
+
const ifaceName = networkInterfaceName ? networkInterfaceName : 'eth0';
|
|
2356
|
+
const isStaticIp = ipConfig === 'none' || ipConfig === 'off';
|
|
2357
|
+
const ipParam = isStaticIp
|
|
2358
|
+
? `ip=${ipClient}:${ipFileServer}:${ipDhcpServer}:${netmask}:${hostname}:${ifaceName}:${ipConfig}:${dnsServer}`
|
|
2359
|
+
: `ip=::::${hostname}:${ifaceName}:${ipConfig}`;
|
|
2360
|
+
|
|
2361
|
+
let nfsMountOptions = [];
|
|
2362
|
+
if (type === 'chroot-debootstrap' || type === 'chroot-container') {
|
|
2363
|
+
nfsMountOptions = [
|
|
2364
|
+
'tcp',
|
|
2365
|
+
'nfsvers=3',
|
|
2366
|
+
'nolock',
|
|
2367
|
+
'port=2049',
|
|
2368
|
+
'hard',
|
|
2369
|
+
'intr',
|
|
2370
|
+
'rsize=32768',
|
|
2371
|
+
'wsize=32768',
|
|
2372
|
+
'acregmin=0',
|
|
2373
|
+
'acregmax=0',
|
|
2374
|
+
'acdirmin=0',
|
|
2375
|
+
'acdirmax=0',
|
|
2376
|
+
'noac',
|
|
2377
|
+
];
|
|
2378
|
+
} else if (type === 'iso-nfs' && isDebianBased) {
|
|
2379
|
+
nfsMountOptions = ['nolock', 'nfsvers=3', 'tcp', 'hard', 'port=2049', 'rsize=32768', 'wsize=32768'];
|
|
2380
|
+
}
|
|
2381
|
+
const nfsOptions = nfsMountOptions.join(',');
|
|
2382
|
+
const nfsServerPath = `${ipFileServer}:${process.env.NFS_EXPORT_PATH}/${hostname}`;
|
|
2383
|
+
const nfsRootParam = `nfsroot=${nfsServerPath}${nfsOptions ? `,${nfsOptions}` : ''}`;
|
|
2384
|
+
const casperNfsParams = [`nfsroot=${nfsServerPath}`, ...(nfsOptions ? [`nfsopts=${nfsOptions}`] : [])];
|
|
2378
2385
|
const permissionsParams = [
|
|
2379
2386
|
`rw`,
|
|
2380
2387
|
// `ro`
|
|
@@ -2447,8 +2454,12 @@ fi
|
|
|
2447
2454
|
let qemuNfsRootParams = [`root=/dev/nfs`, `rootfstype=nfs`];
|
|
2448
2455
|
cmd = [ipParam, ...qemuNfsRootParams, nfsRootParam, ...kernelParams];
|
|
2449
2456
|
} else {
|
|
2450
|
-
// 'iso-nfs' —
|
|
2451
|
-
|
|
2457
|
+
// 'iso-nfs' — kernel/initrd from ISO, root filesystem served via NFS.
|
|
2458
|
+
if (isDebianBased) {
|
|
2459
|
+
cmd = [ipParam, `boot=casper`, `netboot=nfs`, ...casperNfsParams, ...kernelParams];
|
|
2460
|
+
} else {
|
|
2461
|
+
cmd = [ipParam, `netboot=nfs`, nfsRootParam, ...kernelParams, ...performanceParams];
|
|
2462
|
+
}
|
|
2452
2463
|
}
|
|
2453
2464
|
|
|
2454
2465
|
// Add RHEL/Rocky/Fedora based images specific parameters
|
|
@@ -2458,7 +2469,7 @@ fi
|
|
|
2458
2469
|
}
|
|
2459
2470
|
// Add Debian/Ubuntu based images specific parameters
|
|
2460
2471
|
else if (isDebianBased) {
|
|
2461
|
-
cmd = cmd.concat([`initrd=initrd.img`, `init=/sbin/init`]);
|
|
2472
|
+
if (type !== 'iso-nfs') cmd = cmd.concat([`initrd=initrd.img`, `init=/sbin/init`]);
|
|
2462
2473
|
if (options.dev) cmd = cmd.concat([`debug`, `ignore_loglevel`]);
|
|
2463
2474
|
}
|
|
2464
2475
|
|
|
@@ -2704,7 +2715,7 @@ fi
|
|
|
2704
2715
|
shellExec(`sudo podman run --rm --privileged docker.io/multiarch/qemu-user-static:latest --reset -p yes`);
|
|
2705
2716
|
// Mount binfmt_misc filesystem.
|
|
2706
2717
|
shellExec(`sudo modprobe binfmt_misc`);
|
|
2707
|
-
shellExec(`sudo mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
|
|
2718
|
+
shellExec(`sudo mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc`, { silentOnError: true });
|
|
2708
2719
|
},
|
|
2709
2720
|
|
|
2710
2721
|
/**
|
|
@@ -2761,6 +2772,19 @@ fi
|
|
|
2761
2772
|
await Underpost.baremetal.macMonitor({ nfsHostPath });
|
|
2762
2773
|
},
|
|
2763
2774
|
|
|
2775
|
+
/**
|
|
2776
|
+
* @method installGrubModules
|
|
2777
|
+
* @description Installs the necessary GRUB modules for both ARM64 and AMD64 architectures.
|
|
2778
|
+
* This ensures that the GRUB bootloader can properly load the kernel and initrd images
|
|
2779
|
+
* during the network boot process, regardless of the target architecture.
|
|
2780
|
+
* @memberof UnderpostBaremetal
|
|
2781
|
+
* @returns {void}
|
|
2782
|
+
*/
|
|
2783
|
+
installGrubModules() {
|
|
2784
|
+
if (!fs.existsSync('/usr/lib/grub/x86_64-efi')) shellExec(`sudo dnf install -y grub2-efi-x64-modules`);
|
|
2785
|
+
if (!fs.existsSync('/usr/lib/grub/arm64-efi')) shellExec(`sudo dnf install -y grub2-efi-aa64-modules`);
|
|
2786
|
+
},
|
|
2787
|
+
|
|
2764
2788
|
/**
|
|
2765
2789
|
* @method crossArchBinFactory
|
|
2766
2790
|
* @description Copies the appropriate QEMU static binary into the NFS root filesystem
|
|
@@ -2786,9 +2810,6 @@ fi
|
|
|
2786
2810
|
logger.warn(`Unsupported bootstrap architecture: ${bootstrapArch}`);
|
|
2787
2811
|
break;
|
|
2788
2812
|
}
|
|
2789
|
-
// Install GRUB EFI modules for both architectures to ensure compatibility.
|
|
2790
|
-
shellExec(`sudo dnf install -y grub2-efi-aa64-modules`);
|
|
2791
|
-
shellExec(`sudo dnf install -y grub2-efi-x64-modules`);
|
|
2792
2813
|
},
|
|
2793
2814
|
|
|
2794
2815
|
/**
|
|
@@ -2904,9 +2925,10 @@ EOF`);
|
|
|
2904
2925
|
stdout: true,
|
|
2905
2926
|
silentOnError: true,
|
|
2906
2927
|
});
|
|
2907
|
-
const isPathMounted =
|
|
2908
|
-
|
|
2909
|
-
|
|
2928
|
+
const isPathMounted =
|
|
2929
|
+
typeof mountpointOut === 'string' && mountpointOut.length > 0
|
|
2930
|
+
? !mountpointOut.match('not a mountpoint') && !mountpointOut.match('No such file')
|
|
2931
|
+
: false;
|
|
2910
2932
|
|
|
2911
2933
|
if (isPathMounted) {
|
|
2912
2934
|
logger.warn('Nfs path already mounted', mountPath);
|
|
@@ -2966,54 +2988,48 @@ EOF`);
|
|
|
2966
2988
|
|
|
2967
2989
|
/**
|
|
2968
2990
|
* @method rebuildNfsServer
|
|
2969
|
-
* @description Configures and
|
|
2970
|
-
* This is crucial for allowing baremetal machines to boot via NFS.
|
|
2991
|
+
* @description Configures NFS exports and aligns host firewall/NFS daemon ports for MAAS workflows.
|
|
2971
2992
|
* @param {object} params - The parameters for the function.
|
|
2972
2993
|
* @param {string} params.nfsHostPath - The path to the NFS server export.
|
|
2973
2994
|
* @memberof UnderpostBaremetal
|
|
2974
2995
|
* @param {string} [params.subnet='192.168.1.0/24'] - The subnet allowed to access the NFS export.
|
|
2975
2996
|
* @param {boolean} [params.nfsReset=false] - Flag to completely reset the NFS server (restart service).
|
|
2997
|
+
* @param {string} [params.underpostRoot] - Repository root used to locate helper scripts.
|
|
2976
2998
|
* @returns {void}
|
|
2977
2999
|
*/
|
|
2978
|
-
rebuildNfsServer({ nfsHostPath, subnet, nfsReset }) {
|
|
3000
|
+
rebuildNfsServer({ nfsHostPath, subnet, nfsReset, underpostRoot }) {
|
|
2979
3001
|
if (!subnet) subnet = '192.168.1.0/24'; // Default subnet if not provided.
|
|
3002
|
+
if (!underpostRoot) {
|
|
3003
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
3004
|
+
underpostRoot = path.resolve(__dirname, '../..');
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
const maasNatFirewalldPath = path.resolve(underpostRoot, 'scripts/maas-nat-firewalld.sh');
|
|
3008
|
+
const nfsPorts = UnderpostBaremetal.NFS_V3_PORTS;
|
|
3009
|
+
const exportOptions = ['rw', 'sync', 'no_root_squash', 'no_subtree_check', 'insecure'].join(',');
|
|
3010
|
+
|
|
3011
|
+
if (!fs.existsSync(maasNatFirewalldPath)) {
|
|
3012
|
+
throw new Error(`MAAS firewalld helper not found: ${maasNatFirewalldPath}`);
|
|
3013
|
+
}
|
|
3014
|
+
|
|
2980
3015
|
// Write the NFS exports configuration to /etc/exports.
|
|
2981
|
-
fs.
|
|
2982
|
-
|
|
2983
|
-
`${nfsHostPath} ${subnet}(${[
|
|
2984
|
-
'rw', // Read-write access.
|
|
2985
|
-
// 'all_squash', // Squash all client UIDs/GIDs to anonymous.
|
|
2986
|
-
'sync', // Synchronous writes.
|
|
2987
|
-
'no_root_squash', // Do not squash root user.
|
|
2988
|
-
'no_subtree_check', // Disable subtree checking.
|
|
2989
|
-
'insecure', // Allow connections from non-privileged ports.
|
|
2990
|
-
]})`,
|
|
2991
|
-
'utf8',
|
|
2992
|
-
);
|
|
3016
|
+
if (!fs.existsSync(nfsHostPath)) fs.mkdirSync(nfsHostPath, { recursive: true });
|
|
3017
|
+
fs.writeFileSync(`/etc/exports`, `${nfsHostPath} ${subnet}(${exportOptions})`, 'utf8');
|
|
2993
3018
|
|
|
2994
|
-
logger.info('
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
rdma=y
|
|
3008
|
-
rdma-port=20049
|
|
3009
|
-
|
|
3010
|
-
[lockd]
|
|
3011
|
-
port = 32766
|
|
3012
|
-
udp-port = 32766
|
|
3013
|
-
`,
|
|
3014
|
-
'utf8',
|
|
3019
|
+
logger.info('Configuring MAAS firewalld and fixed NFSv3 ports...');
|
|
3020
|
+
shellExec(
|
|
3021
|
+
[
|
|
3022
|
+
`MAAS_LAN_CIDR=${subnet}`,
|
|
3023
|
+
`NFS_MODE=v3`,
|
|
3024
|
+
`CONFIGURE_NFS_V3_PORTS=true`,
|
|
3025
|
+
`NFS_MOUNTD_PORT=${nfsPorts.mountd}`,
|
|
3026
|
+
`NFS_STATD_PORT=${nfsPorts.statd}`,
|
|
3027
|
+
`NFS_STATD_OUTGOING_PORT=${nfsPorts.statdOutgoing}`,
|
|
3028
|
+
`NFS_LOCKD_PORT=${nfsPorts.lockd}`,
|
|
3029
|
+
`NFS_LOCKD_UDP_PORT=${nfsPorts.lockd}`,
|
|
3030
|
+
`bash "${maasNatFirewalldPath}"`,
|
|
3031
|
+
].join(' '),
|
|
3015
3032
|
);
|
|
3016
|
-
logger.info('NFS configuration written.');
|
|
3017
3033
|
|
|
3018
3034
|
logger.info('Reloading NFS exports...');
|
|
3019
3035
|
shellExec(`sudo exportfs -rav`);
|
|
@@ -3022,12 +3038,18 @@ udp-port = 32766
|
|
|
3022
3038
|
logger.info('Displaying active NFS exports');
|
|
3023
3039
|
shellExec(`sudo exportfs -s`);
|
|
3024
3040
|
|
|
3025
|
-
// Restart the nfs-server service to apply all configuration changes,
|
|
3026
|
-
// including port settings from /etc/nfs.conf and export changes.
|
|
3027
3041
|
if (nfsReset) {
|
|
3028
|
-
logger.info('Restarting
|
|
3029
|
-
|
|
3030
|
-
|
|
3042
|
+
logger.info('Restarting NFS server service...');
|
|
3043
|
+
let restarted = false;
|
|
3044
|
+
for (const unit of ['nfs-server', 'nfs-kernel-server']) {
|
|
3045
|
+
const result = shellExec(`sudo systemctl restart ${unit}`, { silentOnError: true });
|
|
3046
|
+
if (result.code === 0) {
|
|
3047
|
+
restarted = true;
|
|
3048
|
+
logger.info(`NFS server restarted via ${unit}.`);
|
|
3049
|
+
break;
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
if (!restarted) logger.warn('Unable to restart nfs-server or nfs-kernel-server after export reload.');
|
|
3031
3053
|
}
|
|
3032
3054
|
},
|
|
3033
3055
|
|