underpost 2.8.79 → 2.8.82
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 +23 -21
- package/.github/workflows/npmpkg.yml +16 -11
- package/.github/workflows/pwa-microservices-template.page.yml +12 -3
- package/.github/workflows/pwa-microservices-template.test.yml +20 -17
- package/.vscode/extensions.json +1 -2
- package/.vscode/settings.json +3 -0
- package/Dockerfile +14 -33
- package/README.md +25 -24
- package/bin/db.js +1 -0
- package/bin/deploy.js +88 -796
- package/bin/vs.js +10 -3
- package/cli.md +340 -207
- package/conf.js +4 -0
- package/docker-compose.yml +1 -1
- package/manifests/deployment/dd-template-development/deployment.yaml +167 -0
- package/manifests/deployment/dd-template-development/proxy.yaml +46 -0
- package/manifests/lxd/lxd-admin-profile.yaml +1 -0
- package/manifests/lxd/lxd-preseed.yaml +9 -37
- package/manifests/lxd/underpost-setup.sh +98 -81
- package/manifests/maas/device-scan.sh +43 -0
- package/manifests/maas/lxd-preseed.yaml +32 -0
- package/manifests/maas/maas-setup.sh +120 -0
- package/manifests/maas/nat-iptables.sh +26 -0
- package/manifests/mariadb/statefulset.yaml +2 -1
- package/manifests/mariadb/storage-class.yaml +10 -0
- package/manifests/mongodb-4.4/service-deployment.yaml +2 -2
- package/manifests/valkey/service.yaml +3 -9
- package/manifests/valkey/statefulset.yaml +10 -12
- package/package.json +1 -1
- package/src/cli/baremetal.js +1248 -0
- package/src/cli/cloud-init.js +528 -0
- package/src/cli/cluster.js +424 -240
- package/src/cli/deploy.js +27 -3
- package/src/cli/env.js +2 -2
- package/src/cli/image.js +57 -9
- package/src/cli/index.js +252 -231
- package/src/cli/lxd.js +314 -81
- package/src/index.js +33 -15
- package/src/runtime/lampp/Dockerfile +41 -47
- package/src/server/conf.js +58 -0
- package/src/server/logger.js +3 -3
- package/src/server/runtime.js +1 -6
- package/src/server/ssl.js +1 -12
- package/src/server/valkey.js +3 -3
- package/supervisord-openssh-server.conf +0 -5
package/bin/deploy.js
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
setUpProxyMaintenanceServer,
|
|
28
28
|
writeEnv,
|
|
29
29
|
getUnderpostRootPath,
|
|
30
|
+
buildCliDoc,
|
|
30
31
|
} from '../src/server/conf.js';
|
|
31
32
|
import { buildClient } from '../src/server/client-build.js';
|
|
32
33
|
import { range, s4, setPad, timer, uniqueArray } from '../src/client/components/core/CommonJs.js';
|
|
@@ -37,10 +38,10 @@ import { JSONweb } from '../src/server/client-formatted.js';
|
|
|
37
38
|
|
|
38
39
|
import { Xampp } from '../src/runtime/xampp/Xampp.js';
|
|
39
40
|
import { ejs } from '../src/server/json-schema.js';
|
|
40
|
-
import { buildCliDoc } from '../src/cli/index.js';
|
|
41
41
|
import { getLocalIPv4Address, ip } from '../src/server/dns.js';
|
|
42
42
|
import { Downloader } from '../src/server/downloader.js';
|
|
43
43
|
import colors from 'colors';
|
|
44
|
+
import { program } from '../src/cli/index.js';
|
|
44
45
|
|
|
45
46
|
colors.enable();
|
|
46
47
|
|
|
@@ -50,82 +51,6 @@ logger.info('argv', process.argv);
|
|
|
50
51
|
|
|
51
52
|
const [exe, dir, operator] = process.argv;
|
|
52
53
|
|
|
53
|
-
const updateVirtualRoot = async ({ nfsHostPath, IP_ADDRESS, ipaddr }) => {
|
|
54
|
-
const steps = [
|
|
55
|
-
`apt update`,
|
|
56
|
-
`ln -sf /lib/systemd/systemd /sbin/init`,
|
|
57
|
-
// `sudo apt install linux-modules-extra-6.8.0-31-generic`,
|
|
58
|
-
`apt install -y sudo`,
|
|
59
|
-
`apt install -y ntp`,
|
|
60
|
-
`apt install -y openssh-server`,
|
|
61
|
-
`apt install -y iptables`,
|
|
62
|
-
`update-alternatives --set iptables /usr/sbin/iptables-legacy`,
|
|
63
|
-
`update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy`,
|
|
64
|
-
`apt install -y locales`,
|
|
65
|
-
`apt install -y cloud-init`,
|
|
66
|
-
`mkdir -p /var/lib/cloud`,
|
|
67
|
-
`chown -R root:root /var/lib/cloud`,
|
|
68
|
-
`chmod -R 0755 /var/lib/cloud`,
|
|
69
|
-
`mkdir -p /home/root/.ssh`,
|
|
70
|
-
`echo '${fs.readFileSync(
|
|
71
|
-
`/home/dd/engine/engine-private/deploy/id_rsa.pub`,
|
|
72
|
-
'utf8',
|
|
73
|
-
)}' >> /home/root/.ssh/authorized_keys`,
|
|
74
|
-
`chmod 700 /home/root/.ssh`,
|
|
75
|
-
`chmod 600 /home/root/.ssh/authorized_keys`,
|
|
76
|
-
`systemctl enable ssh`,
|
|
77
|
-
`systemctl enable ntp`,
|
|
78
|
-
`apt install -y linux-generic-hwe-24.04`,
|
|
79
|
-
`modprobe ip_tables`,
|
|
80
|
-
`cat <<EOF_MAAS_CFG > /etc/cloud/cloud.cfg.d/90_maas.cfg
|
|
81
|
-
datasource_list: [ MAAS ]
|
|
82
|
-
datasource:
|
|
83
|
-
MAAS:
|
|
84
|
-
metadata_url: http://${IP_ADDRESS}:5248/MAAS/metadata
|
|
85
|
-
users:
|
|
86
|
-
- name: ${process.env.MAAS_ADMIN_USERNAME}
|
|
87
|
-
ssh_authorized_keys:
|
|
88
|
-
- ${fs.readFileSync(`/home/dd/engine/engine-private/deploy/id_rsa.pub`, 'utf8')}
|
|
89
|
-
sudo: "ALL=(ALL) NOPASSWD:ALL"
|
|
90
|
-
groups: sudo
|
|
91
|
-
shell: /bin/bash
|
|
92
|
-
packages:
|
|
93
|
-
- git
|
|
94
|
-
- htop
|
|
95
|
-
- ufw
|
|
96
|
-
# package_update: true
|
|
97
|
-
runcmd:
|
|
98
|
-
- ufw enable
|
|
99
|
-
- ufw allow ssh
|
|
100
|
-
resize_rootfs: false
|
|
101
|
-
growpart:
|
|
102
|
-
mode: off
|
|
103
|
-
network:
|
|
104
|
-
version: 2
|
|
105
|
-
ethernets:
|
|
106
|
-
${process.env.RPI4_INTERFACE_NAME}:
|
|
107
|
-
dhcp4: true
|
|
108
|
-
addresses:
|
|
109
|
-
- ${ipaddr}/24
|
|
110
|
-
EOF_MAAS_CFG`,
|
|
111
|
-
];
|
|
112
|
-
|
|
113
|
-
shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
|
|
114
|
-
${steps
|
|
115
|
-
.map(
|
|
116
|
-
(s, i) => `echo "step ${i + 1}/${steps.length}: ${s.split('\n')[0]}"
|
|
117
|
-
${s}
|
|
118
|
-
`,
|
|
119
|
-
)
|
|
120
|
-
.join(``)}
|
|
121
|
-
EOF`);
|
|
122
|
-
|
|
123
|
-
shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
|
|
124
|
-
echo "nameserver ${process.env.MAAS_DNS}" | tee /etc/resolv.conf > /dev/null
|
|
125
|
-
apt update
|
|
126
|
-
EOF`);
|
|
127
|
-
};
|
|
128
|
-
|
|
129
54
|
try {
|
|
130
55
|
switch (operator) {
|
|
131
56
|
case 'save':
|
|
@@ -797,6 +722,13 @@ try {
|
|
|
797
722
|
.replaceAll(`engine.version: '${version}'`, `engine.version: '${newVersion}'`),
|
|
798
723
|
'utf8',
|
|
799
724
|
);
|
|
725
|
+
fs.writeFileSync(
|
|
726
|
+
`./manifests/deployment/dd-template-development/deployment.yaml`,
|
|
727
|
+
fs
|
|
728
|
+
.readFileSync(`./manifests/deployment/dd-template-development/deployment.yaml`, 'utf8')
|
|
729
|
+
.replaceAll(`underpost:v${version}`, `underpost:v${newVersion}`),
|
|
730
|
+
'utf8',
|
|
731
|
+
);
|
|
800
732
|
|
|
801
733
|
if (fs.existsSync(`./.github/workflows/docker-image.yml`))
|
|
802
734
|
fs.writeFileSync(
|
|
@@ -921,6 +853,16 @@ ${shellExec(`git log | grep Author: | sort -u`, { stdout: true }).split(`\n`).jo
|
|
|
921
853
|
};
|
|
922
854
|
DefaultConf.server[host][path].apiBaseProxyPath = '/';
|
|
923
855
|
DefaultConf.server[host][path].apiBaseHost = 'www.nexodev.org';
|
|
856
|
+
} else if (confName === 'template') {
|
|
857
|
+
const host = 'default.net';
|
|
858
|
+
const path = '/';
|
|
859
|
+
DefaultConf.server[host][path].valkey = {
|
|
860
|
+
port: 6379,
|
|
861
|
+
host: 'valkey-service.default.svc.cluster.local',
|
|
862
|
+
};
|
|
863
|
+
// mongodb-0.mongodb-service
|
|
864
|
+
DefaultConf.server[host][path].db.host = 'mongodb://mongodb-service:27017';
|
|
865
|
+
confName = '';
|
|
924
866
|
} else if (confName) {
|
|
925
867
|
DefaultConf.client = JSON.parse(fs.readFileSync(`./engine-private/conf/${confName}/conf.client.json`, 'utf8'));
|
|
926
868
|
DefaultConf.server = JSON.parse(fs.readFileSync(`./engine-private/conf/${confName}/conf.server.json`, 'utf8'));
|
|
@@ -1141,7 +1083,7 @@ EOF`);
|
|
|
1141
1083
|
}
|
|
1142
1084
|
|
|
1143
1085
|
case 'cli-docs': {
|
|
1144
|
-
buildCliDoc();
|
|
1086
|
+
buildCliDoc(program);
|
|
1145
1087
|
break;
|
|
1146
1088
|
}
|
|
1147
1089
|
|
|
@@ -1193,12 +1135,63 @@ EOF`);
|
|
|
1193
1135
|
break;
|
|
1194
1136
|
}
|
|
1195
1137
|
|
|
1138
|
+
case 'postgresql-17': {
|
|
1139
|
+
if (process.argv.includes('install')) {
|
|
1140
|
+
shellExec(`sudo dnf module reset postgresql -y`);
|
|
1141
|
+
shellExec(`sudo dnf -qy module disable postgresql`);
|
|
1142
|
+
shellExec(
|
|
1143
|
+
`sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm`,
|
|
1144
|
+
);
|
|
1145
|
+
shellExec(`sudo dnf -qy module disable postgresql`);
|
|
1146
|
+
shellExec(`sudo dnf install -y postgresql17 postgresql17-server postgresql17-contrib`);
|
|
1147
|
+
|
|
1148
|
+
shellExec(`sudo /usr/pgsql-17/bin/postgresql-17-setup initdb`);
|
|
1149
|
+
}
|
|
1150
|
+
if (process.argv.includes('uninstall')) {
|
|
1151
|
+
shellExec(`sudo systemctl stop postgresql-17`);
|
|
1152
|
+
shellExec(`sudo systemctl disable postgresql-17`);
|
|
1153
|
+
|
|
1154
|
+
// Remove PostgreSQL 17 packages and repo
|
|
1155
|
+
shellExec(`sudo dnf remove -y postgresql17 postgresql17-server postgresql17-contrib`);
|
|
1156
|
+
shellExec(`sudo rpm -e pgdg-redhat-repo-$(rpm -q pgdg-redhat-repo --qf '%{VERSION}-%{RELEASE}') || true`);
|
|
1157
|
+
shellExec(`sudo rm -f /etc/yum.repos.d/pgdg-redhat-*.repo`);
|
|
1158
|
+
|
|
1159
|
+
// Clean up data, logs, config, and the postgres user
|
|
1160
|
+
shellExec(`sudo rm -rf /var/lib/pgsql/17 /var/log/pgsql`);
|
|
1161
|
+
shellExec(`sudo rm -rf /etc/postgresql`);
|
|
1162
|
+
} else {
|
|
1163
|
+
shellExec(`sudo systemctl enable postgresql-17`);
|
|
1164
|
+
shellExec(`sudo systemctl start postgresql-17`);
|
|
1165
|
+
}
|
|
1166
|
+
break;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1196
1169
|
case 'postgresql-14': {
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1170
|
+
if (process.argv.includes('install')) {
|
|
1171
|
+
shellExec(`sudo dnf module reset postgresql -y`);
|
|
1172
|
+
shellExec(`sudo dnf -qy module disable postgresql`);
|
|
1173
|
+
|
|
1174
|
+
shellExec(`sudo systemctl stop postgresql-14`);
|
|
1175
|
+
shellExec(`sudo systemctl disable postgresql-14`);
|
|
1176
|
+
|
|
1177
|
+
shellExec(`sudo dnf remove -y postgresql14 postgresql14-server postgresql14-contrib`);
|
|
1178
|
+
shellExec(`sudo rm -rf /var/lib/pgsql`);
|
|
1179
|
+
|
|
1180
|
+
shellExec(`sudo dnf install postgresql14 postgresql14-server postgresql14-contrib -y`);
|
|
1181
|
+
}
|
|
1182
|
+
if (process.argv.includes('uninstall')) {
|
|
1183
|
+
shellExec(`sudo systemctl stop postgresql-14`);
|
|
1184
|
+
shellExec(`sudo systemctl disable postgresql-14`);
|
|
1185
|
+
shellExec(`sudo dnf remove -y postgresql14 postgresql14-server postgresql14-contrib`);
|
|
1186
|
+
shellExec(`sudo rm -rf /var/lib/pgsql /var/log/pgsql /etc/postgresql`);
|
|
1187
|
+
} else {
|
|
1188
|
+
shellExec(`sudo /usr/pgsql-14/bin/postgresql-14-setup initdb`);
|
|
1189
|
+
shellExec(`sudo systemctl start postgresql-14`);
|
|
1190
|
+
shellExec(`sudo systemctl enable postgresql-14`);
|
|
1191
|
+
shellExec(`sudo systemctl status postgresql-14`);
|
|
1192
|
+
// sudo dnf install postgresql14-contrib
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1202
1195
|
break;
|
|
1203
1196
|
}
|
|
1204
1197
|
|
|
@@ -1234,592 +1227,6 @@ EOF`);
|
|
|
1234
1227
|
break;
|
|
1235
1228
|
}
|
|
1236
1229
|
|
|
1237
|
-
case 'maas': {
|
|
1238
|
-
dotenv.config({ path: `${getUnderpostRootPath()}/.env`, override: true });
|
|
1239
|
-
const IP_ADDRESS = getLocalIPv4Address();
|
|
1240
|
-
const serverip = IP_ADDRESS;
|
|
1241
|
-
const tftpRoot = process.env.TFTP_ROOT;
|
|
1242
|
-
const ipaddr = process.env.RPI4_IP;
|
|
1243
|
-
const netmask = process.env.NETMASK;
|
|
1244
|
-
const gatewayip = process.env.GATEWAY_IP;
|
|
1245
|
-
|
|
1246
|
-
let resources;
|
|
1247
|
-
try {
|
|
1248
|
-
resources = JSON.parse(
|
|
1249
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-resources read`, {
|
|
1250
|
-
silent: true,
|
|
1251
|
-
stdout: true,
|
|
1252
|
-
}),
|
|
1253
|
-
).map((o) => ({
|
|
1254
|
-
id: o.id,
|
|
1255
|
-
name: o.name,
|
|
1256
|
-
architecture: o.architecture,
|
|
1257
|
-
}));
|
|
1258
|
-
} catch (error) {
|
|
1259
|
-
logger.error(error);
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
const machineFactory = (m) => ({
|
|
1263
|
-
system_id: m.interface_set[0].system_id,
|
|
1264
|
-
mac_address: m.interface_set[0].mac_address,
|
|
1265
|
-
hostname: m.hostname,
|
|
1266
|
-
status_name: m.status_name,
|
|
1267
|
-
});
|
|
1268
|
-
|
|
1269
|
-
let machines;
|
|
1270
|
-
try {
|
|
1271
|
-
machines = JSON.parse(
|
|
1272
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} machines read`, {
|
|
1273
|
-
stdout: true,
|
|
1274
|
-
silent: true,
|
|
1275
|
-
}),
|
|
1276
|
-
).map((m) => machineFactory(m));
|
|
1277
|
-
} catch (error) {
|
|
1278
|
-
logger.error(error);
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
if (process.argv.includes('db')) {
|
|
1282
|
-
// DROP, ALTER, CREATE, WITH ENCRYPTED
|
|
1283
|
-
// sudo -u <user> -h <host> psql <db-name>
|
|
1284
|
-
shellExec(`DB_PG_MAAS_NAME=${process.env.DB_PG_MAAS_NAME}`);
|
|
1285
|
-
shellExec(`DB_PG_MAAS_PASS=${process.env.DB_PG_MAAS_PASS}`);
|
|
1286
|
-
shellExec(`DB_PG_MAAS_USER=${process.env.DB_PG_MAAS_USER}`);
|
|
1287
|
-
shellExec(`DB_PG_MAAS_HOST=${process.env.DB_PG_MAAS_HOST}`);
|
|
1288
|
-
shellExec(
|
|
1289
|
-
`sudo -i -u postgres psql -c "CREATE USER \"$DB_PG_MAAS_USER\" WITH ENCRYPTED PASSWORD '$DB_PG_MAAS_PASS'"`,
|
|
1290
|
-
);
|
|
1291
|
-
shellExec(
|
|
1292
|
-
`sudo -i -u postgres psql -c "ALTER USER \"$DB_PG_MAAS_USER\" WITH ENCRYPTED PASSWORD '$DB_PG_MAAS_PASS'"`,
|
|
1293
|
-
);
|
|
1294
|
-
const actions = ['LOGIN', 'SUPERUSER', 'INHERIT', 'CREATEDB', 'CREATEROLE', 'REPLICATION'];
|
|
1295
|
-
shellExec(`sudo -i -u postgres psql -c "ALTER USER \"$DB_PG_MAAS_USER\" WITH ${actions.join(' ')}"`);
|
|
1296
|
-
shellExec(`sudo -i -u postgres psql -c "\\du"`);
|
|
1297
|
-
|
|
1298
|
-
shellExec(`sudo -i -u postgres createdb -O "$DB_PG_MAAS_USER" "$DB_PG_MAAS_NAME"`);
|
|
1299
|
-
|
|
1300
|
-
shellExec(`sudo -i -u postgres psql -c "\\l"`);
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
if (process.argv.includes('ls')) {
|
|
1304
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-sources read`);
|
|
1305
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} commissioning-scripts read`);
|
|
1306
|
-
// shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-source-selections read 60`);
|
|
1307
|
-
console.table(resources);
|
|
1308
|
-
console.table(machines);
|
|
1309
|
-
process.exit(0);
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
// TODO: - Disable maas proxy (egress forwarding to public dns)
|
|
1313
|
-
// - Configure maas dns forwarding ${process.env.MAAS_DNS}
|
|
1314
|
-
// - Enable DNSSEC validation of upstream zones: Automatic (use default root key)
|
|
1315
|
-
|
|
1316
|
-
if (process.argv.includes('clear')) {
|
|
1317
|
-
for (const machine of machines) {
|
|
1318
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} machine delete ${machine.system_id}`);
|
|
1319
|
-
}
|
|
1320
|
-
// machines = [];
|
|
1321
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} discoveries clear all=true`);
|
|
1322
|
-
if (process.argv.includes('force')) {
|
|
1323
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} discoveries scan force=true`);
|
|
1324
|
-
}
|
|
1325
|
-
process.exit(0);
|
|
1326
|
-
}
|
|
1327
|
-
if (process.argv.includes('grub-arm64')) {
|
|
1328
|
-
shellExec(`sudo dnf install grub2-efi-aa64-modules`);
|
|
1329
|
-
shellExec(`sudo dnf install grub2-efi-x64-modules`);
|
|
1330
|
-
// sudo grub2-mknetdir --net-directory=${tftpRoot} --subdir=/boot/grub --module-path=/usr/lib/grub/arm64-efi arm64-efi
|
|
1331
|
-
process.exit(0);
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
|
-
if (process.argv.includes('psql')) {
|
|
1335
|
-
const cmd = `psql -U ${process.env.DB_PG_MAAS_USER} -h ${process.env.DB_PG_MAAS_HOST} -W ${process.env.DB_PG_MAAS_NAME}`;
|
|
1336
|
-
pbcopy(cmd);
|
|
1337
|
-
process.exit(0);
|
|
1338
|
-
}
|
|
1339
|
-
if (process.argv.includes('logs')) {
|
|
1340
|
-
shellExec(`maas status`);
|
|
1341
|
-
const cmd = `journalctl -f -t dhcpd -u snap.maas.pebble.service`;
|
|
1342
|
-
pbcopy(cmd);
|
|
1343
|
-
process.exit(0);
|
|
1344
|
-
}
|
|
1345
|
-
if (process.argv.includes('reset')) {
|
|
1346
|
-
// shellExec(
|
|
1347
|
-
// `maas init region+rack --database-uri "postgres://$DB_PG_MAAS_USER:$DB_PG_MAAS_PASS@$DB_PG_MAAS_HOST/$DB_PG_MAAS_NAME"` +
|
|
1348
|
-
// ` --maas-url http://${IP_ADDRESS}:5240/MAAS`,
|
|
1349
|
-
// );
|
|
1350
|
-
const cmd =
|
|
1351
|
-
`maas init region+rack --database-uri "postgres://${process.env.DB_PG_MAAS_USER}:${process.env.DB_PG_MAAS_PASS}@${process.env.DB_PG_MAAS_HOST}/${process.env.DB_PG_MAAS_NAME}"` +
|
|
1352
|
-
` --maas-url http://${IP_ADDRESS}:5240/MAAS`;
|
|
1353
|
-
pbcopy(cmd);
|
|
1354
|
-
process.exit(0);
|
|
1355
|
-
}
|
|
1356
|
-
if (process.argv.includes('dhcp')) {
|
|
1357
|
-
const snippets = JSON.parse(
|
|
1358
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} dhcpsnippets read`, {
|
|
1359
|
-
stdout: true,
|
|
1360
|
-
silent: true,
|
|
1361
|
-
disableLog: true,
|
|
1362
|
-
}),
|
|
1363
|
-
);
|
|
1364
|
-
for (const snippet of snippets) {
|
|
1365
|
-
switch (snippet.name) {
|
|
1366
|
-
case 'arm64':
|
|
1367
|
-
snippet.value = snippet.value.split(`\n`);
|
|
1368
|
-
snippet.value[1] = ` filename "http://${IP_ADDRESS}:5248/images/bootloaders/uefi/arm64/grubaa64.efi";`;
|
|
1369
|
-
snippet.value[5] = ` filename "http://${IP_ADDRESS}:5248/images/bootloaders/uefi/arm64/grubaa64.efi";`;
|
|
1370
|
-
snippet.value = snippet.value.join(`\n`);
|
|
1371
|
-
shellExec(
|
|
1372
|
-
`maas ${process.env.MAAS_ADMIN_USERNAME} dhcpsnippet update ${snippet.name} value='${snippet.value}'`,
|
|
1373
|
-
);
|
|
1374
|
-
break;
|
|
1375
|
-
|
|
1376
|
-
default:
|
|
1377
|
-
break;
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
console.log(snippets);
|
|
1382
|
-
|
|
1383
|
-
process.exit(0);
|
|
1384
|
-
}
|
|
1385
|
-
// shellExec(`MAAS_ADMIN_USERNAME=${process.env.MAAS_ADMIN_USERNAME}`);
|
|
1386
|
-
// shellExec(`MAAS_ADMIN_EMAIL=${process.env.MAAS_ADMIN_EMAIL}`);
|
|
1387
|
-
// shellExec(`maas createadmin --username $MAAS_ADMIN_USERNAME --email $MAAS_ADMIN_EMAIL`);
|
|
1388
|
-
|
|
1389
|
-
// MaaS admin CLI:
|
|
1390
|
-
// maas login <maas-admin-username> http://localhost:5240/MAAS
|
|
1391
|
-
// paste GUI API KEY (profile section)
|
|
1392
|
-
|
|
1393
|
-
// Import custom image
|
|
1394
|
-
// maas <maas-admin-username> boot-resources create name='custom/RockyLinuxRpi4' \
|
|
1395
|
-
// title='RockyLinuxRpi4' \
|
|
1396
|
-
// architecture='arm64/generic' \
|
|
1397
|
-
// filetype='tgz' \
|
|
1398
|
-
// content@=/home/RockyLinuxRpi_9-latest.tar.gz
|
|
1399
|
-
|
|
1400
|
-
// Image boot resource:
|
|
1401
|
-
// /var/snap/maas/current/root/snap/maas
|
|
1402
|
-
// /var/snap/maas/common/maas/tftp_root
|
|
1403
|
-
// sudo chmod 755 /var/snap/maas/common/maas/tftp_root
|
|
1404
|
-
|
|
1405
|
-
// /var/snap/maas/common/maas/dhcpd.conf
|
|
1406
|
-
// sudo snap restart maas.pebble
|
|
1407
|
-
|
|
1408
|
-
// PXE Linux files:
|
|
1409
|
-
// /var/snap/maas/common/maas/image-storage/bootloaders/pxe/i386
|
|
1410
|
-
// sudo nmcli con modify <interface-device-name-connection-id> ethtool.feature-rx on ethtool.feature-tx off
|
|
1411
|
-
// sudo nmcli connection up <interface-device-name-connection-id>
|
|
1412
|
-
|
|
1413
|
-
// man nm-settings |grep feature-tx-checksum
|
|
1414
|
-
|
|
1415
|
-
// nmcli c modify <interface-device-name-connection-id> \
|
|
1416
|
-
// ethtool.feature-tx-checksum-fcoe-crc off \
|
|
1417
|
-
// ethtool.feature-tx-checksum-ip-generic off \
|
|
1418
|
-
// ethtool.feature-tx-checksum-ipv4 off \
|
|
1419
|
-
// ethtool.feature-tx-checksum-ipv6 off \
|
|
1420
|
-
// ethtool.feature-tx-checksum-sctp off
|
|
1421
|
-
|
|
1422
|
-
// Ensure Rocky NFS server and /etc/exports configured
|
|
1423
|
-
// sudo systemctl restart nfs-server
|
|
1424
|
-
// Check mounts: showmount -e <server-ip>
|
|
1425
|
-
// Check nfs ports: rpcinfo -p
|
|
1426
|
-
// sudo chown -R root:root ${process.env.NFS_EXPORT_PATH}/rpi4mb
|
|
1427
|
-
// sudo chmod 755 ${process.env.NFS_EXPORT_PATH}/rpi4mb
|
|
1428
|
-
|
|
1429
|
-
// tftp server
|
|
1430
|
-
// sudo chown -R root:root /var/snap/maas/common/maas/tftp_root/rpi4mb
|
|
1431
|
-
|
|
1432
|
-
// tftp client
|
|
1433
|
-
// sudo dnf install tftp
|
|
1434
|
-
// tftp <server-ip> -c get <path>
|
|
1435
|
-
|
|
1436
|
-
// Check firewall-cmd
|
|
1437
|
-
// firewall-cmd --permanent --add-service=rpc-bind
|
|
1438
|
-
// firewall-cmd --reload
|
|
1439
|
-
// systemctl disable firewalld
|
|
1440
|
-
// sudo firewall-cmd --permanent --add-port=10259/tcp --zone=public
|
|
1441
|
-
|
|
1442
|
-
// Image extension transform (.img.xz to .tar.gz):
|
|
1443
|
-
// tar -cvzf image-name.tar.gz image-name.img.xz
|
|
1444
|
-
|
|
1445
|
-
// Rocky network configuration:
|
|
1446
|
-
// /etc/NetworkManager/system-connections
|
|
1447
|
-
|
|
1448
|
-
// Rocky kernel params update
|
|
1449
|
-
// sudo grubby --args="<key>=<value> <key>=<value>" --update-kernel=ALL
|
|
1450
|
-
// sudo reboot now
|
|
1451
|
-
|
|
1452
|
-
// Temporal:
|
|
1453
|
-
// sudo snap install temporal
|
|
1454
|
-
// journalctl -u snap.maas.pebble -t maas-regiond
|
|
1455
|
-
// journalctl -u snap.maas.pebble -t maas-temporal -n 100 --no-pager -f
|
|
1456
|
-
|
|
1457
|
-
// Remove:
|
|
1458
|
-
// sudo dnf remove <package> -y; sudo dnf autoremove -y; sudo dnf clean packages
|
|
1459
|
-
// check: ~
|
|
1460
|
-
// check: ~./cache
|
|
1461
|
-
// check: ~./config
|
|
1462
|
-
|
|
1463
|
-
// Check file logs
|
|
1464
|
-
// grep -i -E -C 1 '<key-a>|<key-b>' /example.log | tail -n 600
|
|
1465
|
-
|
|
1466
|
-
// Back into your firmware setup (UEFI or BIOS config screen).
|
|
1467
|
-
// grub> fwsetup
|
|
1468
|
-
|
|
1469
|
-
// Poweroff:
|
|
1470
|
-
// grub > halt
|
|
1471
|
-
// initramfs > poweroff
|
|
1472
|
-
|
|
1473
|
-
// Check interface
|
|
1474
|
-
// ip link show
|
|
1475
|
-
// nmcli con show
|
|
1476
|
-
|
|
1477
|
-
let firmwarePath,
|
|
1478
|
-
tftpSubDir,
|
|
1479
|
-
kernelFilesPaths,
|
|
1480
|
-
name,
|
|
1481
|
-
architecture,
|
|
1482
|
-
resource,
|
|
1483
|
-
nfsConnectStr,
|
|
1484
|
-
etcExports,
|
|
1485
|
-
nfsServerRootPath,
|
|
1486
|
-
bootConf,
|
|
1487
|
-
zipFirmwareFileName,
|
|
1488
|
-
zipFirmwareName,
|
|
1489
|
-
zipFirmwareUrl,
|
|
1490
|
-
interfaceName,
|
|
1491
|
-
nfsHost;
|
|
1492
|
-
|
|
1493
|
-
switch (process.argv[3]) {
|
|
1494
|
-
case 'rpi4mb':
|
|
1495
|
-
const resourceId = process.argv[4] ?? '39';
|
|
1496
|
-
tftpSubDir = '/rpi4mb';
|
|
1497
|
-
zipFirmwareFileName = `RPi4_UEFI_Firmware_v1.41.zip`;
|
|
1498
|
-
zipFirmwareName = zipFirmwareFileName.split('.zip')[0];
|
|
1499
|
-
zipFirmwareUrl = `https://github.com/pftf/RPi4/releases/download/v1.41/RPi4_UEFI_Firmware_v1.41.zip`;
|
|
1500
|
-
firmwarePath = `../${zipFirmwareName}`;
|
|
1501
|
-
interfaceName = process.env.RPI4_INTERFACE_NAME;
|
|
1502
|
-
nfsHost = 'rpi4mb';
|
|
1503
|
-
if (!fs.existsSync(firmwarePath)) {
|
|
1504
|
-
await Downloader(zipFirmwareUrl, `../${zipFirmwareFileName}`);
|
|
1505
|
-
shellExec(`cd .. && mkdir ${zipFirmwareName} && cd ${zipFirmwareName} && unzip ../${zipFirmwareFileName}`);
|
|
1506
|
-
}
|
|
1507
|
-
resource = resources.find((o) => o.id == resourceId);
|
|
1508
|
-
name = resource.name;
|
|
1509
|
-
architecture = resource.architecture;
|
|
1510
|
-
resource = resources.find((o) => o.name === name && o.architecture === architecture);
|
|
1511
|
-
nfsServerRootPath = `${process.env.NFS_EXPORT_PATH}/rpi4mb`;
|
|
1512
|
-
// ,anonuid=1001,anongid=100
|
|
1513
|
-
// etcExports = `${nfsServerRootPath} *(rw,all_squash,sync,no_root_squash,insecure)`;
|
|
1514
|
-
etcExports = `${nfsServerRootPath} 192.168.1.0/24(${[
|
|
1515
|
-
'rw',
|
|
1516
|
-
// 'all_squash',
|
|
1517
|
-
'sync',
|
|
1518
|
-
'no_root_squash',
|
|
1519
|
-
'no_subtree_check',
|
|
1520
|
-
'insecure',
|
|
1521
|
-
]})`;
|
|
1522
|
-
const resourceData = JSON.parse(
|
|
1523
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-resource read ${resource.id}`, {
|
|
1524
|
-
stdout: true,
|
|
1525
|
-
silent: true,
|
|
1526
|
-
disableLog: true,
|
|
1527
|
-
}),
|
|
1528
|
-
);
|
|
1529
|
-
const bootFiles = resourceData.sets[Object.keys(resourceData.sets)[0]].files;
|
|
1530
|
-
const suffix = architecture.match('xgene') ? '.xgene' : '';
|
|
1531
|
-
|
|
1532
|
-
kernelFilesPaths = {
|
|
1533
|
-
'vmlinuz-efi': bootFiles['boot-kernel' + suffix].filename_on_disk,
|
|
1534
|
-
'initrd.img': bootFiles['boot-initrd' + suffix].filename_on_disk,
|
|
1535
|
-
squashfs: bootFiles['squashfs'].filename_on_disk,
|
|
1536
|
-
};
|
|
1537
|
-
const protocol = 'tcp'; // v3 -> tcp, v4 -> udp
|
|
1538
|
-
|
|
1539
|
-
const mountOptions = [
|
|
1540
|
-
protocol,
|
|
1541
|
-
'vers=3',
|
|
1542
|
-
'nfsvers=3',
|
|
1543
|
-
'nolock',
|
|
1544
|
-
// 'protocol=tcp',
|
|
1545
|
-
// 'hard=true',
|
|
1546
|
-
'port=2049',
|
|
1547
|
-
// 'sec=none',
|
|
1548
|
-
'rw',
|
|
1549
|
-
'hard',
|
|
1550
|
-
'intr',
|
|
1551
|
-
'rsize=32768',
|
|
1552
|
-
'wsize=32768',
|
|
1553
|
-
'acregmin=0',
|
|
1554
|
-
'acregmax=0',
|
|
1555
|
-
'acdirmin=0',
|
|
1556
|
-
'acdirmax=0',
|
|
1557
|
-
'noac',
|
|
1558
|
-
// 'nodev',
|
|
1559
|
-
// 'nosuid',
|
|
1560
|
-
];
|
|
1561
|
-
const cmd = [
|
|
1562
|
-
`console=serial0,115200`,
|
|
1563
|
-
`console=tty1`,
|
|
1564
|
-
// `initrd=-1`,
|
|
1565
|
-
// `net.ifnames=0`,
|
|
1566
|
-
// `dwc_otg.lpm_enable=0`,
|
|
1567
|
-
// `elevator=deadline`,
|
|
1568
|
-
`root=/dev/nfs`,
|
|
1569
|
-
`nfsroot=${serverip}:${process.env.NFS_EXPORT_PATH}/rpi4mb,${mountOptions}`,
|
|
1570
|
-
// `nfsroot=${serverip}:${process.env.NFS_EXPORT_PATH}/rpi4mb`,
|
|
1571
|
-
`ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${nfsHost}:${interfaceName}:static`,
|
|
1572
|
-
`rootfstype=nfs`,
|
|
1573
|
-
`rw`,
|
|
1574
|
-
`rootwait`,
|
|
1575
|
-
`fixrtc`,
|
|
1576
|
-
'initrd=initrd.img',
|
|
1577
|
-
// 'boot=casper',
|
|
1578
|
-
// 'ro',
|
|
1579
|
-
'netboot=nfs',
|
|
1580
|
-
`cloud-config-url=/dev/null`,
|
|
1581
|
-
// 'ip=dhcp',
|
|
1582
|
-
// 'ip=dfcp',
|
|
1583
|
-
// 'autoinstall',
|
|
1584
|
-
// 'rd.break',
|
|
1585
|
-
];
|
|
1586
|
-
|
|
1587
|
-
nfsConnectStr = cmd.join(' ');
|
|
1588
|
-
bootConf = `[all]
|
|
1589
|
-
MAC_ADDRESS=00:00:00:00:00:00
|
|
1590
|
-
MAC_ADDRESS_OTP=0,1
|
|
1591
|
-
BOOT_UART=0
|
|
1592
|
-
WAKE_ON_GPIO=1
|
|
1593
|
-
POWER_OFF_ON_HALT=0
|
|
1594
|
-
ENABLE_SELF_UPDATE=1
|
|
1595
|
-
DISABLE_HDMI=0
|
|
1596
|
-
TFTP_IP=${serverip}
|
|
1597
|
-
TFTP_PREFIX=1
|
|
1598
|
-
TFTP_PREFIX_STR=${tftpSubDir.slice(1)}/
|
|
1599
|
-
NET_INSTALL_ENABLED=1
|
|
1600
|
-
DHCP_TIMEOUT=45000
|
|
1601
|
-
DHCP_REQ_TIMEOUT=4000
|
|
1602
|
-
TFTP_FILE_TIMEOUT=30000
|
|
1603
|
-
BOOT_ORDER=0x21`;
|
|
1604
|
-
|
|
1605
|
-
break;
|
|
1606
|
-
|
|
1607
|
-
default:
|
|
1608
|
-
break;
|
|
1609
|
-
}
|
|
1610
|
-
shellExec(`sudo chmod 755 ${process.env.NFS_EXPORT_PATH}/${nfsHost}`);
|
|
1611
|
-
|
|
1612
|
-
shellExec(`sudo rm -rf ${tftpRoot}${tftpSubDir}`);
|
|
1613
|
-
shellExec(`sudo cp -a ${firmwarePath} ${tftpRoot}${tftpSubDir}`);
|
|
1614
|
-
shellExec(`mkdir -p ${tftpRoot}${tftpSubDir}/pxe`);
|
|
1615
|
-
|
|
1616
|
-
fs.writeFileSync(`/etc/exports`, etcExports, 'utf8');
|
|
1617
|
-
if (bootConf) fs.writeFileSync(`${tftpRoot}${tftpSubDir}/boot.conf`, bootConf, 'utf8');
|
|
1618
|
-
|
|
1619
|
-
shellExec(`node bin/deploy nfs`);
|
|
1620
|
-
|
|
1621
|
-
if (process.argv.includes('restart')) {
|
|
1622
|
-
shellExec(`sudo snap restart maas.pebble`);
|
|
1623
|
-
let secs = 0;
|
|
1624
|
-
while (
|
|
1625
|
-
!(
|
|
1626
|
-
shellExec(`maas status`, { silent: true, disableLog: true, stdout: true })
|
|
1627
|
-
.split(' ')
|
|
1628
|
-
.filter((l) => l.match('inactive')).length === 1
|
|
1629
|
-
)
|
|
1630
|
-
) {
|
|
1631
|
-
await timer(1000);
|
|
1632
|
-
console.log(`Waiting... (${++secs}s)`);
|
|
1633
|
-
}
|
|
1634
|
-
}
|
|
1635
|
-
|
|
1636
|
-
switch (process.argv[3]) {
|
|
1637
|
-
case 'rpi4mb':
|
|
1638
|
-
{
|
|
1639
|
-
// subnet DHCP snippets
|
|
1640
|
-
// # UEFI ARM64
|
|
1641
|
-
// if option arch = 00:0B {
|
|
1642
|
-
// filename "rpi4mb/pxe/grubaa64.efi";
|
|
1643
|
-
// }
|
|
1644
|
-
// elsif option arch = 00:13 {
|
|
1645
|
-
// filename "http://<IP_ADDRESS>:5248/images/bootloaders/uefi/arm64/grubaa64.efi";
|
|
1646
|
-
// option vendor-class-identifier "HTTPClient";
|
|
1647
|
-
// }
|
|
1648
|
-
for (const file of ['bootaa64.efi', 'grubaa64.efi']) {
|
|
1649
|
-
shellExec(
|
|
1650
|
-
`sudo cp -a /var/snap/maas/common/maas/image-storage/bootloaders/uefi/arm64/${file} ${tftpRoot}${tftpSubDir}/pxe/${file}`,
|
|
1651
|
-
);
|
|
1652
|
-
}
|
|
1653
|
-
// const file = 'bcm2711-rpi-4-b.dtb';
|
|
1654
|
-
// shellExec(
|
|
1655
|
-
// `sudo cp -a ${firmwarePath}/${file} /var/snap/maas/common/maas/image-storage/bootloaders/uefi/arm64/${file}`,
|
|
1656
|
-
// );
|
|
1657
|
-
|
|
1658
|
-
// const ipxeSrc = fs
|
|
1659
|
-
// .readFileSync(`${tftpRoot}/ipxe.cfg`, 'utf8')
|
|
1660
|
-
// .replaceAll('amd64', 'arm64')
|
|
1661
|
-
// .replaceAll('${next-server}', IP_ADDRESS);
|
|
1662
|
-
// fs.writeFileSync(`${tftpRoot}/ipxe.cfg`, ipxeSrc, 'utf8');
|
|
1663
|
-
|
|
1664
|
-
{
|
|
1665
|
-
for (const file of Object.keys(kernelFilesPaths)) {
|
|
1666
|
-
shellExec(
|
|
1667
|
-
`sudo cp -a /var/snap/maas/common/maas/image-storage/${kernelFilesPaths[file]} ${tftpRoot}${tftpSubDir}/pxe/${file}`,
|
|
1668
|
-
);
|
|
1669
|
-
}
|
|
1670
|
-
// const configTxtSrc = fs.readFileSync(`${firmwarePath}/config.txt`, 'utf8');
|
|
1671
|
-
// fs.writeFileSync(
|
|
1672
|
-
// `${tftpRoot}${tftpSubDir}/config.txt`,
|
|
1673
|
-
// configTxtSrc
|
|
1674
|
-
// .replace(`kernel=kernel8.img`, `kernel=vmlinuz`)
|
|
1675
|
-
// .replace(`# max_framebuffers=2`, `max_framebuffers=2`)
|
|
1676
|
-
// .replace(`initramfs initramfs8 followkernel`, `initramfs initrd.img followkernel`),
|
|
1677
|
-
// 'utf8',
|
|
1678
|
-
// );
|
|
1679
|
-
|
|
1680
|
-
// grub:
|
|
1681
|
-
// set root=(pxe)
|
|
1682
|
-
|
|
1683
|
-
// UNDERPOST.NET UEFI/GRUB/MAAS RPi4 commissioning (ARM64)
|
|
1684
|
-
const menuentryStr = 'underpost.net rpi4mb maas commissioning (ARM64)';
|
|
1685
|
-
const grubCfgPath = `${tftpRoot}/grub/grub.cfg`;
|
|
1686
|
-
fs.writeFileSync(
|
|
1687
|
-
grubCfgPath,
|
|
1688
|
-
`
|
|
1689
|
-
insmod gzio
|
|
1690
|
-
insmod http
|
|
1691
|
-
insmod nfs
|
|
1692
|
-
set timeout=5
|
|
1693
|
-
set default=0
|
|
1694
|
-
|
|
1695
|
-
menuentry '${menuentryStr}' {
|
|
1696
|
-
set root=(tftp,${serverip})
|
|
1697
|
-
linux ${tftpSubDir}/pxe/vmlinuz-efi ${nfsConnectStr}
|
|
1698
|
-
initrd ${tftpSubDir}/pxe/initrd.img
|
|
1699
|
-
boot
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
|
-
`,
|
|
1703
|
-
'utf8',
|
|
1704
|
-
);
|
|
1705
|
-
}
|
|
1706
|
-
const arm64EfiPath = `${tftpRoot}/grub/arm64-efi`;
|
|
1707
|
-
if (fs.existsSync(arm64EfiPath)) shellExec(`sudo rm -rf ${arm64EfiPath}`);
|
|
1708
|
-
shellExec(`sudo cp -a /usr/lib/grub/arm64-efi ${arm64EfiPath}`);
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
break;
|
|
1712
|
-
|
|
1713
|
-
default:
|
|
1714
|
-
break;
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1717
|
-
logger.info('succes maas deploy', {
|
|
1718
|
-
resource,
|
|
1719
|
-
kernelFilesPaths,
|
|
1720
|
-
tftpRoot,
|
|
1721
|
-
tftpSubDir,
|
|
1722
|
-
firmwarePath,
|
|
1723
|
-
etcExports,
|
|
1724
|
-
nfsServerRootPath,
|
|
1725
|
-
nfsConnectStr,
|
|
1726
|
-
});
|
|
1727
|
-
if (process.argv.includes('restart')) {
|
|
1728
|
-
if (fs.existsSync(`node engine-private/r.js`)) shellExec(`node engine-private/r`);
|
|
1729
|
-
shellExec(`node bin/deploy maas dhcp`);
|
|
1730
|
-
shellExec(`sudo chown -R root:root ${tftpRoot}`);
|
|
1731
|
-
shellExec(`sudo sudo chmod 755 ${tftpRoot}`);
|
|
1732
|
-
}
|
|
1733
|
-
// for (const machine of machines) {
|
|
1734
|
-
// // shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} machine delete ${machine.system_id}`);
|
|
1735
|
-
// shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} machine commission ${machine.system_id}`, {
|
|
1736
|
-
// silent: true,
|
|
1737
|
-
// });
|
|
1738
|
-
// }
|
|
1739
|
-
// machines = [];
|
|
1740
|
-
|
|
1741
|
-
const monitor = async () => {
|
|
1742
|
-
// discoveries Query observed discoveries.
|
|
1743
|
-
// discovery Read or delete an observed discovery.
|
|
1744
|
-
|
|
1745
|
-
const discoveries = JSON.parse(
|
|
1746
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} discoveries read`, {
|
|
1747
|
-
silent: true,
|
|
1748
|
-
stdout: true,
|
|
1749
|
-
}),
|
|
1750
|
-
).filter(
|
|
1751
|
-
(o) => o.ip !== IP_ADDRESS && o.ip !== gatewayip && !machines.find((_o) => _o.mac_address === o.mac_address),
|
|
1752
|
-
);
|
|
1753
|
-
|
|
1754
|
-
// {
|
|
1755
|
-
// "discovery_id": "",
|
|
1756
|
-
// "ip": "192.168.1.189",
|
|
1757
|
-
// "mac_address": "00:00:00:00:00:00",
|
|
1758
|
-
// "last_seen": "2025-05-05T14:17:37.354",
|
|
1759
|
-
// "hostname": null,
|
|
1760
|
-
// "fabric_name": "",
|
|
1761
|
-
// "vid": null,
|
|
1762
|
-
// "mac_organization": "",
|
|
1763
|
-
// "observer": {
|
|
1764
|
-
// "system_id": "",
|
|
1765
|
-
// "hostname": "",
|
|
1766
|
-
// "interface_id": 1,
|
|
1767
|
-
// "interface_name": ""
|
|
1768
|
-
// },
|
|
1769
|
-
// "resource_uri": "/MAAS/api/2.0/discovery/MTkyLjE2OC4xLjE4OSwwMDowMDowMDowMDowMDowMA==/"
|
|
1770
|
-
// },
|
|
1771
|
-
|
|
1772
|
-
for (const discovery of discoveries) {
|
|
1773
|
-
const machine = {
|
|
1774
|
-
architecture: architecture.match('amd') ? 'amd64/generic' : 'arm64/generic',
|
|
1775
|
-
mac_address: discovery.mac_address,
|
|
1776
|
-
hostname: discovery.hostname ?? discovery.mac_organization ?? discovery.domain ?? `generic-host-${s4()}`,
|
|
1777
|
-
// discovery.ip.match(ipaddr)
|
|
1778
|
-
// ? nfsHost
|
|
1779
|
-
// : `unknown-${s4()}`,
|
|
1780
|
-
// description: '',
|
|
1781
|
-
// https://maas.io/docs/reference-power-drivers
|
|
1782
|
-
power_type: 'manual', // manual
|
|
1783
|
-
// power_parameters_power_address: discovery.ip,
|
|
1784
|
-
mac_addresses: discovery.mac_address,
|
|
1785
|
-
};
|
|
1786
|
-
machine.hostname = machine.hostname.replaceAll(' ', '').replaceAll('.', '');
|
|
1787
|
-
|
|
1788
|
-
try {
|
|
1789
|
-
let newMachine = shellExec(
|
|
1790
|
-
`maas ${process.env.MAAS_ADMIN_USERNAME} machines create ${Object.keys(machine)
|
|
1791
|
-
.map((k) => `${k}="${machine[k]}"`)
|
|
1792
|
-
.join(' ')}`,
|
|
1793
|
-
{
|
|
1794
|
-
silent: true,
|
|
1795
|
-
stdout: true,
|
|
1796
|
-
},
|
|
1797
|
-
);
|
|
1798
|
-
newMachine = machineFactory(JSON.parse(newMachine));
|
|
1799
|
-
machines.push(newMachine);
|
|
1800
|
-
console.log(newMachine);
|
|
1801
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} machine commission ${newMachine.system_id}`, {
|
|
1802
|
-
silent: true,
|
|
1803
|
-
});
|
|
1804
|
-
} catch (error) {
|
|
1805
|
-
logger.error(error, error.stack);
|
|
1806
|
-
}
|
|
1807
|
-
}
|
|
1808
|
-
// if (discoveries.length > 0) {
|
|
1809
|
-
// shellExec(
|
|
1810
|
-
// `maas ${process.env.MAAS_ADMIN_USERNAME} machines read | jq '.[] | {system_id: .interface_set[0].system_id, hostname, status_name, mac_address: .interface_set[0].mac_address}'`,
|
|
1811
|
-
// );
|
|
1812
|
-
// }
|
|
1813
|
-
await timer(1000);
|
|
1814
|
-
monitor();
|
|
1815
|
-
};
|
|
1816
|
-
// shellExec(`node bin/deploy open-virtual-root ${architecture.match('amd') ? 'amd64' : 'arm64'} ${nfsHost}`);
|
|
1817
|
-
machines = [];
|
|
1818
|
-
shellExec(`node bin/deploy maas clear`);
|
|
1819
|
-
monitor();
|
|
1820
|
-
break;
|
|
1821
|
-
}
|
|
1822
|
-
|
|
1823
1230
|
case 'nfs': {
|
|
1824
1231
|
// Daemon RPC NFSv3. ports:
|
|
1825
1232
|
|
|
@@ -1895,129 +1302,6 @@ udp-port = 32766
|
|
|
1895
1302
|
shellExec(`sudo systemctl restart nfs-server`);
|
|
1896
1303
|
break;
|
|
1897
1304
|
}
|
|
1898
|
-
case 'update-virtual-root': {
|
|
1899
|
-
dotenv.config({ path: `${getUnderpostRootPath()}/.env`, override: true });
|
|
1900
|
-
const IP_ADDRESS = getLocalIPv4Address();
|
|
1901
|
-
const architecture = process.argv[3];
|
|
1902
|
-
const host = process.argv[4];
|
|
1903
|
-
const nfsHostPath = `${process.env.NFS_EXPORT_PATH}/${host}`;
|
|
1904
|
-
const ipaddr = process.env.RPI4_IP;
|
|
1905
|
-
await updateVirtualRoot({
|
|
1906
|
-
IP_ADDRESS,
|
|
1907
|
-
architecture,
|
|
1908
|
-
host,
|
|
1909
|
-
nfsHostPath,
|
|
1910
|
-
ipaddr,
|
|
1911
|
-
});
|
|
1912
|
-
break;
|
|
1913
|
-
}
|
|
1914
|
-
case 'open-virtual-root': {
|
|
1915
|
-
dotenv.config({ path: `${getUnderpostRootPath()}/.env`, override: true });
|
|
1916
|
-
const IP_ADDRESS = getLocalIPv4Address();
|
|
1917
|
-
const architecture = process.argv[3];
|
|
1918
|
-
const host = process.argv[4];
|
|
1919
|
-
const nfsHostPath = `${process.env.NFS_EXPORT_PATH}/${host}`;
|
|
1920
|
-
shellExec(`sudo dnf install -y iptables-legacy`);
|
|
1921
|
-
shellExec(`sudo dnf install -y debootstrap`);
|
|
1922
|
-
shellExec(`sudo dnf install kernel-modules-extra-$(uname -r)`);
|
|
1923
|
-
switch (architecture) {
|
|
1924
|
-
case 'arm64':
|
|
1925
|
-
shellExec(`sudo podman run --rm --privileged multiarch/qemu-user-static --reset -p yes`);
|
|
1926
|
-
|
|
1927
|
-
break;
|
|
1928
|
-
|
|
1929
|
-
default:
|
|
1930
|
-
break;
|
|
1931
|
-
}
|
|
1932
|
-
|
|
1933
|
-
shellExec(`sudo modprobe binfmt_misc`);
|
|
1934
|
-
shellExec(`sudo mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc`);
|
|
1935
|
-
|
|
1936
|
-
if (process.argv.includes('build')) {
|
|
1937
|
-
// shellExec(`depmod -a`);
|
|
1938
|
-
shellExec(`mkdir -p ${nfsHostPath}`);
|
|
1939
|
-
let cmd;
|
|
1940
|
-
switch (host) {
|
|
1941
|
-
case 'rpi4mb':
|
|
1942
|
-
shellExec(`sudo rm -rf ${nfsHostPath}/*`);
|
|
1943
|
-
shellExec(`sudo chown -R root:root ${nfsHostPath}`);
|
|
1944
|
-
cmd = [
|
|
1945
|
-
`sudo debootstrap`,
|
|
1946
|
-
`--arch=arm64`,
|
|
1947
|
-
`--variant=minbase`,
|
|
1948
|
-
`--foreign`, // arm64 on amd64
|
|
1949
|
-
`noble`,
|
|
1950
|
-
nfsHostPath,
|
|
1951
|
-
`http://ports.ubuntu.com/ubuntu-ports/`,
|
|
1952
|
-
];
|
|
1953
|
-
break;
|
|
1954
|
-
|
|
1955
|
-
default:
|
|
1956
|
-
break;
|
|
1957
|
-
}
|
|
1958
|
-
shellExec(cmd.join(' '));
|
|
1959
|
-
|
|
1960
|
-
shellExec(`sudo podman create --name extract multiarch/qemu-user-static`);
|
|
1961
|
-
shellExec(`podman ps -a`);
|
|
1962
|
-
shellExec(`sudo podman cp extract:/usr/bin/qemu-aarch64-static ${nfsHostPath}/usr/bin/`);
|
|
1963
|
-
shellExec(`sudo podman rm extract`);
|
|
1964
|
-
shellExec(`podman ps -a`);
|
|
1965
|
-
|
|
1966
|
-
switch (host) {
|
|
1967
|
-
case 'rpi4mb':
|
|
1968
|
-
shellExec(`file ${nfsHostPath}/bin/bash`); // expected: ELF 64-bit LSB pie executable, ARM aarch64 …
|
|
1969
|
-
break;
|
|
1970
|
-
|
|
1971
|
-
default:
|
|
1972
|
-
break;
|
|
1973
|
-
}
|
|
1974
|
-
|
|
1975
|
-
shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
|
|
1976
|
-
/debootstrap/debootstrap --second-stage
|
|
1977
|
-
EOF`);
|
|
1978
|
-
}
|
|
1979
|
-
if (process.argv.includes('mount')) {
|
|
1980
|
-
shellExec(`sudo mount --bind /proc ${nfsHostPath}/proc`);
|
|
1981
|
-
shellExec(`sudo mount --bind /sys ${nfsHostPath}/sys`);
|
|
1982
|
-
shellExec(`sudo mount --rbind /dev ${nfsHostPath}/dev`);
|
|
1983
|
-
}
|
|
1984
|
-
|
|
1985
|
-
if (process.argv.includes('build')) {
|
|
1986
|
-
switch (host) {
|
|
1987
|
-
case 'rpi4mb':
|
|
1988
|
-
const ipaddr = process.env.RPI4_IP;
|
|
1989
|
-
|
|
1990
|
-
await updateVirtualRoot({
|
|
1991
|
-
IP_ADDRESS,
|
|
1992
|
-
architecture,
|
|
1993
|
-
host,
|
|
1994
|
-
nfsHostPath,
|
|
1995
|
-
ipaddr,
|
|
1996
|
-
});
|
|
1997
|
-
|
|
1998
|
-
break;
|
|
1999
|
-
|
|
2000
|
-
default:
|
|
2001
|
-
break;
|
|
2002
|
-
}
|
|
2003
|
-
}
|
|
2004
|
-
// if (process.argv.includes('mount')) {
|
|
2005
|
-
// shellExec(`sudo mount --bind /lib/modules ${nfsHostPath}/lib/modules`);
|
|
2006
|
-
// }
|
|
2007
|
-
|
|
2008
|
-
break;
|
|
2009
|
-
}
|
|
2010
|
-
|
|
2011
|
-
case 'close-virtual-root': {
|
|
2012
|
-
const architecture = process.argv[3];
|
|
2013
|
-
const host = process.argv[4];
|
|
2014
|
-
const nfsHostPath = `${process.env.NFS_EXPORT_PATH}/${host}`;
|
|
2015
|
-
shellExec(`sudo umount ${nfsHostPath}/proc`);
|
|
2016
|
-
shellExec(`sudo umount ${nfsHostPath}/sys`);
|
|
2017
|
-
shellExec(`sudo umount ${nfsHostPath}/dev`);
|
|
2018
|
-
// shellExec(`sudo umount ${nfsHostPath}/lib/modules`);
|
|
2019
|
-
break;
|
|
2020
|
-
}
|
|
2021
1305
|
|
|
2022
1306
|
case 'mount': {
|
|
2023
1307
|
const mounts = shellExec(`mount`).split(`\n`);
|
|
@@ -2040,10 +1324,10 @@ EOF`);
|
|
|
2040
1324
|
|
|
2041
1325
|
case 'create-ports': {
|
|
2042
1326
|
const cmd = [];
|
|
2043
|
-
const
|
|
1327
|
+
const commissioningDeviceIp = getLocalIPv4Address();
|
|
2044
1328
|
for (const port of ['5240']) {
|
|
2045
1329
|
const name = 'maas';
|
|
2046
|
-
cmd.push(`${name}:${port}-${port}:${
|
|
1330
|
+
cmd.push(`${name}:${port}-${port}:${commissioningDeviceIp}`);
|
|
2047
1331
|
}
|
|
2048
1332
|
pbcopy(`node engine-private/r create-port ${cmd}`);
|
|
2049
1333
|
break;
|
|
@@ -2223,7 +1507,7 @@ EOF`);
|
|
|
2223
1507
|
const args = [
|
|
2224
1508
|
`node bin dockerfile-image-build --path ${path}/backend/`,
|
|
2225
1509
|
`--image-name=${imageName} --image-path=${path}`,
|
|
2226
|
-
`--podman-save --${process.argv.includes('kubeadm') ? 'kubeadm' : 'kind'}-load --
|
|
1510
|
+
`--podman-save --${process.argv.includes('kubeadm') ? 'kubeadm' : 'kind'}-load --reset`,
|
|
2227
1511
|
];
|
|
2228
1512
|
shellExec(args.join(' '));
|
|
2229
1513
|
}
|
|
@@ -2235,7 +1519,7 @@ EOF`);
|
|
|
2235
1519
|
const args = [
|
|
2236
1520
|
`node bin dockerfile-image-build --path ${path}/frontend/`,
|
|
2237
1521
|
`--image-name=${imageName} --image-path=${path}`,
|
|
2238
|
-
`--podman-save --${process.argv.includes('kubeadm') ? 'kubeadm' : 'kind'}-load --
|
|
1522
|
+
`--podman-save --${process.argv.includes('kubeadm') ? 'kubeadm' : 'kind'}-load --reset`,
|
|
2239
1523
|
];
|
|
2240
1524
|
shellExec(args.join(' '));
|
|
2241
1525
|
}
|
|
@@ -2408,6 +1692,14 @@ nvidia/gpu-operator \
|
|
|
2408
1692
|
// sudo yum install sbt
|
|
2409
1693
|
break;
|
|
2410
1694
|
}
|
|
1695
|
+
|
|
1696
|
+
case 'chrony': {
|
|
1697
|
+
shellExec(`sudo dnf install chrony -y`);
|
|
1698
|
+
// debian chroot: sudo apt install chrony
|
|
1699
|
+
for (const cmd of chronySetUp(`/etc/chrony.conf`)) shellExec(cmd);
|
|
1700
|
+
|
|
1701
|
+
break;
|
|
1702
|
+
}
|
|
2411
1703
|
}
|
|
2412
1704
|
} catch (error) {
|
|
2413
1705
|
logger.error(error, error.stack);
|