underpost 2.8.798 → 2.8.811

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,137 @@ 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 }) => {
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`)[1].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
+ const installSteps = [
55
80
  `apt update`,
81
+ `apt install -y cloud-init systemd-sysv openssh-server sudo locales udev util-linux systemd-sysv iproute2 netplan.io ca-certificates curl wget chrony keyboard-configuration`,
56
82
  `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`,
83
+
84
+ `echo 'deb http://ports.ubuntu.com/ubuntu-ports noble main restricted universe multiverse
85
+ deb http://ports.ubuntu.com/ubuntu-ports noble-updates main restricted universe multiverse
86
+ deb http://ports.ubuntu.com/ubuntu-ports noble-security main restricted universe multiverse
87
+
88
+ # Uncomment the following lines if you also need source packages (for building from source)
89
+ # deb-src http://ports.ubuntu.com/ubuntu-ports noble main restricted universe multiverse
90
+ # deb-src http://ports.ubuntu.com/ubuntu-ports noble-updates main restricted universe multiverse
91
+ # deb-src http://ports.ubuntu.com/ubuntu-ports noble-security main restricted universe multiverse
92
+ ' > /etc/apt/sources.list`,
93
+ `apt update`,
94
+ `apt -y full-upgrade`,
95
+ // `apt install -y cloud-init=25.1.2-0ubuntu0~24.04.1`,
96
+
97
+ `systemctl enable ssh`,
98
+
99
+ `apt update -qq`,
100
+ `apt install -y xinput x11-xkb-utils usbutils`,
101
+ ];
102
+
103
+ let steps = [
104
+ // `date -s "${shellExec(`date '+%Y-%m-%d %H:%M:%S'`, { stdout: true }).trim()}"`,
105
+ // `date`,
106
+
107
+ ...timeZoneSteps,
108
+ ...chronySetUp(chronyConfPath),
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
+ // Configure cloud-init for MAAS
80
123
  `cat <<EOF_MAAS_CFG > /etc/cloud/cloud.cfg.d/90_maas.cfg
124
+ #cloud-config
125
+
126
+ hostname: ${host}
127
+ # fqdn: server01.midominio.cl
128
+ # prefer_fqdn_over_hostname: true
129
+ # metadata_url: http://${IP_ADDRESS}:5240/MAAS/metadata
130
+ # metadata_url: http://${IP_ADDRESS}:5248/MAAS/metadata
131
+
132
+ # Check:
133
+ # /MAAS/metadata/latest/enlist-preseed/?op=get_enlist_preseed
134
+
135
+ # Debug:
136
+ # https://maas.io/docs/how-to-use-logging
137
+
81
138
  datasource_list: [ MAAS ]
82
139
  datasource:
83
140
  MAAS:
84
- metadata_url: http://${IP_ADDRESS}:5248/MAAS/metadata
141
+ metadata_url: http://${IP_ADDRESS}:5240/MAAS/metadata
142
+ consumer_key: ${consumer_key}
143
+ token_key: ${consumer_token}
144
+ token_secret: ${secret}
85
145
  users:
86
- - name: ${process.env.MAAS_ADMIN_USERNAME}
146
+ - name: rpiadmin
147
+ sudo: ['ALL=(ALL) NOPASSWD:ALL']
148
+ shell: /bin/bash
149
+ lock_passwd: true
87
150
  ssh_authorized_keys:
88
151
  - ${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
152
+
153
+
154
+ # keyboard:
155
+ # layout: es
156
+
157
+
158
+ # check timedatectl on host
159
+ # timezone: America/Santiago
160
+ timezone: ${timezone}
161
+
162
+ ntp:
163
+ enabled: true
164
+ servers:
165
+ - ${IP_ADDRESS}
166
+ ntp_client: chrony
167
+ config:
168
+ confpath: ${chronyConfPath}
169
+ packages:
170
+ - chrony
171
+ service_name: chrony
172
+
173
+ # ssh:
174
+ # allow-pw: false
175
+ # install-server: true
176
+
177
+ # ssh_pwauth: false
178
+
179
+ package_update: true
180
+ package_upgrade: true
92
181
  packages:
93
182
  - git
94
183
  - htop
95
- - ufw
96
- # package_update: true
97
- runcmd:
98
- - ufw enable
99
- - ufw allow ssh
184
+ - snapd
100
185
  resize_rootfs: false
101
186
  growpart:
102
187
  mode: off
@@ -107,9 +192,36 @@ network:
107
192
  dhcp4: true
108
193
  addresses:
109
194
  - ${ipaddr}/24
195
+
196
+ # chpasswd:
197
+ # expire: false
198
+ # users:
199
+ # - {name: rpiadmin, password: changeme, type: text}
200
+
201
+ final_message: "The system is up, after $UPTIME seconds"
202
+
203
+ # power_state:
204
+ # mode: reboot
205
+ # message: Rebooting after initial setup
206
+ # timeout: 30
207
+ # condition: True
208
+ bootcmd:
209
+ - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
210
+ - echo "Init bootcmd"
211
+ - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
212
+ # - ${JSON.stringify([...timeZoneSteps, ...chronySetUp(chronyConfPath)])}
213
+ runcmd:
214
+ - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
215
+ - echo "Init runcmd"
216
+ - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
110
217
  EOF_MAAS_CFG`,
218
+ ...keyboardSteps,
111
219
  ];
