#cloud-config
# Autoinstall-Seed für die EspoCRM-Kunden-VM (Ubuntu Server 24.04 LTS auf Hyper-V).
# Stand 2026-09-22, abgeleitet aus gitea gordon.zimm/ubuntu-autoinstall (Commit 0cd9fc6).
# Auf einer Test-VM am 22.09.2026 vollständig durchgelaufen (Ubuntu 24.04.5, Hyper-V, 127-GiB-Platte).
#
# Grundsätze:
#   * Der Seed wird per NoCloud über HTTP geladen und kann sich nicht authentisieren
#     -> er enthält KEIN Geheimnis: kein benutzbares Passwort, kein RMM-Token.
#   * Die ISO richtet nur das Minimum ein. Docker, Härtung, Logrotation, Firewall, Hostname und
#     Instanz kommen reproduzierbar über RMM-Tasks ("alles Weitere erfolgt über ConnectWise RMM").
autoinstall:
  version: 1

  source:
    id: ubuntu-server

  updates: all

  locale: de_DE.UTF-8
  keyboard:
    layout: de
  timezone: Europe/Berlin

  # Schnittstellennamen nicht festnageln: Hyper-V meldet je nach Kernel eth0 oder enp*.
  network:
    version: 2
    ethernets:
      primary:
        match:
          name: "e*"
        dhcp4: true
        dhcp6: false

  identity:
    realname: administrator
    username: administrator
    hostname: unkonfiguriert          # setzt der RMM-Baseline-Task auf crm-<site>
    # Hash eines einmalig erzeugten 48-Zeichen-Zufallspassworts; der Klartext wurde nirgends abgelegt.
    # Das Konto ist damit faktisch gesperrt, bis die late-commands je VM ein Initialpasswort setzen.
    password: '$6$KDLfMzLPV6wWtwA4$9VnUET9kFWUVp07z2hkN9Kv9.WjgdIPGLmm7zb4Te47Ms7lyrw/9Ewpqf759xVfXcOfAkWJSFrxUClfeyxeuI0'

  ssh:
    install-server: true
    allow-pw: true
    authorized-keys: []

  packages:
    - linux-cloud-tools-virtual            # hv_kvp_daemon, hv_vss_daemon, hv_fcopy_daemon
    - curl                                 # Voraussetzung des RMM-Agenten (libcurl4 kommt mit)
    - bzip2                                # der .run-Installer entpackt sich damit
    # kein linux-azure: der Azure-Kernel ist für Azure gebaut. Soll er trotzdem bleiben,
    # gehört linux-cloud-tools-azure dazu, sonst fehlen die Hyper-V-Integrationsdienste.

  # Explizite Aufteilung: klein für das Betriebssystem, groß für die Nutzdaten.
  # `layout: {name: lvm, sizing-policy: scaled}` wäre kürzer, gibt aber rund die Hälfte der Platte an "/" –
  # auf einer reinen Docker-VM ist das an der falschen Stelle.
  storage:
    config:
      - {type: disk, id: disk0, ptable: gpt, match: {size: largest}, wipe: superblock-recursive, preserve: false, grub_device: false}

      - {type: partition, id: part-esp,  device: disk0, size: 1G,  flag: boot, grub_device: true, preserve: false}
      - {type: format,    id: fmt-esp,   volume: part-esp, fstype: fat32, preserve: false}
      - {type: mount,     id: mnt-esp,   device: fmt-esp, path: /boot/efi}

      - {type: partition, id: part-boot, device: disk0, size: 2G, preserve: false}
      - {type: format,    id: fmt-boot,  volume: part-boot, fstype: ext4, preserve: false}
      - {type: mount,     id: mnt-boot,  device: fmt-boot, path: /boot}

      - {type: partition, id: part-pv,   device: disk0, size: -1, flag: lvm, preserve: false}
      - {type: lvm_volgroup, id: vg0, name: ubuntu-vg, devices: [part-pv], preserve: false}

      # Betriebssystem, RMM-Agent, Logs – 20 GiB sind reichlich (Bedarf real 8–12 GiB)
      - {type: lvm_partition, id: lv-root, name: root-lv, volgroup: vg0, size: 20G, preserve: false}
      - {type: format,        id: fmt-root, volume: lv-root, fstype: ext4, preserve: false}
      - {type: mount,         id: mnt-root, device: fmt-root, path: /}

      # `path: none` für Swap ist am 22.09.2026 auf einer Test-VM bestätigt worden.
      - {type: lvm_partition, id: lv-swap, name: swap-lv, volgroup: vg0, size: 4G, preserve: false}
      - {type: format,        id: fmt-swap, volume: lv-swap, fstype: swap, preserve: false}
      - {type: mount,         id: mnt-swap, device: fmt-swap, path: none}

      # Images, Container, Container-Logs – reproduzierbar, wird nicht gesichert
      - {type: lvm_partition, id: lv-docker, name: docker-lv, volgroup: vg0, size: 20G, preserve: false}
      - {type: format,        id: fmt-docker, volume: lv-docker, fstype: ext4, preserve: false}
      - {type: mount,         id: mnt-docker, device: fmt-docker, path: /var/lib/docker}

      # /srv (Nutzdaten) wird in late-commands anteilig angelegt, damit der Seed für jede Plattengröße passt.

  late-commands:
    # 1. /srv bekommt 80 % des verbliebenen Platzes; ~20 % bleiben unbelegt als Reserve und für LVM-Snapshots.
    #    Beispiel 128-GiB-Platte: / 20, swap 4, docker 20, /srv ~65, frei ~16 GiB.
    - lvcreate -y -l 80%FREE -n srv-lv ubuntu-vg
    - mkfs.ext4 -q -L srv /dev/ubuntu-vg/srv-lv
    - mkdir -p /target/srv
    #    Eintrag über UUID, wie curtin es für die übrigen Dateisysteme tut.
    - >-
      SRVUUID=$(blkid -s UUID -o value /dev/ubuntu-vg/srv-lv);
      printf 'UUID=%s /srv ext4 defaults 0 2\n' "$SRVUUID" >> /target/etc/fstab
    # 2. Je VM zufälliges Initialpasswort, am Konsolen-Login sichtbar, Wechsel beim ersten Anmelden erzwungen.
    - >-
      PW=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 20);
      echo "administrator:$PW" | curtin in-target -- chpasswd;
      curtin in-target -- chage -d 0 administrator;
      printf '\n Initialpasswort administrator: %s\n (beim ersten Anmelden ändern, danach diese Zeile aus /etc/issue entfernen)\n' "$PW" >> /target/etc/issue
    # 3. Hyper-V-Integrationsdienste (Zeit/IP-Meldung, Dateisystem-Quiesce für Veeam).
    #    Normalerweise startet udev sie selbst; enable schadet nicht und darf fehlschlagen.
    - curtin in-target -- systemctl enable hv-kvp-daemon.service hv-vss-daemon.service || true
    # 4. Kurze Anleitung für den einen Handgriff nach dem ersten Start (Passwort + RMM-Agent).
    - >-
      printf '%s\n'
      '# Erstinbetriebnahme dieser VM (Entscheidung 2026-09-22: Registrierung im RMM von Hand)'
      '# 1. Initialpasswort steht am Konsolen-Login (/etc/issue), Wechsel wird erzwungen.'
      '#    Neues Passwort im Secure Information Store der Site hinterlegen.'
      '# 2. RMM-Agent installieren (Token aus: Endpoints > Devices > Manage > Download Agent):'
      '#      cd /tmp && curl -fsSLOJ "<Download-Link aus dem Portal>"   # -OJ behaelt den Namen mit _TKN...'
      '#      chmod +x *_ITSPlatform_TKN*.run && sudo ./*_ITSPlatform_TKN*.run && rm -f *_ITSPlatform_TKN*.run'
      '#    Pruefen: systemctl status ITSPlatform ; tail /var/log/ITSPlatform-install.log'
      '# 3. Zeile mit dem Initialpasswort aus /etc/issue entfernen.'
      '# Alles Weitere erledigt der Baseline-Task, den der Trigger "First check-in" anstoesst.'
      > /target/root/ERSTINBETRIEBNAHME.txt
    # 5. Zum Schluss alles auf den neuesten Stand bringen. `updates: all` deckt den Stand zu Beginn der
    #    Installation ab; dieser Durchgang holt, was währenddessen dazugekommen ist, und räumt auf.
    #    NEEDRESTART_SUSPEND verhindert Dienst-Neustarts im chroot.
    - curtin in-target -- sh -c 'DEBIAN_FRONTEND=noninteractive NEEDRESTART_SUSPEND=1 apt-get update'
    - curtin in-target -- sh -c 'DEBIAN_FRONTEND=noninteractive NEEDRESTART_SUSPEND=1 apt-get -y -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef full-upgrade'
    - curtin in-target -- sh -c 'DEBIAN_FRONTEND=noninteractive apt-get -y autoremove --purge'
    - curtin in-target -- sh -c 'apt-get clean'

  shutdown: poweroff
