underpost 2.8.82 → 2.8.84
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/.github/workflows/ghpkg.yml +4 -4
- package/.github/workflows/npmpkg.yml +4 -4
- package/.vscode/extensions.json +1 -1
- package/.vscode/settings.json +0 -43
- package/README.md +19 -2
- package/bin/deploy.js +25 -10
- package/bin/file.js +18 -1
- package/bin/vs.js +12 -4
- package/cli.md +28 -1
- package/docker-compose.yml +1 -1
- package/manifests/deployment/dd-template-development/deployment.yaml +2 -2
- package/manifests/deployment/tensorflow/tf-gpu-test.yaml +65 -0
- package/manifests/maas/device-scan.sh +3 -3
- package/manifests/maas/gpu-diag.sh +19 -0
- package/manifests/maas/maas-setup.sh +10 -10
- package/manifests/maas/snap-clean.sh +26 -0
- package/package.json +1 -1
- package/src/cli/baremetal.js +105 -73
- package/src/cli/cloud-init.js +21 -12
- package/src/cli/cluster.js +185 -106
- package/src/cli/deploy.js +14 -0
- package/src/cli/index.js +19 -1
- package/src/cli/repository.js +7 -4
- package/src/cli/run.js +262 -0
- package/src/cli/test.js +1 -1
- package/src/index.js +26 -17
- package/src/server/conf.js +6 -3
- package/src/server/process.js +16 -19
package/src/cli/baremetal.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getNpmRootPath, getUnderpostRootPath } from '../server/conf.js';
|
|
2
|
-
import { pbcopy, shellExec } from '../server/process.js';
|
|
2
|
+
import { openTerminal, pbcopy, shellExec } from '../server/process.js';
|
|
3
3
|
import dotenv from 'dotenv';
|
|
4
4
|
import { loggerFactory } from '../server/logger.js';
|
|
5
5
|
import { getLocalIPv4Address } from '../server/dns.js';
|
|
@@ -75,6 +75,9 @@ class UnderpostBaremetal {
|
|
|
75
75
|
// Set default MAC address
|
|
76
76
|
let macAddress = '00:00:00:00:00:00';
|
|
77
77
|
|
|
78
|
+
// Define the debootstrap architecture.
|
|
79
|
+
let debootstrapArch;
|
|
80
|
+
|
|
78
81
|
// Define the database provider ID.
|
|
79
82
|
const dbProviderId = 'postgresql-17';
|
|
80
83
|
|
|
@@ -88,7 +91,7 @@ class UnderpostBaremetal {
|
|
|
88
91
|
const callbackMetaData = {
|
|
89
92
|
args: { hostname, ipAddress, workflowId },
|
|
90
93
|
options,
|
|
91
|
-
runnerHost: { architecture: UnderpostBaremetal.API.getHostArch(), ip: getLocalIPv4Address() },
|
|
94
|
+
runnerHost: { architecture: UnderpostBaremetal.API.getHostArch().alias, ip: getLocalIPv4Address() },
|
|
92
95
|
nfsHostPath,
|
|
93
96
|
tftpRootPath,
|
|
94
97
|
};
|
|
@@ -119,8 +122,23 @@ class UnderpostBaremetal {
|
|
|
119
122
|
|
|
120
123
|
// Handle NFS shell access option.
|
|
121
124
|
if (options.nfsSh === true) {
|
|
125
|
+
const { debootstrap } = UnderpostBaremetal.API.workflowsConfig[workflowId];
|
|
122
126
|
// Copy the chroot command to the clipboard for easy execution.
|
|
123
|
-
|
|
127
|
+
if (debootstrap.image.architecture !== callbackMetaData.runnerHost.architecture)
|
|
128
|
+
switch (debootstrap.image.architecture) {
|
|
129
|
+
case 'arm64':
|
|
130
|
+
pbcopy(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash`);
|
|
131
|
+
break;
|
|
132
|
+
|
|
133
|
+
case 'amd64':
|
|
134
|
+
pbcopy(`sudo chroot ${nfsHostPath} /usr/bin/qemu-x86_64-static /bin/bash`);
|
|
135
|
+
break;
|
|
136
|
+
|
|
137
|
+
default:
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
else pbcopy(`sudo chroot ${nfsHostPath} /bin/bash`);
|
|
141
|
+
|
|
124
142
|
return; // Exit early as this is a specific interactive operation.
|
|
125
143
|
}
|
|
126
144
|
|
|
@@ -131,6 +149,7 @@ class UnderpostBaremetal {
|
|
|
131
149
|
shellExec(`chmod +x ${underpostRoot}/manifests/maas/nat-iptables.sh`);
|
|
132
150
|
shellExec(`${underpostRoot}/manifests/maas/maas-setup.sh`);
|
|
133
151
|
shellExec(`${underpostRoot}/manifests/maas/nat-iptables.sh`);
|
|
152
|
+
return;
|
|
134
153
|
}
|
|
135
154
|
|
|
136
155
|
// Handle control server uninstallation.
|
|
@@ -148,6 +167,7 @@ class UnderpostBaremetal {
|
|
|
148
167
|
shellExec(`sudo rm -rf /etc/maas`);
|
|
149
168
|
shellExec(`sudo rm -rf /var/lib/maas`);
|
|
150
169
|
shellExec(`sudo rm -rf /var/log/maas`);
|
|
170
|
+
return;
|
|
151
171
|
}
|
|
152
172
|
|
|
153
173
|
// Handle control server database installation.
|
|
@@ -157,16 +177,26 @@ class UnderpostBaremetal {
|
|
|
157
177
|
shellExec(
|
|
158
178
|
`node ${underpostRoot}/bin/deploy pg-drop-db ${process.env.DB_PG_MAAS_NAME} ${process.env.DB_PG_MAAS_USER}`,
|
|
159
179
|
);
|
|
160
|
-
shellExec(`node ${underpostRoot}/bin/deploy maas
|
|
180
|
+
shellExec(`node ${underpostRoot}/bin/deploy maas-db`);
|
|
181
|
+
return;
|
|
161
182
|
}
|
|
162
183
|
|
|
163
184
|
// Handle control server database uninstallation.
|
|
164
185
|
if (options.controlServerDbUninstall === true) {
|
|
165
186
|
shellExec(`node ${underpostRoot}/bin/deploy ${dbProviderId} uninstall`);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Set debootstrap architecture.
|
|
191
|
+
{
|
|
192
|
+
const { architecture } = UnderpostBaremetal.API.workflowsConfig[workflowId].debootstrap.image;
|
|
193
|
+
debootstrapArch = architecture;
|
|
166
194
|
}
|
|
167
195
|
|
|
168
196
|
// Handle NFS mount operation.
|
|
169
197
|
if (options.nfsMount === true) {
|
|
198
|
+
// Mount binfmt_misc filesystem.
|
|
199
|
+
UnderpostBaremetal.API.mountBinfmtMisc({ nfsHostPath });
|
|
170
200
|
UnderpostBaremetal.API.nfsMountCallback({ hostname, workflowId, mount: true });
|
|
171
201
|
}
|
|
172
202
|
|
|
@@ -185,27 +215,16 @@ class UnderpostBaremetal {
|
|
|
185
215
|
}
|
|
186
216
|
logger.info('NFS root filesystem is not mounted, building...');
|
|
187
217
|
|
|
188
|
-
// Install necessary packages for debootstrap and QEMU.
|
|
189
|
-
shellExec(`sudo dnf install -y iptables-legacy`);
|
|
190
|
-
shellExec(`sudo dnf install -y debootstrap`);
|
|
191
|
-
shellExec(`sudo dnf install kernel-modules-extra-$(uname -r)`);
|
|
192
|
-
// Reset QEMU user-static binfmt for proper cross-architecture execution.
|
|
193
|
-
shellExec(`sudo podman run --rm --privileged multiarch/qemu-user-static --reset -p yes`);
|
|
194
|
-
shellExec(`sudo modprobe binfmt_misc`);
|
|
195
|
-
shellExec(`sudo mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc`);
|
|
196
|
-
|
|
197
218
|
// Clean and create the NFS host path.
|
|
198
219
|
shellExec(`sudo rm -rf ${nfsHostPath}/*`);
|
|
199
220
|
shellExec(`mkdir -p ${nfsHostPath}`);
|
|
200
|
-
shellExec(`sudo chown -R root:root ${nfsHostPath}`);
|
|
201
|
-
shellExec(`sudo chmod 755 ${nfsHostPath}`);
|
|
202
221
|
|
|
203
|
-
|
|
222
|
+
// Mount binfmt_misc filesystem.
|
|
223
|
+
UnderpostBaremetal.API.mountBinfmtMisc({ nfsHostPath });
|
|
204
224
|
|
|
205
225
|
// Perform the first stage of debootstrap.
|
|
206
226
|
{
|
|
207
227
|
const { architecture, name } = UnderpostBaremetal.API.workflowsConfig[workflowId].debootstrap.image;
|
|
208
|
-
debootstrapArch = architecture;
|
|
209
228
|
shellExec(
|
|
210
229
|
[
|
|
211
230
|
`sudo debootstrap`,
|
|
@@ -272,44 +291,43 @@ class UnderpostBaremetal {
|
|
|
272
291
|
}
|
|
273
292
|
}
|
|
274
293
|
|
|
275
|
-
let resources, resource, machines;
|
|
276
|
-
|
|
277
294
|
// Fetch boot resources and machines if commissioning or listing.
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
}
|
|
295
|
+
|
|
296
|
+
let resources = JSON.parse(
|
|
297
|
+
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-resources read`, {
|
|
298
|
+
silent: true,
|
|
299
|
+
stdout: true,
|
|
300
|
+
}),
|
|
301
|
+
).map((o) => ({
|
|
302
|
+
id: o.id,
|
|
303
|
+
name: o.name,
|
|
304
|
+
architecture: o.architecture,
|
|
305
|
+
}));
|
|
306
|
+
if (options.ls === true) {
|
|
307
|
+
console.table(resources);
|
|
308
|
+
}
|
|
309
|
+
let machines = JSON.parse(
|
|
310
|
+
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} machines read`, {
|
|
311
|
+
stdout: true,
|
|
312
|
+
silent: true,
|
|
313
|
+
}),
|
|
314
|
+
).map((m) => ({
|
|
315
|
+
system_id: m.interface_set[0].system_id,
|
|
316
|
+
mac_address: m.interface_set[0].mac_address,
|
|
317
|
+
hostname: m.hostname,
|
|
318
|
+
status_name: m.status_name,
|
|
319
|
+
}));
|
|
320
|
+
if (options.ls === true) {
|
|
321
|
+
console.table(machines);
|
|
306
322
|
}
|
|
307
323
|
|
|
308
324
|
// Handle commissioning tasks (placeholder for future implementation).
|
|
309
325
|
if (options.commission === true) {
|
|
310
326
|
const { firmwares, networkInterfaceName, maas, netmask, menuentryStr } =
|
|
311
327
|
UnderpostBaremetal.API.workflowsConfig[workflowId];
|
|
312
|
-
resource = resources.find(
|
|
328
|
+
const resource = resources.find(
|
|
329
|
+
(o) => o.architecture === maas.image.architecture && o.name === maas.image.name,
|
|
330
|
+
);
|
|
313
331
|
logger.info('Commissioning resource', resource);
|
|
314
332
|
|
|
315
333
|
// Clean and create TFTP root path.
|
|
@@ -466,8 +484,12 @@ menuentry '${menuentryStr}' {
|
|
|
466
484
|
shellExec(`sudo sudo chmod 755 ${process.env.TFTP_ROOT}`);
|
|
467
485
|
}
|
|
468
486
|
|
|
469
|
-
//
|
|
487
|
+
// Final commissioning steps.
|
|
470
488
|
if (options.commission === true || options.cloudInitUpdate === true) {
|
|
489
|
+
const { debootstrap, networkInterfaceName, chronyc, maas } = UnderpostBaremetal.API.workflowsConfig[workflowId];
|
|
490
|
+
const { timezone, chronyConfPath } = chronyc;
|
|
491
|
+
|
|
492
|
+
// Build cloud-init tools.
|
|
471
493
|
UnderpostCloudInit.API.buildTools({
|
|
472
494
|
workflowId,
|
|
473
495
|
nfsHostPath,
|
|
@@ -475,15 +497,6 @@ menuentry '${menuentryStr}' {
|
|
|
475
497
|
callbackMetaData,
|
|
476
498
|
dev: options.dev,
|
|
477
499
|
});
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
// Final commissioning steps.
|
|
481
|
-
if (options.commission === true) {
|
|
482
|
-
const { debootstrap, networkInterfaceName, chronyc, maas } = UnderpostBaremetal.API.workflowsConfig[workflowId];
|
|
483
|
-
const { timezone, chronyConfPath } = chronyc;
|
|
484
|
-
|
|
485
|
-
// Remove existing machines from MAAS.
|
|
486
|
-
machines = UnderpostBaremetal.API.removeMachines({ machines });
|
|
487
500
|
|
|
488
501
|
// Run cloud-init reset and configure cloud-init.
|
|
489
502
|
UnderpostBaremetal.API.crossArchRunner({
|
|
@@ -491,7 +504,8 @@ menuentry '${menuentryStr}' {
|
|
|
491
504
|
debootstrapArch: debootstrap.image.architecture,
|
|
492
505
|
callbackMetaData,
|
|
493
506
|
steps: [
|
|
494
|
-
`/underpost/reset.sh`,
|
|
507
|
+
options.cloudInitUpdate === true ? '' : `/underpost/reset.sh`,
|
|
508
|
+
`chown root:root /usr/bin/sudo && chmod 4755 /usr/bin/sudo`,
|
|
495
509
|
UnderpostCloudInit.API.configFactory({
|
|
496
510
|
controlServerIp: callbackMetaData.runnerHost.ip,
|
|
497
511
|
hostname,
|
|
@@ -505,6 +519,8 @@ menuentry '${menuentryStr}' {
|
|
|
505
519
|
],
|
|
506
520
|
});
|
|
507
521
|
|
|
522
|
+
if (options.cloudInitUpdate === true) return;
|
|
523
|
+
|
|
508
524
|
// Apply NAT iptables rules.
|
|
509
525
|
shellExec(`${underpostRoot}/manifests/maas/nat-iptables.sh`, { silent: true });
|
|
510
526
|
|
|
@@ -533,6 +549,9 @@ menuentry '${menuentryStr}' {
|
|
|
533
549
|
],
|
|
534
550
|
});
|
|
535
551
|
|
|
552
|
+
// Remove existing machines from MAAS.
|
|
553
|
+
machines = UnderpostBaremetal.API.removeMachines({ machines });
|
|
554
|
+
|
|
536
555
|
// Monitor commissioning process.
|
|
537
556
|
UnderpostBaremetal.API.commissionMonitor({
|
|
538
557
|
macAddress,
|
|
@@ -680,18 +699,8 @@ menuentry '${menuentryStr}' {
|
|
|
680
699
|
fs.writeFileSync(`${nfsHostPath}/underpost/token-secret`, token_secret, 'utf8');
|
|
681
700
|
|
|
682
701
|
// Open new terminals for live cloud-init logs.
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
{
|
|
686
|
-
async: true,
|
|
687
|
-
},
|
|
688
|
-
);
|
|
689
|
-
shellExec(
|
|
690
|
-
`gnome-terminal -- bash -c "node ${underpostRoot}/bin baremetal --logs machine; exec bash" & disown`,
|
|
691
|
-
{
|
|
692
|
-
async: true,
|
|
693
|
-
},
|
|
694
|
-
);
|
|
702
|
+
openTerminal(`node ${underpostRoot}/bin baremetal --logs cloud`);
|
|
703
|
+
openTerminal(`node ${underpostRoot}/bin baremetal --logs machine`);
|
|
695
704
|
} catch (error) {
|
|
696
705
|
logger.error(error, error.stack);
|
|
697
706
|
} finally {
|
|
@@ -710,6 +719,29 @@ menuentry '${menuentryStr}' {
|
|
|
710
719
|
}
|
|
711
720
|
},
|
|
712
721
|
|
|
722
|
+
/**
|
|
723
|
+
* @method mountBinfmtMisc
|
|
724
|
+
* @description Mounts the binfmt_misc filesystem to enable QEMU user-static binfmt support.
|
|
725
|
+
* This is necessary for cross-architecture execution within a chroot environment.
|
|
726
|
+
* @param {object} params - The parameters for the function.
|
|
727
|
+
* @param {string} params.nfsHostPath - The path to the NFS root filesystem on the host.
|
|
728
|
+
* @returns {void}
|
|
729
|
+
*/
|
|
730
|
+
mountBinfmtMisc({ nfsHostPath }) {
|
|
731
|
+
// Install necessary packages for debootstrap and QEMU.
|
|
732
|
+
shellExec(`sudo dnf install -y iptables-legacy`);
|
|
733
|
+
shellExec(`sudo dnf install -y debootstrap`);
|
|
734
|
+
shellExec(`sudo dnf install kernel-modules-extra-$(uname -r)`);
|
|
735
|
+
// Reset QEMU user-static binfmt for proper cross-architecture execution.
|
|
736
|
+
shellExec(`sudo podman run --rm --privileged multiarch/qemu-user-static --reset -p yes`);
|
|
737
|
+
// Mount binfmt_misc filesystem.
|
|
738
|
+
shellExec(`sudo modprobe binfmt_misc`);
|
|
739
|
+
shellExec(`sudo mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc`);
|
|
740
|
+
// Set ownership and permissions for the NFS host path.
|
|
741
|
+
shellExec(`sudo chown -R root:root ${nfsHostPath}`);
|
|
742
|
+
shellExec(`sudo chmod 755 ${nfsHostPath}`);
|
|
743
|
+
},
|
|
744
|
+
|
|
713
745
|
/**
|
|
714
746
|
* @method removeMachines
|
|
715
747
|
* @description Deletes all specified machines from MAAS.
|
|
@@ -903,8 +935,8 @@ EOF`);
|
|
|
903
935
|
getHostArch() {
|
|
904
936
|
// `uname -m` returns e.g. 'x86_64' or 'aarch64'
|
|
905
937
|
const machine = shellExec('uname -m', { stdout: true }).trim();
|
|
906
|
-
if (machine === 'x86_64') return 'amd64';
|
|
907
|
-
if (machine === 'aarch64') return 'arm64';
|
|
938
|
+
if (machine === 'x86_64') return { alias: 'amd64', name: 'x86_64' };
|
|
939
|
+
if (machine === 'aarch64') return { alias: 'arm64', name: 'aarch64' };
|
|
908
940
|
throw new Error(`Unsupported host architecture: ${machine}`);
|
|
909
941
|
},
|
|
910
942
|
|
package/src/cli/cloud-init.js
CHANGED
|
@@ -198,17 +198,23 @@ TOKEN_SECRET=$(cat /underpost/token-secret)
|
|
|
198
198
|
echo ">>> Starting MAAS machine commissioning for system_id: $MACHINE_ID …"
|
|
199
199
|
|
|
200
200
|
curl -X POST \\
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
201
|
+
--fail --location --verbose --include --raw --trace-ascii /dev/stdout\\
|
|
202
|
+
--header "Authorization:\\
|
|
203
|
+
OAuth oauth_version=1.0,\\
|
|
204
|
+
oauth_signature_method=PLAINTEXT,\\
|
|
205
|
+
oauth_consumer_key=$CONSUMER_KEY,\\
|
|
206
|
+
oauth_token=$TOKEN_KEY,\\
|
|
207
|
+
oauth_signature=&$TOKEN_SECRET,\\
|
|
208
|
+
oauth_nonce=$(uuidgen),\\
|
|
209
|
+
oauth_timestamp=$(date +%s)"\\
|
|
210
|
+
-F "commissioning_scripts=20-maas-01-install-lldpd"\\
|
|
211
|
+
-F "enable_ssh=1"\\
|
|
212
|
+
-F "skip_bmc_config=1"\\
|
|
213
|
+
-F "skip_networking=1"\\
|
|
214
|
+
-F "skip_storage=1"\\
|
|
215
|
+
-F "testing_scripts=none"\\
|
|
216
|
+
http://${callbackMetaData.runnerHost.ip}:5240/MAAS/api/2.0/machines/$MACHINE_ID/op-commission \\
|
|
217
|
+
2>&1 | tee /underpost/enlistment.log || echo "ERROR: MAAS commissioning returned code $?"`,
|
|
212
218
|
'utf8',
|
|
213
219
|
);
|
|
214
220
|
|
|
@@ -365,6 +371,9 @@ packages:
|
|
|
365
371
|
- htop
|
|
366
372
|
- snapd
|
|
367
373
|
- chrony
|
|
374
|
+
- lldpd
|
|
375
|
+
- lshw
|
|
376
|
+
|
|
368
377
|
resize_rootfs: false
|
|
369
378
|
growpart:
|
|
370
379
|
mode: "off"
|
|
@@ -470,7 +479,7 @@ cloud_final_modules:
|
|
|
470
479
|
- scripts-per-once
|
|
471
480
|
- scripts-per-boot
|
|
472
481
|
# - scripts-per-instance
|
|
473
|
-
|
|
482
|
+
- scripts-user
|
|
474
483
|
- ssh-authkey-fingerprints
|
|
475
484
|
- keys-to-console
|
|
476
485
|
# - phone-home
|