112
220
 
221
+ if (!update) {
222
+ steps = installSteps.concat(steps);
223
+ }
224
+
113
225
  shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
114
226
  ${steps
115
227
  .map(
@@ -124,6 +236,82 @@ EOF`);
124
236
  echo "nameserver ${process.env.MAAS_DNS}" | tee /etc/resolv.conf > /dev/null
125
237
  apt update
126
238
  EOF`);
239
+
240
+ if (update) {
241
+ shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
242
+ sudo cloud-init clean --logs --reboot
243
+ EOF`);
244
+ fs.writeFileSync(`${nfsHostPath}/var/log/cloud-init.log`, '', 'utf8');
245
+
246
+ fs.writeFileSync(
247
+ `${nfsHostPath}/dns.sh`,
248
+ `rm /etc/resolv.conf
249
+ echo 'nameserver 8.8.8.8' > /run/systemd/resolve/stub-resolv.conf
250
+ ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf`,
251
+ 'utf8',
252
+ );
253
+ }
254
+ };
255
+
256
+ const chronySetUp = (path) => {
257
+ return [
258
+ `echo '
259
+ # Use public servers from the pool.ntp.org project.
260
+ # Please consider joining the pool (http://www.pool.ntp.org/join.html).
261
+ # pool 2.pool.ntp.org iburst
262
+ server ntp.ubuntu.com iburst
263
+
264
+ # Record the rate at which the system clock gains/losses time.
265
+ driftfile /var/lib/chrony/drift
266
+
267
+ # Allow the system clock to be stepped in the first three updates
268
+ # if its offset is larger than 1 second.
269
+ makestep 1.0 3
270
+
271
+ # Enable kernel synchronization of the real-time clock (RTC).
272
+ rtcsync
273
+
274
+ # Enable hardware timestamping on all interfaces that support it.
275
+ #hwtimestamp *
276
+
277
+ # Increase the minimum number of selectable sources required to adjust
278
+ # the system clock.
279
+ #minsources 2
280
+
281
+ # Allow NTP client access from local network.
282
+ #allow 192.168.0.0/16
283
+
284
+ # Serve time even if not synchronized to a time source.
285
+ #local stratum 10
286
+
287
+ # Specify file containing keys for NTP authentication.
288
+ keyfile /etc/chrony.keys
289
+
290
+ # Get TAI-UTC offset and leap seconds from the system tz database.
291
+ leapsectz right/UTC
292
+
293
+ # Specify directory for log files.
294
+ logdir /var/log/chrony
295
+
296
+ # Select which information is logged.
297
+ #log measurements statistics tracking
298
+ ' > ${path} `,
299
+ `sudo systemctl stop chronyd`,
300
+
301
+ // `chronyd -q 'server 0.europe.pool.ntp.org iburst'`,
302
+ `chronyd -q 'server ntp.ubuntu.com iburst'`,
303
+
304
+ `sudo systemctl enable --now chronyd`,
305
+ `sudo systemctl restart chronyd`,
306
+ `sudo systemctl status chronyd`,
307
+
308
+ `chronyc sources`,
309
+ `chronyc tracking`,
310
+ // sudo firewall-cmd --add-service=ntp --permanent
311
+ // sudo firewall-cmd --reload
312
+
313
+ `chronyc sourcestats -v`,
314
+ ];
127
315
  };
