underpost 2.8.79 → 2.8.82

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.
Files changed (45) hide show
  1. package/.github/workflows/ghpkg.yml +23 -21
  2. package/.github/workflows/npmpkg.yml +16 -11
  3. package/.github/workflows/pwa-microservices-template.page.yml +12 -3
  4. package/.github/workflows/pwa-microservices-template.test.yml +20 -17
  5. package/.vscode/extensions.json +1 -2
  6. package/.vscode/settings.json +3 -0
  7. package/Dockerfile +14 -33
  8. package/README.md +25 -24
  9. package/bin/db.js +1 -0
  10. package/bin/deploy.js +88 -796
  11. package/bin/vs.js +10 -3
  12. package/cli.md +340 -207
  13. package/conf.js +4 -0
  14. package/docker-compose.yml +1 -1
  15. package/manifests/deployment/dd-template-development/deployment.yaml +167 -0
  16. package/manifests/deployment/dd-template-development/proxy.yaml +46 -0
  17. package/manifests/lxd/lxd-admin-profile.yaml +1 -0
  18. package/manifests/lxd/lxd-preseed.yaml +9 -37
  19. package/manifests/lxd/underpost-setup.sh +98 -81
  20. package/manifests/maas/device-scan.sh +43 -0
  21. package/manifests/maas/lxd-preseed.yaml +32 -0
  22. package/manifests/maas/maas-setup.sh +120 -0
  23. package/manifests/maas/nat-iptables.sh +26 -0
  24. package/manifests/mariadb/statefulset.yaml +2 -1
  25. package/manifests/mariadb/storage-class.yaml +10 -0
  26. package/manifests/mongodb-4.4/service-deployment.yaml +2 -2
  27. package/manifests/valkey/service.yaml +3 -9
  28. package/manifests/valkey/statefulset.yaml +10 -12
  29. package/package.json +1 -1
  30. package/src/cli/baremetal.js +1248 -0
  31. package/src/cli/cloud-init.js +528 -0
  32. package/src/cli/cluster.js +424 -240
  33. package/src/cli/deploy.js +27 -3
  34. package/src/cli/env.js +2 -2
  35. package/src/cli/image.js +57 -9
  36. package/src/cli/index.js +252 -231
  37. package/src/cli/lxd.js +314 -81
  38. package/src/index.js +33 -15
  39. package/src/runtime/lampp/Dockerfile +41 -47
  40. package/src/server/conf.js +58 -0
  41. package/src/server/logger.js +3 -3
  42. package/src/server/runtime.js +1 -6
  43. package/src/server/ssl.js +1 -12
  44. package/src/server/valkey.js +3 -3
  45. package/supervisord-openssh-server.conf +0 -5
