underpost 2.8.799 → 2.8.812

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/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,53 +51,139 @@ 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 = [
54
+ const updateVirtualRoot = async ({ IP_ADDRESS, architecture, host, nfsHostPath, ipaddr, update, gatewayip }) => {
55
+ // <consumer_key>:<consumer_token>:<secret>
56
+ const MAAS_API_TOKEN = shellExec(`maas apikey --username ${process.env.MAAS_ADMIN_USERNAME}`, {
57
+ stdout: true,
58
+ }).trim();
59
+ const [consumer_key, consumer_token, secret] = MAAS_API_TOKEN.split(`\n`)[0].split(':');
60
+ const chronyConfPath = `/etc/chrony/chrony.conf`;
61
+ const timezone = 'America/New_York';
62
+ const timeZoneSteps = [
63
+ `apt-get update`,
64
+
65
+ `export DEBIAN_FRONTEND=noninteractive`,
66
+
67
+ `ln -fs /usr/share/zoneinfo/${timezone} /etc/localtime`,
68
+
69
+ `DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata`,
70
+ `dpkg-reconfigure --frontend noninteractive tzdata`,
71
+ ];
72
+ const keyboardSteps = [
73
+ `sudo locale-gen en_US.UTF-8`,
74
+ `sudo update-locale LANG=en_US.UTF-8`,
75
+ `sudo sed -i 's/XKBLAYOUT="us"/XKBLAYOUT="es"/' /etc/default/keyboard`,
76
+ `sudo dpkg-reconfigure --frontend noninteractive keyboard-configuration`,
77
+ `sudo systemctl restart keyboard-setup.service`,
78
+ ];
79
+ // # - ${JSON.stringify([...timeZoneSteps, ...chronySetUp(chronyConfPath)])}
80
+ const installSteps = [
55
81
  `apt update`,
82
+ `apt install -y cloud-init systemd-sysv openssh-server sudo locales udev util-linux systemd-sysv iproute2 netplan.io ca-certificates curl wget chrony ntpdate keyboard-configuration`,
56
83
  `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`,
84
+
85
+ `echo 'deb http://ports.ubuntu.com/ubuntu-ports noble main restricted universe multiverse
86
+ deb http://ports.ubuntu.com/ubuntu-ports noble-updates main restricted universe multiverse
87
+ deb http://ports.ubuntu.com/ubuntu-ports noble-security main restricted universe multiverse
88
+
89
+ # Uncomment the following lines if you also need source packages (for building from source)
90
+ # deb-src http://ports.ubuntu.com/ubuntu-ports noble main restricted universe multiverse
91
+ # deb-src http://ports.ubuntu.com/ubuntu-ports noble-updates main restricted universe multiverse
92
+ # deb-src http://ports.ubuntu.com/ubuntu-ports noble-security main restricted universe multiverse
93
+ ' > /etc/apt/sources.list`,
94
+ `apt update`,
95
+ `apt -y full-upgrade`,
96
+ // `apt install -y cloud-init=25.1.2-0ubuntu0~24.04.1`,
97
+
98
+ `systemctl enable ssh`,
99
+
100
+ `apt update -qq`,
101
+ `apt install -y xinput x11-xkb-utils usbutils`,
102
+
103
+ // `date -s "${shellExec(`date '+%Y-%m-%d %H:%M:%S'`, { stdout: true }).trim()}"`,
104
+ // `date`,
105
+
106
+ ...timeZoneSteps,
107
+ ...chronySetUp(chronyConfPath),
108
+ ...keyboardSteps,
109
+
110
+ // Create root user
111
+ `useradd -m -s /bin/bash -G sudo root`,
112
+ `echo 'root:root' | chpasswd`,
69
113
  `mkdir -p /home/root/.ssh`,
70
114
  `echo '${fs.readFileSync(
71
115
  `/home/dd/engine/engine-private/deploy/id_rsa.pub`,
72
116
  'utf8',
73
- )}' >> /home/root/.ssh/authorized_keys`,
117
+ )}' > /home/root/.ssh/authorized_keys`,
118
+ `chown -R root /home/root/.ssh`,
74
119
  `chmod 700 /home/root/.ssh`,
75
120
  `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`,
121
+ ];
122
+
123
+ let steps = [
124
+ // Configure cloud-init for MAAS
80
125
  `cat <<EOF_MAAS_CFG > /etc/cloud/cloud.cfg.d/90_maas.cfg
126
+ #cloud-config
127
+
128
+ hostname: ${host}
129
+ # fqdn: server01.midominio.cl
130
+ # prefer_fqdn_over_hostname: true
131
+ # metadata_url: http://${IP_ADDRESS}:5240/MAAS/metadata
132
+ # metadata_url: http://${IP_ADDRESS}:5248/MAAS/metadata
133
+
134
+ # Check:
135
+ # /MAAS/metadata/latest/enlist-preseed/?op=get_enlist_preseed
136
+
137
+ # Debug:
138
+ # https://maas.io/docs/how-to-use-logging
139
+
81
140
  datasource_list: [ MAAS ]
82
141
  datasource:
83
142
  MAAS:
84
- metadata_url: http://${IP_ADDRESS}:5248/MAAS/metadata
143
+ metadata_url: http://${IP_ADDRESS}:5240/MAAS/metadata
144
+ consumer_key: ${consumer_key}
145
+ token_key: ${consumer_token}
146
+ token_secret: ${secret}
85
147
  users:
86
- - name: ${process.env.MAAS_ADMIN_USERNAME}
148
+ - name: rpiadmin
149
+ sudo: ['ALL=(ALL) NOPASSWD:ALL']
150
+ shell: /bin/bash
151
+ lock_passwd: true
87
152
  ssh_authorized_keys:
88
153
  - ${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
154
+
155
+
156
+ # keyboard:
157
+ # layout: es
158
+
159
+
160
+ # check timedatectl on host
161
+ # timezone: America/Santiago
162
+ timezone: ${timezone}
163
+
164
+ ntp:
165
+ enabled: true
166
+ servers:
167
+ - ${IP_ADDRESS}
168
+ ntp_client: chrony
169
+ config:
170
+ confpath: ${chronyConfPath}
171
+ packages:
172
+ - chrony
173
+ service_name: chrony
174
+
175
+ # ssh:
176
+ # allow-pw: false
177
+ # install-server: true
178
+
179
+ # ssh_pwauth: false
180
+
181
+ package_update: true
182
+ package_upgrade: true
92
183
  packages:
93
184
  - git
94
185
  - htop
95
- - ufw
96
- # package_update: true
97
- runcmd:
98
- - ufw enable
99
- - ufw allow ssh
186
+ - snapd
100
187
  resize_rootfs: false
101
188
  growpart:
102
189
  mode: off
@@ -104,26 +191,141 @@ network:
104
191
  version: 2
105
192
  ethernets:
106
193
  ${process.env.RPI4_INTERFACE_NAME}:
107
- dhcp4: true
194
+ dhcp4: false
108
195
  addresses:
109
196
  - ${ipaddr}/24
197
+ routes:
198
+ - to: default
199
+ via: ${gatewayip}
200
+
201
+ # chpasswd:
202
+ # expire: false
203
+ # users:
204
+ # - {name: rpiadmin, password: changeme, type: text}
205
+
206
+ final_message: "The system is up, after $UPTIME seconds"
207
+
208
+ # power_state:
209
+ # mode: reboot
210
+ # message: Rebooting after initial setup
211
+ # timeout: 30
212
+ # condition: True
213
+ bootcmd:
214
+ - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
215
+ - echo "Init bootcmd"
216
+ - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
217
+ - ntpdate -u ${IP_ADDRESS} || ntpdate -u ${process.env.MAAS_NTP_SERVER}
218
+ runcmd:
219
+ - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
220
+ - echo "Init runcmd"
221
+ - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
110
222
  EOF_MAAS_CFG`,
111
223
  ];