128
316
 
129
317
  try {
@@ -1158,7 +1346,7 @@ EOF`);
1158
1346
  }
1159
1347
 
1160
1348
  case 'cli-docs': {
1161
- buildCliDoc();
1349
+ buildCliDoc(program);
1162
1350
  break;
1163
1351
  }
1164
1352
 
@@ -1210,12 +1398,63 @@ EOF`);
1210
1398
  break;
1211
1399
  }
1212
1400
 
1401
+ case 'postgresql-17': {
1402
+ if (process.argv.includes('install')) {
1403
+ shellExec(`sudo dnf module reset postgresql -y`);
1404
+ shellExec(`sudo dnf -qy module disable postgresql`);
1405
+ shellExec(
1406
+ `sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm`,
1407
+ );
1408
+ shellExec(`sudo dnf -qy module disable postgresql`);
1409
+ shellExec(`sudo dnf install -y postgresql17 postgresql17-server postgresql17-contrib`);
1410
+
1411
+ shellExec(`sudo /usr/pgsql-17/bin/postgresql-17-setup initdb`);
1412
+ }
1413
+ if (process.argv.includes('uninstall')) {
1414
+ shellExec(`sudo systemctl stop postgresql-17`);
1415
+ shellExec(`sudo systemctl disable postgresql-17`);
1416
+
1417
+ // Remove PostgreSQL 17 packages and repo
1418
+ shellExec(`sudo dnf remove -y postgresql17 postgresql17-server postgresql17-contrib`);
1419
+ shellExec(`sudo rpm -e pgdg-redhat-repo-$(rpm -q pgdg-redhat-repo --qf '%{VERSION}-%{RELEASE}') || true`);
1420
+ shellExec(`sudo rm -f /etc/yum.repos.d/pgdg-redhat-*.repo`);
1421
+
1422
+ // Clean up data, logs, config, and the postgres user
1423
+ shellExec(`sudo rm -rf /var/lib/pgsql/17 /var/log/pgsql`);
1424
+ shellExec(`sudo rm -rf /etc/postgresql`);
1425
+ } else {
1426
+ shellExec(`sudo systemctl enable postgresql-17`);
1427
+ shellExec(`sudo systemctl start postgresql-17`);
1428
+ }
1429
+ break;
1430
+ }
1431
+
1213
1432
  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
1433
+ if (process.argv.includes('install')) {
1434
+ shellExec(`sudo dnf module reset postgresql -y`);
1435
+ shellExec(`sudo dnf -qy module disable postgresql`);
1436
+
1437
+ shellExec(`sudo systemctl stop postgresql-14`);
1438
+ shellExec(`sudo systemctl disable postgresql-14`);
1439
+
1440
+ shellExec(`sudo dnf remove -y postgresql14 postgresql14-server postgresql14-contrib`);
1441
+ shellExec(`sudo rm -rf /var/lib/pgsql`);
1442
+
1443
+ shellExec(`sudo dnf install postgresql14 postgresql14-server postgresql14-contrib -y`);
1444
+ }
1445
+ if (process.argv.includes('uninstall')) {
1446
+ shellExec(`sudo systemctl stop postgresql-14`);
1447
+ shellExec(`sudo systemctl disable postgresql-14`);
1448
+ shellExec(`sudo dnf remove -y postgresql14 postgresql14-server postgresql14-contrib`);
1449
+ shellExec(`sudo rm -rf /var/lib/pgsql /var/log/pgsql /etc/postgresql`);
1450
+ } else {
1451
+ shellExec(`sudo /usr/pgsql-14/bin/postgresql-14-setup initdb`);
1452
+ shellExec(`sudo systemctl start postgresql-14`);
1453
+ shellExec(`sudo systemctl enable postgresql-14`);
1454
+ shellExec(`sudo systemctl status postgresql-14`);
1455
+ // sudo dnf install postgresql14-contrib
1456
+ }
1457
+
1219
1458
  break;
