@underpostnet/underpost 2.96.1 → 2.97.0

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.
@@ -42,7 +42,7 @@ class UnderpostCloudInit {
42
42
  */
43
43
  buildTools({ workflowId, nfsHostPath, hostname, callbackMetaData, dev }) {
44
44
  // Destructure workflow configuration for easier access.
45
- const { systemProvisioning, chronyc, networkInterfaceName, debootstrap } =
45
+ const { chronyc, networkInterfaceName, debootstrap, keyboard } =
46
46
  UnderpostBaremetal.API.loadWorkflowsConfig()[workflowId];
47
47
  const { timezone, chronyConfPath } = chronyc;
48
48
  // Define the specific directory for underpost tools within the NFS host path.
@@ -51,7 +51,7 @@ class UnderpostCloudInit {
51
51
  // Determine the root path for npm and underpost based on development mode.
52
52
  const npmRoot = getNpmRootPath();
53
53
  const underpostRoot = dev === true ? '.' : `${npmRoot}/underpost`;
54
-
54
+ const systemProvisioning = 'ubuntu';
55
55
  // Use a switch statement to handle different system provisioning types.
56
56
  switch (systemProvisioning) {
57
57
  case 'ubuntu': {
@@ -78,7 +78,7 @@ class UnderpostCloudInit {
78
78
  fs.writeFileSync(
79
79
  `${nfsHostToolsPath}/keyboard.sh`,
80
80
  UnderpostBaremetal.API.stepsRender(
81
- UnderpostBaremetal.API.systemProvisioningFactory[systemProvisioning].keyboard(),
81
+ UnderpostBaremetal.API.systemProvisioningFactory[systemProvisioning].keyboard(keyboard.layout),
82
82
  false,
83
83
  ),
84
84
  'utf8',
@@ -190,10 +190,6 @@ cat /etc/default/keyboard`,
190
190
  logger.info('Build', `${nfsHostToolsPath}/device_scan.sh`);
191
191
  fs.copySync(`${underpostRoot}/scripts/device-scan.sh`, `${nfsHostToolsPath}/device_scan.sh`);
192
192
 
193
- // Build and write the config path script.
194
- logger.info('Build', `${nfsHostToolsPath}/config-path.sh`);
195
- fs.writeFileSync(`${nfsHostToolsPath}/config-path.sh`, `echo "/etc/cloud/cloud.cfg.d/90_maas.cfg"`, 'utf8');
196
-
197
193
  // Build and write the MAAS enlistment script.
198
194
  logger.info('Build', `${nfsHostToolsPath}/enlistment.sh`);
199
195
  fs.writeFileSync(
@@ -240,36 +236,6 @@ curl -X POST \\
240
236
  logger.info('Copy', `/root/.ssh -> ${nfsHostPath}/root/.ssh`);
241
237
  fs.copySync(`/root/.ssh`, `${nfsHostPath}/root/.ssh`);
242
238
 
243
- // Enable execution permissions for all generated scripts and run a test.
244
- logger.info('Enable tools execution and test');
245
- UnderpostBaremetal.API.crossArchRunner({
246
- nfsHostPath,
247
- debootstrapArch: debootstrap.image.architecture,
248
- callbackMetaData,
249
- steps: [
250
- `chmod +x /underpost/date.sh`,
251
- `chmod +x /underpost/keyboard.sh`,
252
- `chmod +x /underpost/dns.sh`,
253
- `chmod +x /underpost/help.sh`,
254
- `chmod +x /underpost/config-path.sh`,
255
- `chmod +x /underpost/host.sh`,
256
- `chmod +x /underpost/test.sh`,
257
- `chmod +x /underpost/start.sh`,
258
- `chmod +x /underpost/reset.sh`,
259
- `chmod +x /underpost/shutdown.sh`,
260
- `chmod +x /underpost/device_scan.sh`,
261
- `chmod +x /underpost/mac.sh`,
262
- `chmod +x /underpost/enlistment.sh`,
263
- `sudo chmod 700 ~/.ssh/`, // Set secure permissions for .ssh directory.
264
- `sudo chmod 600 ~/.ssh/authorized_keys`, // Set secure permissions for authorized_keys.
265
- `sudo chmod 644 ~/.ssh/known_hosts`, // Set permissions for known_hosts.
266
- `sudo chmod 600 ~/.ssh/id_rsa`, // Set secure permissions for private key.
267
- `sudo chmod 600 /etc/ssh/ssh_host_ed25519_key`, // Set secure permissions for host key.
268
- `chown -R root:root ~/.ssh`, // Ensure root owns the .ssh directory.
269
- `/underpost/test.sh`, // Run the test script to verify setup.
270
- ],
271
- });
272
-
273
239
  break;
274
240
  }
275
241
  default:
@@ -280,7 +246,7 @@ curl -X POST \\
280
246
 
281
247
  /**
282
248
  * @method configFactory
283
- * @description Generates the cloud-init configuration file (`90_maas.cfg`)
249
+ * @description Generates the cloud-init configuration file
284
250
  * for MAAS integration. This configuration includes hostname, network settings,
285
251
  * user accounts, SSH keys, timezone, NTP, and various cloud-init modules.
286
252
  * @param {object} params - The parameters for generating the configuration.
@@ -288,14 +254,15 @@ curl -X POST \\
288
254
  * @param {string} params.hostname - The hostname of the target baremetal machine.
289
255
  * @param {string} params.commissioningDeviceIp - The IP address to assign to the commissioning device.
290
256
  * @param {string} params.gatewayip - The gateway IP address for the network.
291
- * @param {boolean} params.auth - Flag indicating whether to include MAAS authentication credentials.
292
257
  * @param {string} params.mac - The MAC address of the network interface.
293
258
  * @param {string} params.timezone - The timezone to set for the machine.
294
259
  * @param {string} params.chronyConfPath - The path to the Chrony configuration file.
295
260
  * @param {string} params.networkInterfaceName - The name of the primary network interface.
261
+ * @param {boolean} params.ubuntuToolsBuild - Flag to determine if Ubuntu tools should be built.
262
+ * @param {string} [params.bootcmd] - Optional custom commands to run during boot.
263
+ * @param {string} [params.runcmd] - Optional custom commands to run during first boot.
296
264
  * @param {object} [authCredentials={}] - Optional MAAS authentication credentials.
297
- * @param {string} [path='/etc/cloud/cloud.cfg.d/90_maas.cfg'] - The target path for the cloud-init configuration file.
298
- * @returns {string} The generated cloud-init configuration content.
265
+ * @returns {object} The generated cloud-init configuration content.
299
266
  * @memberof UnderpostCloudInit
300
267
  */
301
268
  configFactory(
@@ -304,204 +271,179 @@ curl -X POST \\
304
271
  hostname,
305
272
  commissioningDeviceIp,
306
273
  gatewayip,
307
- auth,
308
274
  mac,
309
275
  timezone,
310
276
  chronyConfPath,
311
277
  networkInterfaceName,
278
+ ubuntuToolsBuild,
279
+ bootcmd: bootcmdParam,
280
+ runcmd: runcmdParam,
312
281
  },
313
282
  authCredentials = { consumer_key: '', consumer_secret: '', token_key: '', token_secret: '' },
314
- path = '/etc/cloud/cloud.cfg.d/90_maas.cfg',
315
283
  ) {
316
284
  const { consumer_key, consumer_secret, token_key, token_secret } = authCredentials;
317
- // Configure cloud-init for MAAS using a heredoc string.
318
- return `cat <<EOF_MAAS_CFG > ${path}
319
- #cloud-config
320
-
321
- hostname: ${hostname}
322
- fqdn: ${hostname}.maas
323
- # prefer_fqdn_over_hostname: true
324
- # metadata_url: http://${controlServerIp}:5240/MAAS/metadata
325
- # metadata_url: http://${controlServerIp}:5248/MAAS/metadata
326
-
327
- # Check:
328
- # /MAAS/metadata/latest/enlist-preseed/?op=get_enlist_preseed
329
-
330
- # Debug:
331
- # https://maas.io/docs/how-to-use-logging
332
-
333
- datasource_list: [ MAAS ]
334
- datasource:
335
- MAAS:
336
- metadata_url: http://${controlServerIp}:5240/MAAS/metadata/
337
- ${
338
- // Conditionally include authentication details if 'auth' flag is true.
339
- !auth
340
- ? ''
341
- : `consumer_key: ${consumer_key}
342
- consumer_secret: ${consumer_secret}
343
- token_key: ${token_key}
344
- token_secret: ${token_secret}`
345
- }
346
-
347
-
348
- users:
349
- - name: ${process.env.MAAS_ADMIN_USERNAME}
350
- sudo: ["ALL=(ALL) NOPASSWD:ALL"]
351
- shell: /bin/bash
352
- lock_passwd: false
353
- groups: sudo,users,admin,wheel,lxd
354
- plain_text_passwd: '${process.env.MAAS_ADMIN_USERNAME}'
355
- ssh_authorized_keys:
356
- - ${fs.readFileSync(`/home/dd/engine/engine-private/deploy/id_rsa.pub`, 'utf8')}
357
-
358
- # manage_resolv_conf: true
359
- # resolv_conf:
360
- # nameservers: [8.8.8.8]
361
-
362
- # keyboard:
363
- # layout: es
364
-
365
- # check timedatectl on hostname
366
- # timezone: America/Santiago
367
- timezone: ${timezone}
368
-
369
- ntp:
370
- enabled: true
371
- servers:
372
- - ${process.env.MAAS_NTP_SERVER}
373
- ntp_client: chrony
374
- config:
375
- confpath: ${chronyConfPath}
376
-
377
- # ssh:
378
- # allow-pw: false
379
- # install-server: true
380
-
381
- # ssh_pwauth: false
382
-
383
- package_update: true
384
- package_upgrade: true
385
- packages:
386
- - git
387
- - htop
388
- - snapd
389
- - chrony
390
- - lldpd
391
- - lshw
392
-
393
- resize_rootfs: false
394
- growpart:
395
- mode: "off"
396
- network:
397
- version: 2
398
- ethernets:
399
- ${networkInterfaceName}:
400
- match:
401
- macaddress: "${mac}"
402
- mtu: 1500
403
- set-name: ${networkInterfaceName}
404
- dhcp4: false
405
- addresses:
406
- - ${commissioningDeviceIp}/24
407
- routes:
408
- - to: default
409
- via: ${gatewayip}
410
- # gateway4: ${gatewayip}
411
- nameservers:
412
- addresses:
413
- - ${process.env.MAAS_DNS}
414
-
415
- final_message: "====== Cloud init finished ======"
416
-
417
- # power_state:
418
- # mode: reboot
419
- # message: Rebooting after initial setup
420
- # timeout: 30
421
- # condition: True
422
-
423
- bootcmd:
424
- - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
425
- - echo "Init bootcmd"
426
- - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
427
- ${UnderpostBaremetal.API.stepsRender(
428
- [`/underpost/dns.sh`, `/underpost/host.sh`, `/underpost/mac.sh`, `cat /underpost/mac`],
429
- true,
430
- )}
431
- runcmd:
432
- - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
433
- - echo "Init runcmd"
434
- - echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
435
-
436
- # If this is set, 'root' will not be able to ssh in and they
437
- # will get a message to login instead as the default $user
438
- disable_root: true
439
-
440
- # This will cause the set+update hostname module to not operate (if true)
441
- preserve_hostname: false
442
-
443
- # The modules that run in the 'init' stage
444
- cloud_init_modules:
445
- - migrator
446
- - seed_random
447
- - bootcmd
448
- - write-files
449
- - growpart
450
- - resizefs
451
- - set_hostname
452
- - update_hostname
453
- - update_etc_hosts
454
- - ca-certs
455
- - rsyslog
456
- - users-groups
457
- - ssh
458
-
459
- # The modules that run in the 'config' stage
460
- cloud_config_modules:
461
- # Emit the cloud config ready event
462
- # this can be used by upstart jobs for 'start on cloud-config'.
463
- - emit_upstart
464
- - disk_setup
465
- - mounts
466
- - ssh-import-id
467
- - locale
468
- - set-passwords
469
- - grub-dpkg
470
- - apt-pipelining
471
- - apt-configure
472
- - package-update-upgrade-install
473
- - landscape
474
- - timezone
475
- - puppet
476
- - chef
477
- - salt-minion
478
- - mcollective
479
- - disable-ec2-metadata
480
- - runcmd
481
- - byobu
482
- - ssh-import-id
483
- - ntp
484
-
485
-
486
- # phone_home:
487
- # url: "http://${controlServerIp}:5240/MAAS/metadata/v1/?op=phone_home"
488
- # post: all
489
- # tries: 3
490
-
491
- # The modules that run in the 'final' stage
492
- cloud_final_modules:
493
- - rightscale_userdata
494
- - scripts-vendor
495
- - scripts-per-once
496
- - scripts-per-boot
497
- # - scripts-per-instance
498
- - scripts-user
499
- - ssh-authkey-fingerprints
500
- - keys-to-console
501
- # - phone-home
502
- - final-message
503
- - power-state-change
504
- EOF_MAAS_CFG`;
285
+
286
+ let bootcmd = [
287
+ 'echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"',
288
+ 'echo "Init bootcmd"',
289
+ 'echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"',
290
+ ];
291
+
292
+ if (ubuntuToolsBuild) {
293
+ bootcmd = [
294
+ ...bootcmd,
295
+ ...UnderpostBaremetal.API.stepsRender(
296
+ [`/underpost/dns.sh`, `/underpost/host.sh`, `/underpost/mac.sh`, `cat /underpost/mac`],
297
+ false,
298
+ ).split('\n'),
299
+ ];
300
+ }
301
+
302
+ if (bootcmdParam) {
303
+ bootcmd = [...bootcmd, ...bootcmdParam.split(',')];
304
+ }
305
+
306
+ let runcmd = [
307
+ 'echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"',
308
+ 'echo "Init runcmd"',
309
+ 'echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"',
310
+ ];
311
+
312
+ if (runcmdParam) {
313
+ runcmd = [...runcmd, ...runcmdParam.split(',')];
314
+ }
315
+
316
+ const cloudConfigSrc = UnderpostCloudInit.API.generateCloudConfig({
317
+ hostname,
318
+ fqdn: `${hostname}.maas`,
319
+ datasource_list: ['MAAS'],
320
+ datasource: {
321
+ MAAS: {
322
+ metadata_url: `http://${controlServerIp}:5240/MAAS/metadata/`,
323
+ ...(authCredentials?.consumer_key
324
+ ? {
325
+ consumer_key,
326
+ consumer_secret,
327
+ token_key,
328
+ token_secret,
329
+ }
330
+ : {}),
331
+ },
332
+ },
333
+ users: [
334
+ {
335
+ name: process.env.MAAS_ADMIN_USERNAME,
336
+ sudo: ['ALL=(ALL) NOPASSWD:ALL'],
337
+ shell: '/bin/bash',
338
+ lock_passwd: false,
339
+ groups: 'sudo,users,admin,wheel,lxd',
340
+ plain_text_passwd: process.env.MAAS_ADMIN_USERNAME,
341
+ ssh_authorized_keys: [fs.readFileSync(`/home/dd/engine/engine-private/deploy/id_rsa.pub`, 'utf8')],
342
+ },
343
+ ],
344
+ timezone,
345
+ ntp: {
346
+ enabled: true,
347
+ servers: [process.env.MAAS_NTP_SERVER],
348
+ ntp_client: 'chrony',
349
+ config: { confpath: chronyConfPath },
350
+ },
351
+ package_update: true,
352
+ package_upgrade: true,
353
+ packages: [
354
+ 'git',
355
+ 'htop',
356
+ 'curl',
357
+ 'wget',
358
+ 'chrony',
359
+ 'lldpd',
360
+ 'lshw',
361
+ 'smartmontools',
362
+ 'net-tools',
363
+ 'util-linux',
364
+ ],
365
+ resize_rootfs: false,
366
+ growpart: { mode: 'off' },
367
+ network: {
368
+ version: 2,
369
+ ethernets: {
370
+ [networkInterfaceName]: {
371
+ match: { macaddress: mac },
372
+ mtu: 1500,
373
+ 'set-name': networkInterfaceName,
374
+ dhcp4: false,
375
+ addresses: [`${commissioningDeviceIp}/24`],
376
+ routes: [{ to: 'default', via: gatewayip }],
377
+ nameservers: { addresses: [process.env.MAAS_DNS] },
378
+ },
379
+ },
380
+ },
381
+ final_message: '====== Cloud init finished ======',
382
+ bootcmd,
383
+ runcmd,
384
+ disable_root: true,
385
+ preserve_hostname: false,
386
+ cloud_init_modules: [
387
+ // minimal for commissioning
388
+ 'bootcmd', // run very early commands (useful to inject things)
389
+ 'write-files', // write files (commissioning scripts, helpers)
390
+ 'set_hostname',
391
+ 'update_hostname',
392
+ 'update_etc_hosts',
393
+ 'ca-certs',
394
+ 'rsyslog', // remote logging for diagnosis
395
+ 'ssh', // enable/configure SSH for temporary access
396
+
397
+ // optional modules (commented out by default)
398
+ // 'migrator',
399
+ // 'seed_random',
400
+ // 'growpart',
401
+ // 'resizefs',
402
+ // 'users-groups',
403
+ ],
404
+ cloud_config_modules: [
405
+ // minimal so MAAS can run commissioning scripts
406
+ 'runcmd', // commissioning / final script execution
407
+ 'mounts', // mount devices during commissioning if needed
408
+ // 'ntp', // optional enable if you want time sync
409
+
410
+ // typically not required for basic commissioning (commented)
411
+ // 'emit_upstart',
412
+ // 'disk_setup',
413
+ // 'ssh-import-id',
414
+ // 'locale',
415
+ // 'set-passwords',
416
+ // 'grub-dpkg',
417
+ // 'apt-pipelining',
418
+ // 'apt-configure',
419
+ // 'package-update-upgrade-install', // heavy; do NOT enable by default
420
+ // 'landscape',
421
+ // 'timezone',
422
+ // 'puppet',
423
+ // 'chef',
424
+ // 'salt-minion',
425
+ // 'mcollective',
426
+ // 'disable-ec2-metadata',
427
+ // 'byobu',
428
+ // 'ssh-import-id', // duplicate in original list
429
+ ],
430
+ cloud_final_modules: [
431
+ // minimal suggestions so final scripts run and node reports status
432
+ 'scripts-per-boot', // scripts to run each boot (useful for testing)
433
+ 'final-message', // useful for logs/reporting
434
+
435
+ // optional / commented
436
+ // 'rightscale_userdata',
437
+ // 'scripts-vendor',
438
+ // 'scripts-per-once',
439
+ // 'scripts-user',
440
+ // 'ssh-authkey-fingerprints',
441
+ // 'keys-to-console',
442
+ // 'power-state-change', // use carefully (can poweroff/reboot)
443
+ ],
444
+ });
445
+
446
+ return { cloudConfigSrc };
505
447
  },
506
448
 
507
449
  /**
@@ -548,6 +490,187 @@ EOF_MAAS_CFG`;
548
490
  logger.info('Maas api token generated', { consumer_key, consumer_secret, token_key, token_secret });
549
491
  return { consumer_key, consumer_secret, token_key, token_secret };
550
492
  },
493
+
494
+ /**
495
+ * @method generateCloudConfig
496
+ * @description Generates a generic cloud-init configuration string.
497
+ * @param {object} config - Configuration object.
498
+ * @returns {string} Cloud-init YAML content.
499
+ * @memberof UnderpostCloudInit
500
+ */
501
+ generateCloudConfig(config) {
502
+ const {
503
+ hostname,
504
+ fqdn,
505
+ prefer_fqdn_over_hostname,
506
+ datasource_list,
507
+ datasource,
508
+ users,
509
+ timezone,
510
+ ntp,
511
+ keyboard,
512
+ ssh,
513
+ ssh_pwauth,
514
+ package_update,
515
+ package_upgrade,
516
+ package_reboot_if_required,
517
+ packages,
518
+ resize_rootfs,
519
+ growpart,
520
+ network,
521
+ runcmd,
522
+ final_message,
523
+ bootcmd,
524
+ disable_root,
525
+ preserve_hostname,
526
+ cloud_init_modules,
527
+ cloud_config_modules,
528
+ cloud_final_modules,
529
+ } = config;
530
+
531
+ const yaml = [];
532
+ yaml.push('#cloud-config');
533
+ if (hostname) yaml.push(`hostname: ${hostname}`);
534
+ if (fqdn) yaml.push(`fqdn: ${fqdn}`);
535
+ if (prefer_fqdn_over_hostname) yaml.push(`prefer_fqdn_over_hostname: ${prefer_fqdn_over_hostname}`);
536
+
537
+ if (datasource_list) yaml.push(`datasource_list: ${JSON.stringify(datasource_list)}`);
538
+ if (datasource) {
539
+ yaml.push('datasource:');
540
+ for (const [key, value] of Object.entries(datasource)) {
541
+ yaml.push(` ${key}:`);
542
+ for (const [k, v] of Object.entries(value)) {
543
+ yaml.push(` ${k}: ${v}`);
544
+ }
545
+ }
546
+ }
547
+
548
+ if (users) {
549
+ yaml.push('users:');
550
+ users.forEach((user) => {
551
+ yaml.push(`- name: ${user.name}`);
552
+ if (user.sudo) yaml.push(` sudo: ${JSON.stringify(user.sudo)}`);
553
+ if (user.shell) yaml.push(` shell: ${user.shell}`);
554
+ if (user.lock_passwd !== undefined) yaml.push(` lock_passwd: ${user.lock_passwd}`);
555
+ if (user.groups) yaml.push(` groups: ${user.groups}`);
556
+ if (user.plain_text_passwd) yaml.push(` plain_text_passwd: '${user.plain_text_passwd}'`);
557
+ if (user.ssh_authorized_keys) {
558
+ yaml.push(` ssh_authorized_keys:`);
559
+ user.ssh_authorized_keys.forEach((key) => yaml.push(` - ${key}`));
560
+ }
561
+ });
562
+ }
563
+
564
+ if (timezone) yaml.push(`timezone: ${timezone}`);
565
+
566
+ if (ntp) {
567
+ yaml.push('ntp:');
568
+ if (ntp.enabled !== undefined) yaml.push(` enabled: ${ntp.enabled}`);
569
+ if (ntp.servers) {
570
+ yaml.push(' servers:');
571
+ ntp.servers.forEach((s) => yaml.push(` - ${s}`));
572
+ }
573
+ if (ntp.ntp_client) yaml.push(` ntp_client: ${ntp.ntp_client}`);
574
+ if (ntp.config) {
575
+ yaml.push(' config:');
576
+ if (ntp.config.confpath) yaml.push(` confpath: ${ntp.config.confpath}`);
577
+ }
578
+ }
579
+
580
+ if (keyboard) {
581
+ yaml.push('keyboard:');
582
+ if (keyboard.layout) yaml.push(` layout: ${keyboard.layout}`);
583
+ }
584
+
585
+ if (ssh) {
586
+ yaml.push('ssh:');
587
+ if (ssh['install-server'] !== undefined) yaml.push(` install-server: ${ssh['install-server']}`);
588
+ if (ssh['allow-pw'] !== undefined) yaml.push(` allow-pw: ${ssh['allow-pw']}`);
589
+ }
590
+ if (ssh_pwauth !== undefined) yaml.push(`ssh_pwauth: ${ssh_pwauth}`);
591
+
592
+ if (package_update !== undefined) yaml.push(`package_update: ${package_update}`);
593
+ if (package_upgrade !== undefined) yaml.push(`package_upgrade: ${package_upgrade}`);
594
+ if (package_reboot_if_required !== undefined)
595
+ yaml.push(`package_reboot_if_required: ${package_reboot_if_required}`);
596
+
597
+ if (packages) {
598
+ yaml.push('packages:');
599
+ packages.forEach((p) => yaml.push(` - ${p}`));
600
+ }
601
+
602
+ if (resize_rootfs !== undefined) yaml.push(`resize_rootfs: ${resize_rootfs}`);
603
+ if (growpart) {
604
+ yaml.push('growpart:');
605
+ if (growpart.mode) yaml.push(` mode: "${growpart.mode}"`);
606
+ }
607
+
608
+ if (network) {
609
+ yaml.push('network:');
610
+ yaml.push(` version: ${network.version}`);
611
+ if (network.ethernets) {
612
+ yaml.push(' ethernets:');
613
+ for (const [iface, conf] of Object.entries(network.ethernets)) {
614
+ yaml.push(` ${iface}:`);
615
+ if (conf.match) {
616
+ yaml.push(' match:');
617
+ if (conf.match.macaddress) yaml.push(` macaddress: "${conf.match.macaddress}"`);
618
+ }
619
+ if (conf.mtu) yaml.push(` mtu: ${conf.mtu}`);
620
+ if (conf['set-name']) yaml.push(` set-name: ${conf['set-name']}`);
621
+ if (conf.dhcp4 !== undefined) yaml.push(` dhcp4: ${conf.dhcp4}`);
622
+ if (conf.addresses) {
623
+ yaml.push(' addresses:');
624
+ conf.addresses.forEach((a) => yaml.push(` - ${a}`));
625
+ }
626
+ if (conf.routes) {
627
+ yaml.push(' routes:');
628
+ conf.routes.forEach((r) => {
629
+ yaml.push(` - to: ${r.to}`);
630
+ yaml.push(` via: ${r.via}`);
631
+ });
632
+ }
633
+ if (conf.nameservers) {
634
+ yaml.push(' nameservers:');
635
+ if (conf.nameservers.addresses) {
636
+ yaml.push(' addresses:');
637
+ conf.nameservers.addresses.forEach((a) => yaml.push(` - ${a}`));
638
+ }
639
+ }
640
+ }
641
+ }
642
+ }
643
+
644
+ if (runcmd) {
645
+ yaml.push('runcmd:');
646
+ runcmd.forEach((cmd) => yaml.push(` - ${cmd}`));
647
+ }
648
+
649
+ if (final_message) yaml.push(`final_message: "${final_message}"`);
650
+
651
+ if (bootcmd) {
652
+ yaml.push('bootcmd:');
653
+ bootcmd.forEach((cmd) => yaml.push(` - ${cmd}`));
654
+ }
655
+
656
+ if (disable_root !== undefined) yaml.push(`disable_root: ${disable_root}`);
657
+ if (preserve_hostname !== undefined) yaml.push(`preserve_hostname: ${preserve_hostname}`);
658
+
659
+ if (cloud_init_modules) {
660
+ yaml.push('cloud_init_modules:');
661
+ cloud_init_modules.forEach((m) => yaml.push(` - ${m}`));
662
+ }
663
+ if (cloud_config_modules) {
664
+ yaml.push('cloud_config_modules:');
665
+ cloud_config_modules.forEach((m) => yaml.push(` - ${m}`));
666
+ }
667
+ if (cloud_final_modules) {
668
+ yaml.push('cloud_final_modules:');
669
+ cloud_final_modules.forEach((m) => yaml.push(` - ${m}`));
670
+ }
671
+
672
+ return yaml.join('\n');
673
+ },
551
674
  };
552
675
  }
553
676
 
@@ -352,7 +352,7 @@ EOF
352
352
  );
353
353
  shellExec(`sudo mkdir -p /mnt/data`);
354
354
  shellExec(`sudo chmod 777 /mnt/data`);
355
- shellExec(`sudo chown -R root:root /mnt/data`);
355
+ shellExec(`sudo chown -R $(whoami):$(whoami) /mnt/data`);
356
356
  shellExec(`kubectl apply -k ${underpostRoot}/manifests/mysql -n ${options.namespace}`);
357
357
  }
358
358
  if (options.full === true || options.postgresql === true) {