112
224
 
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(``)}
225
+ const runSteps = (steps = []) => {
226
+ const script = steps
227
+ .map(
228
+ (s, i) => `echo "step ${i + 1}/${steps.length}: ${s.split('\n')[0]}"
229
+ ${s}`,
230
+ )
231
+ .join('\n');
232
+
233
+ const cmd = `sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF_OUTER'
234
+ ${script}
235
+ EOF_OUTER`;
236
+
237
+ shellExec(cmd);
238
+ };
239
+
240
+ if (update) {
241
+ // --reboot
242
+ shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
243
+ sudo cloud-init clean --logs --seed --configs all --machine-id
244
+ sudo rm -rf /var/lib/cloud/*
121
245
  EOF`);
122
246
 
123
- shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
247
+ if (fs.existsSync(`${nfsHostPath}/var/log/`)) {
248
+ fs.writeFileSync(`${nfsHostPath}/var/log/cloud-init.log`, '', 'utf8');
249
+ fs.writeFileSync(`${nfsHostPath}/var/log/cloud-init-output.log`, '', 'utf8');
250
+ }
251
+
252
+ runSteps(steps);
253
+ } else {
254
+ runSteps(installSteps.concat(steps));
255
+
256
+ shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
124
257
  echo "nameserver ${process.env.MAAS_DNS}" | tee /etc/resolv.conf > /dev/null
125
258
  apt update
126
259
  EOF`);
260
+ fs.writeFileSync(
261
+ `${nfsHostPath}/dns.sh`,
262
+ `rm /etc/resolv.conf
263
+ echo 'nameserver 8.8.8.8' > /run/systemd/resolve/stub-resolv.conf
264
+ ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf`,
265
+ 'utf8',
266
+ );
267
+ }
268
+ };
269
+
270
+ const chronySetUp = (path) => {
271
+ return [
272
+ `echo '
273
+ # Use public servers from the pool.ntp.org project.
274
+ # Please consider joining the pool (http://www.pool.ntp.org/join.html).
275
+ # pool 2.pool.ntp.org iburst
276
+ server ${process.env.MAAS_NTP_SERVER} iburst
277
+
278
+ # Record the rate at which the system clock gains/losses time.
279
+ driftfile /var/lib/chrony/drift
280
+
281
+ # Allow the system clock to be stepped in the first three updates
282
+ # if its offset is larger than 1 second.
283
+ makestep 1.0 3
284
+
285
+ # Enable kernel synchronization of the real-time clock (RTC).
286
+ rtcsync
287
+
288
+ # Enable hardware timestamping on all interfaces that support it.
289
+ #hwtimestamp *
290
+
291
+ # Increase the minimum number of selectable sources required to adjust
292
+ # the system clock.
293
+ #minsources 2
294
+
295
+ # Allow NTP client access from local network.
296
+ #allow 192.168.0.0/16
297
+
298
+ # Serve time even if not synchronized to a time source.
299
+ #local stratum 10
300
+
301
+ # Specify file containing keys for NTP authentication.
302
+ keyfile /etc/chrony.keys
303
+
304
+ # Get TAI-UTC offset and leap seconds from the system tz database.
305
+ leapsectz right/UTC
306
+
307
+ # Specify directory for log files.
308
+ logdir /var/log/chrony
309
+
310
+ # Select which information is logged.
311
+ #log measurements statistics tracking
312
+ ' > ${path} `,
313
+ `sudo systemctl stop chronyd`,
314
+
315
+ // `chronyd -q 'server 0.europe.pool.ntp.org iburst'`,
316
+ `chronyd -q 'server ntp.ubuntu.com iburst'`,
317
+
318
+ `sudo systemctl enable --now chronyd`,
319
+ `sudo systemctl restart chronyd`,
320
+ `sudo systemctl status chronyd`,
321
+
322
+ `chronyc sources`,
323
+ `chronyc tracking`,
324
+ // sudo firewall-cmd --add-service=ntp --permanent
325
+ // sudo firewall-cmd --reload
326
+
327
+ `chronyc sourcestats -v`,
328
+ ];
127
329
  };
128
330
 
129
331
  try {
@@ -1158,7 +1360,7 @@ EOF`);
1158
1360
  }
1159
1361
 
1160
1362
  case 'cli-docs': {
1161
- buildCliDoc();
1363
+ buildCliDoc(program);
1162
1364
  break;
1163
1365
  }
1164
1366
 
@@ -1210,12 +1412,63 @@ EOF`);
1210
1412
  break;
1211
1413
  }
1212
1414
 
1415
+ case 'postgresql-17': {
1416
+ if (process.argv.includes('install')) {
1417
+ shellExec(`sudo dnf module reset postgresql -y`);
1418
+ shellExec(`sudo dnf -qy module disable postgresql`);
1419
+ shellExec(
1420
+ `sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm`,
1421
+ );
1422
+ shellExec(`sudo dnf -qy module disable postgresql`);
1423
+ shellExec(`sudo dnf install -y postgresql17 postgresql17-server postgresql17-contrib`);
1424
+
1425
+ shellExec(`sudo /usr/pgsql-17/bin/postgresql-17-setup initdb`);
1426
+ }
1427
+ if (process.argv.includes('uninstall')) {
1428
+ shellExec(`sudo systemctl stop postgresql-17`);
1429
+ shellExec(`sudo systemctl disable postgresql-17`);
1430
+
1431
+ // Remove PostgreSQL 17 packages and repo
1432
+ shellExec(`sudo dnf remove -y postgresql17 postgresql17-server postgresql17-contrib`);
1433
+ shellExec(`sudo rpm -e pgdg-redhat-repo-$(rpm -q pgdg-redhat-repo --qf '%{VERSION}-%{RELEASE}') || true`);
1434
+ shellExec(`sudo rm -f /etc/yum.repos.d/pgdg-redhat-*.repo`);
1435
+
1436
+ // Clean up data, logs, config, and the postgres user
1437
+ shellExec(`sudo rm -rf /var/lib/pgsql/17 /var/log/pgsql`);
1438
+ shellExec(`sudo rm -rf /etc/postgresql`);
1439
+ } else {
1440
+ shellExec(`sudo systemctl enable postgresql-17`);
1441
+ shellExec(`sudo systemctl start postgresql-17`);
1442
+ }
1443
+ break;
1444
+ }
1445
+
1213
1446
  case 'postgresql-14': {
1214
- shellExec(`sudo /usr/pgsql-14/bin/postgresql-14-setup initdb`);
1215
- shellExec(`sudo systemctl start postgresql-14`);
1216
- shellExec(`sudo systemctl enable postgresql-14`);
1217
- shellExec(`sudo systemctl status postgresql-14`);
1218
- // sudo dnf install postgresql14-contrib
1447
+ if (process.argv.includes('install')) {
1448
+ shellExec(`sudo dnf module reset postgresql -y`);
1449
+ shellExec(`sudo dnf -qy module disable postgresql`);
1450
+
1451
+ shellExec(`sudo systemctl stop postgresql-14`);
1452
+ shellExec(`sudo systemctl disable postgresql-14`);
1453
+
1454
+ shellExec(`sudo dnf remove -y postgresql14 postgresql14-server postgresql14-contrib`);
1455
+ shellExec(`sudo rm -rf /var/lib/pgsql`);
1456
+
1457
+ shellExec(`sudo dnf install postgresql14 postgresql14-server postgresql14-contrib -y`);
1458
+ }
1459
+ if (process.argv.includes('uninstall')) {
1460
+ shellExec(`sudo systemctl stop postgresql-14`);
1461
+ shellExec(`sudo systemctl disable postgresql-14`);
1462
+ shellExec(`sudo dnf remove -y postgresql14 postgresql14-server postgresql14-contrib`);
1463
+ shellExec(`sudo rm -rf /var/lib/pgsql /var/log/pgsql /etc/postgresql`);
1464
+ } else {
1465
+ shellExec(`sudo /usr/pgsql-14/bin/postgresql-14-setup initdb`);
1466
+ shellExec(`sudo systemctl start postgresql-14`);
1467
+ shellExec(`sudo systemctl enable postgresql-14`);
1468
+ shellExec(`sudo systemctl status postgresql-14`);
1469
+ // sudo dnf install postgresql14-contrib
1470
+ }
1471
+
1219
1472
  break;
1220
1473
  }
1221
1474
 
@@ -1252,6 +1505,9 @@ EOF`);
1252
1505
  }
1253
1506
 
1254
1507
  case 'maas': {
1508
+ shellExec(
1509
+ `underpost secret underpost --create-from-file /home/dd/engine/engine-private/conf/dd-cron/.env.production`,
1510
+ );
1255
1511
  dotenv.config({ path: `${getUnderpostRootPath()}/.env`, override: true });
1256
1512
  const IP_ADDRESS = getLocalIPv4Address();
1257
1513
  const serverip = IP_ADDRESS;
@@ -1260,6 +1516,13 @@ EOF`);
1260
1516
  const netmask = process.env.NETMASK;
1261
1517
  const gatewayip = process.env.GATEWAY_IP;
1262
1518
 
1519
+ const machineFactory = (m) => ({
1520
+ system_id: m.interface_set[0].system_id,
1521
+ mac_address: m.interface_set[0].mac_address,
1522
+ hostname: m.hostname,
1523
+ status_name: m.status_name,
1524
+ });
1525
+
1263
1526
  let resources;
1264
1527
  try {
1265
1528
  resources = JSON.parse(
@@ -1276,13 +1539,6 @@ EOF`);
1276
1539
  logger.error(error);
1277
1540
  }
1278
1541
 
1279
- const machineFactory = (m) => ({
1280
- system_id: m.interface_set[0].system_id,
1281
- mac_address: m.interface_set[0].mac_address,
1282
- hostname: m.hostname,
1283
- status_name: m.status_name,
1284
- });
1285
-
1286
1542
  let machines;
1287
1543
  try {
1288
1544
  machines = JSON.parse(
@@ -1295,6 +1551,25 @@ EOF`);
1295
1551
  logger.error(error);
1296
1552
  }
1297
1553
 
1554
+ if (process.argv.includes('ls')) {
1555
+ shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-sources read`);
1556
+ shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} commissioning-scripts read`);
1557
+ // shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-source-selections read 60`);
1558
+ logger.info('Resources');
1559
+ console.table(resources);
1560
+ logger.info('Machines');
1561
+ console.table(machines);
1562
+ process.exit(0);
1563
+ }
1564
+
1565
+ if (process.argv.includes('config')) {
1566
+ shellExec(`sudo sed -i 's/^#Storage=auto/Storage=volatile/' /etc/systemd/journald.conf`);
1567
+ shellExec(`sudo systemctl daemon-reload`);
1568
+ shellExec(`sudo systemctl restart systemd-journald`);
1569
+ shellExec(`journalctl --disk-usage`);
1570
+ process.exit(0);
1571
+ }
1572
+
1298
1573
  if (process.argv.includes('db')) {
1299
1574
  // DROP, ALTER, CREATE, WITH ENCRYPTED
1300
1575
  // sudo -u <user> -h <host> psql <db-name>
@@ -1315,20 +1590,13 @@ EOF`);
1315
1590
  shellExec(`sudo -i -u postgres createdb -O "$DB_PG_MAAS_USER" "$DB_PG_MAAS_NAME"`);
1316
1591
 
1317
1592
  shellExec(`sudo -i -u postgres psql -c "\\l"`);
1318
- }
1319
-
1320
- if (process.argv.includes('ls')) {
1321
- shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-sources read`);
1322
- shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} commissioning-scripts read`);
1323
- // shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-source-selections read 60`);
1324
- console.table(resources);
1325
- console.table(machines);
1326
1593
  process.exit(0);
1327
1594
  }
1328
1595
 
1329
1596
  // TODO: - Disable maas proxy (egress forwarding to public dns)
1597
+ // - Configure maas dhcp control server
1330
1598
  // - Configure maas dns forwarding ${process.env.MAAS_DNS}
1331
- // - Enable DNSSEC validation of upstream zones: Automatic (use default root key)
1599
+ // - Disable DNSSEC validation to No (Disable DNSSEC; useful when upstream DNS is misconfigured)
1332
1600
 
1333
1601
  if (process.argv.includes('clear')) {
1334
1602
  for (const machine of machines) {
@@ -1370,35 +1638,23 @@ EOF`);
1370
1638
  pbcopy(cmd);
1371
1639
  process.exit(0);
1372
1640
  }
1373
- if (process.argv.includes('dhcp')) {
1374
- const snippets = JSON.parse(
1375
- shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} dhcpsnippets read`, {
1376
- stdout: true,
1377
- silent: true,
1378
- disableLog: true,
1379
- }),
1380
- );
1381
- for (const snippet of snippets) {
1382
- switch (snippet.name) {
1383
- case 'arm64':
1384
- snippet.value = snippet.value.split(`\n`);
1385
- snippet.value[1] = ` filename "http://${IP_ADDRESS}:5248/images/bootloaders/uefi/arm64/grubaa64.efi";`;
1386
- snippet.value[5] = ` filename "http://${IP_ADDRESS}:5248/images/bootloaders/uefi/arm64/grubaa64.efi";`;
1387
- snippet.value = snippet.value.join(`\n`);
1388
- shellExec(
1389
- `maas ${process.env.MAAS_ADMIN_USERNAME} dhcpsnippet update ${snippet.name} value='${snippet.value}'`,
1390
- );
1391
- break;
1392
1641
 
1393
- default:
1394
- break;
1395
- }
1642
+ if (process.argv.includes('restart')) {
1643
+ shellExec(`sudo snap restart maas.pebble`);
1644
+ let secs = 0;
1645
+ while (
1646
+ !(
1647
+ shellExec(`maas status`, { silent: true, disableLog: true, stdout: true })
1648
+ .split(' ')
1649
+ .filter((l) => l.match('inactive')).length === 1
1650
+ )
1651
+ ) {
1652
+ await timer(1000);
1653
+ console.log(`Waiting... (${++secs}s)`);
1396
1654
  }
1397
-
1398
- console.log(snippets);
1399
-
1400
1655
  process.exit(0);
1401
1656
  }
1657
+
1402
1658
  // shellExec(`MAAS_ADMIN_USERNAME=${process.env.MAAS_ADMIN_USERNAME}`);
1403
1659
  // shellExec(`MAAS_ADMIN_EMAIL=${process.env.MAAS_ADMIN_EMAIL}`);
1404
1660
  // shellExec(`maas createadmin --username $MAAS_ADMIN_USERNAME --email $MAAS_ADMIN_EMAIL`);
@@ -1509,7 +1765,6 @@ EOF`);
1509
1765
 
1510
1766
  switch (process.argv[3]) {
1511
1767
  case 'rpi4mb':
1512
- const resourceId = process.argv[4] ?? '39';
1513
1768
  tftpSubDir = '/rpi4mb';
1514
1769
  zipFirmwareFileName = `RPi4_UEFI_Firmware_v1.41.zip`;
1515
1770
  zipFirmwareName = zipFirmwareFileName.split('.zip')[0];
@@ -1521,7 +1776,7 @@ EOF`);
1521
1776
  await Downloader(zipFirmwareUrl, `../${zipFirmwareFileName}`);
1522
1777
  shellExec(`cd .. && mkdir ${zipFirmwareName} && cd ${zipFirmwareName} && unzip ../${zipFirmwareFileName}`);
1523
1778
  }
1524
- resource = resources.find((o) => o.id == resourceId);
1779
+ resource = resources.find((o) => o.architecture === 'arm64/ga-24.04' && o.name === 'ubuntu/noble');
1525
1780
  name = resource.name;
1526
1781
  architecture = resource.architecture;
1527
1782
  resource = resources.find((o) => o.name === name && o.architecture === architecture);
@@ -1594,13 +1849,48 @@ EOF`);
1594
1849
  // 'boot=casper',
1595
1850
  // 'ro',
1596
1851
  'netboot=nfs',
1597
- `cloud-config-url=/dev/null`,
1852
+ `init=/sbin/init`,
1853
+ // `cloud-config-url=/dev/null`,
1598
1854
  // 'ip=dhcp',
1599
1855
  // 'ip=dfcp',
1600
1856
  // 'autoinstall',
1601
1857
  // 'rd.break',
1602
1858
  ];
1603
1859
 
1860
+ // TODO: use autoinstall cloud-config-url=http://<MAAS_IP>:5240/MAAS/metadata/latest
1861
+ // #cloud-config
1862
+ // autoinstall:
1863
+ // version: 1
1864
+
1865
+ // keyboard:
1866
+ // layout: es
1867
+ // variant: latinamerican
1868
+
1869
+ // identity:
1870
+ // hostname: rpi4
1871
+ // username: rpiadmin
1872
+ // password: "{{PASSWORD}}"
1873
+
1874
+ // ssh:
1875
+ // install-server: true
1876
+ // allow-pw: true
1877
+ // authorized-keys:
1878
+ // - "{{SSH_KEY}}"
1879
+
1880
+ // locale: es_ES.UTF-8
1881
+ // timezone: America/Santiago
1882
+
1883
+ // packages:
1884
+ // - cloud-init
1885
+ // - systemd-sysv
1886
+ // - openssh-server
1887
+ // - sudo
1888
+ // - udev
1889
+ // - netplan.io
1890
+
1891
+ // late-commands:
1892
+ // - curtin in-target --target=/target ln -sf /lib/systemd/systemd /sbin/init
1893
+
1604
1894
  nfsConnectStr = cmd.join(' ');
1605
1895
  bootConf = `[all]
1606
1896
  MAC_ADDRESS=00:00:00:00:00:00
@@ -1618,7 +1908,8 @@ DHCP_TIMEOUT=45000
1618
1908
  DHCP_REQ_TIMEOUT=4000
1619
1909
  TFTP_FILE_TIMEOUT=30000
1620
1910
  BOOT_ORDER=0x21`;
1621
-
1911
+ // CLIENT_IP=${ipaddr}
1912
+ // SUBNET=255.255.255.0
1622
1913
  break;
1623
1914
 
1624
1915
  default:
@@ -1635,21 +1926,6 @@ BOOT_ORDER=0x21`;
1635
1926
 
1636
1927
  shellExec(`node bin/deploy nfs`);
1637
1928
 
1638
- if (process.argv.includes('restart')) {
1639
- shellExec(`sudo snap restart maas.pebble`);
1640
- let secs = 0;
1641
- while (
1642
- !(
1643
- shellExec(`maas status`, { silent: true, disableLog: true, stdout: true })
1644
- .split(' ')
1645
- .filter((l) => l.match('inactive')).length === 1
1646
- )
1647
- ) {
1648
- await timer(1000);
1649
- console.log(`Waiting... (${++secs}s)`);
1650
- }
1651
- }
1652
-
1653
1929
  switch (process.argv[3]) {
1654
1930
  case 'rpi4mb':
1655
1931
  {
@@ -1815,9 +2091,13 @@ BOOT_ORDER=0x21`;
1815
2091
  newMachine = machineFactory(JSON.parse(newMachine));
1816
2092
  machines.push(newMachine);
1817
2093
  console.log(newMachine);
1818
- shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} machine commission ${newMachine.system_id}`, {
1819
- silent: true,
1820
- });
2094
+ // commissioning_scripts=90-verify-user.sh
2095
+ shellExec(
2096
+ `maas ${process.env.MAAS_ADMIN_USERNAME} machine commission ${newMachine.system_id} enable_ssh=1 skip_bmc_config=1 skip_networking=1 skip_storage=1`,
2097
+ {
2098
+ silent: true,
2099
+ },
2100
+ );
1821
2101
  } catch (error) {
1822
2102
  logger.error(error, error.stack);
1823
2103
  }
@@ -1919,12 +2199,15 @@ udp-port = 32766
1919
2199
  const host = process.argv[4];
1920
2200
  const nfsHostPath = `${process.env.NFS_EXPORT_PATH}/${host}`;
1921
2201
  const ipaddr = process.env.RPI4_IP;
2202
+ const gatewayip = process.env.GATEWAY_IP;
1922
2203
  await updateVirtualRoot({
1923
2204
  IP_ADDRESS,
1924
2205
  architecture,
1925
2206
  host,
1926
2207
  nfsHostPath,
1927
2208
  ipaddr,
2209
+ update: true,
2210
+ gatewayip,
1928
2211
  });
1929
2212
  break;
1930
2213
  }
@@ -1934,6 +2217,7 @@ udp-port = 32766
1934
2217
  const architecture = process.argv[3];
1935
2218
  const host = process.argv[4];
1936
2219
  const nfsHostPath = `${process.env.NFS_EXPORT_PATH}/${host}`;
2220
+ const gatewayip = process.env.GATEWAY_IP;
1937
2221
  shellExec(`sudo dnf install -y iptables-legacy`);
1938
2222
  shellExec(`sudo dnf install -y debootstrap`);
1939
2223
  shellExec(`sudo dnf install kernel-modules-extra-$(uname -r)`);
@@ -1963,7 +2247,7 @@ udp-port = 32766
1963
2247
  `--arch=arm64`,
1964
2248
  `--variant=minbase`,
1965
2249
  `--foreign`, // arm64 on amd64
1966
- `noble`,
2250
+ [`noble`, `jammy`][0],
1967
2251
  nfsHostPath,
1968
2252
  `http://ports.ubuntu.com/ubuntu-ports/`,
1969
2253
  ];
@@ -1995,8 +2279,10 @@ EOF`);
1995
2279
  }
1996
2280
  if (process.argv.includes('mount')) {
1997
2281
  shellExec(`sudo mount --bind /proc ${nfsHostPath}/proc`);
1998
- shellExec(`sudo mount --bind /sys ${nfsHostPath}/sys`);
1999
- shellExec(`sudo mount --rbind /dev ${nfsHostPath}/dev`);
2282
+ shellExec(`sudo mount --bind /sys ${nfsHostPath}/sys`);
2283
+ shellExec(`sudo mount --rbind /dev ${nfsHostPath}/dev`);
2284
+ shellExec(`sudo mount --rbind /dev/pts ${nfsHostPath}/dev/pts`);
2285
+ shellExec(`sudo mount --bind /run ${nfsHostPath}/run`);
2000
2286
  }
2001
2287
 
2002
2288
  if (process.argv.includes('build')) {
@@ -2010,6 +2296,7 @@ EOF`);
2010
2296
  host,
2011
2297
  nfsHostPath,
2012
2298
  ipaddr,
2299
+ gatewayip,
2013
2300
  });
2014
2301
 
2015
2302
  break;
@@ -2031,7 +2318,9 @@ EOF`);
2031
2318
  const nfsHostPath = `${process.env.NFS_EXPORT_PATH}/${host}`;
2032
2319
  shellExec(`sudo umount ${nfsHostPath}/proc`);
2033
2320
  shellExec(`sudo umount ${nfsHostPath}/sys`);
2321
+ shellExec(`sudo umount ${nfsHostPath}/dev/pts`);
2034
2322
  shellExec(`sudo umount ${nfsHostPath}/dev`);
2323
+ shellExec(`sudo umount ${nfsHostPath}/run`);
2035
2324
  // shellExec(`sudo umount ${nfsHostPath}/lib/modules`);
2036
2325
  break;
2037
2326
  }
@@ -2425,6 +2714,14 @@ nvidia/gpu-operator \
2425
2714
  // sudo yum install sbt
2426
2715
  break;
2427
2716
  }
2717
+
2718
+ case 'chrony': {
2719
+ shellExec(`sudo dnf install chrony -y`);
2720
+ // debian chroot: sudo apt install chrony
2721
+ for (const cmd of chronySetUp(`/etc/chrony.conf`)) shellExec(cmd);
2722
+
2723
+ break;
2724
+ }
2428
2725
  }
2429
2726
  } catch (error) {
2430
2727
  logger.error(error, error.stack);