underpost 2.8.818 → 2.8.821
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/README.md +2 -2
- package/bin/deploy.js +0 -1320
- package/cli.md +24 -16
- package/docker-compose.yml +1 -1
- package/manifests/deployment/dd-template-development/deployment.yaml +2 -2
- package/manifests/maas/device-scan.sh +1 -1
- package/manifests/maas/maas-setup.sh +81 -7
- package/manifests/maas/nat-iptables.sh +10 -5
- package/package.json +1 -1
- package/src/cli/baremetal.js +1233 -47
- package/src/cli/cloud-init.js +537 -0
- package/src/cli/index.js +15 -10
- package/src/index.js +26 -16
- package/src/server/runtime.js +0 -5
- package/src/server/ssl.js +1 -12
package/bin/deploy.js
CHANGED
|
@@ -51,585 +51,6 @@ logger.info('argv', process.argv);
|
|
|
51
51
|
|
|
52
52
|
const [exe, dir, operator] = process.argv;
|
|
53
53
|
|
|
54
|
-
const chronyConfPath = `/etc/chrony/chrony.conf`;
|
|
55
|
-
|
|
56
|
-
const timezone = 'America/New_York';
|
|
57
|
-
|
|
58
|
-
const timeZoneSteps = [
|
|
59
|
-
`export DEBIAN_FRONTEND=noninteractive`,
|
|
60
|
-
|
|
61
|
-
`ln -fs /usr/share/zoneinfo/${timezone} /etc/localtime`,
|
|
62
|
-
|
|
63
|
-
`sudo dpkg-reconfigure --frontend noninteractive tzdata`,
|
|
64
|
-
];
|
|
65
|
-
const keyboardSteps = [
|
|
66
|
-
`sudo locale-gen en_US.UTF-8`,
|
|
67
|
-
`sudo update-locale LANG=en_US.UTF-8`,
|
|
68
|
-
`sudo sed -i 's/XKBLAYOUT="us"/XKBLAYOUT="es"/' /etc/default/keyboard`,
|
|
69
|
-
`sudo dpkg-reconfigure --frontend noninteractive keyboard-configuration`,
|
|
70
|
-
`sudo systemctl restart keyboard-setup.service`,
|
|
71
|
-
];
|
|
72
|
-
|
|
73
|
-
const kernelLibVersion = `6.8.0-41-generic`;
|
|
74
|
-
|
|
75
|
-
const installSteps = [
|
|
76
|
-
`cat <<EOF | tee /etc/apt/sources.list
|
|
77
|
-
deb http://ports.ubuntu.com/ubuntu-ports noble main restricted universe multiverse
|
|
78
|
-
deb http://ports.ubuntu.com/ubuntu-ports noble-updates main restricted universe multiverse
|
|
79
|
-
deb http://ports.ubuntu.com/ubuntu-ports noble-security main restricted universe multiverse
|
|
80
|
-
EOF`,
|
|
81
|
-
|
|
82
|
-
`apt update -qq`,
|
|
83
|
-
`apt -y full-upgrade`,
|
|
84
|
-
`apt install -y build-essential xinput x11-xkb-utils usbutils`,
|
|
85
|
-
'apt install -y linux-image-generic',
|
|
86
|
-
`apt install -y linux-modules-${kernelLibVersion} linux-modules-extra-${kernelLibVersion}`,
|
|
87
|
-
|
|
88
|
-
`depmod -a ${kernelLibVersion}`,
|
|
89
|
-
// `apt install -y cloud-init=25.1.2-0ubuntu0~24.04.1`,
|
|
90
|
-
`apt install -y cloud-init systemd-sysv openssh-server sudo locales udev util-linux systemd-sysv iproute2 netplan.io ca-certificates curl wget chrony`,
|
|
91
|
-
`ln -sf /lib/systemd/systemd /sbin/init`,
|
|
92
|
-
|
|
93
|
-
`apt-get update`,
|
|
94
|
-
`DEBIAN_FRONTEND=noninteractive apt-get install -y apt-utils`,
|
|
95
|
-
`DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata kmod keyboard-configuration console-setup iputils-ping`,
|
|
96
|
-
];
|
|
97
|
-
|
|
98
|
-
const bootCmdSteps = [
|
|
99
|
-
`/underpost/dns.sh`,
|
|
100
|
-
`/underpost/host.sh`,
|
|
101
|
-
// `/underpost/date.sh`,
|
|
102
|
-
`/underpost/keys_import.sh`,
|
|
103
|
-
`/underpost/mac.sh`,
|
|
104
|
-
`cat /underpost/mac`,
|
|
105
|
-
];
|
|
106
|
-
|
|
107
|
-
const cloudInitReset = `sudo cloud-init clean --logs --seed --configs all --machine-id
|
|
108
|
-
sudo rm -rf /var/lib/cloud/*`;
|
|
109
|
-
|
|
110
|
-
const cloudConfigCmdRunFactory = (steps = []) =>
|
|
111
|
-
steps
|
|
112
|
-
.map(
|
|
113
|
-
(step, i, a) =>
|
|
114
|
-
' - echo "\\$(date) | ' + (i + 1) + '/' + a.length + ' - ' + step.split('\n')[0] + '"' + `\n` + ` - ${step}`,
|
|
115
|
-
)
|
|
116
|
-
.join('\n');
|
|
117
|
-
|
|
118
|
-
const cloudConfigFactory = (
|
|
119
|
-
{ controlServerIp, architecture, host, nfsHostPath, commissioningDeviceIp, update, gatewayip, auth },
|
|
120
|
-
{ consumer_key, consumer_secret, token_key, token_secret },
|
|
121
|
-
path = '/etc/cloud/cloud.cfg.d/90_maas.cfg',
|
|
122
|
-
) => [
|
|
123
|
-
// Configure cloud-init for MAAS
|
|
124
|
-
`cat <<EOF_MAAS_CFG > ${path}
|
|
125
|
-
#cloud-config
|
|
126
|
-
|
|
127
|
-
hostname: ${host}
|
|
128
|
-
# fqdn: server01.midominio.cl
|
|
129
|
-
# prefer_fqdn_over_hostname: true
|
|
130
|
-
# metadata_url: http://${controlServerIp}:5240/MAAS/metadata
|
|
131
|
-
# metadata_url: http://${controlServerIp}:5248/MAAS/metadata
|
|
132
|
-
|
|
133
|
-
# Check:
|
|
134
|
-
# /MAAS/metadata/latest/enlist-preseed/?op=get_enlist_preseed
|
|
135
|
-
|
|
136
|
-
# Debug:
|
|
137
|
-
# https://maas.io/docs/how-to-use-logging
|
|
138
|
-
|
|
139
|
-
datasource_list: [ MAAS ]
|
|
140
|
-
datasource:
|
|
141
|
-
MAAS:
|
|
142
|
-
metadata_url: http://${controlServerIp}:5240/MAAS/metadata/
|
|
143
|
-
${
|
|
144
|
-
!auth
|
|
145
|
-
? ''
|
|
146
|
-
: `consumer_key: ${consumer_key}
|
|
147
|
-
consumer_secret: ${consumer_secret}
|
|
148
|
-
token_key: ${token_key}
|
|
149
|
-
token_secret: ${token_secret}`
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
users:
|
|
154
|
-
- name: ${process.env.MAAS_ADMIN_USERNAME}
|
|
155
|
-
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
|
156
|
-
shell: /bin/bash
|
|
157
|
-
lock_passwd: false
|
|
158
|
-
groups: sudo,users,admin,wheel,lxd
|
|
159
|
-
plain_text_passwd: '${process.env.MAAS_ADMIN_USERNAME}'
|
|
160
|
-
ssh_authorized_keys:
|
|
161
|
-
- ${fs.readFileSync(`/home/dd/engine/engine-private/deploy/id_rsa.pub`, 'utf8')}
|
|
162
|
-
|
|
163
|
-
# manage_resolv_conf: true
|
|
164
|
-
# resolv_conf:
|
|
165
|
-
# nameservers: [8.8.8.8]
|
|
166
|
-
|
|
167
|
-
# keyboard:
|
|
168
|
-
# layout: es
|
|
169
|
-
|
|
170
|
-
# check timedatectl on host
|
|
171
|
-
# timezone: America/Santiago
|
|
172
|
-
timezone: ${timezone}
|
|
173
|
-
|
|
174
|
-
ntp:
|
|
175
|
-
enabled: true
|
|
176
|
-
servers:
|
|
177
|
-
- ${process.env.MAAS_NTP_SERVER}
|
|
178
|
-
ntp_client: chrony
|
|
179
|
-
config:
|
|
180
|
-
confpath: ${chronyConfPath}
|
|
181
|
-
|
|
182
|
-
# ssh:
|
|
183
|
-
# allow-pw: false
|
|
184
|
-
# install-server: true
|
|
185
|
-
|
|
186
|
-
# ssh_pwauth: false
|
|
187
|
-
|
|
188
|
-
package_update: true
|
|
189
|
-
package_upgrade: true
|
|
190
|
-
packages:
|
|
191
|
-
- git
|
|
192
|
-
- htop
|
|
193
|
-
- snapd
|
|
194
|
-
- chrony
|
|
195
|
-
resize_rootfs: false
|
|
196
|
-
growpart:
|
|
197
|
-
mode: false
|
|
198
|
-
network:
|
|
199
|
-
version: 2
|
|
200
|
-
ethernets:
|
|
201
|
-
${process.env.RPI4_INTERFACE_NAME}:
|
|
202
|
-
match:
|
|
203
|
-
macaddress: "${process.env.RPI4_MAC_ADDRESS}"
|
|
204
|
-
mtu: 1500
|
|
205
|
-
set-name: ${process.env.RPI4_INTERFACE_NAME}
|
|
206
|
-
dhcp4: false
|
|
207
|
-
addresses:
|
|
208
|
-
- ${commissioningDeviceIp}/24
|
|
209
|
-
gateway4: ${gatewayip}
|
|
210
|
-
nameservers:
|
|
211
|
-
addresses:
|
|
212
|
-
- ${process.env.MAAS_DNS}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
final_message: "====== Cloud init finished ======"
|
|
216
|
-
|
|
217
|
-
# power_state:
|
|
218
|
-
# mode: reboot
|
|
219
|
-
# message: Rebooting after initial setup
|
|
220
|
-
# timeout: 30
|
|
221
|
-
# condition: True
|
|
222
|
-
|
|
223
|
-
bootcmd:
|
|
224
|
-
- echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
|
|
225
|
-
- echo "Init bootcmd"
|
|
226
|
-
- echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
|
|
227
|
-
${cloudConfigCmdRunFactory(bootCmdSteps)}
|
|
228
|
-
runcmd:
|
|
229
|
-
- echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
|
|
230
|
-
- echo "Init runcmd"
|
|
231
|
-
- echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
|
|
232
|
-
|
|
233
|
-
# If this is set, 'root' will not be able to ssh in and they
|
|
234
|
-
# will get a message to login instead as the default $user
|
|
235
|
-
disable_root: true
|
|
236
|
-
|
|
237
|
-
# This will cause the set+update hostname module to not operate (if true)
|
|
238
|
-
preserve_hostname: false
|
|
239
|
-
|
|
240
|
-
# The modules that run in the 'init' stage
|
|
241
|
-
cloud_init_modules:
|
|
242
|
-
- migrator
|
|
243
|
-
- bootcmd
|
|
244
|
-
- write-files
|
|
245
|
-
- growpart
|
|
246
|
-
- resizefs
|
|
247
|
-
- set_hostname
|
|
248
|
-
- update_etc_hosts
|
|
249
|
-
- rsyslog
|
|
250
|
-
- users-groups
|
|
251
|
-
- ssh
|
|
252
|
-
|
|
253
|
-
cloud_config_modules:
|
|
254
|
-
- mounts
|
|
255
|
-
- locale
|
|
256
|
-
- set-passwords
|
|
257
|
-
- package-update-upgrade-install
|
|
258
|
-
- timezone
|
|
259
|
-
- runcmd
|
|
260
|
-
- ssh-import-id
|
|
261
|
-
- ntp
|
|
262
|
-
|
|
263
|
-
cloud_final_modules:
|
|
264
|
-
- rightscale_userdata
|
|
265
|
-
- scripts-per-once
|
|
266
|
-
- scripts-per-boot
|
|
267
|
-
- scripts-per-instance
|
|
268
|
-
- scripts-user
|
|
269
|
-
- ssh-authkey-fingerprints
|
|
270
|
-
- keys-to-console
|
|
271
|
-
- phone-home
|
|
272
|
-
- final-message
|
|
273
|
-
|
|
274
|
-
EOF_MAAS_CFG`,
|
|
275
|
-
];
|
|
276
|
-
|
|
277
|
-
const runSteps = (nfsHostPath, steps = []) => {
|
|
278
|
-
const script = steps
|
|
279
|
-
.map(
|
|
280
|
-
(s, i) => `echo "step ${i + 1}/${steps.length}: ${s.split('\n')[0]}"
|
|
281
|
-
${s}`,
|
|
282
|
-
)
|
|
283
|
-
.join('\n');
|
|
284
|
-
|
|
285
|
-
const cmd = `sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF_OUTER'
|
|
286
|
-
${script}
|
|
287
|
-
EOF_OUTER`;
|
|
288
|
-
|
|
289
|
-
shellExec(cmd);
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
const chronySetUp = (path, alias = 'chrony') => {
|
|
293
|
-
// use alias = 'chronyd' for RHEL
|
|
294
|
-
// use alias = 'chrony' for Ubuntu
|
|
295
|
-
return [
|
|
296
|
-
`echo '
|
|
297
|
-
# Use public servers from the pool.ntp.org project.
|
|
298
|
-
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
|
|
299
|
-
# pool 2.pool.ntp.org iburst
|
|
300
|
-
server ${process.env.MAAS_NTP_SERVER} iburst
|
|
301
|
-
|
|
302
|
-
# Record the rate at which the system clock gains/losses time.
|
|
303
|
-
driftfile /var/lib/chrony/drift
|
|
304
|
-
|
|
305
|
-
# Allow the system clock to be stepped in the first three updates
|
|
306
|
-
# if its offset is larger than 1 second.
|
|
307
|
-
makestep 1.0 3
|
|
308
|
-
|
|
309
|
-
# Enable kernel synchronization of the real-time clock (RTC).
|
|
310
|
-
rtcsync
|
|
311
|
-
|
|
312
|
-
# Enable hardware timestamping on all interfaces that support it.
|
|
313
|
-
#hwtimestamp *
|
|
314
|
-
|
|
315
|
-
# Increase the minimum number of selectable sources required to adjust
|
|
316
|
-
# the system clock.
|
|
317
|
-
#minsources 2
|
|
318
|
-
|
|
319
|
-
# Allow NTP client access from local network.
|
|
320
|
-
#allow 192.168.0.0/16
|
|
321
|
-
|
|
322
|
-
# Serve time even if not synchronized to a time source.
|
|
323
|
-
#local stratum 10
|
|
324
|
-
|
|
325
|
-
# Specify file containing keys for NTP authentication.
|
|
326
|
-
keyfile /etc/chrony.keys
|
|
327
|
-
|
|
328
|
-
# Get TAI-UTC offset and leap seconds from the system tz database.
|
|
329
|
-
leapsectz right/UTC
|
|
330
|
-
|
|
331
|
-
# Specify directory for log files.
|
|
332
|
-
logdir /var/log/chrony
|
|
333
|
-
|
|
334
|
-
# Select which information is logged.
|
|
335
|
-
#log measurements statistics tracking
|
|
336
|
-
' > ${path} `,
|
|
337
|
-
`systemctl stop ${alias}`,
|
|
338
|
-
|
|
339
|
-
`${alias}d -q 'server ntp.ubuntu.com iburst'`,
|
|
340
|
-
|
|
341
|
-
// `chronyd -q 'server 0.europe.pool.ntp.org iburst'`,
|
|
342
|
-
|
|
343
|
-
`sudo systemctl enable --now ${alias}`,
|
|
344
|
-
`sudo systemctl restart ${alias}`,
|
|
345
|
-
`sudo systemctl status ${alias}`,
|
|
346
|
-
|
|
347
|
-
`chronyc sources`,
|
|
348
|
-
`chronyc tracking`,
|
|
349
|
-
|
|
350
|
-
`chronyc sourcestats -v`,
|
|
351
|
-
`timedatectl status`,
|
|
352
|
-
];
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
const installUbuntuUnderpostTools = ({ nfsHostPath, host }) => {
|
|
356
|
-
fs.mkdirSync(`${nfsHostPath}/underpost`, { recursive: true });
|
|
357
|
-
|
|
358
|
-
logger.info('Build', `${nfsHostPath}/underpost/date.sh`);
|
|
359
|
-
fs.writeFileSync(
|
|
360
|
-
`${nfsHostPath}/underpost/date.sh`,
|
|
361
|
-
`${timeZoneSteps.join('\n')}
|
|
362
|
-
${chronySetUp(chronyConfPath).join('\n')}
|
|
363
|
-
`,
|
|
364
|
-
'utf8',
|
|
365
|
-
);
|
|
366
|
-
|
|
367
|
-
logger.info('Build', `${nfsHostPath}/underpost/host.sh`);
|
|
368
|
-
fs.writeFileSync(
|
|
369
|
-
`${nfsHostPath}/underpost/host.sh`,
|
|
370
|
-
`echo -e "127.0.0.1 localhost\n127.0.1.1 ${host}" | tee -a /etc/hosts`,
|
|
371
|
-
'utf8',
|
|
372
|
-
);
|
|
373
|
-
|
|
374
|
-
logger.info('Build', `${nfsHostPath}/underpost/keys_current.sh`);
|
|
375
|
-
fs.writeFileSync(
|
|
376
|
-
`${nfsHostPath}/underpost/keys_current.sh`,
|
|
377
|
-
`cat /etc/cloud/cloud.cfg.d/90_maas.cfg | grep -C 5 'metadata'`,
|
|
378
|
-
'utf8',
|
|
379
|
-
);
|
|
380
|
-
|
|
381
|
-
logger.info('Build', `${nfsHostPath}/underpost/keys_remove.sh`);
|
|
382
|
-
fs.writeFileSync(
|
|
383
|
-
`${nfsHostPath}/underpost/keys_remove.sh`,
|
|
384
|
-
`cp -a /underpost/90_maas_no_keys.cfg /etc/cloud/cloud.cfg.d/90_maas.cfg
|
|
385
|
-
/underpost/keys_current.sh`,
|
|
386
|
-
'utf8',
|
|
387
|
-
);
|
|
388
|
-
|
|
389
|
-
logger.info('Build', `${nfsHostPath}/underpost/keys_import.sh`);
|
|
390
|
-
fs.writeFileSync(
|
|
391
|
-
`${nfsHostPath}/underpost/keys_import.sh`,
|
|
392
|
-
`cp -a /underpost/90_maas_keys.cfg /etc/cloud/cloud.cfg.d/90_maas.cfg
|
|
393
|
-
/underpost/keys_current.sh`,
|
|
394
|
-
'utf8',
|
|
395
|
-
);
|
|
396
|
-
|
|
397
|
-
logger.info('Build', `${nfsHostPath}/underpost/keyboard.sh`);
|
|
398
|
-
fs.writeFileSync(
|
|
399
|
-
`${nfsHostPath}/underpost/keyboard.sh`,
|
|
400
|
-
`${keyboardSteps.join('\n')}
|
|
401
|
-
`,
|
|
402
|
-
'utf8',
|
|
403
|
-
);
|
|
404
|
-
|
|
405
|
-
logger.info('Build', `${nfsHostPath}/underpost/dns.sh`);
|
|
406
|
-
// echo "nameserver ${process.env.MAAS_DNS}" | tee /etc/resolv.conf > /dev/null
|
|
407
|
-
fs.writeFileSync(
|
|
408
|
-
`${nfsHostPath}/underpost/dns.sh`,
|
|
409
|
-
`rm /etc/resolv.conf
|
|
410
|
-
echo 'nameserver 8.8.8.8' > /run/systemd/resolve/stub-resolv.conf
|
|
411
|
-
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf`,
|
|
412
|
-
'utf8',
|
|
413
|
-
);
|
|
414
|
-
|
|
415
|
-
logger.info('Build', `${nfsHostPath}/underpost/start.sh`);
|
|
416
|
-
fs.writeFileSync(
|
|
417
|
-
`${nfsHostPath}/underpost/start.sh`,
|
|
418
|
-
`#!/bin/bash
|
|
419
|
-
set -x
|
|
420
|
-
sudo cloud-init --all-stages
|
|
421
|
-
`,
|
|
422
|
-
'utf8',
|
|
423
|
-
);
|
|
424
|
-
|
|
425
|
-
logger.info('Build', `${nfsHostPath}/underpost/reset.sh`);
|
|
426
|
-
fs.writeFileSync(
|
|
427
|
-
`${nfsHostPath}/underpost/reset.sh`,
|
|
428
|
-
`${cloudInitReset}
|
|
429
|
-
${bootCmdSteps.join('\n')}`,
|
|
430
|
-
'utf8',
|
|
431
|
-
);
|
|
432
|
-
|
|
433
|
-
logger.info('Build', `${nfsHostPath}/underpost/help.sh`);
|
|
434
|
-
fs.writeFileSync(
|
|
435
|
-
`${nfsHostPath}/underpost/help.sh`,
|
|
436
|
-
`echo "=== Cloud init utils ==="
|
|
437
|
-
echo "sudo cloud-init --all-stages"
|
|
438
|
-
echo "sudo cloud-init clean --logs --seed --configs all --machine-id --reboot"
|
|
439
|
-
echo "sudo cloud-init init --local"
|
|
440
|
-
echo "sudo cloud-init init"
|
|
441
|
-
echo "sudo cloud-init modules --mode=config"
|
|
442
|
-
echo "sudo cloud-init modules --mode=final"`,
|
|
443
|
-
'utf8',
|
|
444
|
-
);
|
|
445
|
-
|
|
446
|
-
logger.info('Build', `${nfsHostPath}/underpost/test.sh`);
|
|
447
|
-
fs.writeFileSync(
|
|
448
|
-
`${nfsHostPath}/underpost/test.sh`,
|
|
449
|
-
`echo -e "\n=== Current date/time ==="
|
|
450
|
-
date '+%Y-%m-%d %H:%M:%S'
|
|
451
|
-
echo -e "\n=== Keyboard layout ==="
|
|
452
|
-
cat /etc/default/keyboard
|
|
453
|
-
echo -e "\n=== Registered users ==="
|
|
454
|
-
cut -d: -f1 /etc/passwd
|
|
455
|
-
`,
|
|
456
|
-
'utf8',
|
|
457
|
-
);
|
|
458
|
-
|
|
459
|
-
logger.info('Build', `${nfsHostPath}/underpost/shutdown.sh`);
|
|
460
|
-
fs.writeFileSync(
|
|
461
|
-
`${nfsHostPath}/underpost/shutdown.sh`,
|
|
462
|
-
`cp -a /underpost/90_maas_no_keys.cfg /etc/cloud/cloud.cfg.d/90_maas.cfg
|
|
463
|
-
sudo shutdown -h now`,
|
|
464
|
-
'utf8',
|
|
465
|
-
);
|
|
466
|
-
|
|
467
|
-
logger.info('Build', `${nfsHostPath}/underpost/mac.sh`);
|
|
468
|
-
fs.writeFileSync(
|
|
469
|
-
`${nfsHostPath}/underpost/mac.sh`,
|
|
470
|
-
`echo "$(cat /sys/class/net/${process.env.RPI4_INTERFACE_NAME}/address)" > /underpost/mac`,
|
|
471
|
-
'utf8',
|
|
472
|
-
);
|
|
473
|
-
|
|
474
|
-
logger.info('Build', `${nfsHostPath}/underpost/device_scan.sh`);
|
|
475
|
-
fs.copySync(`./manifests/maas/device-scan.sh`, `${nfsHostPath}/underpost/device_scan.sh`);
|
|
476
|
-
|
|
477
|
-
logger.info('Build', `${nfsHostPath}/underpost/config-path.sh`);
|
|
478
|
-
fs.writeFileSync(`${nfsHostPath}/underpost/config-path.sh`, `echo "/etc/cloud/cloud.cfg.d/90_maas.cfg"`, 'utf8');
|
|
479
|
-
|
|
480
|
-
shellExec(`sudo rm -rf ${nfsHostPath}/root/.ssh`);
|
|
481
|
-
shellExec(`sudo rm -rf ${nfsHostPath}/home/root/.ssh`);
|
|
482
|
-
|
|
483
|
-
fs.copySync(`/root/.ssh`, `${nfsHostPath}/root/.ssh`);
|
|
484
|
-
|
|
485
|
-
logger.info('Run', `${nfsHostPath}/underpost/test.sh`);
|
|
486
|
-
runSteps(nfsHostPath, [
|
|
487
|
-
`chmod +x /underpost/date.sh`,
|
|
488
|
-
`chmod +x /underpost/keyboard.sh`,
|
|
489
|
-
`chmod +x /underpost/dns.sh`,
|
|
490
|
-
`chmod +x /underpost/help.sh`,
|
|
491
|
-
`chmod +x /underpost/config-path.sh`,
|
|
492
|
-
`chmod +x /underpost/host.sh`,
|
|
493
|
-
`chmod +x /underpost/keys_current.sh`,
|
|
494
|
-
`chmod +x /underpost/keys_import.sh`,
|
|
495
|
-
`chmod +x /underpost/keys_remove.sh`,
|
|
496
|
-
`chmod +x /underpost/test.sh`,
|
|
497
|
-
`chmod +x /underpost/start.sh`,
|
|
498
|
-
`chmod +x /underpost/reset.sh`,
|
|
499
|
-
`chmod +x /underpost/shutdown.sh`,
|
|
500
|
-
`chmod +x /underpost/device_scan.sh`,
|
|
501
|
-
`chmod +x /underpost/mac.sh`,
|
|
502
|
-
chronySetUp(chronyConfPath)[0],
|
|
503
|
-
`sudo chmod 700 ~/.ssh/`,
|
|
504
|
-
`sudo chmod 600 ~/.ssh/authorized_keys`,
|
|
505
|
-
`sudo chmod 644 ~/.ssh/known_hosts`,
|
|
506
|
-
`sudo chmod 600 ~/.ssh/id_rsa`,
|
|
507
|
-
`sudo chmod 600 /etc/ssh/ssh_host_ed25519_key`,
|
|
508
|
-
`chown -R root:root ~/.ssh`,
|
|
509
|
-
`/underpost/test.sh`,
|
|
510
|
-
]);
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
const updateVirtualRoot = async ({
|
|
514
|
-
controlServerIp,
|
|
515
|
-
architecture,
|
|
516
|
-
host,
|
|
517
|
-
nfsHostPath,
|
|
518
|
-
commissioningDeviceIp,
|
|
519
|
-
update,
|
|
520
|
-
gatewayip,
|
|
521
|
-
}) => {
|
|
522
|
-
// <consumer_key>:<consumer_token>:<secret>
|
|
523
|
-
// <consumer_key>:<consumer_secret>:<token_key>:<token_secret>
|
|
524
|
-
// maas apikey --with-names --username ${process.env.MAAS_ADMIN_USERNAME}
|
|
525
|
-
// maas ${process.env.MAAS_ADMIN_USERNAME} account create-authorisation-token
|
|
526
|
-
// maas apikey --generate --username ${process.env.MAAS_ADMIN_USERNAME}
|
|
527
|
-
// https://github.com/CanonicalLtd/maas-docs/issues/647
|
|
528
|
-
|
|
529
|
-
const parts = shellExec(`maas apikey --with-names --username ${process.env.MAAS_ADMIN_USERNAME}`, {
|
|
530
|
-
stdout: true,
|
|
531
|
-
})
|
|
532
|
-
.trim()
|
|
533
|
-
.split(`\n`)[0]
|
|
534
|
-
.split(':');
|
|
535
|
-
|
|
536
|
-
let consumer_key, consumer_secret, token_key, token_secret;
|
|
537
|
-
|
|
538
|
-
if (parts.length === 4) {
|
|
539
|
-
[consumer_key, consumer_secret, token_key, token_secret] = parts;
|
|
540
|
-
} else if (parts.length === 3) {
|
|
541
|
-
[consumer_key, token_key, token_secret] = parts;
|
|
542
|
-
consumer_secret = '""';
|
|
543
|
-
token_secret = token_secret.split(' MAAS consumer')[0].trim();
|
|
544
|
-
} else {
|
|
545
|
-
throw new Error('Invalid token format');
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
logger.info('Maas api token generated', { consumer_key, consumer_secret, token_key, token_secret });
|
|
549
|
-
|
|
550
|
-
if (update) {
|
|
551
|
-
// --reboot
|
|
552
|
-
if (process.argv.includes('reset'))
|
|
553
|
-
shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
|
|
554
|
-
${cloudInitReset}
|
|
555
|
-
EOF`);
|
|
556
|
-
|
|
557
|
-
if (fs.existsSync(`${nfsHostPath}/var/log/`)) {
|
|
558
|
-
fs.writeFileSync(`${nfsHostPath}/var/log/cloud-init.log`, '', 'utf8');
|
|
559
|
-
fs.writeFileSync(`${nfsHostPath}/var/log/cloud-init-output.log`, '', 'utf8');
|
|
560
|
-
}
|
|
561
|
-
} else {
|
|
562
|
-
runSteps(nfsHostPath, installSteps);
|
|
563
|
-
runSteps(nfsHostPath, [
|
|
564
|
-
`useradd -m -s /bin/bash -G sudo root`,
|
|
565
|
-
`echo 'root:root' | chpasswd`,
|
|
566
|
-
`mkdir -p /home/root/.ssh`,
|
|
567
|
-
`echo '${fs.readFileSync(
|
|
568
|
-
`/home/dd/engine/engine-private/deploy/id_rsa.pub`,
|
|
569
|
-
'utf8',
|
|
570
|
-
)}' > /home/root/.ssh/authorized_keys`,
|
|
571
|
-
`chown -R root /home/root/.ssh`,
|
|
572
|
-
`chmod 700 /home/root/.ssh`,
|
|
573
|
-
`chmod 600 /home/root/.ssh/authorized_keys`,
|
|
574
|
-
]);
|
|
575
|
-
runSteps(nfsHostPath, [
|
|
576
|
-
// `date -s "${shellExec(`date '+%Y-%m-%d %H:%M:%S'`, { stdout: true }).trim()}"`,
|
|
577
|
-
// `date`,
|
|
578
|
-
...timeZoneSteps,
|
|
579
|
-
...chronySetUp(chronyConfPath),
|
|
580
|
-
...keyboardSteps,
|
|
581
|
-
]);
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
runSteps(
|
|
585
|
-
nfsHostPath,
|
|
586
|
-
cloudConfigFactory(
|
|
587
|
-
{
|
|
588
|
-
auth: true,
|
|
589
|
-
controlServerIp,
|
|
590
|
-
architecture,
|
|
591
|
-
host,
|
|
592
|
-
nfsHostPath,
|
|
593
|
-
commissioningDeviceIp,
|
|
594
|
-
update,
|
|
595
|
-
gatewayip,
|
|
596
|
-
},
|
|
597
|
-
{ consumer_key, consumer_secret, token_key, token_secret },
|
|
598
|
-
'/underpost/90_maas_keys.cfg',
|
|
599
|
-
),
|
|
600
|
-
);
|
|
601
|
-
|
|
602
|
-
runSteps(
|
|
603
|
-
nfsHostPath,
|
|
604
|
-
cloudConfigFactory(
|
|
605
|
-
{
|
|
606
|
-
auth: false,
|
|
607
|
-
controlServerIp,
|
|
608
|
-
architecture,
|
|
609
|
-
host,
|
|
610
|
-
nfsHostPath,
|
|
611
|
-
commissioningDeviceIp,
|
|
612
|
-
update,
|
|
613
|
-
gatewayip,
|
|
614
|
-
},
|
|
615
|
-
{ consumer_key, consumer_secret, token_key, token_secret },
|
|
616
|
-
'/underpost/90_maas_no_keys.cfg',
|
|
617
|
-
),
|
|
618
|
-
);
|
|
619
|
-
|
|
620
|
-
if (process.argv.includes('auth')) {
|
|
621
|
-
shellExec(`cp ${nfsHostPath}/underpost/90_maas_keys.cfg ${nfsHostPath}/etc/cloud/cloud.cfg.d/90_maas.cfg`);
|
|
622
|
-
} else {
|
|
623
|
-
shellExec(`cp ${nfsHostPath}/underpost/90_maas_no_keys.cfg ${nfsHostPath}/etc/cloud/cloud.cfg.d/90_maas.cfg`);
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
installUbuntuUnderpostTools({ nfsHostPath, host });
|
|
627
|
-
|
|
628
|
-
shellExec(`./manifests/maas/nat-iptables.sh`, { silent: true });
|
|
629
|
-
|
|
630
|
-
shellExec(`cat ${nfsHostPath}/etc/cloud/cloud.cfg.d/90_maas.cfg`);
|
|
631
|
-
};
|
|
632
|
-
|
|
633
54
|
try {
|
|
634
55
|
switch (operator) {
|
|
635
56
|
case 'save':
|
|
@@ -1806,616 +1227,6 @@ EOF`);
|
|
|
1806
1227
|
break;
|
|
1807
1228
|
}
|
|
1808
1229
|
|
|
1809
|
-
case 'maas': {
|
|
1810
|
-
dotenv.config({ path: `/home/dd/engine/engine-private/conf/dd-cron/.env.production`, override: true });
|
|
1811
|
-
const controlServerIp = getLocalIPv4Address();
|
|
1812
|
-
const tftpRoot = process.argv.includes('v3.0')
|
|
1813
|
-
? `/var/snap/maas/common/maas/boot-resources/snapshot-20250720-162718`
|
|
1814
|
-
: process.env.TFTP_ROOT;
|
|
1815
|
-
const commissioningDeviceIp = process.env.RPI4_IP;
|
|
1816
|
-
const netmask = process.env.NETMASK;
|
|
1817
|
-
const gatewayip = process.env.GATEWAY_IP;
|
|
1818
|
-
let commissioningMac = '00:00:00:00:00:00';
|
|
1819
|
-
|
|
1820
|
-
const removeMachines = () => {
|
|
1821
|
-
for (const machine of machines) {
|
|
1822
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} machine delete ${machine.system_id}`);
|
|
1823
|
-
}
|
|
1824
|
-
machines = [];
|
|
1825
|
-
};
|
|
1826
|
-
|
|
1827
|
-
const clearDiscoveries = () => {
|
|
1828
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} discoveries clear all=true`);
|
|
1829
|
-
if (process.argv.includes('force')) {
|
|
1830
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} discoveries scan force=true`);
|
|
1831
|
-
}
|
|
1832
|
-
};
|
|
1833
|
-
|
|
1834
|
-
const macMonitor = async (nfsServerRootPath) => {
|
|
1835
|
-
if (fs.existsSync(`${nfsServerRootPath}/underpost/mac`)) {
|
|
1836
|
-
commissioningMac = fs.readFileSync(`${nfsServerRootPath}/underpost/mac`, 'utf8').trim();
|
|
1837
|
-
logger.info('Commissioning MAC', commissioningMac);
|
|
1838
|
-
return;
|
|
1839
|
-
}
|
|
1840
|
-
await timer(1000);
|
|
1841
|
-
await macMonitor(nfsServerRootPath);
|
|
1842
|
-
};
|
|
1843
|
-
|
|
1844
|
-
let resources;
|
|
1845
|
-
if (!process.argv.includes('machines'))
|
|
1846
|
-
try {
|
|
1847
|
-
resources = JSON.parse(
|
|
1848
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-resources read`, {
|
|
1849
|
-
silent: true,
|
|
1850
|
-
stdout: true,
|
|
1851
|
-
}),
|
|
1852
|
-
).map((o) => ({
|
|
1853
|
-
id: o.id,
|
|
1854
|
-
name: o.name,
|
|
1855
|
-
architecture: o.architecture,
|
|
1856
|
-
}));
|
|
1857
|
-
if (process.argv.includes('images')) {
|
|
1858
|
-
console.table(resources);
|
|
1859
|
-
process.exit(0);
|
|
1860
|
-
}
|
|
1861
|
-
} catch (error) {
|
|
1862
|
-
logger.error(error);
|
|
1863
|
-
}
|
|
1864
|
-
|
|
1865
|
-
let machines;
|
|
1866
|
-
try {
|
|
1867
|
-
machines = JSON.parse(
|
|
1868
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} machines read`, {
|
|
1869
|
-
stdout: true,
|
|
1870
|
-
silent: true,
|
|
1871
|
-
}),
|
|
1872
|
-
).map((m) => ({
|
|
1873
|
-
system_id: m.interface_set[0].system_id,
|
|
1874
|
-
mac_address: m.interface_set[0].mac_address,
|
|
1875
|
-
hostname: m.hostname,
|
|
1876
|
-
status_name: m.status_name,
|
|
1877
|
-
}));
|
|
1878
|
-
if (process.argv.includes('machines')) {
|
|
1879
|
-
console.table(machines);
|
|
1880
|
-
process.exit(0);
|
|
1881
|
-
}
|
|
1882
|
-
} catch (error) {
|
|
1883
|
-
logger.error(error);
|
|
1884
|
-
}
|
|
1885
|
-
|
|
1886
|
-
if (process.argv.includes('journald')) {
|
|
1887
|
-
shellExec(`sudo sed -i 's/^#Storage=auto/Storage=volatile/' /etc/systemd/journald.conf`);
|
|
1888
|
-
shellExec(`sudo systemctl daemon-reload`);
|
|
1889
|
-
shellExec(`sudo systemctl restart systemd-journald`);
|
|
1890
|
-
shellExec(`journalctl --disk-usage`);
|
|
1891
|
-
process.exit(0);
|
|
1892
|
-
}
|
|
1893
|
-
|
|
1894
|
-
if (process.argv.includes('db')) {
|
|
1895
|
-
// DROP, ALTER, CREATE, WITH ENCRYPTED
|
|
1896
|
-
// sudo -u <user> -h <host> psql <db-name>
|
|
1897
|
-
shellExec(`DB_PG_MAAS_NAME=${process.env.DB_PG_MAAS_NAME}`);
|
|
1898
|
-
shellExec(`DB_PG_MAAS_PASS=${process.env.DB_PG_MAAS_PASS}`);
|
|
1899
|
-
shellExec(`DB_PG_MAAS_USER=${process.env.DB_PG_MAAS_USER}`);
|
|
1900
|
-
shellExec(`DB_PG_MAAS_HOST=${process.env.DB_PG_MAAS_HOST}`);
|
|
1901
|
-
shellExec(
|
|
1902
|
-
`sudo -i -u postgres psql -c "CREATE USER \"$DB_PG_MAAS_USER\" WITH ENCRYPTED PASSWORD '$DB_PG_MAAS_PASS'"`,
|
|
1903
|
-
);
|
|
1904
|
-
shellExec(
|
|
1905
|
-
`sudo -i -u postgres psql -c "ALTER USER \"$DB_PG_MAAS_USER\" WITH ENCRYPTED PASSWORD '$DB_PG_MAAS_PASS'"`,
|
|
1906
|
-
);
|
|
1907
|
-
const actions = ['LOGIN', 'SUPERUSER', 'INHERIT', 'CREATEDB', 'CREATEROLE', 'REPLICATION'];
|
|
1908
|
-
shellExec(`sudo -i -u postgres psql -c "ALTER USER \"$DB_PG_MAAS_USER\" WITH ${actions.join(' ')}"`);
|
|
1909
|
-
shellExec(`sudo -i -u postgres psql -c "\\du"`);
|
|
1910
|
-
|
|
1911
|
-
shellExec(`sudo -i -u postgres createdb -O "$DB_PG_MAAS_USER" "$DB_PG_MAAS_NAME"`);
|
|
1912
|
-
|
|
1913
|
-
shellExec(`sudo -i -u postgres psql -c "\\l"`);
|
|
1914
|
-
process.exit(0);
|
|
1915
|
-
}
|
|
1916
|
-
|
|
1917
|
-
// TODO: - Disable maas proxy (egress forwarding to public dns)
|
|
1918
|
-
// - Configure maas dhcp control server
|
|
1919
|
-
// - Configure maas dns forwarding ${process.env.MAAS_DNS}
|
|
1920
|
-
// - Disable DNSSEC validation to No (Disable DNSSEC; useful when upstream DNS is misconfigured)
|
|
1921
|
-
|
|
1922
|
-
if (process.argv.includes('clear')) {
|
|
1923
|
-
removeMachines();
|
|
1924
|
-
clearDiscoveries();
|
|
1925
|
-
process.exit(0);
|
|
1926
|
-
}
|
|
1927
|
-
if (process.argv.includes('grub-arm64')) {
|
|
1928
|
-
shellExec(`sudo dnf install grub2-efi-aa64-modules`);
|
|
1929
|
-
shellExec(`sudo dnf install grub2-efi-x64-modules`);
|
|
1930
|
-
// sudo grub2-mknetdir --net-directory=${tftpRoot} --subdir=/boot/grub --module-path=/usr/lib/grub/arm64-efi arm64-efi
|
|
1931
|
-
process.exit(0);
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
if (process.argv.includes('psql')) {
|
|
1935
|
-
const cmd = `psql -U ${process.env.DB_PG_MAAS_USER} -h ${process.env.DB_PG_MAAS_HOST} -W ${process.env.DB_PG_MAAS_NAME}`;
|
|
1936
|
-
pbcopy(cmd);
|
|
1937
|
-
process.exit(0);
|
|
1938
|
-
}
|
|
1939
|
-
if (process.argv.includes('logs')) {
|
|
1940
|
-
shellExec(`maas status`);
|
|
1941
|
-
const cmd = `journalctl -f -t dhcpd -u snap.maas.pebble.service`;
|
|
1942
|
-
pbcopy(cmd);
|
|
1943
|
-
process.exit(0);
|
|
1944
|
-
}
|
|
1945
|
-
|
|
1946
|
-
// shellExec(`MAAS_ADMIN_USERNAME=${process.env.MAAS_ADMIN_USERNAME}`);
|
|
1947
|
-
// shellExec(`MAAS_ADMIN_EMAIL=${process.env.MAAS_ADMIN_EMAIL}`);
|
|
1948
|
-
// shellExec(`maas createadmin --username $MAAS_ADMIN_USERNAME --email $MAAS_ADMIN_EMAIL`);
|
|
1949
|
-
// shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-sources read`);
|
|
1950
|
-
// shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} commissioning-scripts read`);
|
|
1951
|
-
// shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-source-selections read 60`);
|
|
1952
|
-
|
|
1953
|
-
// MaaS admin CLI:
|
|
1954
|
-
// maas login <maas-admin-username> http://localhost:5240/MAAS
|
|
1955
|
-
// paste GUI API KEY (profile section)
|
|
1956
|
-
|
|
1957
|
-
// Import custom image
|
|
1958
|
-
// maas <maas-admin-username> boot-resources create name='custom/RockyLinuxRpi4' \
|
|
1959
|
-
// title='RockyLinuxRpi4' \
|
|
1960
|
-
// architecture='arm64/generic' \
|
|
1961
|
-
// filetype='tgz' \
|
|
1962
|
-
// content@=/home/RockyLinuxRpi_9-latest.tar.gz
|
|
1963
|
-
|
|
1964
|
-
// Image boot resource:
|
|
1965
|
-
// /var/snap/maas/current/root/snap/maas
|
|
1966
|
-
// /var/snap/maas/common/maas/tftp_root
|
|
1967
|
-
// sudo chmod 755 /var/snap/maas/common/maas/tftp_root
|
|
1968
|
-
|
|
1969
|
-
// /var/snap/maas/common/maas/dhcpd.conf
|
|
1970
|
-
// sudo snap restart maas.pebble
|
|
1971
|
-
|
|
1972
|
-
// PXE Linux files:
|
|
1973
|
-
// /var/snap/maas/common/maas/image-storage/bootloaders/pxe/i386
|
|
1974
|
-
// sudo nmcli con modify <interface-device-name-connection-id> ethtool.feature-rx on ethtool.feature-tx off
|
|
1975
|
-
// sudo nmcli connection up <interface-device-name-connection-id>
|
|
1976
|
-
|
|
1977
|
-
// man nm-settings |grep feature-tx-checksum
|
|
1978
|
-
|
|
1979
|
-
// nmcli c modify <interface-device-name-connection-id> \
|
|
1980
|
-
// ethtool.feature-tx-checksum-fcoe-crc off \
|
|
1981
|
-
// ethtool.feature-tx-checksum-ip-generic off \
|
|
1982
|
-
// ethtool.feature-tx-checksum-ipv4 off \
|
|
1983
|
-
// ethtool.feature-tx-checksum-ipv6 off \
|
|
1984
|
-
// ethtool.feature-tx-checksum-sctp off
|
|
1985
|
-
|
|
1986
|
-
// Ensure Rocky NFS server and /etc/exports configured
|
|
1987
|
-
// sudo systemctl restart nfs-server
|
|
1988
|
-
// Check mounts: showmount -e <server-ip>
|
|
1989
|
-
// Check nfs ports: rpcinfo -p
|
|
1990
|
-
// sudo chown -R root:root ${process.env.NFS_EXPORT_PATH}/rpi4mb
|
|
1991
|
-
// sudo chmod 755 ${process.env.NFS_EXPORT_PATH}/rpi4mb
|
|
1992
|
-
|
|
1993
|
-
// tftp server
|
|
1994
|
-
// sudo chown -R root:root /var/snap/maas/common/maas/tftp_root/rpi4mb
|
|
1995
|
-
|
|
1996
|
-
// tftp client
|
|
1997
|
-
// sudo dnf install tftp
|
|
1998
|
-
// tftp <server-ip> -c get <path>
|
|
1999
|
-
|
|
2000
|
-
// Check firewall-cmd
|
|
2001
|
-
// firewall-cmd --permanent --add-service=rpc-bind
|
|
2002
|
-
// firewall-cmd --reload
|
|
2003
|
-
// systemctl disable firewalld
|
|
2004
|
-
// sudo firewall-cmd --permanent --add-port=10259/tcp --zone=public
|
|
2005
|
-
|
|
2006
|
-
// Image extension transform (.img.xz to .tar.gz):
|
|
2007
|
-
// tar -cvzf image-name.tar.gz image-name.img.xz
|
|
2008
|
-
|
|
2009
|
-
// Rocky network configuration:
|
|
2010
|
-
// /etc/NetworkManager/system-connections
|
|
2011
|
-
|
|
2012
|
-
// Rocky kernel params update
|
|
2013
|
-
// sudo grubby --args="<key>=<value> <key>=<value>" --update-kernel=ALL
|
|
2014
|
-
// sudo reboot now
|
|
2015
|
-
|
|
2016
|
-
// Temporal:
|
|
2017
|
-
// sudo snap install temporal
|
|
2018
|
-
// journalctl -u snap.maas.pebble -t maas-regiond
|
|
2019
|
-
// journalctl -u snap.maas.pebble -t maas-temporal -n 100 --no-pager -f
|
|
2020
|
-
|
|
2021
|
-
// Remove:
|
|
2022
|
-
// sudo dnf remove <package> -y; sudo dnf autoremove -y; sudo dnf clean packages
|
|
2023
|
-
// check: ~
|
|
2024
|
-
// check: ~./cache
|
|
2025
|
-
// check: ~./config
|
|
2026
|
-
|
|
2027
|
-
// Check file logs
|
|
2028
|
-
// grep -i -E -C 1 '<key-a>|<key-b>' /example.log | tail -n 600
|
|
2029
|
-
|
|
2030
|
-
// Back into your firmware setup (UEFI or BIOS config screen).
|
|
2031
|
-
// grub> fwsetup
|
|
2032
|
-
|
|
2033
|
-
// Poweroff:
|
|
2034
|
-
// grub > halt
|
|
2035
|
-
// initramfs > poweroff
|
|
2036
|
-
|
|
2037
|
-
// Check interface
|
|
2038
|
-
// ip link show
|
|
2039
|
-
// nmcli con show
|
|
2040
|
-
|
|
2041
|
-
let firmwarePath,
|
|
2042
|
-
tftpSubDir,
|
|
2043
|
-
kernelFilesPaths,
|
|
2044
|
-
name,
|
|
2045
|
-
architecture,
|
|
2046
|
-
resource,
|
|
2047
|
-
nfsConnectStr,
|
|
2048
|
-
etcExports,
|
|
2049
|
-
nfsServerRootPath,
|
|
2050
|
-
bootConf,
|
|
2051
|
-
zipFirmwareFileName,
|
|
2052
|
-
zipFirmwareName,
|
|
2053
|
-
zipFirmwareUrl,
|
|
2054
|
-
interfaceName,
|
|
2055
|
-
nfsHost,
|
|
2056
|
-
bootResourcesPath,
|
|
2057
|
-
bootKernelPath;
|
|
2058
|
-
|
|
2059
|
-
switch (process.argv[3]) {
|
|
2060
|
-
case 'rpi4mb':
|
|
2061
|
-
tftpSubDir = '/rpi4mb';
|
|
2062
|
-
zipFirmwareFileName = `RPi4_UEFI_Firmware_v1.41.zip`;
|
|
2063
|
-
zipFirmwareName = zipFirmwareFileName.split('.zip')[0];
|
|
2064
|
-
zipFirmwareUrl = `https://github.com/pftf/RPi4/releases/download/v1.41/RPi4_UEFI_Firmware_v1.41.zip`;
|
|
2065
|
-
firmwarePath = `../${zipFirmwareName}`;
|
|
2066
|
-
interfaceName = process.env.RPI4_INTERFACE_NAME;
|
|
2067
|
-
nfsHost = 'rpi4mb';
|
|
2068
|
-
if (!fs.existsSync(firmwarePath)) {
|
|
2069
|
-
await Downloader(zipFirmwareUrl, `../${zipFirmwareFileName}`);
|
|
2070
|
-
shellExec(`cd .. && mkdir ${zipFirmwareName} && cd ${zipFirmwareName} && unzip ../${zipFirmwareFileName}`);
|
|
2071
|
-
}
|
|
2072
|
-
resource = resources.find((o) => o.architecture === 'arm64/ga-24.04' && o.name === 'ubuntu/noble');
|
|
2073
|
-
name = resource.name;
|
|
2074
|
-
architecture = resource.architecture;
|
|
2075
|
-
// resource = resources.find((o) => o.name === name && o.architecture === architecture);
|
|
2076
|
-
nfsServerRootPath = `${process.env.NFS_EXPORT_PATH}/rpi4mb`;
|
|
2077
|
-
// ,anonuid=1001,anongid=100
|
|
2078
|
-
// etcExports = `${nfsServerRootPath} *(rw,all_squash,sync,no_root_squash,insecure)`;
|
|
2079
|
-
etcExports = `${nfsServerRootPath} 192.168.1.0/24(${[
|
|
2080
|
-
'rw',
|
|
2081
|
-
// 'all_squash',
|
|
2082
|
-
'sync',
|
|
2083
|
-
'no_root_squash',
|
|
2084
|
-
'no_subtree_check',
|
|
2085
|
-
'insecure',
|
|
2086
|
-
]})`;
|
|
2087
|
-
if (process.argv.includes('v3.0')) {
|
|
2088
|
-
bootResourcesPath = `/var/snap/maas/common/maas/boot-resources/snapshot-20250720-162718`;
|
|
2089
|
-
bootKernelPath = `/var/snap/maas/common/maas/boot-resources/snapshot-20250720-162718/ubuntu/arm64/hwe-24.04/noble/stable`;
|
|
2090
|
-
kernelFilesPaths = {
|
|
2091
|
-
'vmlinuz-efi': `${bootKernelPath}/boot-kernel`,
|
|
2092
|
-
'initrd.img': `${bootKernelPath}/boot-initrd`,
|
|
2093
|
-
squashfs: `${bootKernelPath}/squashfs`,
|
|
2094
|
-
};
|
|
2095
|
-
} else {
|
|
2096
|
-
const resourceData = JSON.parse(
|
|
2097
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-resource read ${resource.id}`, {
|
|
2098
|
-
stdout: true,
|
|
2099
|
-
silent: true,
|
|
2100
|
-
disableLog: true,
|
|
2101
|
-
}),
|
|
2102
|
-
);
|
|
2103
|
-
const bootFiles = resourceData.sets[Object.keys(resourceData.sets)[0]].files;
|
|
2104
|
-
const suffix = architecture.match('xgene') ? '.xgene' : '';
|
|
2105
|
-
bootResourcesPath = `/var/snap/maas/common/maas/image-storage/bootloaders/uefi/arm64`;
|
|
2106
|
-
bootKernelPath = `/var/snap/maas/common/maas/image-storage`;
|
|
2107
|
-
kernelFilesPaths = {
|
|
2108
|
-
'vmlinuz-efi': `${bootKernelPath}/${bootFiles['boot-kernel' + suffix].filename_on_disk}`,
|
|
2109
|
-
'initrd.img': `${bootKernelPath}/${bootFiles['boot-initrd' + suffix].filename_on_disk}`,
|
|
2110
|
-
squashfs: `${bootKernelPath}/${bootFiles['squashfs'].filename_on_disk}`,
|
|
2111
|
-
};
|
|
2112
|
-
}
|
|
2113
|
-
|
|
2114
|
-
const protocol = 'tcp'; // v3 -> tcp, v4 -> udp
|
|
2115
|
-
|
|
2116
|
-
const mountOptions = [
|
|
2117
|
-
protocol,
|
|
2118
|
-
'vers=3',
|
|
2119
|
-
'nfsvers=3',
|
|
2120
|
-
'nolock',
|
|
2121
|
-
// 'protocol=tcp',
|
|
2122
|
-
// 'hard=true',
|
|
2123
|
-
'port=2049',
|
|
2124
|
-
// 'sec=none',
|
|
2125
|
-
'rw',
|
|
2126
|
-
'hard',
|
|
2127
|
-
'intr',
|
|
2128
|
-
'rsize=32768',
|
|
2129
|
-
'wsize=32768',
|
|
2130
|
-
'acregmin=0',
|
|
2131
|
-
'acregmax=0',
|
|
2132
|
-
'acdirmin=0',
|
|
2133
|
-
'acdirmax=0',
|
|
2134
|
-
'noac',
|
|
2135
|
-
// 'nodev',
|
|
2136
|
-
// 'nosuid',
|
|
2137
|
-
];
|
|
2138
|
-
const cmd = [
|
|
2139
|
-
`console=serial0,115200`,
|
|
2140
|
-
// `console=ttyAMA0,115200`,
|
|
2141
|
-
`console=tty1`,
|
|
2142
|
-
// `initrd=-1`,
|
|
2143
|
-
// `net.ifnames=0`,
|
|
2144
|
-
// `dwc_otg.lpm_enable=0`,
|
|
2145
|
-
// `elevator=deadline`,
|
|
2146
|
-
`root=/dev/nfs`,
|
|
2147
|
-
`nfsroot=${controlServerIp}:${process.env.NFS_EXPORT_PATH}/rpi4mb,${mountOptions}`,
|
|
2148
|
-
// `nfsroot=${controlServerIp}:${process.env.NFS_EXPORT_PATH}/rpi4mb`,
|
|
2149
|
-
`ip=${commissioningDeviceIp}:${controlServerIp}:${gatewayip}:${netmask}:${nfsHost}:${interfaceName}:static`,
|
|
2150
|
-
`rootfstype=nfs`,
|
|
2151
|
-
`rw`,
|
|
2152
|
-
`rootwait`,
|
|
2153
|
-
`fixrtc`,
|
|
2154
|
-
'initrd=initrd.img',
|
|
2155
|
-
// 'boot=casper',
|
|
2156
|
-
// 'ro',
|
|
2157
|
-
'netboot=nfs',
|
|
2158
|
-
`init=/sbin/init`,
|
|
2159
|
-
// `cloud-config-url=/dev/null`,
|
|
2160
|
-
// 'ip=dhcp',
|
|
2161
|
-
// 'ip=dfcp',
|
|
2162
|
-
// 'autoinstall',
|
|
2163
|
-
// 'rd.break',
|
|
2164
|
-
|
|
2165
|
-
// Disable services that not apply over nfs
|
|
2166
|
-
`systemd.mask=systemd-network-generator.service`,
|
|
2167
|
-
`systemd.mask=systemd-networkd.service`,
|
|
2168
|
-
`systemd.mask=systemd-fsck-root.service`,
|
|
2169
|
-
`systemd.mask=systemd-udev-trigger.service`,
|
|
2170
|
-
];
|
|
2171
|
-
|
|
2172
|
-
// TODO: use autoinstall cloud-config-url=http://<MAAS_IP>:5240/MAAS/metadata/latest
|
|
2173
|
-
// #cloud-config
|
|
2174
|
-
// autoinstall:
|
|
2175
|
-
// version: 1
|
|
2176
|
-
|
|
2177
|
-
// keyboard:
|
|
2178
|
-
// layout: es
|
|
2179
|
-
// variant: latinamerican
|
|
2180
|
-
|
|
2181
|
-
// identity:
|
|
2182
|
-
// hostname: rpi4
|
|
2183
|
-
// username: root
|
|
2184
|
-
// password: "{{PASSWORD}}"
|
|
2185
|
-
|
|
2186
|
-
// ssh:
|
|
2187
|
-
// install-server: true
|
|
2188
|
-
// allow-pw: true
|
|
2189
|
-
// authorized-keys:
|
|
2190
|
-
// - "{{SSH_KEY}}"
|
|
2191
|
-
|
|
2192
|
-
// locale: es_ES.UTF-8
|
|
2193
|
-
// timezone: America/Santiago
|
|
2194
|
-
|
|
2195
|
-
// packages:
|
|
2196
|
-
// - cloud-init
|
|
2197
|
-
// - systemd-sysv
|
|
2198
|
-
// - openssh-server
|
|
2199
|
-
// - sudo
|
|
2200
|
-
// - udev
|
|
2201
|
-
// - netplan.io
|
|
2202
|
-
|
|
2203
|
-
// late-commands:
|
|
2204
|
-
// - curtin in-target --target=/target ln -sf /lib/systemd/systemd /sbin/init
|
|
2205
|
-
|
|
2206
|
-
nfsConnectStr = cmd.join(' ');
|
|
2207
|
-
bootConf = `[all]
|
|
2208
|
-
BOOT_UART=0
|
|
2209
|
-
WAKE_ON_GPIO=1
|
|
2210
|
-
POWER_OFF_ON_HALT=0
|
|
2211
|
-
ENABLE_SELF_UPDATE=1
|
|
2212
|
-
DISABLE_HDMI=0
|
|
2213
|
-
NET_INSTALL_ENABLED=1
|
|
2214
|
-
DHCP_TIMEOUT=45000
|
|
2215
|
-
DHCP_REQ_TIMEOUT=4000
|
|
2216
|
-
TFTP_FILE_TIMEOUT=30000
|
|
2217
|
-
BOOT_ORDER=0x21
|
|
2218
|
-
|
|
2219
|
-
# ─────────────────────────────────────────────────────────────
|
|
2220
|
-
# TFTP configuration
|
|
2221
|
-
# ─────────────────────────────────────────────────────────────
|
|
2222
|
-
|
|
2223
|
-
# Custom TFTP prefix string (e.g., based on MAC address, no colons)
|
|
2224
|
-
#TFTP_PREFIX_STR=AA-BB-CC-DD-EE-FF/
|
|
2225
|
-
|
|
2226
|
-
# Optional PXE Option43 override (leave commented if unused)
|
|
2227
|
-
#PXE_OPTION43="Raspberry Pi Boot"
|
|
2228
|
-
|
|
2229
|
-
# DHCP client GUID (Option 97); 0x34695052 is the FourCC for Raspberry Pi 4
|
|
2230
|
-
#DHCP_OPTION97=0x34695052
|
|
2231
|
-
|
|
2232
|
-
TFTP_IP=${controlServerIp}
|
|
2233
|
-
TFTP_PREFIX=1
|
|
2234
|
-
TFTP_PREFIX_STR=${tftpSubDir.slice(1)}/
|
|
2235
|
-
|
|
2236
|
-
# ─────────────────────────────────────────────────────────────
|
|
2237
|
-
# Manually override Ethernet MAC address
|
|
2238
|
-
# ─────────────────────────────────────────────────────────────
|
|
2239
|
-
|
|
2240
|
-
MAC_ADDRESS=${process.env.RPI4_MAC_ADDRESS}
|
|
2241
|
-
|
|
2242
|
-
# OTP MAC address override
|
|
2243
|
-
#MAC_ADDRESS_OTP=0,1
|
|
2244
|
-
|
|
2245
|
-
# ─────────────────────────────────────────────────────────────
|
|
2246
|
-
# Static IP configuration (bypasses DHCP completely)
|
|
2247
|
-
# ─────────────────────────────────────────────────────────────
|
|
2248
|
-
CLIENT_IP=${commissioningDeviceIp}
|
|
2249
|
-
SUBNET=255.255.255.0
|
|
2250
|
-
GATEWAY=192.168.1.1
|
|
2251
|
-
|
|
2252
|
-
`;
|
|
2253
|
-
break;
|
|
2254
|
-
|
|
2255
|
-
default:
|
|
2256
|
-
break;
|
|
2257
|
-
}
|
|
2258
|
-
|
|
2259
|
-
shellExec(`sudo chmod 755 ${process.env.NFS_EXPORT_PATH}/${nfsHost}`);
|
|
2260
|
-
shellExec(`sudo rm -rf ${tftpRoot}${tftpSubDir}`);
|
|
2261
|
-
shellExec(`sudo cp -a ${firmwarePath} ${tftpRoot}${tftpSubDir}`);
|
|
2262
|
-
shellExec(`mkdir -p ${tftpRoot}${tftpSubDir}/pxe`);
|
|
2263
|
-
|
|
2264
|
-
fs.writeFileSync(`/etc/exports`, etcExports, 'utf8');
|
|
2265
|
-
if (bootConf) fs.writeFileSync(`${tftpRoot}${tftpSubDir}/boot.conf`, bootConf, 'utf8');
|
|
2266
|
-
|
|
2267
|
-
shellExec(`node bin/deploy nfs`);
|
|
2268
|
-
|
|
2269
|
-
switch (process.argv[3]) {
|
|
2270
|
-
case 'rpi4mb':
|
|
2271
|
-
{
|
|
2272
|
-
for (const file of ['bootaa64.efi', 'grubaa64.efi']) {
|
|
2273
|
-
shellExec(`sudo cp -a ${bootResourcesPath}/${file} ${tftpRoot}${tftpSubDir}/pxe/${file}`);
|
|
2274
|
-
}
|
|
2275
|
-
|
|
2276
|
-
{
|
|
2277
|
-
for (const file of Object.keys(kernelFilesPaths)) {
|
|
2278
|
-
shellExec(`sudo cp -a ${kernelFilesPaths[file]} ${tftpRoot}${tftpSubDir}/pxe/${file}`);
|
|
2279
|
-
}
|
|
2280
|
-
|
|
2281
|
-
fs.mkdirSync(`${tftpRoot}/grub`, { recursive: true });
|
|
2282
|
-
|
|
2283
|
-
const menuentryStr = 'UNDERPOST.NET UEFI/GRUB/MAAS RPi4 commissioning (ARM64)';
|
|
2284
|
-
const grubCfgPath = `${tftpRoot}/grub/grub.cfg`;
|
|
2285
|
-
fs.writeFileSync(
|
|
2286
|
-
grubCfgPath,
|
|
2287
|
-
`
|
|
2288
|
-
insmod gzio
|
|
2289
|
-
insmod http
|
|
2290
|
-
insmod nfs
|
|
2291
|
-
set timeout=5
|
|
2292
|
-
set default=0
|
|
2293
|
-
|
|
2294
|
-
menuentry '${menuentryStr}' {
|
|
2295
|
-
set root=(tftp,${controlServerIp})
|
|
2296
|
-
linux ${tftpSubDir}/pxe/vmlinuz-efi ${nfsConnectStr}
|
|
2297
|
-
initrd ${tftpSubDir}/pxe/initrd.img
|
|
2298
|
-
boot
|
|
2299
|
-
}
|
|
2300
|
-
|
|
2301
|
-
`,
|
|
2302
|
-
'utf8',
|
|
2303
|
-
);
|
|
2304
|
-
}
|
|
2305
|
-
const arm64EfiPath = `${tftpRoot}/grub/arm64-efi`;
|
|
2306
|
-
if (fs.existsSync(arm64EfiPath)) shellExec(`sudo rm -rf ${arm64EfiPath}`);
|
|
2307
|
-
shellExec(`sudo cp -a /usr/lib/grub/arm64-efi ${arm64EfiPath}`);
|
|
2308
|
-
}
|
|
2309
|
-
|
|
2310
|
-
break;
|
|
2311
|
-
|
|
2312
|
-
default:
|
|
2313
|
-
break;
|
|
2314
|
-
}
|
|
2315
|
-
|
|
2316
|
-
logger.info('succes maas deploy', {
|
|
2317
|
-
resource,
|
|
2318
|
-
kernelFilesPaths,
|
|
2319
|
-
tftpRoot,
|
|
2320
|
-
tftpSubDir,
|
|
2321
|
-
firmwarePath,
|
|
2322
|
-
etcExports,
|
|
2323
|
-
nfsServerRootPath,
|
|
2324
|
-
nfsConnectStr,
|
|
2325
|
-
});
|
|
2326
|
-
shellExec(`sudo chown -R root:root ${tftpRoot}`);
|
|
2327
|
-
shellExec(`sudo sudo chmod 755 ${tftpRoot}`);
|
|
2328
|
-
|
|
2329
|
-
logger.info('Waiting for MAC assignment...');
|
|
2330
|
-
fs.removeSync(`${nfsServerRootPath}/underpost/mac`);
|
|
2331
|
-
await macMonitor(nfsServerRootPath);
|
|
2332
|
-
|
|
2333
|
-
const monitor = async () => {
|
|
2334
|
-
// discoveries Query observed discoveries.
|
|
2335
|
-
// discovery Read or delete an observed discovery.
|
|
2336
|
-
|
|
2337
|
-
const discoveries = JSON.parse(
|
|
2338
|
-
shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} discoveries read`, {
|
|
2339
|
-
silent: true,
|
|
2340
|
-
stdout: true,
|
|
2341
|
-
}),
|
|
2342
|
-
);
|
|
2343
|
-
|
|
2344
|
-
// {
|
|
2345
|
-
// "discovery_id": "",
|
|
2346
|
-
// "ip": "192.168.1.189",
|
|
2347
|
-
// "mac_address": "00:00:00:00:00:00",
|
|
2348
|
-
// "last_seen": "2025-05-05T14:17:37.354",
|
|
2349
|
-
// "hostname": null,
|
|
2350
|
-
// "fabric_name": "",
|
|
2351
|
-
// "vid": null,
|
|
2352
|
-
// "mac_organization": "",
|
|
2353
|
-
// "observer": {
|
|
2354
|
-
// "system_id": "",
|
|
2355
|
-
// "hostname": "",
|
|
2356
|
-
// "interface_id": 1,
|
|
2357
|
-
// "interface_name": ""
|
|
2358
|
-
// },
|
|
2359
|
-
// "resource_uri": "/MAAS/api/2.0/discovery/MTkyLjE2OC4xLjE4OSwwMDowMDowMDowMDowMDowMA==/"
|
|
2360
|
-
// },
|
|
2361
|
-
|
|
2362
|
-
console.log(discoveries.map((d) => d.ip).join(' | '));
|
|
2363
|
-
|
|
2364
|
-
for (const discovery of discoveries) {
|
|
2365
|
-
const machine = {
|
|
2366
|
-
architecture: architecture.match('amd') ? 'amd64/generic' : 'arm64/generic',
|
|
2367
|
-
mac_address: discovery.mac_address,
|
|
2368
|
-
hostname: discovery.hostname ?? discovery.mac_organization ?? discovery.domain ?? `generic-host-${s4()}`,
|
|
2369
|
-
// discovery.ip.match(commissioningDeviceIp)
|
|
2370
|
-
// ? nfsHost
|
|
2371
|
-
// : `unknown-${s4()}`,
|
|
2372
|
-
// description: '',
|
|
2373
|
-
// https://maas.io/docs/reference-power-drivers
|
|
2374
|
-
power_type: 'manual', // manual
|
|
2375
|
-
// power_parameters_power_address: discovery.ip,
|
|
2376
|
-
mac_addresses: discovery.mac_address,
|
|
2377
|
-
ip: discovery.ip,
|
|
2378
|
-
};
|
|
2379
|
-
machine.hostname = machine.hostname.replaceAll(' ', '').replaceAll('.', '');
|
|
2380
|
-
|
|
2381
|
-
if (machine.mac_addresses === commissioningMac)
|
|
2382
|
-
try {
|
|
2383
|
-
machine.hostname = nfsHost;
|
|
2384
|
-
machine.mac_address = commissioningMac;
|
|
2385
|
-
let newMachine = shellExec(
|
|
2386
|
-
`maas ${process.env.MAAS_ADMIN_USERNAME} machines create ${Object.keys(machine)
|
|
2387
|
-
.map((k) => `${k}="${machine[k]}"`)
|
|
2388
|
-
.join(' ')}`,
|
|
2389
|
-
{
|
|
2390
|
-
silent: true,
|
|
2391
|
-
stdout: true,
|
|
2392
|
-
},
|
|
2393
|
-
);
|
|
2394
|
-
newMachine = { discovery, machine: JSON.parse(newMachine) };
|
|
2395
|
-
machines.push(newMachine);
|
|
2396
|
-
console.log(newMachine);
|
|
2397
|
-
// commissioning_scripts=90-verify-user.sh
|
|
2398
|
-
shellExec(
|
|
2399
|
-
`maas ${process.env.MAAS_ADMIN_USERNAME} machine commission ${newMachine.machine.boot_interface.system_id} enable_ssh=1 skip_bmc_config=1 skip_networking=1 skip_storage=1`,
|
|
2400
|
-
{
|
|
2401
|
-
silent: true,
|
|
2402
|
-
},
|
|
2403
|
-
);
|
|
2404
|
-
} catch (error) {
|
|
2405
|
-
logger.error(error, error.stack);
|
|
2406
|
-
} finally {
|
|
2407
|
-
process.exit(0);
|
|
2408
|
-
}
|
|
2409
|
-
}
|
|
2410
|
-
await timer(1000);
|
|
2411
|
-
monitor();
|
|
2412
|
-
};
|
|
2413
|
-
// clearDiscoveries();
|
|
2414
|
-
removeMachines();
|
|
2415
|
-
monitor();
|
|
2416
|
-
break;
|
|
2417
|
-
}
|
|
2418
|
-
|
|
2419
1230
|
case 'nfs': {
|
|
2420
1231
|
// Daemon RPC NFSv3. ports:
|
|
2421
1232
|
|
|
@@ -2491,137 +1302,6 @@ udp-port = 32766
|
|
|
2491
1302
|
shellExec(`sudo systemctl restart nfs-server`);
|
|
2492
1303
|
break;
|
|
2493
1304
|
}
|
|
2494
|
-
case 'update-virtual-root': {
|
|
2495
|
-
dotenv.config({ path: `${getUnderpostRootPath()}/.env`, override: true });
|
|
2496
|
-
const controlServerIp = getLocalIPv4Address();
|
|
2497
|
-
const architecture = process.argv[3];
|
|
2498
|
-
const host = process.argv[4];
|
|
2499
|
-
const nfsHostPath = `${process.env.NFS_EXPORT_PATH}/${host}`;
|
|
2500
|
-
const commissioningDeviceIp = process.env.RPI4_IP;
|
|
2501
|
-
const gatewayip = process.env.GATEWAY_IP;
|
|
2502
|
-
await updateVirtualRoot({
|
|
2503
|
-
controlServerIp,
|
|
2504
|
-
architecture,
|
|
2505
|
-
host,
|
|
2506
|
-
nfsHostPath,
|
|
2507
|
-
commissioningDeviceIp,
|
|
2508
|
-
update: true,
|
|
2509
|
-
gatewayip,
|
|
2510
|
-
});
|
|
2511
|
-
break;
|
|
2512
|
-
}
|
|
2513
|
-
case 'open-virtual-root': {
|
|
2514
|
-
dotenv.config({ path: `${getUnderpostRootPath()}/.env`, override: true });
|
|
2515
|
-
const controlServerIp = getLocalIPv4Address();
|
|
2516
|
-
const architecture = process.argv[3];
|
|
2517
|
-
const host = process.argv[4];
|
|
2518
|
-
const nfsHostPath = `${process.env.NFS_EXPORT_PATH}/${host}`;
|
|
2519
|
-
const gatewayip = process.env.GATEWAY_IP;
|
|
2520
|
-
shellExec(`sudo dnf install -y iptables-legacy`);
|
|
2521
|
-
shellExec(`sudo dnf install -y debootstrap`);
|
|
2522
|
-
shellExec(`sudo dnf install kernel-modules-extra-$(uname -r)`);
|
|
2523
|
-
switch (architecture) {
|
|
2524
|
-
case 'arm64':
|
|
2525
|
-
shellExec(`sudo podman run --rm --privileged multiarch/qemu-user-static --reset -p yes`);
|
|
2526
|
-
|
|
2527
|
-
break;
|
|
2528
|
-
|
|
2529
|
-
default:
|
|
2530
|
-
break;
|
|
2531
|
-
}
|
|
2532
|
-
|
|
2533
|
-
shellExec(`sudo modprobe binfmt_misc`);
|
|
2534
|
-
shellExec(`sudo mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc`);
|
|
2535
|
-
|
|
2536
|
-
if (process.argv.includes('build')) {
|
|
2537
|
-
shellExec(`mkdir -p ${nfsHostPath}`);
|
|
2538
|
-
let cmd;
|
|
2539
|
-
switch (host) {
|
|
2540
|
-
case 'rpi4mb':
|
|
2541
|
-
shellExec(`sudo rm -rf ${nfsHostPath}/*`);
|
|
2542
|
-
shellExec(`sudo chown -R root:root ${nfsHostPath}`);
|
|
2543
|
-
cmd = [
|
|
2544
|
-
`sudo debootstrap`,
|
|
2545
|
-
`--arch=arm64`,
|
|
2546
|
-
`--variant=minbase`,
|
|
2547
|
-
`--foreign`, // arm64 on amd64
|
|
2548
|
-
[`noble`, `jammy`][0],
|
|
2549
|
-
nfsHostPath,
|
|
2550
|
-
`http://ports.ubuntu.com/ubuntu-ports/`,
|
|
2551
|
-
];
|
|
2552
|
-
break;
|
|
2553
|
-
|
|
2554
|
-
default:
|
|
2555
|
-
break;
|
|
2556
|
-
}
|
|
2557
|
-
shellExec(cmd.join(' '));
|
|
2558
|
-
|
|
2559
|
-
shellExec(`sudo podman create --name extract multiarch/qemu-user-static`);
|
|
2560
|
-
shellExec(`podman ps -a`);
|
|
2561
|
-
shellExec(`sudo podman cp extract:/usr/bin/qemu-aarch64-static ${nfsHostPath}/usr/bin/`);
|
|
2562
|
-
shellExec(`sudo podman rm extract`);
|
|
2563
|
-
shellExec(`podman ps -a`);
|
|
2564
|
-
|
|
2565
|
-
switch (host) {
|
|
2566
|
-
case 'rpi4mb':
|
|
2567
|
-
shellExec(`file ${nfsHostPath}/bin/bash`); // expected: ELF 64-bit LSB pie executable, ARM aarch64 …
|
|
2568
|
-
break;
|
|
2569
|
-
|
|
2570
|
-
default:
|
|
2571
|
-
break;
|
|
2572
|
-
}
|
|
2573
|
-
|
|
2574
|
-
shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
|
|
2575
|
-
/debootstrap/debootstrap --second-stage
|
|
2576
|
-
EOF`);
|
|
2577
|
-
}
|
|
2578
|
-
if (process.argv.includes('mount')) {
|
|
2579
|
-
shellExec(`sudo mount --bind /proc ${nfsHostPath}/proc`);
|
|
2580
|
-
shellExec(`sudo mount --bind /sys ${nfsHostPath}/sys`);
|
|
2581
|
-
shellExec(`sudo mount --rbind /dev ${nfsHostPath}/dev`);
|
|
2582
|
-
shellExec(`sudo mount --rbind /dev/pts ${nfsHostPath}/dev/pts`);
|
|
2583
|
-
shellExec(`sudo mount --bind /run ${nfsHostPath}/run`);
|
|
2584
|
-
}
|
|
2585
|
-
|
|
2586
|
-
if (process.argv.includes('build')) {
|
|
2587
|
-
switch (host) {
|
|
2588
|
-
case 'rpi4mb':
|
|
2589
|
-
const commissioningDeviceIp = process.env.RPI4_IP;
|
|
2590
|
-
|
|
2591
|
-
await updateVirtualRoot({
|
|
2592
|
-
controlServerIp,
|
|
2593
|
-
architecture,
|
|
2594
|
-
host,
|
|
2595
|
-
nfsHostPath,
|
|
2596
|
-
commissioningDeviceIp,
|
|
2597
|
-
gatewayip,
|
|
2598
|
-
});
|
|
2599
|
-
|
|
2600
|
-
break;
|
|
2601
|
-
|
|
2602
|
-
default:
|
|
2603
|
-
break;
|
|
2604
|
-
}
|
|
2605
|
-
}
|
|
2606
|
-
// if (process.argv.includes('mount')) {
|
|
2607
|
-
// shellExec(`sudo mount --bind /lib/modules ${nfsHostPath}/lib/modules`);
|
|
2608
|
-
// }
|
|
2609
|
-
|
|
2610
|
-
break;
|
|
2611
|
-
}
|
|
2612
|
-
|
|
2613
|
-
case 'close-virtual-root': {
|
|
2614
|
-
const architecture = process.argv[3];
|
|
2615
|
-
const host = process.argv[4];
|
|
2616
|
-
const nfsHostPath = `${process.env.NFS_EXPORT_PATH}/${host}`;
|
|
2617
|
-
shellExec(`sudo umount ${nfsHostPath}/proc`);
|
|
2618
|
-
shellExec(`sudo umount ${nfsHostPath}/sys`);
|
|
2619
|
-
shellExec(`sudo umount ${nfsHostPath}/dev/pts`);
|
|
2620
|
-
shellExec(`sudo umount ${nfsHostPath}/dev`);
|
|
2621
|
-
shellExec(`sudo umount ${nfsHostPath}/run`);
|
|
2622
|
-
// shellExec(`sudo umount ${nfsHostPath}/lib/modules`);
|
|
2623
|
-
break;
|
|
2624
|
-
}
|
|
2625
1305
|
|
|
2626
1306
|
case 'mount': {
|
|
2627
1307
|
const mounts = shellExec(`mount`).split(`\n`);
|