1220
1459
  }
1221
1460
 
@@ -1252,6 +1491,9 @@ EOF`);
1252
1491
  }
1253
1492
 
1254
1493
  case 'maas': {
1494
+ shellExec(
1495
+ `underpost secret underpost --create-from-file /home/dd/engine/engine-private/conf/dd-cron/.env.production`,
1496
+ );
1255
1497
  dotenv.config({ path: `${getUnderpostRootPath()}/.env`, override: true });
1256
1498
  const IP_ADDRESS = getLocalIPv4Address();
1257
1499
  const serverip = IP_ADDRESS;
@@ -1260,6 +1502,13 @@ EOF`);
1260
1502
  const netmask = process.env.NETMASK;
1261
1503
  const gatewayip = process.env.GATEWAY_IP;
1262
1504
 
1505
+ const machineFactory = (m) => ({
1506
+ system_id: m.interface_set[0].system_id,
1507
+ mac_address: m.interface_set[0].mac_address,
1508
+ hostname: m.hostname,
1509
+ status_name: m.status_name,
1510
+ });
1511
+
1263
1512
  let resources;
1264
1513
  try {
1265
1514
  resources = JSON.parse(
@@ -1276,13 +1525,6 @@ EOF`);
1276
1525
  logger.error(error);
1277
1526
  }
1278
1527
 
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
1528
  let machines;
1287
1529
  try {
1288
1530
  machines = JSON.parse(
@@ -1295,6 +1537,25 @@ EOF`);
1295
1537
  logger.error(error);
1296
1538
  }
1297
1539
 
1540
+ if (process.argv.includes('ls')) {
1541
+ shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-sources read`);
1542
+ shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} commissioning-scripts read`);
1543
+ // shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-source-selections read 60`);
1544
+ logger.info('Resources');
1545
+ console.table(resources);
1546
+ logger.info('Machines');
1547
+ console.table(machines);
1548
+ process.exit(0);
1549
+ }
1550
+
1551
+ if (process.argv.includes('config')) {
1552
+ shellExec(`sudo sed -i 's/^#Storage=auto/Storage=volatile/' /etc/systemd/journald.conf`);
1553
+ shellExec(`sudo systemctl daemon-reload`);
1554
+ shellExec(`sudo systemctl restart systemd-journald`);
1555
+ shellExec(`journalctl --disk-usage`);
1556
+ process.exit(0);
1557
+ }
1558
+
1298
1559
  if (process.argv.includes('db')) {
1299
1560
  // DROP, ALTER, CREATE, WITH ENCRYPTED
1300
1561
  // sudo -u <user> -h <host> psql <db-name>
@@ -1315,20 +1576,13 @@ EOF`);
1315
1576
  shellExec(`sudo -i -u postgres createdb -O "$DB_PG_MAAS_USER" "$DB_PG_MAAS_NAME"`);
1316
1577
 
1317
1578
  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
1579
  process.exit(0);
1327
1580
  }
1328
1581
 
1329
1582
  // TODO: - Disable maas proxy (egress forwarding to public dns)
1583
+ // - Configure maas dhcp control server
1330
1584
  // - Configure maas dns forwarding ${process.env.MAAS_DNS}
1331
- // - Enable DNSSEC validation of upstream zones: Automatic (use default root key)
1585
+ // - Disable DNSSEC validation to No (Disable DNSSEC; useful when upstream DNS is misconfigured)
1332
1586
 
1333
1587
  if (process.argv.includes('clear')) {
1334
1588
  for (const machine of machines) {
@@ -1370,35 +1624,23 @@ EOF`);
1370
1624
  pbcopy(cmd);
1371
1625
  process.exit(0);
