underpost 2.8.814 → 2.8.816

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 CHANGED
@@ -68,7 +68,7 @@ Run dev client server
68
68
  npm run dev
69
69
  ```
70
70
  <!-- -->
71
- ## underpost ci/cd cli v2.8.814
71
+ ## underpost ci/cd cli v2.8.816
72
72
 
73
73
  ### Usage: `underpost [options] [command]`
74
74
  ```
package/bin/deploy.js CHANGED
@@ -51,52 +51,50 @@ logger.info('argv', process.argv);
51
51
 
52
52
  const [exe, dir, operator] = process.argv;
53
53
 
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
-
63
- const timeZoneSteps = [
64
- `export DEBIAN_FRONTEND=noninteractive`,
65
-
66
- `ln -fs /usr/share/zoneinfo/${timezone} /etc/localtime`,
67
-
68
- `sudo dpkg-reconfigure --frontend noninteractive tzdata`,
69
- ];
70
- const keyboardSteps = [
71
- `sudo locale-gen en_US.UTF-8`,
72
- `sudo update-locale LANG=en_US.UTF-8`,
73
- `sudo sed -i 's/XKBLAYOUT="us"/XKBLAYOUT="es"/' /etc/default/keyboard`,
74
- `sudo dpkg-reconfigure --frontend noninteractive keyboard-configuration`,
75
- `sudo systemctl restart keyboard-setup.service`,
76
- ];
77
- // # - ${JSON.stringify([...timeZoneSteps, ...chronySetUp(chronyConfPath)])}
78
- const installSteps = [
79
- `cat <<EOF | tee /etc/apt/sources.list
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
+ // # - ${JSON.stringify([...timeZoneSteps, ...chronySetUp(chronyConfPath)])}
73
+ const installSteps = [
74
+ `cat <<EOF | tee /etc/apt/sources.list
80
75
  deb http://ports.ubuntu.com/ubuntu-ports noble main restricted universe multiverse
81
76
  deb http://ports.ubuntu.com/ubuntu-ports noble-updates main restricted universe multiverse
82
77
  deb http://ports.ubuntu.com/ubuntu-ports noble-security main restricted universe multiverse
83
78
  EOF`,
84
79
 
85
- `apt update -qq`,
86
- `apt -y full-upgrade`,
87
- `apt install -y xinput x11-xkb-utils usbutils`,
88
- // `apt install -y cloud-init=25.1.2-0ubuntu0~24.04.1`,
89
- `apt install -y cloud-init systemd-sysv openssh-server sudo locales udev util-linux systemd-sysv iproute2 netplan.io ca-certificates curl wget chrony`,
90
- `ln -sf /lib/systemd/systemd /sbin/init`,
91
-
92
- `apt-get update`,
93
- `DEBIAN_FRONTEND=noninteractive apt-get install -y apt-utils`,
94
- `DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata kmod keyboard-configuration console-setup`,
95
- ];
96
-
97
- let steps = [
98
- // Configure cloud-init for MAAS
99
- `cat <<EOF_MAAS_CFG > /etc/cloud/cloud.cfg.d/90_maas.cfg
80
+ `apt update -qq`,
81
+ `apt -y full-upgrade`,
82
+ `apt install -y xinput x11-xkb-utils usbutils`,
83
+ // `apt install -y cloud-init=25.1.2-0ubuntu0~24.04.1`,
84
+ `apt install -y cloud-init systemd-sysv openssh-server sudo locales udev util-linux systemd-sysv iproute2 netplan.io ca-certificates curl wget chrony`,
85
+ `ln -sf /lib/systemd/systemd /sbin/init`,
86
+
87
+ `apt-get update`,
88
+ `DEBIAN_FRONTEND=noninteractive apt-get install -y apt-utils`,
89
+ `DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata kmod keyboard-configuration console-setup iputils-ping`,
90
+ ];
91
+
92
+ const cloudConfigFactory = (
93
+ { IP_ADDRESS, architecture, host, nfsHostPath, ipaddr, update, gatewayip },
94
+ { consumer_key, consumer_secret, token_key, token_secret },
95
+ ) => [
96
+ // Configure cloud-init for MAAS
97
+ `cat <<EOF_MAAS_CFG > /etc/cloud/cloud.cfg.d/90_maas.cfg
100
98
  #cloud-config
101
99
 
102
100
  hostname: ${host}
@@ -114,37 +112,48 @@ hostname: ${host}
114
112
  datasource_list: [ MAAS ]
115
113
  datasource:
116
114
  MAAS:
117
- metadata_url: http://${IP_ADDRESS}:5240/MAAS/metadata
118
- consumer_key: ${consumer_key}
119
- token_key: ${consumer_token}
120
- token_secret: ${secret}
121
- users:
122
- - name: rpiadmin
123
- sudo: ['ALL=(ALL) NOPASSWD:ALL']
124
- shell: /bin/bash
125
- lock_passwd: true
126
- ssh_authorized_keys:
127
- - ${fs.readFileSync(`/home/dd/engine/engine-private/deploy/id_rsa.pub`, 'utf8')}
115
+ metadata_url: http://${IP_ADDRESS}:5240/MAAS/metadata/
116
+ ${
117
+ process.argv.includes('reset')
118
+ ? ''
119
+ : `consumer_key: ${consumer_key}
120
+ consumer_secret: ${consumer_secret}
121
+ token_key: ${token_key}
122
+ token_secret: ${token_secret}`
123
+ }
128
124
 
129
125
 
126
+ users:
127
+ - name: ${process.env.MAAS_ADMIN_USERNAME}
128
+ sudo: ['ALL=(ALL) NOPASSWD:ALL']
129
+ shell: /bin/bash
130
+ lock_passwd: false
131
+ groups: sudo,users,admin,wheel,lxd
132
+ plain_text_passwd: '${process.env.MAAS_ADMIN_USERNAME}'
133
+ ssh_authorized_keys:
134
+ - ${fs.readFileSync(`/home/dd/engine/engine-private/deploy/id_rsa.pub`, 'utf8')}
135
+
136
+ # manage_resolv_conf: true
137
+ # resolv_conf:
138
+ # nameservers: [8.8.8.8]
139
+
130
140
  # keyboard:
131
141
  # layout: es
132
142
 
133
-
134
143
  # check timedatectl on host
135
144
  # timezone: America/Santiago
136
- timezone: ${timezone}
145
+ # timezone: ${timezone}
137
146
 
138
147
  ntp:
139
148
  enabled: true
140
149
  servers:
141
- - ${IP_ADDRESS}
150
+ - ${process.env.MAAS_NTP_SERVER}
142
151
  ntp_client: chrony
143
- config:
144
- confpath: ${chronyConfPath}
145
- packages:
146
- - chrony
147
- service_name: chrony
152
+ # config:
153
+ # confpath: ${chronyConfPath}
154
+ # packages:
155
+ # - chrony
156
+ # service_name: chrony
148
157
 
149
158
  # ssh:
150
159
  # allow-pw: false
@@ -165,9 +174,9 @@ network:
165
174
  version: 2
166
175
  ethernets:
167
176
  ${process.env.RPI4_INTERFACE_NAME}:
168
- dhcp4: true
169
- addresses:
170
- - ${ipaddr}/24
177
+ dhcp4: true
178
+ addresses:
179
+ - ${ipaddr}/24
171
180
  # routes:
172
181
  # - to: default
173
182
  # via: ${gatewayip}
@@ -175,7 +184,7 @@ network:
175
184
  # chpasswd:
176
185
  # expire: false
177
186
  # users:
178
- # - {name: rpiadmin, password: changeme, type: text}
187
+ # - {name: root, password: changeme, type: text}
179
188
 
180
189
  final_message: "The system is up, after $UPTIME seconds"
181
190
 
@@ -192,87 +201,88 @@ runcmd:
192
201
  - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
193
202
  - echo "Init runcmd"
194
203
  - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
204
+
205
+ # If this is set, 'root' will not be able to ssh in and they
206
+ # will get a message to login instead as the default $user
207
+ disable_root: true
208
+
209
+ # This will cause the set+update hostname module to not operate (if true)
210
+ preserve_hostname: false
211
+
212
+ # The modules that run in the 'init' stage
213
+ cloud_init_modules:
214
+ - migrator
215
+ - seed_random
216
+ - bootcmd
217
+ - write-files
218
+ - growpart
219
+ - resizefs
220
+ - disk_setup
221
+ - mounts
222
+ - set_hostname
223
+ - update_hostname
224
+ - update_etc_hosts
225
+ - ca-certs
226
+ - rsyslog
227
+ - users-groups
228
+ - ssh
229
+
230
+ # The modules that run in the 'config' stage
231
+ cloud_config_modules:
232
+ # Emit the cloud config ready event
233
+ # this can be used by upstart jobs for 'start on cloud-config'.
234
+ - emit_upstart
235
+ - snap_config
236
+ - ssh-import-id
237
+ - locale
238
+ - set-passwords
239
+ - grub-dpkg
240
+ - apt-pipelining
241
+ - apt-configure
242
+ - ntp
243
+ - timezone
244
+ - disable-ec2-metadata
245
+ - runcmd
246
+ - byobu
247
+
248
+ # The modules that run in the 'final' stage
249
+ cloud_final_modules:
250
+ - snappy
251
+ - package-update-upgrade-install
252
+ # - fan
253
+ # - landscape
254
+ # - lxd
255
+ # - puppet
256
+ - chef
257
+ - salt-minion
258
+ - mcollective
259
+ - rightscale_userdata
260
+ - scripts-vendor
261
+ - scripts-per-once
262
+ - scripts-per-boot
263
+ - scripts-per-instance
264
+ - scripts-user
265
+ - ssh-authkey-fingerprints
266
+ - keys-to-console
267
+ # - phone-home
268
+ - final-message
269
+ # - power-state-change
195
270
  EOF_MAAS_CFG`,
196
- ];
271
+ ];
197
272
 
