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 +1 -1
- package/bin/deploy.js +368 -219
- package/cli.md +1 -1
- package/docker-compose.yml +1 -1
- package/manifests/deployment/dd-template-development/deployment.yaml +2 -2
- package/manifests/maas/maas-setup.sh +1 -0
- package/package.json +1 -1
- package/src/index.js +1 -1
package/README.md
CHANGED
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
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
- ${
|
|
150
|
+
- ${process.env.MAAS_NTP_SERVER}
|
|
142
151
|
ntp_client: chrony
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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:
|
|
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
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
278
|
+
)
|
|
279
|
+
.join('\n');
|
|
205
280
|
|
|
206
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
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:
|
|
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
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
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
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
.
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
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
package/docker-compose.yml
CHANGED
|
@@ -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.
|
|
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.
|
|
103
|
+
image: localhost/rockylinux9-underpost:v2.8.816
|
|
104
104
|
# resources:
|
|
105
105
|
# requests:
|
|
106
106
|
# memory: "124Ki"
|
package/package.json
CHANGED