1372
1626
  }
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
1627
 
1393
- default:
1394
- break;
1395
- }
1628
+ if (process.argv.includes('restart')) {
1629
+ shellExec(`sudo snap restart maas.pebble`);
1630
+ let secs = 0;
1631
+ while (
1632
+ !(
1633
+ shellExec(`maas status`, { silent: true, disableLog: true, stdout: true })
1634
+ .split(' ')
1635
+ .filter((l) => l.match('inactive')).length === 1
1636
+ )
1637
+ ) {
1638
+ await timer(1000);
1639
+ console.log(`Waiting... (${++secs}s)`);
1396
1640
  }
1397
-
1398
- console.log(snippets);
1399
-
1400
1641
  process.exit(0);
1401
1642
  }
1643
+
1402
1644
  // shellExec(`MAAS_ADMIN_USERNAME=${process.env.MAAS_ADMIN_USERNAME}`);
1403
1645
  // shellExec(`MAAS_ADMIN_EMAIL=${process.env.MAAS_ADMIN_EMAIL}`);
1404
1646
  // shellExec(`maas createadmin --username $MAAS_ADMIN_USERNAME --email $MAAS_ADMIN_EMAIL`);
@@ -1509,7 +1751,7 @@ EOF`);
1509
1751
 
1510
1752
  switch (process.argv[3]) {
1511
1753
  case 'rpi4mb':
1512
- const resourceId = process.argv[4] ?? '39';
1754
+ const resourceId = process.argv[4] ?? '12';
1513
1755
  tftpSubDir = '/rpi4mb';
1514
1756
  zipFirmwareFileName = `RPi4_UEFI_Firmware_v1.41.zip`;
1515
1757
  zipFirmwareName = zipFirmwareFileName.split('.zip')[0];
@@ -1594,13 +1836,48 @@ EOF`);
1594
1836
  // 'boot=casper',
1595
1837
  // 'ro',
1596
1838
  'netboot=nfs',
1597
- `cloud-config-url=/dev/null`,
1839
+ `init=/sbin/init`,
1840
+ // `cloud-config-url=/dev/null`,
1598
1841
  // 'ip=dhcp',
1599
1842
  // 'ip=dfcp',
1600
1843
  // 'autoinstall',
1601
1844
  // 'rd.break',
1602
1845
  ];
1603
1846
 
1847
+ // TODO: use autoinstall cloud-config-url=http://<MAAS_IP>:5240/MAAS/metadata/latest
1848
+ // #cloud-config
1849
+ // autoinstall:
1850
+ // version: 1
1851
+
1852
+ // keyboard:
1853
+ // layout: es
1854
+ // variant: latinamerican
1855
+
1856
+ // identity:
1857
+ // hostname: rpi4
1858
+ // username: rpiadmin
1859
+ // password: "{{PASSWORD}}"
1860
+
1861
+ // ssh:
1862
+ // install-server: true
1863
+ // allow-pw: true
1864
+ // authorized-keys:
1865
+ // - "{{SSH_KEY}}"
1866
+
1867
+ // locale: es_ES.UTF-8
1868
+ // timezone: America/Santiago
1869
+
1870
+ // packages:
1871
+ // - cloud-init
1872
+ // - systemd-sysv
1873
+ // - openssh-server
1874
+ // - sudo
1875
+ // - udev
1876
+ // - netplan.io
1877
+
1878
+ // late-commands:
1879
+ // - curtin in-target --target=/target ln -sf /lib/systemd/systemd /sbin/init
1880
+
1604
1881
  nfsConnectStr = cmd.join(' ');
1605
1882
  bootConf = `[all]
1606
1883
  MAC_ADDRESS=00:00:00:00:00:00
@@ -1618,7 +1895,8 @@ DHCP_TIMEOUT=45000
1618
1895
  DHCP_REQ_TIMEOUT=4000
1619
1896
  TFTP_FILE_TIMEOUT=30000
1620
1897
  BOOT_ORDER=0x21`;
1621
-
1898
+ // CLIENT_IP=${ipaddr}
1899
+ // SUBNET=255.255.255.0
1622
1900
  break;