198
- const runSteps = (steps = []) => {
199
- const script = steps
200
- .map(
201
- (s, i) => `echo "step ${i + 1}/${steps.length}: ${s.split('\n')[0]}"
273
+ const runSteps = (nfsHostPath, steps = []) => {
274
+ const script = steps
275
+ .map(
276
+ (s, i) => `echo "step ${i + 1}/${steps.length}: ${s.split('\n')[0]}"
202
277
  ${s}`,
203
- )
204
- .join('\n');
278
+ )
279
+ .join('\n');
205
280
 
206
- const cmd = `sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF_OUTER'
281
+ const cmd = `sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF_OUTER'
207
282
  ${script}
208
283
  EOF_OUTER`;
209
284
 
210
- shellExec(cmd);
211
- };
212
-
213
- if (update) {
214
- // --reboot
215
- shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
216
- sudo cloud-init clean --logs --seed --configs all --machine-id
217
- sudo rm -rf /var/lib/cloud/*
218
- EOF`);
219
-
220
- if (fs.existsSync(`${nfsHostPath}/var/log/`)) {
221
- fs.writeFileSync(`${nfsHostPath}/var/log/cloud-init.log`, '', 'utf8');
222
- fs.writeFileSync(`${nfsHostPath}/var/log/cloud-init-output.log`, '', 'utf8');
223
- }
224
-
225
- runSteps(steps);
226
- } else {
227
- runSteps(installSteps.concat(steps));
228
-
229
- shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
230
- echo "nameserver ${process.env.MAAS_DNS}" | tee /etc/resolv.conf > /dev/null
231
- apt update
232
- EOF`);
233
- fs.writeFileSync(
234
- `${nfsHostPath}/dns.sh`,
235
- `rm /etc/resolv.conf
236
- echo 'nameserver 8.8.8.8' > /run/systemd/resolve/stub-resolv.conf
237
- ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf`,
238
- 'utf8',
239
- );
240
-
241
- runSteps([
242
- // `date -s "${shellExec(`date '+%Y-%m-%d %H:%M:%S'`, { stdout: true }).trim()}"`,
243
- // `date`,
244
- ...timeZoneSteps,
245
- ...chronySetUp(chronyConfPath),
246
- ...keyboardSteps,
247
- ]);
248
-
249
- runSteps([
250
- `useradd -m -s /bin/bash -G sudo root`,
251
- `echo 'root:root' | chpasswd`,
252
- `mkdir -p /home/root/.ssh`,
253
- `echo '${fs.readFileSync(
254
- `/home/dd/engine/engine-private/deploy/id_rsa.pub`,
255
- 'utf8',
256
- )}' > /home/root/.ssh/authorized_keys`,
257
- `chown -R root /home/root/.ssh`,
258
- `chmod 700 /home/root/.ssh`,
259
- `chmod 600 /home/root/.ssh/authorized_keys`,
260
- ]);
261
- }
262
-
263
- logger.info('Check virtual root user config');
264
- {
265
- const cmd = `sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF_OUTER'
266
- echo -e "\n=== Current date/time ==="
267
- date '+%Y-%m-%d %H:%M:%S'
268
- echo -e "\n=== Keyboard layout ==="
269
- cat /etc/default/keyboard
270
- echo -e "\n=== Registered users ==="
271
- cut -d: -f1 /etc/passwd
272
- EOF_OUTER`;
273
-
274
- shellExec(cmd);
275
- }
285
+ shellExec(cmd);
276
286
  };
277
287
 
278
288
  const chronySetUp = (path) => {
@@ -336,6 +346,162 @@ logdir /var/log/chrony
336
346
  ];
337
347
  };
338
348
 
349
+ const installUbuntuUnderpostTools = (nfsHostPath) => {
350
+ fs.mkdirSync(`${nfsHostPath}/underpost`, { recursive: true });
351
+
352
+ logger.info('Build', `${nfsHostPath}/underpost/date.sh`);
353
+ fs.writeFileSync(
354
+ `${nfsHostPath}/underpost/date.sh`,
355
+ `${timeZoneSteps.join('\n')}
356
+ ${chronySetUp(chronyConfPath).join('\n')}
357
+ `,
358
+ 'utf8',
359
+ );
360
+
361
+ logger.info('Build', `${nfsHostPath}/underpost/keyboard.sh`);
362
+ fs.writeFileSync(
363
+ `${nfsHostPath}/underpost/keyboard.sh`,
364
+ `${keyboardSteps.join('\n')}
365
+ `,
366
+ 'utf8',
367
+ );
368
+
369
+ logger.info('Build', `${nfsHostPath}/underpost/dns.sh`);
370
+ // echo "nameserver ${process.env.MAAS_DNS}" | tee /etc/resolv.conf > /dev/null
371
+ fs.writeFileSync(
372
+ `${nfsHostPath}/underpost/dns.sh`,
373
+ `rm /etc/resolv.conf
374
+ echo 'nameserver 8.8.8.8' > /run/systemd/resolve/stub-resolv.conf
375
+ ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf`,
376
+ 'utf8',
377
+ );
378
+
379
+ logger.info('Build', `${nfsHostPath}/underpost/help.sh`);
380
+ fs.writeFileSync(
381
+ `${nfsHostPath}/underpost/help.sh`,
382
+ `echo "=== Cloud init utils ==="
383
+ echo "sudo cloud-init --all-stages"
384
+ echo "sudo cloud-init clean --logs --seed --configs all --machine-id --reboot"
385
+ echo "sudo cloud-init init --local"
386
+ echo "sudo cloud-init init"
387
+ echo "sudo cloud-init modules --mode=config"
388
+ echo "sudo cloud-init modules --mode=final"`,
389
+ 'utf8',
390
+ );
391
+
392
+ logger.info('Build', `${nfsHostPath}/underpost/test.sh`);
393
+ fs.writeFileSync(
394
+ `${nfsHostPath}/underpost/test.sh`,
395
+ `echo -e "\n=== Current date/time ==="
396
+ date '+%Y-%m-%d %H:%M:%S'
397
+ echo -e "\n=== Keyboard layout ==="
398
+ cat /etc/default/keyboard
399
+ echo -e "\n=== Registered users ==="
400
+ cut -d: -f1 /etc/passwd
401
+ `,
402
+ 'utf8',
403
+ );
404
+
405
+ logger.info('Build', `${nfsHostPath}/underpost/config-path.sh`);
406
+ fs.writeFileSync(`${nfsHostPath}/underpost/config-path.sh`, `echo "/etc/cloud/cloud.cfg.d/90_maas.cfg"`, 'utf8');
407
+
408
+ shellExec(`sudo rm -rf ${nfsHostPath}/root/.ssh`);
409
+ shellExec(`sudo rm -rf ${nfsHostPath}/home/root/.ssh`);
410
+
411
+ fs.copySync(`/root/.ssh`, `${nfsHostPath}/root/.ssh`);
412
+
413
+ logger.info('Run', `${nfsHostPath}/underpost/test.sh`);
414
+ runSteps(nfsHostPath, [
415
+ `chmod +x /underpost/date.sh`,
416
+ `chmod +x /underpost/keyboard.sh`,
417
+ `chmod +x /underpost/dns.sh`,
418
+ `chmod +x /underpost/help.sh`,
419
+ `chmod +x /underpost/config-path.sh`,
420
+ `chmod +x /underpost/test.sh`,
421
+ `sudo chmod 700 ~/.ssh/`,
422
+ `sudo chmod 600 ~/.ssh/authorized_keys`,
423
+ `sudo chmod 644 ~/.ssh/known_hosts`,
424
+ `sudo chmod 600 ~/.ssh/id_rsa`,
425
+ `sudo chmod 600 /etc/ssh/ssh_host_ed25519_key`,
426
+ `chown -R root:root ~/.ssh`,
427
+ `/underpost/test.sh`,
428
+ ]);
429
+ };
430
+
431
+ const updateVirtualRoot = async ({ IP_ADDRESS, architecture, host, nfsHostPath, ipaddr, update, gatewayip }) => {
432
+ // <consumer_key>:<consumer_token>:<secret>
433
+ // <consumer_key>:<consumer_secret>:<token_key>:<token_secret>
434
+ // maas apikey --with-names --username ${process.env.MAAS_ADMIN_USERNAME}
435
+ // maas ${process.env.MAAS_ADMIN_USERNAME} account create-authorisation-token
436
+ // maas apikey --generate --username ${process.env.MAAS_ADMIN_USERNAME}
437
+ // https://github.com/CanonicalLtd/maas-docs/issues/647
438
+
439
+ const parts = shellExec(`maas apikey --with-names --username ${process.env.MAAS_ADMIN_USERNAME}`, {
440
+ stdout: true,
441
+ })
442
+ .trim()
443
+ .split(`\n`)[0]
444
+ .split(':');
445
+
446
+ let consumer_key, consumer_secret, token_key, token_secret;
447
+
448
+ if (parts.length === 4) {
449
+ [consumer_key, consumer_secret, token_key, token_secret] = parts;
450
+ } else if (parts.length === 3) {
451
+ [consumer_key, token_key, token_secret] = parts;
452
+ consumer_secret = '""';
453
+ token_secret = token_secret.split(' MAAS consumer')[0].trim();
454
+ } else {
455
+ throw new Error('Invalid token format');
456
+ }
457
+
458
+ logger.info('Maas api token generated', { consumer_key, consumer_secret, token_key, token_secret });
459
+
460
+ if (update) {
461
+ // --reboot
462
+ if (process.argv.includes('reset'))
463
+ shellExec(`sudo chroot ${nfsHostPath} /usr/bin/qemu-aarch64-static /bin/bash <<'EOF'
464
+ sudo cloud-init clean --logs --seed --configs all --machine-id
465
+ sudo rm -rf /var/lib/cloud/*
466
+ EOF`);
467
+
468
+ if (fs.existsSync(`${nfsHostPath}/var/log/`)) {
469
+ fs.writeFileSync(`${nfsHostPath}/var/log/cloud-init.log`, '', 'utf8');
470
+ fs.writeFileSync(`${nfsHostPath}/var/log/cloud-init-output.log`, '', 'utf8');
471
+ }
472
+ } else {
473
+ runSteps(nfsHostPath, installSteps);
474
+ runSteps(nfsHostPath, [
475
+ `useradd -m -s /bin/bash -G sudo root`,
476
+ `echo 'root:root' | chpasswd`,
477
+ `mkdir -p /home/root/.ssh`,
478
+ `echo '${fs.readFileSync(
479
+ `/home/dd/engine/engine-private/deploy/id_rsa.pub`,
480
+ 'utf8',
481
+ )}' > /home/root/.ssh/authorized_keys`,
482
+ `chown -R root /home/root/.ssh`,
483
+ `chmod 700 /home/root/.ssh`,
484
+ `chmod 600 /home/root/.ssh/authorized_keys`,
485
+ ]);
486
+ runSteps(nfsHostPath, [
487
+ // `date -s "${shellExec(`date '+%Y-%m-%d %H:%M:%S'`, { stdout: true }).trim()}"`,
488
+ // `date`,
489
+ ...timeZoneSteps,
490
+ ...chronySetUp(chronyConfPath),
491
+ ...keyboardSteps,
492
+ ]);
493
+ }
494
+
495
+ runSteps(
496
+ nfsHostPath,
497
+ cloudConfigFactory(
498
+ { IP_ADDRESS, architecture, host, nfsHostPath, ipaddr, update, gatewayip },
499
+ { consumer_key, consumer_secret, token_key, token_secret },
500
+ ),
501
+ );
502
+ installUbuntuUnderpostTools(nfsHostPath);
503
+ };
504
+
339
505
  try {
340
506
  switch (operator) {
341
507
  case 'save':
@@ -1519,7 +1685,9 @@ EOF`);
1519
1685
  dotenv.config({ path: `${getUnderpostRootPath()}/.env`, override: true });
1520
1686
  const IP_ADDRESS = getLocalIPv4Address();
1521
1687
  const serverip = IP_ADDRESS;
1522
- const tftpRoot = process.env.TFTP_ROOT;
1688
+ const tftpRoot = process.argv.includes('v3.0')
1689
+ ? `/var/snap/maas/common/maas/boot-resources/snapshot-20250720-162718`
1690
+ : process.env.TFTP_ROOT;
1523
1691
  const ipaddr = process.env.RPI4_IP;
1524
1692
  const netmask = process.env.NETMASK;
1525
1693
  const gatewayip = process.env.GATEWAY_IP;
@@ -1769,7 +1937,9 @@ EOF`);
1769
1937
  zipFirmwareName,
1770
1938
  zipFirmwareUrl,
1771
1939
  interfaceName,
1772
- nfsHost;
1940
+ nfsHost,
1941
+ bootResourcesPath,
1942
+ bootKernelPath;
1773
1943
 
1774
1944
  switch (process.argv[3]) {
1775
1945
  case 'rpi4mb':
@@ -1787,7 +1957,7 @@ EOF`);
1787
1957
  resource = resources.find((o) => o.architecture === 'arm64/ga-24.04' && o.name === 'ubuntu/noble');
1788
1958
  name = resource.name;
1789
1959
  architecture = resource.architecture;
1790
- resource = resources.find((o) => o.name === name && o.architecture === architecture);
1960
+ // resource = resources.find((o) => o.name === name && o.architecture === architecture);
1791
1961
  nfsServerRootPath = `${process.env.NFS_EXPORT_PATH}/rpi4mb`;
1792
1962
  // ,anonuid=1001,anongid=100
1793
1963
  // etcExports = `${nfsServerRootPath} *(rw,all_squash,sync,no_root_squash,insecure)`;
@@ -1799,21 +1969,33 @@ EOF`);
1799
1969
  'no_subtree_check',
1800
1970
  'insecure',
1801
1971
  ]})`;
1802
- const resourceData = JSON.parse(
1803
- shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-resource read ${resource.id}`, {
1804
- stdout: true,
1805
- silent: true,
1806
- disableLog: true,
1807
- }),
1808
- );
1809
- const bootFiles = resourceData.sets[Object.keys(resourceData.sets)[0]].files;
1810
- const suffix = architecture.match('xgene') ? '.xgene' : '';
1972
+ if (process.argv.includes('v3.0')) {
1973
+ bootResourcesPath = `/var/snap/maas/common/maas/boot-resources/snapshot-20250720-162718`;
1974
+ bootKernelPath = `/var/snap/maas/common/maas/boot-resources/snapshot-20250720-162718/ubuntu/arm64/hwe-24.04/noble/stable`;
1975
+ kernelFilesPaths = {
1976
+ 'vmlinuz-efi': `${bootKernelPath}/boot-kernel`,
1977
+ 'initrd.img': `${bootKernelPath}/boot-initrd`,
1978
+ squashfs: `${bootKernelPath}/squashfs`,
1979
+ };
1980
+ } else {
1981
+ const resourceData = JSON.parse(
1982
+ shellExec(`maas ${process.env.MAAS_ADMIN_USERNAME} boot-resource read ${resource.id}`, {
1983
+ stdout: true,
1984
+ silent: true,
1985
+ disableLog: true,
1986
+ }),
1987
+ );
1988
+ const bootFiles = resourceData.sets[Object.keys(resourceData.sets)[0]].files;
1989
+ const suffix = architecture.match('xgene') ? '.xgene' : '';
1990
+ bootResourcesPath = `/var/snap/maas/common/maas/image-storage/bootloaders/uefi/arm64`;
1991
+ bootKernelPath = `/var/snap/maas/common/maas/image-storage`;
1992
+ kernelFilesPaths = {
1993
+ 'vmlinuz-efi': `${bootKernelPath}/${bootFiles['boot-kernel' + suffix].filename_on_disk}`,
1994
+ 'initrd.img': `${bootKernelPath}/${bootFiles['boot-initrd' + suffix].filename_on_disk}`,
1995
+ squashfs: `${bootKernelPath}/${bootFiles['squashfs'].filename_on_disk}`,
1996
+ };
1997
+ }
1811
1998
 
1812
- kernelFilesPaths = {
1813
- 'vmlinuz-efi': bootFiles['boot-kernel' + suffix].filename_on_disk,
1814
- 'initrd.img': bootFiles['boot-initrd' + suffix].filename_on_disk,
1815
- squashfs: bootFiles['squashfs'].filename_on_disk,
1816
- };
1817
1999
  const protocol = 'tcp'; // v3 -> tcp, v4 -> udp
1818
2000
 
1819
2001
  const mountOptions = [
@@ -1876,7 +2058,7 @@ EOF`);
1876
2058
 
1877
2059
  // identity:
1878
2060
  // hostname: rpi4
1879
- // username: rpiadmin
2061
+ // username: root
1880
2062
  // password: "{{PASSWORD}}"
1881
2063
 
1882
2064
  // ssh:
@@ -1937,52 +2119,18 @@ BOOT_ORDER=0x21`;
1937
2119
  switch (process.argv[3]) {
1938
2120
  case 'rpi4mb':
1939
2121
  {
1940
- // subnet DHCP snippets
1941
- // # UEFI ARM64
1942
- // if option arch = 00:0B {
1943
- // filename "rpi4mb/pxe/grubaa64.efi";
1944
- // }
1945
- // elsif option arch = 00:13 {
1946
- // filename "http://<IP_ADDRESS>:5248/images/bootloaders/uefi/arm64/grubaa64.efi";
1947
- // option vendor-class-identifier "HTTPClient";
1948
- // }
1949
2122
  for (const file of ['bootaa64.efi', 'grubaa64.efi']) {
1950
- shellExec(
1951
- `sudo cp -a /var/snap/maas/common/maas/image-storage/bootloaders/uefi/arm64/${file} ${tftpRoot}${tftpSubDir}/pxe/${file}`,
1952
- );
2123
+ shellExec(`sudo cp -a ${bootResourcesPath}/${file} ${tftpRoot}${tftpSubDir}/pxe/${file}`);
1953
2124
  }
1954
- // const file = 'bcm2711-rpi-4-b.dtb';
1955
- // shellExec(
1956
- // `sudo cp -a ${firmwarePath}/${file} /var/snap/maas/common/maas/image-storage/bootloaders/uefi/arm64/${file}`,
1957
- // );
1958
-
1959
- // const ipxeSrc = fs
1960
- // .readFileSync(`${tftpRoot}/ipxe.cfg`, 'utf8')
1961
- // .replaceAll('amd64', 'arm64')
1962
- // .replaceAll('${next-server}', IP_ADDRESS);
1963
- // fs.writeFileSync(`${tftpRoot}/ipxe.cfg`, ipxeSrc, 'utf8');
1964
2125
 
1965
2126
  {
1966
2127
  for (const file of Object.keys(kernelFilesPaths)) {
1967
- shellExec(
1968
- `sudo cp -a /var/snap/maas/common/maas/image-storage/${kernelFilesPaths[file]} ${tftpRoot}${tftpSubDir}/pxe/${file}`,
1969
- );
2128
+ shellExec(`sudo cp -a ${kernelFilesPaths[file]} ${tftpRoot}${tftpSubDir}/pxe/${file}`);
1970
2129
  }
1971
- // const configTxtSrc = fs.readFileSync(`${firmwarePath}/config.txt`, 'utf8');
1972
- // fs.writeFileSync(
1973
- // `${tftpRoot}${tftpSubDir}/config.txt`,
1974
- // configTxtSrc
1975
- // .replace(`kernel=kernel8.img`, `kernel=vmlinuz`)
1976
- // .replace(`# max_framebuffers=2`, `max_framebuffers=2`)
1977
- // .replace(`initramfs initramfs8 followkernel`, `initramfs initrd.img followkernel`),
1978
- // 'utf8',
1979
- // );
1980
-
1981
- // grub:
1982
- // set root=(pxe)
1983
-
1984
- // UNDERPOST.NET UEFI/GRUB/MAAS RPi4 commissioning (ARM64)
1985
- const menuentryStr = 'underpost.net rpi4mb maas commissioning (ARM64)';
2130
+
2131
+ fs.mkdirSync(`${tftpRoot}/grub`, { recursive: true });
2132
+
2133
+ const menuentryStr = 'UNDERPOST.NET UEFI/GRUB/MAAS RPi4 commissioning (ARM64)';
1986
2134
  const grubCfgPath = `${tftpRoot}/grub/grub.cfg`;
1987
2135
  fs.writeFileSync(
1988
2136
  grubCfgPath,
@@ -2086,29 +2234,30 @@ BOOT_ORDER=0x21`;
2086
2234
  };
2087
2235
  machine.hostname = machine.hostname.replaceAll(' ', '').replaceAll('.', '');
2088
2236
 
2089
- try {
2090
- let newMachine = shellExec(
2091
- `maas ${process.env.MAAS_ADMIN_USERNAME} machines create ${Object.keys(machine)
2092
- .map((k) => `${k}="${machine[k]}"`)
2093
- .join(' ')}`,
2094
- {
2095
- silent: true,
2096
- stdout: true,
2097
- },
2098
- );
2099
- newMachine = machineFactory(JSON.parse(newMachine));
2100
- machines.push(newMachine);
2101
- console.log(newMachine);
2102
- // commissioning_scripts=90-verify-user.sh
2103
- shellExec(
2104
- `maas ${process.env.MAAS_ADMIN_USERNAME} machine commission ${newMachine.system_id} enable_ssh=1 skip_bmc_config=1 skip_networking=1 skip_storage=1`,
2105
- {
2106
- silent: true,
2107
- },
2108
- );
2109
- } catch (error) {
2110
- logger.error(error, error.stack);
2111
- }
2237
+ if (machine.hostname.match('generic-host'))
2238
+ try {
2239
+ let newMachine = shellExec(
2240
+ `maas ${process.env.MAAS_ADMIN_USERNAME} machines create ${Object.keys(machine)
2241
+ .map((k) => `${k}="${machine[k]}"`)
2242
+ .join(' ')}`,
2243
+ {
2244
+ silent: true,
2245
+ stdout: true,
2246
+ },
2247
+ );
2248
+ newMachine = machineFactory(JSON.parse(newMachine));
2249
+ machines.push(newMachine);
2250
+ console.log(newMachine);
2251
+ // commissioning_scripts=90-verify-user.sh
2252
+ shellExec(
2253
+ `maas ${process.env.MAAS_ADMIN_USERNAME} machine commission ${newMachine.system_id} enable_ssh=1 skip_bmc_config=1 skip_networking=1 skip_storage=1`,
2254
+ {
2255
+ silent: true,
2256
+ },
2257
+ );
2258
+ } catch (error) {
2259
+ logger.error(error, error.stack);
2260
+ }
2112
2261
  }
2113
2262
  // if (discoveries.length > 0) {
2114
2263
  // shellExec(
package/cli.md CHANGED
@@ -1,4 +1,4 @@
1
- ## underpost ci/cd cli v2.8.814
1
+ ## underpost ci/cd cli v2.8.816
2
2
 
3
3
  ### Usage: `underpost [options] [command]`
4
4
  ```
@@ -58,7 +58,7 @@ services:
58
58
  cpus: '0.25'
59
59
  memory: 20M
60
60
  labels: # labels in Compose file instead of Dockerfile
61
- engine.version: '2.8.814'
61
+ engine.version: '2.8.816'
62
62
  networks:
63
63
  - load-balancer
64
64
 
@@ -17,7 +17,7 @@ spec:
17
17
  spec:
18
18
  containers:
19
19
  - name: dd-template-development-blue
20
- image: localhost/rockylinux9-underpost:v2.8.814
20
+ image: localhost/rockylinux9-underpost:v2.8.816
21
21
  # resources:
22
22
  # requests:
23
23
  # memory: "124Ki"
@@ -100,7 +100,7 @@ spec:
100
100
  spec:
101
101
  containers:
102
102
  - name: dd-template-development-green
103
- image: localhost/rockylinux9-underpost:v2.8.814
103
+ image: localhost/rockylinux9-underpost:v2.8.816
104
104
  # resources:
105
105
  # requests:
106
106
  # memory: "124Ki"
@@ -2,6 +2,7 @@
2
2
  set -euo pipefail
3
3
 
4
4
  sudo snap install jq
5
+ # sudo snap install --channel=3.0/stable maas
5
6
  sudo snap install maas
6
7
 
7
8
  # Get default interface and IP address
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "main": "src/index.js",
4
4
  "name": "underpost",
5
- "version": "2.8.814",
5
+ "version": "2.8.816",
6
6
  "description": "pwa api rest template",
7
7
  "scripts": {
8
8
  "start": "env-cmd -f .env.production node --max-old-space-size=8192 src/server",
package/src/index.js CHANGED
@@ -32,7 +32,7 @@ class Underpost {
32
32
  * @type {String}
33
33
  * @memberof Underpost
34
34
  */
35
- static version = 'v2.8.814';
35
+ static version = 'v2.8.816';
36
36
  /**
37
37
  * Repository cli API
38
38
  * @static