TerslerThe little junk rig that could

Source files / image · raw

user-data.build.yaml

#cloud-config
# Build-time configuration for the tersler disk image.
# build-image.sh fills in the @PLACEHOLDERS@ and runs this once in a QEMU VM.
# The VM powers off when it's done; the result is the image that goes on the SSD.

hostname: @HOSTNAME@
preserve_hostname: false
timezone: @TZ@
keyboard:
  layout: @KEYMAP@

users:
  - name: @USER@
    gecos: tersler admin
    groups: [adm, sudo, video, render, plugdev, dialout]
    shell: /bin/bash
    sudo: "ALL=(ALL) NOPASSWD:ALL"
    lock_passwd: false
    hashed_passwd: "@PASSWORD_HASH@"      # console login only; SSH is key-only
    ssh_authorized_keys:
      - "@SSH_KEY@"
ssh_pwauth: false
disable_root: true

package_update: true
package_upgrade: true
packages:
  - linux-generic          # the cloud image has only the "virtual" module set; real hardware needs linux-modules-extra
  - avahi-daemon           # ssh @USER@@@HOSTNAME@.local
  - git
  - curl
  - pciutils
  - lm-sensors
  - tmux
  - htop

write_files:
  # DHCP on every wired NIC, whatever it is named on the real board.
  # optional: an unplugged second port must not delay the boot.
  - path: /etc/netplan/01-tersler.yaml
    permissions: "0600"
    content: |
      network:
        version: 2
        ethernets:
          wired:
            match:
              name: "en*"
            dhcp4: true
            dhcp6: true
            optional: true
  # On the rig, cloud-init only grows the root partition, regenerates the SSH
  # host keys and leaves the network alone.
  - path: /etc/cloud/cloud.cfg.d/99-tersler.cfg
    content: |
      datasource_list: [ NoCloud, None ]
      network: {config: disabled}
  # The seed for the first boot on the rig. The new instance-id makes cloud-init
  # run its per-instance modules (growpart, resizefs, SSH host keys) once more.
  - path: /var/lib/cloud/seed/nocloud/meta-data
    content: |
      instance-id: @HOSTNAME@-hw-1
      local-hostname: @HOSTNAME@
  - path: /var/lib/cloud/seed/nocloud/user-data
    content: |
      #cloud-config
      users: []
  # Console on the onboard VGA first, serial second; a short boot menu for recovery.
  - path: /etc/default/grub.d/60-tersler-console.cfg
    content: |
      GRUB_CMDLINE_LINUX_DEFAULT="console=ttyS0,115200n8 console=tty1"
      GRUB_TIMEOUT_STYLE=menu
      GRUB_TIMEOUT=3
  - path: /etc/ssh/sshd_config.d/10-tersler.conf
    content: |
      PasswordAuthentication no
      KbdInteractiveAuthentication no
      PermitRootLogin no

runcmd:
  # the tersler project, from the seed ISO
  - mkdir -p /mnt/seed
  - mount -o ro /dev/sr0 /mnt/seed
  - mkdir -p /home/@USER@/tersler
  - tar -xzf /mnt/seed/tersler.tar.gz -C /home/@USER@/tersler
  - chown -R @USER@:@USER@ /home/@USER@/tersler
  - umount /mnt/seed
  # the cloud-init fallback config matches the build VM's MAC address; it would never match on the rig
  - rm -f /etc/netplan/50-cloud-init.yaml
  # always boot through the initramfs (the cloud image tries an initrd-less boot first)
  - rm -f /etc/default/grub.d/40-force-partuuid.cfg
  - update-grub
  - systemctl enable avahi-daemon ssh
  - apt-get -y purge snapd
  - rm -rf /snap /var/snap /var/lib/snapd /home/@USER@/snap
  - apt-get -y autoremove --purge
  - apt-get clean
  - rm -rf /var/lib/apt/lists/*
  - truncate -s 0 /etc/machine-id
  - rm -f /var/lib/dbus/machine-id
  - fstrim -av
  - echo JUNK-RIG-BUILD-OK > /dev/ttyS0

power_state:
  mode: poweroff
  condition: true