1623
1901
 
1624
1902
  default:
@@ -1635,21 +1913,6 @@ BOOT_ORDER=0x21`;
1635
1913
 
1636
1914
  shellExec(`node bin/deploy nfs`);
1637
1915
 
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
1916
  switch (process.argv[3]) {
1654
1917
  case 'rpi4mb':
1655
1918
  {
@@ -1815,9 +2078,12 @@ BOOT_ORDER=0x21`;
1815
2078
  newMachine = machineFactory(JSON.parse(newMachine));
1816
2079
  machines.push(newMachine);
1817
2080
  console.log(newMachine);
1818
- shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} machine commission ${newMachine.system_id}`, {
1819
- silent: true,
1820
- });
2081
+ shellExec(
2082
+ `maas ${process.env.MAAS_ADMIN_USERNAME} machine commission ${newMachine.system_id} enable_ssh=1 commissioning_scripts=90-verify-user.sh skip_bmc_config=1 skip_networking=1 skip_storage=1`,
2083
+ {
2084
+ silent: true,
2085
+ },
2086
+ );
1821
2087
  } catch (error) {
1822
2088
  logger.error(error, error.stack);
1823
2089
  }
@@ -1925,6 +2191,7 @@ udp-port = 32766
1925
2191
  host,
1926
2192
  nfsHostPath,
1927
2193
  ipaddr,
2194
+ update: true,
1928
2195
  });
1929
2196
  break;
1930
2197
  }
@@ -1963,7 +2230,7 @@ udp-port = 32766
1963
2230
  `--arch=arm64`,
1964
2231
  `--variant=minbase`,
1965
2232
  `--foreign`, // arm64 on amd64
1966
- `noble`,
2233
+ [`noble`, `jammy`][0],
1967
2234
  nfsHostPath,
1968
2235
  `http://ports.ubuntu.com/ubuntu-ports/`,
1969
2236
  ];
@@ -1995,8 +2262,10 @@ EOF`);
1995
2262
  }
1996
2263
  if (process.argv.includes('mount')) {
1997
2264
  shellExec(`sudo mount --bind /proc ${nfsHostPath}/proc`);
1998
- shellExec(`sudo mount --bind /sys ${nfsHostPath}/sys`);
1999
- shellExec(`sudo mount --rbind /dev ${nfsHostPath}/dev`);
2265
+ shellExec(`sudo mount --bind /sys ${nfsHostPath}/sys`);
2266
+ shellExec(`sudo mount --rbind /dev ${nfsHostPath}/dev`);
2267
+ shellExec(`sudo mount --rbind /dev/pts ${nfsHostPath}/dev/pts`);
2268
+ shellExec(`sudo mount --bind /run ${nfsHostPath}/run`);
2000
2269
  }
2001
2270
 
2002
2271
  if (process.argv.includes('build')) {
@@ -2031,6 +2300,7 @@ EOF`);
2031
2300
  const nfsHostPath = `${process.env.NFS_EXPORT_PATH}/${host}`;
2032
2301
  shellExec(`sudo umount ${nfsHostPath}/proc`);
2033
2302
  shellExec(`sudo umount ${nfsHostPath}/sys`);
2303
+ shellExec(`sudo umount ${nfsHostPath}/dev/pts`);
2034
2304
  shellExec(`sudo umount ${nfsHostPath}/dev`);
2035
2305
  // shellExec(`sudo umount ${nfsHostPath}/lib/modules`);
2036
2306
  break;
@@ -2425,6 +2695,14 @@ nvidia/gpu-operator \
2425
2695
  // sudo yum install sbt
2426
2696
  break;
2427
2697
  }
2698
+
2699
+ case 'chrony': {
2700
+ shellExec(`sudo dnf install chrony -y`);
2701
+ // debian chroot: sudo apt install chrony
2702
+ for (const cmd of chronySetUp(`/etc/chrony.conf`)) shellExec(cmd);
2703
+
2704
+ break;
2705
+ }
2428
2706
  }
2429
2707
  } catch (error) {
2430
2708
  logger.error(error, error.stack);