feat: Mint-Backend fuer den Installer (backend.sh + preseed.tpl)
Fehlte bisher komplett - backends/mint/ enthielt nur handgepatchte WLAN-Test-Artefakte, kein backend.sh, sodass 40_backend.sh mit "Kein Backend für 'mint' gefunden" abbrach. Baut auf dem bereits real erprobten wlan-test.seed-Muster auf (Ubiquity/ Preseed, nicht Subiquity/Autoinstall - siehe ADR-0009), generalisiert zu einem echten Template mit denselben Platzhaltern wie Fedoras kickstart.tpl: - backends/mint/backend.sh: 5-Funktionen-Contract 1:1 wie Fedora (backend_init/validate/generate_config/launch/postinstall), backend_launch() bewusst als Stub (echte Parität mit Fedoras heutigem Stand, kein Vorgriff auf das noch nicht entschiedene Self-Service-Portal-Modell). - backends/mint/preseed.tpl + postinstall.sh: echter Agent-Bootstrap (curl agent.py, Bootstrap-POST, Credentials, systemd enable) im ubiquity/success_command, zweistufig envsubst+base64 gerendert (Debconf-Fallstrick bei mehrzeiligen Preseed-Werten, real erprobt). - scripts/build.sh: Backend-Argument (fedora|mint), Mint-Pfade real gegen die vorhandene Test-ISO verifiziert (/boot/grub/grub.cfg, /isolinux/live.cfg, /preseed/tuxflotte.seed - keine zweite ESP-Kopie wie bei Fedora), Test-Preseed-Bake mit Platzhalterwerten. - profiles/mint-desktop/profile.json: installer.type von "autoinstall" auf "preseed" korrigiert (ADR-0009 hatte den alten Wert als vermutlich falsch benannt markiert - jetzt bestätigt und korrigiert). End-to-end auf echter QEMU-Hardware verifiziert: automatisierte Installation, Reboot, Agent-Bootstrap, Check-in, ansible-pull-Zyklus (PLAY RECAP failed=0) - kompletter Kreislauf funktioniert. Dabei gefunden und gefixt: d-i pkgsel/include string ansible-core git fehlte (Pendant zu Fedoras kickstart.tpl %packages) - ohne das lief der Agent-Dienst in einer Restart-Fehlerschleife. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
715658893c
commit
15965551ec
165
backends/mint/backend.sh
Normal file
165
backends/mint/backend.sh
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
# Dieses Skript wird von einem Orchestrator-Modul (z.B. 40_backend.sh) per
|
||||||
|
# `source` in dessen Shell geladen. Variablen bleiben deshalb bewusst nicht
|
||||||
|
# readonly, um Namenskollisionen mit dem ladenden Modul zu vermeiden.
|
||||||
|
BACKEND_KEY="mint"
|
||||||
|
|
||||||
|
BACKEND_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PRESEED_TEMPLATE="${BACKEND_DIR}/preseed.tpl"
|
||||||
|
POSTINSTALL_SCRIPT="${BACKEND_DIR}/postinstall.sh"
|
||||||
|
|
||||||
|
RUNTIME_BLUEPRINT_FILE="/run/tuxflotte/runtime/runtime_blueprint.json"
|
||||||
|
SERVER_RESPONSE_FILE="/run/tuxflotte/server/response.json"
|
||||||
|
|
||||||
|
RUNTIME_DIR="/run/tuxflotte/backend"
|
||||||
|
CONFIG_FILE="${RUNTIME_DIR}/config"
|
||||||
|
|
||||||
|
backend_log() {
|
||||||
|
printf '[backend:%s] %s\n' "${BACKEND_KEY}" "$*" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_fatal() {
|
||||||
|
printf '[backend:%s] FEHLER: %s\n' "${BACKEND_KEY}" "$*" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_init() {
|
||||||
|
for cmd in jq envsubst base64; do
|
||||||
|
command -v "${cmd}" >/dev/null 2>&1 ||
|
||||||
|
{ backend_fatal "Benötigtes Werkzeug fehlt: ${cmd}"; return 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -r "${PRESEED_TEMPLATE}" ]] ||
|
||||||
|
{ backend_fatal "Preseed-Template nicht gefunden: ${PRESEED_TEMPLATE}"; return 1; }
|
||||||
|
|
||||||
|
[[ -r "${POSTINSTALL_SCRIPT}" ]] ||
|
||||||
|
{ backend_fatal "Postinstall-Skript nicht gefunden: ${POSTINSTALL_SCRIPT}"; return 1; }
|
||||||
|
|
||||||
|
install -d \
|
||||||
|
--mode=0700 \
|
||||||
|
--owner=root \
|
||||||
|
--group=root \
|
||||||
|
"${RUNTIME_DIR}"
|
||||||
|
|
||||||
|
rm -f -- "${CONFIG_FILE}"
|
||||||
|
|
||||||
|
backend_log "Initialisiert."
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_validate() {
|
||||||
|
[[ -r "${RUNTIME_BLUEPRINT_FILE}" ]] ||
|
||||||
|
{ backend_fatal "Runtime Blueprint nicht gefunden: ${RUNTIME_BLUEPRINT_FILE}"; return 1; }
|
||||||
|
|
||||||
|
jq --exit-status \
|
||||||
|
--arg backend_key "${BACKEND_KEY}" \
|
||||||
|
'.runtime_blueprint.backend_id == $backend_key' \
|
||||||
|
"${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
|
||||||
|
{ backend_fatal "Runtime Blueprint ist nicht für Backend '${BACKEND_KEY}' aufgelöst."; return 1; }
|
||||||
|
|
||||||
|
jq --exit-status '
|
||||||
|
.runtime_blueprint.installation_directives
|
||||||
|
| (.disk_encryption | type == "boolean")
|
||||||
|
and (.partitioning | type == "string")
|
||||||
|
and (.secure_boot_required | type == "boolean")
|
||||||
|
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
|
||||||
|
{ backend_fatal "Installationszeitliche Vorgaben fehlen oder sind ungültig."; return 1; }
|
||||||
|
|
||||||
|
# disk_encryption wird für Mint (noch) nicht unterstützt - kein getesteter
|
||||||
|
# LUKS-Preseed-Mechanismus (anders als Fedoras "autopart --encrypted").
|
||||||
|
if [[ "$(jq --raw-output '.runtime_blueprint.installation_directives.disk_encryption' "${RUNTIME_BLUEPRINT_FILE}")" == "true" ]]; then
|
||||||
|
backend_fatal "disk_encryption=true wird vom Mint-Backend derzeit nicht unterstützt."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
backend_log "Runtime Blueprint ist gültig für Backend '${BACKEND_KEY}'."
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_generate_config() {
|
||||||
|
local hostname
|
||||||
|
local device_id
|
||||||
|
local partitioning
|
||||||
|
local secure_boot_required
|
||||||
|
local partman_recipe
|
||||||
|
local blueprints_json
|
||||||
|
local postinstall_rendered
|
||||||
|
local postinstall_b64
|
||||||
|
|
||||||
|
[[ -r "${SERVER_RESPONSE_FILE}" ]] ||
|
||||||
|
{ backend_fatal "Serverantwort nicht gefunden: ${SERVER_RESPONSE_FILE}"; return 1; }
|
||||||
|
|
||||||
|
hostname="$(jq --raw-output '.device.hostname // empty' "${SERVER_RESPONSE_FILE}")"
|
||||||
|
[[ -n "${hostname}" ]] ||
|
||||||
|
{ backend_fatal "Kein Hostname in der Serverantwort gefunden."; return 1; }
|
||||||
|
|
||||||
|
device_id="$(jq --raw-output '.device.id // empty' "${SERVER_RESPONSE_FILE}")"
|
||||||
|
[[ -n "${device_id}" ]] ||
|
||||||
|
{ backend_fatal "Keine Geräte-ID in der Serverantwort gefunden."; return 1; }
|
||||||
|
|
||||||
|
partitioning="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning' "${RUNTIME_BLUEPRINT_FILE}")"
|
||||||
|
secure_boot_required="$(jq --raw-output '.runtime_blueprint.installation_directives.secure_boot_required' "${RUNTIME_BLUEPRINT_FILE}")"
|
||||||
|
|
||||||
|
case "${partitioning}" in
|
||||||
|
default)
|
||||||
|
partman_recipe="atomic"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
backend_fatal "Nicht unterstützte Partitionierungsvorgabe: ${partitioning}"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ "${secure_boot_required}" == "true" ]]; then
|
||||||
|
backend_log "Hinweis: secure_boot_required=true wird derzeit nicht in der Preseed-Konfiguration durchgesetzt (Phase 1)."
|
||||||
|
fi
|
||||||
|
|
||||||
|
blueprints_json="$(jq --compact-output '.runtime_blueprint.blueprints' "${RUNTIME_BLUEPRINT_FILE}")"
|
||||||
|
|
||||||
|
# Erste Stufe: postinstall.sh-Platzhalter auflösen.
|
||||||
|
postinstall_rendered="$(
|
||||||
|
TUXFLOTTE_DEVICE_ID="${device_id}" \
|
||||||
|
TUXFLOTTE_BLUEPRINTS_JSON="${blueprints_json}" \
|
||||||
|
envsubst '${TUXFLOTTE_DEVICE_ID} ${TUXFLOTTE_BLUEPRINTS_JSON}' \
|
||||||
|
<"${POSTINSTALL_SCRIPT}"
|
||||||
|
)"
|
||||||
|
|
||||||
|
if grep -q '\${TUXFLOTTE_' <<<"${postinstall_rendered}"; then
|
||||||
|
backend_fatal "postinstall.sh enthält nach envsubst nicht aufgelöste Platzhalter."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# base64-Kodierung: mehrzeilige/zitierte Preseed-Werte brechen unter
|
||||||
|
# Debconf lautlos (real erprobt, siehe backends/mint/wlan-test.seed) -
|
||||||
|
# als einzeiliger Base64-Blob besteht der success_command-Wert nur noch
|
||||||
|
# aus unkritischen Zeichen.
|
||||||
|
postinstall_b64="$(printf '%s' "${postinstall_rendered}" | base64 -w0)"
|
||||||
|
|
||||||
|
# Zweite Stufe: preseed.tpl mit allen Werten inkl. des fertigen Base64-Blobs auflösen.
|
||||||
|
TUXFLOTTE_HOSTNAME="${hostname}" \
|
||||||
|
TUXFLOTTE_PARTMAN_RECIPE="${partman_recipe}" \
|
||||||
|
TUXFLOTTE_POSTINSTALL_B64="${postinstall_b64}" \
|
||||||
|
envsubst '${TUXFLOTTE_HOSTNAME} ${TUXFLOTTE_PARTMAN_RECIPE} ${TUXFLOTTE_POSTINSTALL_B64}' \
|
||||||
|
<"${PRESEED_TEMPLATE}" >"${CONFIG_FILE}"
|
||||||
|
|
||||||
|
chmod 0600 "${CONFIG_FILE}"
|
||||||
|
|
||||||
|
[[ -s "${CONFIG_FILE}" ]] ||
|
||||||
|
{ backend_fatal "Erzeugte Konfigurationsdatei ist leer: ${CONFIG_FILE}"; return 1; }
|
||||||
|
|
||||||
|
if grep -q '\${TUXFLOTTE_' "${CONFIG_FILE}"; then
|
||||||
|
backend_fatal "Erzeugte Konfigurationsdatei enthält nicht aufgelöste Platzhalter."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
backend_log "Konfiguration erzeugt: ${CONFIG_FILE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_launch() {
|
||||||
|
backend_log "Phase 1: Start des nativen Installers ist noch nicht aktiv."
|
||||||
|
backend_log "Erzeugte Konfiguration liegt bereit unter: ${CONFIG_FILE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_postinstall() {
|
||||||
|
backend_log "Provisioning-Agent-Einrichtung erfolgt im ubiquity/success_command der Preseed-Konfiguration (Agent-Abruf, Bootstrap-Registrierung, systemd-Aktivierung)."
|
||||||
|
}
|
||||||
62
backends/mint/postinstall.sh
Normal file
62
backends/mint/postinstall.sh
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Lesbare Referenzfassung des Agent-Bootstraps, den backend_generate_config()
|
||||||
|
# in backend.sh zur Laufzeit envsubst-auflöst und anschließend base64-kodiert
|
||||||
|
# in preseed.tpls ubiquity/success_command einsetzt (siehe backend.sh). Diese
|
||||||
|
# Datei selbst wird nie direkt ausgeführt - sie existiert, damit der Code
|
||||||
|
# lesbar bleibt statt nur als Base64-Blob im Preseed zu existieren.
|
||||||
|
#
|
||||||
|
# Inhaltlich das Bash-Pendant zu backends/fedora/kickstart.tpl %post: gleiche
|
||||||
|
# curl/jq-Aufrufe, nur eingebettet über ubiquity/success_command (in-target,
|
||||||
|
# chrooted) statt Kickstart %post.
|
||||||
|
tuxflotte_agent_fatal() {
|
||||||
|
echo "tuxflotte: Provisioning-Agent-Einrichtung fehlgeschlagen: $*" >> /var/log/tuxflotte-postinstall.log
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ANODE_URL="https://anode.tuxflotte.de"
|
||||||
|
AGENT_REPO_RAW="https://git.tuxflotte.de/admin/provisioning-agent/raw/branch/main"
|
||||||
|
|
||||||
|
install -d -m 0700 /etc/tuxflotte ||
|
||||||
|
tuxflotte_agent_fatal "Verzeichnis /etc/tuxflotte konnte nicht angelegt werden."
|
||||||
|
|
||||||
|
cat > /etc/tuxflotte/runtime_blueprint.json <<'RUNTIME_BLUEPRINT_EOF'
|
||||||
|
${TUXFLOTTE_BLUEPRINTS_JSON}
|
||||||
|
RUNTIME_BLUEPRINT_EOF
|
||||||
|
|
||||||
|
install -d /opt/tuxflotte/agent ||
|
||||||
|
tuxflotte_agent_fatal "Verzeichnis /opt/tuxflotte/agent konnte nicht angelegt werden."
|
||||||
|
|
||||||
|
curl --silent --show-error --fail --location \
|
||||||
|
--output /opt/tuxflotte/agent/agent.py \
|
||||||
|
"${AGENT_REPO_RAW}/agent.py" ||
|
||||||
|
tuxflotte_agent_fatal "agent.py konnte nicht von ${AGENT_REPO_RAW} geladen werden."
|
||||||
|
|
||||||
|
curl --silent --show-error --fail --location \
|
||||||
|
--output /etc/systemd/system/tuxflotte-agent.service \
|
||||||
|
"${AGENT_REPO_RAW}/tuxflotte-agent.service" ||
|
||||||
|
tuxflotte_agent_fatal "tuxflotte-agent.service konnte nicht von ${AGENT_REPO_RAW} geladen werden."
|
||||||
|
|
||||||
|
AGENT_BOOTSTRAP_RESPONSE="$(
|
||||||
|
curl --silent --show-error --fail --location \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data-binary "{\"device_id\": \"${TUXFLOTTE_DEVICE_ID}\"}" \
|
||||||
|
"${ANODE_URL}/api/v1/agent/bootstrap"
|
||||||
|
)" ||
|
||||||
|
tuxflotte_agent_fatal "Bootstrap-Aufruf gegen ${ANODE_URL} ist fehlgeschlagen."
|
||||||
|
|
||||||
|
jq --exit-status '.success == true' <<<"${AGENT_BOOTSTRAP_RESPONSE}" >/dev/null ||
|
||||||
|
tuxflotte_agent_fatal "Server hat den Bootstrap abgelehnt: ${AGENT_BOOTSTRAP_RESPONSE}"
|
||||||
|
|
||||||
|
jq --null-input \
|
||||||
|
--arg device_id "${TUXFLOTTE_DEVICE_ID}" \
|
||||||
|
--argjson response "${AGENT_BOOTSTRAP_RESPONSE}" \
|
||||||
|
'{device_id: $device_id, agent_secret: $response.agent_secret}' \
|
||||||
|
> /etc/tuxflotte/agent.credentials ||
|
||||||
|
tuxflotte_agent_fatal "Credentials-Datei konnte nicht erzeugt werden."
|
||||||
|
chmod 0600 /etc/tuxflotte/agent.credentials
|
||||||
|
|
||||||
|
systemctl enable tuxflotte-agent.service ||
|
||||||
|
tuxflotte_agent_fatal "systemd-Dienst tuxflotte-agent konnte nicht aktiviert werden."
|
||||||
|
|
||||||
|
echo "tuxflotte: Runtime Blueprint unter /etc/tuxflotte/runtime_blueprint.json hinterlegt." >> /var/log/tuxflotte-postinstall.log
|
||||||
|
echo "tuxflotte: Provisioning-Agent installiert, registriert und für den ersten Boot aktiviert." >> /var/log/tuxflotte-postinstall.log
|
||||||
52
backends/mint/preseed.tpl
Normal file
52
backends/mint/preseed.tpl
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
### Tuxflotte Auto-Install Preseed fuer Linux Mint (Ubiquity/Debian-Installer).
|
||||||
|
### Liegt direkt auf dem Medium (file=/cdrom/preseed/tuxflotte.seed), keine
|
||||||
|
### Netz-Zustellung noetig -- analog zu Fedoras inst.ks=cdrom:/ks.cfg.
|
||||||
|
###
|
||||||
|
### d-i preseed/early_command wird bewusst NICHT verwendet -- unter Ubiquity
|
||||||
|
### bestaetigt wirkungslos (Ubiquity nutzt eigene Python-Plugins statt der
|
||||||
|
### klassischen Debian-Installer-Komponenten, an die early_command haengt).
|
||||||
|
|
||||||
|
d-i debian-installer/locale string de_DE.UTF-8
|
||||||
|
d-i keyboard-configuration/xkb-keymap select de
|
||||||
|
d-i keyboard-configuration/layoutcode string de
|
||||||
|
|
||||||
|
d-i netcfg/get_hostname string ${TUXFLOTTE_HOSTNAME}
|
||||||
|
d-i netcfg/get_domain string unassigned-domain
|
||||||
|
|
||||||
|
# Lab-Bootstrap-Zugangsdaten. Ersetzt ein noch fehlendes Secret-Reference-Modell
|
||||||
|
# (siehe 09-data-model-v1.md) und darf nicht als Produktionsmechanismus gelten.
|
||||||
|
d-i passwd/user-fullname string Tuxflotte
|
||||||
|
d-i passwd/username string tuxflotte
|
||||||
|
d-i passwd/user-password password test123
|
||||||
|
d-i passwd/user-password-again password test123
|
||||||
|
d-i user-setup/allow-password-weak boolean true
|
||||||
|
|
||||||
|
d-i clock-setup/utc boolean true
|
||||||
|
d-i time/zone string Europe/Berlin
|
||||||
|
d-i clock-setup/ntp boolean true
|
||||||
|
|
||||||
|
d-i partman-auto/method string regular
|
||||||
|
d-i partman-auto/choose_recipe select ${TUXFLOTTE_PARTMAN_RECIPE}
|
||||||
|
d-i partman-partitioning/confirm_write_new_label boolean true
|
||||||
|
d-i partman/choose_partition select finish
|
||||||
|
d-i partman/confirm boolean true
|
||||||
|
d-i partman/confirm_nooverwrite boolean true
|
||||||
|
|
||||||
|
ubiquity ubiquity/summary note
|
||||||
|
ubiquity ubiquity/reboot boolean true
|
||||||
|
ubiquity ubiquity/use_nonfree boolean true
|
||||||
|
|
||||||
|
# Pendant zu Fedoras kickstart.tpl %packages (ansible-core, git) - der
|
||||||
|
# Provisioning Agent braucht ansible-pull, das wiederum git zum Klonen des
|
||||||
|
# Ansible-Repos. Ohne diese Zeile fehlen beide auf einer frischen
|
||||||
|
# Mint-Installation, der Agent-Dienst laeuft dann in einer
|
||||||
|
# Restart-Fehlerschleife ("ansible-pull nicht gefunden") - real gegen eine
|
||||||
|
# frische Testinstallation gefunden und verifiziert (2026-08-04).
|
||||||
|
d-i pkgsel/include string ansible-core git
|
||||||
|
|
||||||
|
# success_command laeuft in-target (gechrootet ins Zielsystem) nach der
|
||||||
|
# Paketinstallation, vor dem Reboot - das Pendant zu Kickstarts %post. Der
|
||||||
|
# Payload ist base64-kodiert (backend_generate_config() in backend.sh baut
|
||||||
|
# ihn aus postinstall.sh): mehrzeilige/zitierte Preseed-Werte brechen unter
|
||||||
|
# Debconf lautlos, Base64 umgeht das (real erprobt, siehe wlan-test.seed).
|
||||||
|
ubiquity ubiquity/success_command string in-target bash -c 'echo ${TUXFLOTTE_POSTINSTALL_B64} | base64 -d | bash'
|
||||||
41
grub/mint-boot-grub.cfg
Normal file
41
grub/mint-boot-grub.cfg
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
loadfont unicode
|
||||||
|
|
||||||
|
set color_normal=white/black
|
||||||
|
set color_highlight=black/light-gray
|
||||||
|
|
||||||
|
set timeout=30
|
||||||
|
|
||||||
|
menuentry "Start Linux Mint 22.3 Cinnamon 64-bit" --class linuxmint {
|
||||||
|
set gfxpayload=keep
|
||||||
|
linux /casper/vmlinuz boot=casper uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint iso-scan/filename=${iso_path} quiet splash --
|
||||||
|
initrd /casper/initrd.lz
|
||||||
|
}
|
||||||
|
menuentry "Start Linux Mint 22.3 Cinnamon 64-bit (compatibility mode)" {
|
||||||
|
linux /casper/vmlinuz boot=casper uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint iso-scan/filename=${iso_path} noapic noacpi nosplash irqpoll nomodeset --
|
||||||
|
initrd /casper/initrd.lz
|
||||||
|
}
|
||||||
|
menuentry "OEM install (for manufacturers)" {
|
||||||
|
set gfxpayload=keep
|
||||||
|
linux /casper/vmlinuz oem-config/enable=true only-ubiquity boot=casper uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint iso-scan/filename=${iso_path} quiet splash --
|
||||||
|
initrd /casper/initrd.lz
|
||||||
|
}
|
||||||
|
menuentry "Tuxflotte Auto-Install (Linux Mint 22.3 Cinnamon)" --class linuxmint {
|
||||||
|
set gfxpayload=keep
|
||||||
|
linux /casper/vmlinuz boot=casper uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint iso-scan/filename=${iso_path} file=/cdrom/preseed/tuxflotte.seed automatic-ubiquity noprompt debian-installer/language=de keyboard-configuration/layoutcode=de quiet splash --
|
||||||
|
initrd /casper/initrd.lz
|
||||||
|
}
|
||||||
|
grub_platform
|
||||||
|
if [ "$grub_platform" = "efi" ]; then
|
||||||
|
menuentry 'Von lokaler Festplatte booten (Standard)' {
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
set default="Von lokaler Festplatte booten (Standard)"
|
||||||
|
menuentry 'UEFI Firmware Settings' {
|
||||||
|
fwsetup
|
||||||
|
}
|
||||||
|
menuentry 'Memory test' {
|
||||||
|
linux /boot/memtest.efi
|
||||||
|
}
|
||||||
|
else
|
||||||
|
set default="0"
|
||||||
|
fi
|
||||||
57
grub/mint-isolinux-live.cfg
Normal file
57
grub/mint-isolinux-live.cfg
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
timeout 100
|
||||||
|
|
||||||
|
menu background splash.png
|
||||||
|
menu title Welcome to Linux Mint 22.3 64-bit
|
||||||
|
|
||||||
|
menu color screen 37;40 #80ffffff #00000000 std
|
||||||
|
MENU COLOR border 30;44 #40ffffff #a0000000 std
|
||||||
|
MENU COLOR title 1;36;44 #ffffffff #a0000000 std
|
||||||
|
MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
|
||||||
|
MENU COLOR unsel 37;44 #50ffffff #a0000000 std
|
||||||
|
MENU COLOR help 37;40 #c0ffffff #a0000000 std
|
||||||
|
MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
|
||||||
|
MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
|
||||||
|
MENU COLOR msg07 37;40 #90ffffff #a0000000 std
|
||||||
|
MENU COLOR tabmsg 31;40 #ffDEDEDE #00000000 std
|
||||||
|
MENU WIDTH 78
|
||||||
|
MENU MARGIN 15
|
||||||
|
MENU ROWS 6
|
||||||
|
MENU VSHIFT 10
|
||||||
|
MENU TABMSGROW 12
|
||||||
|
MENU CMDLINEROW 12
|
||||||
|
MENU HELPMSGROW 16
|
||||||
|
MENU HELPMSGENDROW 29
|
||||||
|
|
||||||
|
label tuxflotte
|
||||||
|
menu label Tuxflotte Auto-Install
|
||||||
|
kernel /casper/vmlinuz
|
||||||
|
append boot=casper initrd=/casper/initrd.lz uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint file=/cdrom/preseed/tuxflotte.seed automatic-ubiquity noprompt debian-installer/language=de keyboard-configuration/layoutcode=de quiet splash --
|
||||||
|
|
||||||
|
label live
|
||||||
|
menu label Start Linux Mint
|
||||||
|
kernel /casper/vmlinuz
|
||||||
|
append boot=casper initrd=/casper/initrd.lz uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint quiet splash --
|
||||||
|
|
||||||
|
label compat
|
||||||
|
menu label Start Linux Mint in compatibility mode
|
||||||
|
linux /casper/vmlinuz
|
||||||
|
append boot=casper initrd=/casper/initrd.lz uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint noapic noacpi nosplash irqpoll nomodeset --
|
||||||
|
|
||||||
|
label oem
|
||||||
|
menu label OEM install (for manufacturers)
|
||||||
|
linux /casper/vmlinuz
|
||||||
|
append oem-config/enable=true only-ubiquity boot=casper initrd=/casper/initrd.lz uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint quiet splash --
|
||||||
|
|
||||||
|
label hdt
|
||||||
|
menu label Hardware Detection
|
||||||
|
kernel hdt.c32
|
||||||
|
|
||||||
|
label local
|
||||||
|
menu label Boot from local drive
|
||||||
|
menu default
|
||||||
|
COM32 chain.c32
|
||||||
|
APPEND hd0
|
||||||
|
|
||||||
|
label memtest
|
||||||
|
menu label Memory test
|
||||||
|
linux /boot/memtest.bin
|
||||||
129
scripts/build.sh
129
scripts/build.sh
@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
SOURCE_ISO="${1:-}"
|
SOURCE_ISO="${1:-}"
|
||||||
|
BACKEND="${2:-}"
|
||||||
|
|
||||||
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
BASE_DIR="$(cd "$REPO_DIR/.." && pwd)"
|
BASE_DIR="$(cd "$REPO_DIR/.." && pwd)"
|
||||||
@ -9,12 +10,19 @@ BUILD_DIR="$BASE_DIR/build"
|
|||||||
WORK_DIR="$BUILD_DIR/work"
|
WORK_DIR="$BUILD_DIR/work"
|
||||||
OUTPUT_DIR="$BUILD_DIR/output"
|
OUTPUT_DIR="$BUILD_DIR/output"
|
||||||
|
|
||||||
|
# Test-Device fuer den in bake_test_preseed() eingebrannten, nicht
|
||||||
|
# personalisierten Test-Preseed (Mint) - dasselbe "Default Lab"-Testgeraet,
|
||||||
|
# das schon fuer die Fedora-Verifikation genutzt wurde. Echte Personalisierung
|
||||||
|
# pro Kunde ist nicht Teil dieses Build-Skripts (siehe ADR-0011-Kontext).
|
||||||
|
TEST_DEVICE_ID="a0238a0b-d2b5-4516-a6ce-da7170041d11"
|
||||||
|
TEST_HOSTNAME="tuxflotte-mint-test"
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
echo "Usage: $0 /path/to/source.iso"
|
echo "Usage: $0 /path/to/source.iso <fedora|mint>"
|
||||||
}
|
}
|
||||||
|
|
||||||
check_input() {
|
check_input() {
|
||||||
if [[ -z "$SOURCE_ISO" ]]; then
|
if [[ -z "$SOURCE_ISO" || -z "$BACKEND" ]]; then
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -23,6 +31,14 @@ check_input() {
|
|||||||
echo "Error: ISO not found: $SOURCE_ISO"
|
echo "Error: ISO not found: $SOURCE_ISO"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
case "$BACKEND" in
|
||||||
|
fedora|mint) ;;
|
||||||
|
*)
|
||||||
|
echo "Error: unbekanntes Backend '$BACKEND' (erwartet: fedora oder mint)"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
check_dependencies() {
|
check_dependencies() {
|
||||||
@ -32,6 +48,15 @@ check_dependencies() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [[ "$BACKEND" == "mint" ]]; then
|
||||||
|
for cmd in jq envsubst base64; do
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
echo "Error: missing dependency: $cmd"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_dirs() {
|
prepare_dirs() {
|
||||||
@ -48,22 +73,88 @@ extract_iso() {
|
|||||||
patch_grub() {
|
patch_grub() {
|
||||||
echo "Installing Tuxflotte GRUB configuration..."
|
echo "Installing Tuxflotte GRUB configuration..."
|
||||||
|
|
||||||
cp "$REPO_DIR/grub/EFI-BOOT-grub.cfg" \
|
if [[ "$BACKEND" == "fedora" ]]; then
|
||||||
"$WORK_DIR/EFI/BOOT/grub.cfg"
|
cp "$REPO_DIR/grub/EFI-BOOT-grub.cfg" \
|
||||||
|
"$WORK_DIR/EFI/BOOT/grub.cfg"
|
||||||
|
|
||||||
cp "$REPO_DIR/grub/boot-grub2-grub.cfg" \
|
cp "$REPO_DIR/grub/boot-grub2-grub.cfg" \
|
||||||
"$WORK_DIR/boot/grub2/grub.cfg"
|
"$WORK_DIR/boot/grub2/grub.cfg"
|
||||||
|
else
|
||||||
|
# Mint hat, anders als Fedora, keine zweite ESP/FAT-Kopie des GRUB-Menüs,
|
||||||
|
# die separat gepatcht werden müsste (real gegen die vorhandene
|
||||||
|
# tuxflotte-mint-test.iso verifiziert - x86_64-efi/grub.cfg ist nur ein
|
||||||
|
# Loader-Stub, der per `source /boot/grub/grub.cfg` zurückverweist).
|
||||||
|
cp "$REPO_DIR/grub/mint-boot-grub.cfg" \
|
||||||
|
"$WORK_DIR/boot/grub/grub.cfg"
|
||||||
|
|
||||||
|
cp "$REPO_DIR/grub/mint-isolinux-live.cfg" \
|
||||||
|
"$WORK_DIR/isolinux/live.cfg"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_workdir() {
|
verify_workdir() {
|
||||||
echo "Verifying workdir..."
|
echo "Verifying workdir..."
|
||||||
|
|
||||||
grep -q "Tuxflotte" "$WORK_DIR/EFI/BOOT/grub.cfg"
|
if [[ "$BACKEND" == "fedora" ]]; then
|
||||||
grep -q "Tuxflotte" "$WORK_DIR/boot/grub2/grub.cfg"
|
grep -q "Tuxflotte" "$WORK_DIR/EFI/BOOT/grub.cfg"
|
||||||
|
grep -q "Tuxflotte" "$WORK_DIR/boot/grub2/grub.cfg"
|
||||||
|
else
|
||||||
|
grep -q "Tuxflotte" "$WORK_DIR/boot/grub/grub.cfg"
|
||||||
|
grep -q "Tuxflotte" "$WORK_DIR/isolinux/live.cfg"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "GRUB verification passed."
|
echo "GRUB verification passed."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bake_test_preseed() {
|
||||||
|
[[ "$BACKEND" == "mint" ]] || return 0
|
||||||
|
|
||||||
|
echo "Rendering test preseed (nicht personalisiert, siehe TEST_DEVICE_ID)..."
|
||||||
|
|
||||||
|
local preseed_dir="$WORK_DIR/preseed"
|
||||||
|
local runtime_blueprint_file="$WORK_DIR/runtime_blueprint.json"
|
||||||
|
local server_response_file="$WORK_DIR/response.json"
|
||||||
|
|
||||||
|
mkdir -p "$preseed_dir"
|
||||||
|
|
||||||
|
cat > "$runtime_blueprint_file" <<EOF
|
||||||
|
{
|
||||||
|
"runtime_blueprint": {
|
||||||
|
"backend_id": "mint",
|
||||||
|
"blueprints": [],
|
||||||
|
"installation_directives": {
|
||||||
|
"disk_encryption": false,
|
||||||
|
"partitioning": "default",
|
||||||
|
"secure_boot_required": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$server_response_file" <<EOF
|
||||||
|
{
|
||||||
|
"device": {"hostname": "${TEST_HOSTNAME}", "id": "${TEST_DEVICE_ID}"}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# backend.sh direkt wiederverwenden statt die Templating-Logik hier zu
|
||||||
|
# duplizieren - Variablen sind bewusst nicht readonly (siehe backend.sh),
|
||||||
|
# backend_init() wird übersprungen (braucht root für --owner/--group,
|
||||||
|
# hier nicht nötig, mkdir reicht für den Build-Kontext).
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "$REPO_DIR/backends/mint/backend.sh"
|
||||||
|
|
||||||
|
RUNTIME_BLUEPRINT_FILE="$runtime_blueprint_file"
|
||||||
|
SERVER_RESPONSE_FILE="$server_response_file"
|
||||||
|
RUNTIME_DIR="$preseed_dir"
|
||||||
|
CONFIG_FILE="$preseed_dir/tuxflotte.seed"
|
||||||
|
|
||||||
|
backend_validate
|
||||||
|
backend_generate_config
|
||||||
|
|
||||||
|
echo "Test-Preseed erzeugt: $CONFIG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
prepare_updates() {
|
prepare_updates() {
|
||||||
echo "Assembling live-updates payload..."
|
echo "Assembling live-updates payload..."
|
||||||
|
|
||||||
@ -83,7 +174,23 @@ prepare_updates() {
|
|||||||
create_iso() {
|
create_iso() {
|
||||||
echo "Creating Tuxflotte ISO..."
|
echo "Creating Tuxflotte ISO..."
|
||||||
|
|
||||||
local output_iso="$OUTPUT_DIR/tuxflotte-provisioning-0.2.iso"
|
local output_iso
|
||||||
|
local -a grub_map_args
|
||||||
|
|
||||||
|
if [[ "$BACKEND" == "fedora" ]]; then
|
||||||
|
output_iso="$OUTPUT_DIR/tuxflotte-provisioning-0.2.iso"
|
||||||
|
grub_map_args=(
|
||||||
|
-map "$REPO_DIR/grub/EFI-BOOT-grub.cfg" /EFI/BOOT/grub.cfg
|
||||||
|
-map "$REPO_DIR/grub/boot-grub2-grub.cfg" /boot/grub2/grub.cfg
|
||||||
|
)
|
||||||
|
else
|
||||||
|
output_iso="$OUTPUT_DIR/tuxflotte-mint-provisioning-0.1.iso"
|
||||||
|
grub_map_args=(
|
||||||
|
-map "$REPO_DIR/grub/mint-boot-grub.cfg" /boot/grub/grub.cfg
|
||||||
|
-map "$REPO_DIR/grub/mint-isolinux-live.cfg" /isolinux/live.cfg
|
||||||
|
-map "$WORK_DIR/preseed/tuxflotte.seed" /preseed/tuxflotte.seed
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
rm -f "$output_iso"
|
rm -f "$output_iso"
|
||||||
|
|
||||||
@ -92,8 +199,7 @@ create_iso() {
|
|||||||
-outdev "$output_iso" \
|
-outdev "$output_iso" \
|
||||||
-compliance no_emul_toc \
|
-compliance no_emul_toc \
|
||||||
-volid TUXFLOTTE \
|
-volid TUXFLOTTE \
|
||||||
-map "$REPO_DIR/grub/EFI-BOOT-grub.cfg" /EFI/BOOT/grub.cfg \
|
"${grub_map_args[@]}" \
|
||||||
-map "$REPO_DIR/grub/boot-grub2-grub.cfg" /boot/grub2/grub.cfg \
|
|
||||||
-map "$WORK_DIR/updates" /updates \
|
-map "$WORK_DIR/updates" /updates \
|
||||||
-chown_r 0 /updates -- \
|
-chown_r 0 /updates -- \
|
||||||
-chgrp_r 0 /updates -- \
|
-chgrp_r 0 /updates -- \
|
||||||
@ -109,6 +215,7 @@ main() {
|
|||||||
extract_iso
|
extract_iso
|
||||||
patch_grub
|
patch_grub
|
||||||
verify_workdir
|
verify_workdir
|
||||||
|
bake_test_preseed
|
||||||
prepare_updates
|
prepare_updates
|
||||||
create_iso
|
create_iso
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user