@@ -0,0 +1,528 @@
1
+ import dotenv from 'dotenv';
2
+ import { shellExec } from '../server/process.js';
3
+ import fs from 'fs-extra';
4
+ import UnderpostBaremetal from './baremetal.js';
5
+ import { loggerFactory } from '../server/logger.js';
6
+ import { getNpmRootPath } from '../server/conf.js';
7
+
8
+ dotenv.config();
9
+
10
+ const logger = loggerFactory(import.meta);
11
+
12
+ /**
13
+ * @class UnderpostCloudInit
14
+ * @description Manages the generation and deployment of cloud-init configuration files
15
+ * and associated scripts for baremetal provisioning. This class provides methods
16
+ * to build various shell scripts and a cloud-init configuration file tailored
17
+ * for MAAS (Metal as a Service) integration.
18
+ */
19
+ class UnderpostCloudInit {
20
+ static API = {
21
+ /**
22
+ * @method buildTools
23
+ * @description Builds and writes various shell scripts and configuration files
24
+ * to the NFS host path, which are then used by the target baremetal machine
25
+ * during the cloud-init process.
26
+ * @param {object} params - The parameters for building the tools.
27
+ * @param {string} params.workflowId - The identifier for the specific workflow configuration.
28
+ * @param {string} params.nfsHostPath - The base path on the NFS host where tools will be written.
29
+ * @param {string} params.hostname - The hostname of the target baremetal machine.
30
+ * @param {object} params.callbackMetaData - Metadata about the callback, used for dynamic configuration.
31
+ * @param {boolean} params.dev - Development mode flag.
32
+ * @returns {void}
33
+ */
34
+ buildTools({ workflowId, nfsHostPath, hostname, callbackMetaData, dev }) {
35
+ // Destructure workflow configuration for easier access.
36
+ const { systemProvisioning, chronyc, networkInterfaceName, debootstrap } =
37
+ UnderpostBaremetal.API.workflowsConfig[workflowId];
38
+ const { timezone, chronyConfPath } = chronyc;
39
+ // Define the specific directory for underpost tools within the NFS host path.
40
+ const nfsHostToolsPath = `${nfsHostPath}/underpost`;
41
+
42
+ // Determine the root path for npm and underpost based on development mode.
43
+ const npmRoot = getNpmRootPath();
44
+ const underpostRoot = dev === true ? '.' : `${npmRoot}/underpost`;
45
+
46
+ // Use a switch statement to handle different system provisioning types.
47
+ switch (systemProvisioning) {
48
+ case 'ubuntu': {
49
+ // Ensure the target directory for tools is clean and exists.
50
+ if (fs.existsSync(`${nfsHostToolsPath}`)) fs.removeSync(`${nfsHostToolsPath}`);
51
+ fs.mkdirSync(`${nfsHostToolsPath}`, { recursive: true });
52
+
53
+ // Build and write the date configuration script.
54
+ logger.info('Build', `${nfsHostToolsPath}/date.sh`);
55
+ fs.writeFileSync(
56
+ `${nfsHostToolsPath}/date.sh`,
57
+ UnderpostBaremetal.API.stepsRender(
58
+ UnderpostBaremetal.API.systemProvisioningFactory[systemProvisioning].timezone({
59
+ timezone,
60
+ chronyConfPath,
61
+ }),
62
+ false,
63
+ ),
64
+ 'utf8',
65
+ );
66
+
67
+ // Build and write the keyboard configuration script.
68
+ logger.info('Build', `${nfsHostToolsPath}/keyboard.sh`);
69
+ fs.writeFileSync(
70
+ `${nfsHostToolsPath}/keyboard.sh`,
71
+ UnderpostBaremetal.API.stepsRender(
72
+ UnderpostBaremetal.API.systemProvisioningFactory[systemProvisioning].keyboard(),
73
+ false,
74
+ ),
75
+ 'utf8',
76
+ );
77
+
78
+ // Build and write the hosts file configuration script.
79
+ logger.info('Build', `${nfsHostToolsPath}/host.sh`);
80
+ fs.writeFileSync(
81
+ `${nfsHostToolsPath}/host.sh`,
82
+ `echo -e "127.0.0.1 localhost\n127.0.1.1 ${hostname}" | tee -a /etc/hosts`,
83
+ 'utf8',
84
+ );
85
+
86
+ // Build and write the DNS configuration script.
87
+ logger.info('Build', `${nfsHostToolsPath}/dns.sh`);
88
+ fs.writeFileSync(
89
+ `${nfsHostToolsPath}/dns.sh`,
90
+ `rm /etc/resolv.conf
91
+ echo 'nameserver 8.8.8.8' > /run/systemd/resolve/stub-resolv.conf
92
+ ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf`,
93
+ 'utf8',
94
+ );
95
+
96
+ // Build and write the main startup script for cloud-init.
97
+ logger.info('Build', `${nfsHostToolsPath}/start.sh`);
98
+ fs.writeFileSync(
99
+ `${nfsHostToolsPath}/start.sh`,
100
+ `#!/bin/bash
101
+ set -x
102
+ # sudo cloud-init --all-stages
103
+ ${UnderpostBaremetal.API.stepsRender(
104
+ [
105
+ `/underpost/date.sh`,
106
+ `sleep 3`,
107
+ `/underpost/reset.sh`,
108
+ `sleep 3`,
109
+ `cloud-init init --local`,
110
+ `sleep 3`,
111
+ `cloud-init init`,
112
+ `sleep 3`,
113
+ `cloud-init modules --mode=config`,
114
+ `sleep 3`,
115
+ `cloud-init modules --mode=final`,
116
+ `sleep 3`,
117
+ `/underpost/enlistment.sh`,
118
+ ],
119
+ false,
120
+ )}`,
121
+ 'utf8',
122
+ );
123
+
124
+ // Build and write the cloud-init reset script.
125
+ logger.info('Build', `${nfsHostToolsPath}/reset.sh`);
126
+ fs.writeFileSync(
127
+ `${nfsHostToolsPath}/reset.sh`,
128
+ `sudo cloud-init clean --seed --configs all --machine-id # --logs
129
+ sudo rm -rf /var/lib/cloud/*
130
+ echo '' > /var/log/cloud-init.log
131
+ echo '' > /var/log/cloud-init-output.log`,
132
+ 'utf8',
133
+ );
134
+
135
+ // Build and write the cloud-init help script.
136
+ logger.info('Build', `${nfsHostToolsPath}/help.sh`);
137
+ fs.writeFileSync(
138
+ `${nfsHostToolsPath}/help.sh`,
139
+ `echo "=== Cloud init utils ==="
140
+ echo "sudo cloud-init --all-stages"
141
+ echo "sudo cloud-init clean --logs --seed --configs all --machine-id --reboot"
142
+ echo "sudo cloud-init init --local"
143
+ echo "sudo cloud-init init"
144
+ echo "sudo cloud-init modules --mode=config"
145
+ echo "sudo cloud-init modules --mode=final"`,
146
+ 'utf8',
147
+ );
148
+
149
+ // Build and write the test script for verifying configuration.
150
+ logger.info('Build', `${nfsHostToolsPath}/test.sh`);
151
+ fs.writeFileSync(
152
+ `${nfsHostToolsPath}/test.sh`,
153
+ `echo -e "\n=== Current date/time ==="
154
+ date '+%Y-%m-%d %H:%M:%S'
155
+ echo -e "\n=== Keyboard layout ==="
156
+ cat /etc/default/keyboard
157
+ echo -e "\n=== Registered users ==="
158
+ cut -d: -f1 /etc/passwd`,
159
+ 'utf8',
160
+ );
161
+
162
+ // Build and write the shutdown script.
163
+ logger.info('Build', `${nfsHostToolsPath}/shutdown.sh`);
164
+ fs.writeFileSync(`${nfsHostToolsPath}/shutdown.sh`, `sudo shutdown -h now`, 'utf8');
165
+
166
+ // Build and write the MAC address retrieval script.
167
+ logger.info('Build', `${nfsHostToolsPath}/mac.sh`);
168
+ fs.writeFileSync(
169
+ `${nfsHostToolsPath}/mac.sh`,
170
+ `echo "$(cat /sys/class/net/${networkInterfaceName}/address)" > /underpost/mac`,
171
+ 'utf8',
172
+ );
173
+
174
+ // Copy the device scan script from manifests.
175
+ logger.info('Build', `${nfsHostToolsPath}/device_scan.sh`);
176
+ fs.copySync(`${underpostRoot}/manifests/maas/device-scan.sh`, `${nfsHostToolsPath}/device_scan.sh`);
177
+
178
+ // Build and write the config path script.
179
+ logger.info('Build', `${nfsHostToolsPath}/config-path.sh`);
180
+ fs.writeFileSync(`${nfsHostToolsPath}/config-path.sh`, `echo "/etc/cloud/cloud.cfg.d/90_maas.cfg"`, 'utf8');
181
+
182
+ // Build and write the MAAS enlistment script.
183
+ logger.info('Build', `${nfsHostToolsPath}/enlistment.sh`);
184
+ fs.writeFileSync(
185
+ `${nfsHostToolsPath}/enlistment.sh`,
186
+ `#!/bin/bash
187
+ set -x
188
+
189
+ # ------------------------------------------------------------
190
+ # Step: Commission a machine in MAAS using OAuth1 authentication
191
+ # ------------------------------------------------------------
192
+
193
+ MACHINE_ID=$(cat /underpost/system-id)
194
+ CONSUMER_KEY=$(cat /underpost/consumer-key)
195
+ TOKEN_KEY=$(cat /underpost/token-key)
196
+ TOKEN_SECRET=$(cat /underpost/token-secret)
197
+
198
+ echo ">>> Starting MAAS machine commissioning for system_id: $MACHINE_ID …"
199
+
200
+ curl -X POST \\
201
+ --fail --location --verbose --include --raw --trace-ascii /dev/stdout\\
202
+ --header "Authorization:\\
203
+ OAuth oauth_version=1.0,\\
204
+ oauth_signature_method=PLAINTEXT,\\
205
+ oauth_consumer_key=$CONSUMER_KEY,\\
206
+ oauth_token=$TOKEN_KEY,\\
207
+ oauth_signature=&$TOKEN_SECRET,\\
208
+ oauth_nonce=$(uuidgen),\\
209
+ oauth_timestamp=$(date +%s)"\\
210
+ http://${callbackMetaData.runnerHost.ip}:5240/MAAS/api/2.0/machines/$MACHINE_ID/op-commission \\
211
+ 2>&1 | tee /underpost/enlistment.log || echo "ERROR: MAAS commissioning returned code $?"`,
212
+ 'utf8',
213
+ );
214
+
215
+ // Import SSH keys for root user.
216
+ logger.info('Import ssh keys');
217
+ shellExec(`sudo rm -rf ${nfsHostPath}/root/.ssh`);
218
+ shellExec(`sudo rm -rf ${nfsHostPath}/home/root/.ssh`); // Ensure home root .ssh is also clean.
219
+ logger.info('Copy', `/root/.ssh -> ${nfsHostPath}/root/.ssh`);
220
+ fs.copySync(`/root/.ssh`, `${nfsHostPath}/root/.ssh`);
221
+
222
+ // Enable execution permissions for all generated scripts and run a test.
223
+ logger.info('Enable tools execution and test');
224
+ UnderpostBaremetal.API.crossArchRunner({
225
+ nfsHostPath,
226
+ debootstrapArch: debootstrap.image.architecture,
227
+ callbackMetaData,
228
+ steps: [
229
+ `chmod +x /underpost/date.sh`,
230
+ `chmod +x /underpost/keyboard.sh`,
231
+ `chmod +x /underpost/dns.sh`,
232
+ `chmod +x /underpost/help.sh`,
233
+ `chmod +x /underpost/config-path.sh`,
234
+ `chmod +x /underpost/host.sh`,
235
+ `chmod +x /underpost/test.sh`,
236
+ `chmod +x /underpost/start.sh`,
237
+ `chmod +x /underpost/reset.sh`,
238
+ `chmod +x /underpost/shutdown.sh`,
239
+ `chmod +x /underpost/device_scan.sh`,
240
+ `chmod +x /underpost/mac.sh`,
241
+ `chmod +x /underpost/enlistment.sh`,
242
+ `sudo chmod 700 ~/.ssh/`, // Set secure permissions for .ssh directory.
243
+ `sudo chmod 600 ~/.ssh/authorized_keys`, // Set secure permissions for authorized_keys.
244
+ `sudo chmod 644 ~/.ssh/known_hosts`, // Set permissions for known_hosts.
245
+ `sudo chmod 600 ~/.ssh/id_rsa`, // Set secure permissions for private key.
246
+ `sudo chmod 600 /etc/ssh/ssh_host_ed25519_key`, // Set secure permissions for host key.
247
+ `chown -R root:root ~/.ssh`, // Ensure root owns the .ssh directory.
248
+ `/underpost/test.sh`, // Run the test script to verify setup.
249
+ ],
250
+ });
251
+
252
+ break;
253
+ }
254
+ default:
255
+ // Throw an error if an unsupported system provisioning type is provided.
256
+ throw new Error('Invalid system provisioning: ' + systemProvisioning);
257
+ }
258
+ },
259
+
260
+ /**
261
+ * @method configFactory
262
+ * @description Generates the cloud-init configuration file (`90_maas.cfg`)
263
+ * for MAAS integration. This configuration includes hostname, network settings,
264
+ * user accounts, SSH keys, timezone, NTP, and various cloud-init modules.
265
+ * @param {object} params - The parameters for generating the configuration.
266
+ * @param {string} params.controlServerIp - The IP address of the MAAS control server.
267
+ * @param {string} params.hostname - The hostname of the target baremetal machine.
268
+ * @param {string} params.commissioningDeviceIp - The IP address to assign to the commissioning device.
269
+ * @param {string} params.gatewayip - The gateway IP address for the network.
270
+ * @param {boolean} params.auth - Flag indicating whether to include MAAS authentication credentials.
271
+ * @param {string} params.mac - The MAC address of the network interface.
272
+ * @param {string} params.timezone - The timezone to set for the machine.
273
+ * @param {string} params.chronyConfPath - The path to the Chrony configuration file.
274
+ * @param {string} params.networkInterfaceName - The name of the primary network interface.
275
+ * @param {object} [authCredentials={}] - Optional MAAS authentication credentials.
276
+ * @param {string} [path='/etc/cloud/cloud.cfg.d/90_maas.cfg'] - The target path for the cloud-init configuration file.
277
+ * @returns {string} The generated cloud-init configuration content.
278
+ */
279
+ configFactory(
280
+ {
281
+ controlServerIp,
282
+ hostname,
283
+ commissioningDeviceIp,
284
+ gatewayip,
285
+ auth,
286
+ mac,
287
+ timezone,
288
+ chronyConfPath,
289
+ networkInterfaceName,
290
+ },
291
+ authCredentials = { consumer_key: '', consumer_secret: '', token_key: '', token_secret: '' },
292
+ path = '/etc/cloud/cloud.cfg.d/90_maas.cfg',
293
+ ) {
294
+ const { consumer_key, consumer_secret, token_key, token_secret } = authCredentials;
295
+ // Configure cloud-init for MAAS using a heredoc string.
296
+ return `cat <<EOF_MAAS_CFG > ${path}
297
+ #cloud-config
298
+
299
+ hostname: ${hostname}
300
+ fqdn: ${hostname}.maas
301
+ # prefer_fqdn_over_hostname: true
302
+ # metadata_url: http://${controlServerIp}:5240/MAAS/metadata
303
+ # metadata_url: http://${controlServerIp}:5248/MAAS/metadata
304
+
305
+ # Check:
306
+ # /MAAS/metadata/latest/enlist-preseed/?op=get_enlist_preseed
307
+
308
+ # Debug:
309
+ # https://maas.io/docs/how-to-use-logging
310
+
311
+ datasource_list: [ MAAS ]
312
+ datasource:
313
+ MAAS:
314
+ metadata_url: http://${controlServerIp}:5240/MAAS/metadata/
315
+ ${
316
+ // Conditionally include authentication details if 'auth' flag is true.
317
+ !auth
318
+ ? ''
319
+ : `consumer_key: ${consumer_key}
320
+ consumer_secret: ${consumer_secret}
321
+ token_key: ${token_key}
322
+ token_secret: ${token_secret}`
323
+ }
324
+
325
+
326
+ users:
327
+ - name: ${process.env.MAAS_ADMIN_USERNAME}
328
+ sudo: ["ALL=(ALL) NOPASSWD:ALL"]
329
+ shell: /bin/bash
330
+ lock_passwd: false
331
+ groups: sudo,users,admin,wheel,lxd
332
+ plain_text_passwd: '${process.env.MAAS_ADMIN_USERNAME}'
333
+ ssh_authorized_keys:
334
+ - ${fs.readFileSync(`/home/dd/engine/engine-private/deploy/id_rsa.pub`, 'utf8')}
335
+
336
+ # manage_resolv_conf: true
337
+ # resolv_conf:
338
+ # nameservers: [8.8.8.8]
339
+
340
+ # keyboard:
341
+ # layout: es
342
+
343
+ # check timedatectl on hostname
344
+ # timezone: America/Santiago
345
+ timezone: ${timezone}
346
+
347
+ ntp:
348
+ enabled: true
349
+ servers:
350
+ - ${process.env.MAAS_NTP_SERVER}
351
+ ntp_client: chrony
352
+ config:
353
+ confpath: ${chronyConfPath}
354
+
355
+ # ssh:
356
+ # allow-pw: false
357
+ # install-server: true
358
+
359
+ # ssh_pwauth: false
360
+
361
+ package_update: true
362
+ package_upgrade: true
363
+ packages:
364
+ - git
365
+ - htop
366
+ - snapd
367
+ - chrony
368
+ resize_rootfs: false
369
+ growpart:
370
+ mode: "off"
371
+ network:
372
+ version: 2
373
+ ethernets:
374
+ ${networkInterfaceName}:
375
+ match:
376
+ macaddress: "${mac}"
377
+ mtu: 1500
378
+ set-name: ${networkInterfaceName}
379
+ dhcp4: false
380
+ addresses:
381
+ - ${commissioningDeviceIp}/24
382
+ routes:
383
+ - to: default
384
+ via: ${gatewayip}
385
+ # gateway4: ${gatewayip}
386
+ nameservers:
387
+ addresses:
388
+ - ${process.env.MAAS_DNS}
389
+
390
+ final_message: "====== Cloud init finished ======"
391
+
392
+ # power_state:
393
+ # mode: reboot
394
+ # message: Rebooting after initial setup
395
+ # timeout: 30
396
+ # condition: True
397
+
398
+ bootcmd:
399
+ - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
400
+ - echo "Init bootcmd"
401
+ - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
402
+ ${UnderpostBaremetal.API.stepsRender(
403
+ [`/underpost/dns.sh`, `/underpost/host.sh`, `/underpost/mac.sh`, `cat /underpost/mac`],
404
+ true,
405
+ )}
406
+ runcmd:
407
+ - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
408
+ - echo "Init runcmd"
409
+ - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
410
+
411
+ # If this is set, 'root' will not be able to ssh in and they
412
+ # will get a message to login instead as the default $user
413
+ disable_root: true
414
+
415
+ # This will cause the set+update hostname module to not operate (if true)
416
+ preserve_hostname: false
417
+
418
+ # The modules that run in the 'init' stage
419
+ cloud_init_modules:
420
+ - migrator
421
+ - seed_random
422
+ - bootcmd
423
+ - write-files
424
+ - growpart
425
+ - resizefs
426
+ - set_hostname
427
+ - update_hostname
428
+ - update_etc_hosts
429
+ - ca-certs
430
+ - rsyslog
431
+ - users-groups
432
+ - ssh
433
+
434
+ # The modules that run in the 'config' stage
435
+ cloud_config_modules:
436
+ # Emit the cloud config ready event
437
+ # this can be used by upstart jobs for 'start on cloud-config'.
438
+ - emit_upstart
439
+ - disk_setup
440
+ - mounts
441
+ - ssh-import-id
442
+ - locale
443
+ - set-passwords
444
+ - grub-dpkg
445
+ - apt-pipelining
446
+ - apt-configure
447
+ - package-update-upgrade-install
448
+ - landscape
449
+ - timezone
450
+ - puppet
451
+ - chef
452
+ - salt-minion
453
+ - mcollective
454
+ - disable-ec2-metadata
455
+ - runcmd
456
+ - byobu
457
+ - ssh-import-id
458
+ - ntp
459
+
460
+
461
+ # phone_home:
462
+ # url: "http://${controlServerIp}:5240/MAAS/metadata/v1/?op=phone_home"
463
+ # post: all
464
+ # tries: 3
465
+
466
+ # The modules that run in the 'final' stage
467
+ cloud_final_modules:
468
+ - rightscale_userdata
469
+ - scripts-vendor
470
+ - scripts-per-once
471
+ - scripts-per-boot
472
+ # - scripts-per-instance
473
+ # - scripts-user
474
+ - ssh-authkey-fingerprints
475
+ - keys-to-console
476
+ # - phone-home
477
+ - final-message
478
+ - power-state-change
479
+ EOF_MAAS_CFG`;
480
+ },
481
+
482
+ /**
483
+ * @method authCredentialsFactory
484
+ * @description Retrieves MAAS API key credentials from the MAAS CLI.
485
+ * This method parses the output of `maas apikey` to extract the consumer key,
486
+ * consumer secret, token key, and token secret.
487
+ * @returns {object} An object containing the MAAS authentication credentials.
488
+ * @throws {Error} If the MAAS API key format is invalid.
489
+ */
490
+ authCredentialsFactory() {
491
+ // Expected formats:
492
+ // <consumer_key>:<consumer_token>:<secret> (older format)
493
+ // <consumer_key>:<consumer_secret>:<token_key>:<token_secret> (newer format)
494
+ // Commands used to generate API keys:
495
+ // maas apikey --with-names --username ${process.env.MAAS_ADMIN_USERNAME}
496
+ // maas ${process.env.MAAS_ADMIN_USERNAME} account create-authorisation-token
497
+ // maas apikey --generate --username ${process.env.MAAS_ADMIN_USERNAME}
498
+ // Reference: https://github.com/CanonicalLtd/maas-docs/issues/647
499
+
500
+ const parts = shellExec(`maas apikey --with-names --username ${process.env.MAAS_ADMIN_USERNAME}`, {
501
+ stdout: true,
502
+ })
503
+ .trim()
504
+ .split(`\n`)[0] // Take only the first line of output.
505
+ .split(':'); // Split by colon to get individual parts.
506
+
507
+ let consumer_key, consumer_secret, token_key, token_secret;
508
+
509
+ // Determine the format of the API key and assign parts accordingly.
510
+ if (parts.length === 4) {
511
+ [consumer_key, consumer_secret, token_key, token_secret] = parts;
512
+ } else if (parts.length === 3) {
513
+ // Handle older 3-part format, setting consumer_secret as empty.
514
+ [consumer_key, token_key, token_secret] = parts;
515
+ consumer_secret = '""';
516
+ token_secret = token_secret.split(' MAAS consumer')[0].trim(); // Clean up token secret.
517
+ } else {
518
+ // Throw an error if the format is not recognized.
519
+ throw new Error('Invalid token format');
520
+ }
521
+
522
+ logger.info('Maas api token generated', { consumer_key, consumer_secret, token_key, token_secret });
523
+ return { consumer_key, consumer_secret, token_key, token_secret };
524
+ },
525
+ };
526
+ }
527
+
528
+ export default UnderpostCloudInit;