chore(boot-medium): Phase 4 - alte Ubiquity-Ära-Dateien entfernen, build.sh auf Fedora reduzieren
Entfernt (Historie bleibt ueber Git-Log erhalten, siehe ADR-0025 in platform-docs fuer die vollstaendige Begruendung/den Gesamtrueckblick): - backends/mint/ (Ubiquity-Preseed-Backend, backend_launch()-Pfad nicht mehr referenziert seit Phase 1, postinstall.sh dort bereits migriert) - scripts/lib/initrd.sh, initrd-hooks/ (Casper-Bottom-Hook-Injection, nur fuer das Patchen einer fremden fertigen Mint-ISO noetig) - grub/mint-boot-grub.cfg, grub/mint-isolinux-live.cfg - live-updates/ (Cinnamon-Kiosk, AT-SPI-Autoklicker) scripts/build.sh (das alte Test-Build-Skript) bedient jetzt nur noch das Fedora-Backend (Kickstart/Anaconda, unveraendert, ausserhalb dieses Plans) - Mint-Zweig entfernt (bake_test_preseed(), patch_initrd(), initrd.sh-Source, mint-spezifische GRUB-Pfade). Die unbedingte live-updates/-Kopie in prepare_updates() entfiel ebenfalls - sie wurde fuer Fedora nie inhaltlich gebraucht (Anaconda/Kickstart kennt kein Cinnamon-Kiosk/keinen AT-SPI-Autoklicker), nur bisher blind mitkopiert. README.md um einen Abschnitt zum neuen Boot-Medium-Bauweg ergaenzt (build_boot_medium.sh/build_customer_iso.sh vs. weiterhin Fedora-spezifisches build.sh).
This commit is contained in:
parent
b9ccae6e85
commit
d179f9c2f5
21
README.md
21
README.md
@ -14,3 +14,24 @@ Ziele:
|
||||
- lokaler Festplattenstart
|
||||
|
||||
Die eigentliche Provisionierung erfolgt über den Tuxflotte Provisioning Server.
|
||||
|
||||
## Boot-Medium (Mint)
|
||||
|
||||
Das Mint-Boot-Medium ist ein eigenständiges, per Debian `live-build`
|
||||
gebautes Image (`boot-medium/`, siehe ADR-0025) - kein gepatchter
|
||||
Distributions-Installer mehr. Es enthält nur Tuxflottes eigenen,
|
||||
headless-tauglichen Code (Module `scripts/modules/00`-`40`,
|
||||
`backends/mint-image/`) und bootet direkt in einen systemd-Dienst, der
|
||||
`installer.sh` startet.
|
||||
|
||||
- `scripts/build_boot_medium.sh [--dev]` baut das Basis-Image
|
||||
(`boot-medium/live-image-amd64.hybrid.iso`). `--dev` aktiviert einen
|
||||
SSH-Debug-Zugang (`tuxflotte`/`test123`); ohne `--dev` bleibt SSH
|
||||
deaktiviert (Produktiv-Default).
|
||||
- `scripts/build_customer_iso.sh <source.iso> <output.iso> <activation_code> [wifi_ssid] [wifi_psk] [volid]`
|
||||
personalisiert ein bereits gebautes Basis-Image für eine konkrete
|
||||
Kundenorganisation (Aktivierungscode + WLAN-Zugangsdaten).
|
||||
|
||||
Fedora nutzt weiterhin das ältere Kickstart/Anaconda-Muster
|
||||
(`scripts/build.sh <source.iso> fedora`) - noch nicht auf dasselbe
|
||||
Boot-Medium-Muster umgestellt.
|
||||
|
||||
@ -1,454 +0,0 @@
|
||||
#!/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"
|
||||
# Von 10_hardware.sh im selben Live-Boot geschrieben (siehe dort) - Quelle
|
||||
# fuer den Fingerprint, der jetzt auch auf dem installierten Geraet selbst
|
||||
# hinterlegt wird (siehe backend_generate_config()/postinstall.sh).
|
||||
HARDWARE_FILE="/run/tuxflotte/hardware/hardware.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() {
|
||||
# jq/envsubst(gettext-base)/cpio/kexec-tools sind auf dem Live-Medium
|
||||
# selbst (anders als im Zielsystem, siehe pkgsel/include in preseed.tpl)
|
||||
# nicht vorinstalliert - real gegen das Live-Abbild verifiziert
|
||||
# (Phase-1-Spike, zunächst nur für kexec-tools behoben, hier auf alle
|
||||
# vier Live-only-Werkzeuge ausgeweitet). base64 kommt aus coreutils und
|
||||
# ist auf jedem Debian-Derivat immer vorhanden, deshalb ohne Nachinstal-
|
||||
# lationspfad.
|
||||
local live_packages_needed=()
|
||||
|
||||
command -v jq >/dev/null 2>&1 || live_packages_needed+=(jq)
|
||||
command -v envsubst >/dev/null 2>&1 || live_packages_needed+=(gettext-base)
|
||||
command -v cpio >/dev/null 2>&1 || live_packages_needed+=(cpio)
|
||||
command -v kexec >/dev/null 2>&1 || live_packages_needed+=(kexec-tools)
|
||||
|
||||
if [[ "${#live_packages_needed[@]}" -gt 0 ]]; then
|
||||
backend_log "Werkzeuge fehlen auf dem Live-Medium, installiere nach: ${live_packages_needed[*]}"
|
||||
|
||||
sed -i '/^deb cdrom/d' /etc/apt/sources.list 2>/dev/null || true
|
||||
rm -f /etc/apt/sources.list.d/*cdrom* 2>/dev/null || true
|
||||
|
||||
apt-get update -qq ||
|
||||
{ backend_fatal "apt-get update fehlgeschlagen."; return 1; }
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y "${live_packages_needed[@]}" ||
|
||||
{ backend_fatal "Installation fehlender Werkzeuge fehlgeschlagen."; return 1; }
|
||||
fi
|
||||
|
||||
command -v base64 >/dev/null 2>&1 ||
|
||||
{ backend_fatal "Benötigtes Werkzeug fehlt: base64"; return 1; }
|
||||
|
||||
[[ -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 == "object")
|
||||
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}'."
|
||||
}
|
||||
|
||||
|
||||
# Baut einen einzelnen partman-auto/expert_recipe-Partitionsblock als
|
||||
# EINZEILIGEN String (Felder durch Leerzeichen statt Zeilenumbrueche
|
||||
# getrennt) - Debconf-Preseed-Werte mit eingebetteten Zeilenumbruechen
|
||||
# brechen leicht lautlos (siehe base64-Kommentar bei success_command weiter
|
||||
# unten fuer denselben Fallstrick an anderer Stelle), partmans Parser selbst
|
||||
# ist bei Leerzeichen als Trenner tolerant.
|
||||
_tuxflotte_partman_stanza() {
|
||||
local size_mb="$1"
|
||||
local filesystem="$2"
|
||||
local mountpoint="$3"
|
||||
local extra_flags="${4:-}"
|
||||
|
||||
printf '%s %s %s %s %s method{ format } format{ } use_filesystem{ } filesystem{ %s } mountpoint{ %s } . ' \
|
||||
"${size_mb}" "${size_mb}" "${size_mb}" "${filesystem}" "${extra_flags}" "${filesystem}" "${mountpoint}"
|
||||
}
|
||||
|
||||
# Ermittelt den ersten echten Datentraeger des Zielgeraets fuer die
|
||||
# Groessenberechnung bei prozentualer Partitionierung (Fedoras autopart macht
|
||||
# implizit dieselbe Ein-Datentraeger-Annahme, siehe fedora/backend.sh).
|
||||
# Groessenfilter (>0) und Namensausschluss noetig - reale Systeme koennen
|
||||
# nbd-/zram-/loop-Geraete mit type=="disk" aber ohne echte Speicherkapazitaet
|
||||
# auflisten, die sonst faelschlich vor dem echten Zieldatentraeger gewaehlt
|
||||
# wuerden (real beim Testen entdeckt).
|
||||
_tuxflotte_detect_target_disk() {
|
||||
lsblk --nodeps --noheadings --bytes --output NAME,TYPE,SIZE --paths |
|
||||
awk '$2 == "disk" && $3 > 0 && $1 !~ /(nbd|zram|loop)[0-9]*$/ { print $1; exit }'
|
||||
}
|
||||
|
||||
# Baut den kompletten partman-auto/expert_recipe-Rezeptkoerper aus dem
|
||||
# installation_directives.partitioning-Objekt. Prozentangaben werden anhand
|
||||
# der realen Zieldatentraegergroesse (erst hier, live auf dem Zielgeraet,
|
||||
# bekannt - nicht beim ISO-Bau) in feste MB-Groessen umgerechnet. Bewusst
|
||||
# feste Groessen (min=priority=max) statt partmans eigener proportionaler
|
||||
# Prioritaets-Verteilung - deterministischer und leichter zu verifizieren.
|
||||
_tuxflotte_render_partman_recipe() {
|
||||
local partitioning_json="$1"
|
||||
local root_filesystem="$2"
|
||||
local scheme
|
||||
local disk_device
|
||||
local disk_size_mb
|
||||
local extra_count
|
||||
local extra_percent_sum=0
|
||||
local root_mb
|
||||
local recipe_body=""
|
||||
local i
|
||||
local mountpoint
|
||||
local filesystem
|
||||
local percent
|
||||
local size_mb
|
||||
local esp_mb=0
|
||||
local bios_grub_mb=0
|
||||
local root_extra_flags
|
||||
|
||||
scheme="$(jq --raw-output '.scheme // "single"' <<<"${partitioning_json}")"
|
||||
|
||||
disk_device="$(_tuxflotte_detect_target_disk)"
|
||||
[[ -n "${disk_device}" ]] ||
|
||||
{ backend_fatal "Zieldatenträger konnte nicht ermittelt werden."; return 1; }
|
||||
disk_size_mb="$(( $(blockdev --getsize64 "${disk_device}") / 1024 / 1024 ))"
|
||||
|
||||
# Die eingebauten partman-Recipes ("atomic" etc.) legen auf UEFI-Systemen
|
||||
# automatisch eine EFI-System-Partition an - ein eigenes expert_recipe
|
||||
# muss das selbst tun, sonst warnt/verweigert der Installer (real beim
|
||||
# Testen entdeckt: "No EFI System Partition was found"). 512 MB vorab
|
||||
# reserviert, vor der Prozentaufteilung der restlichen Platte.
|
||||
if [[ -d /sys/firmware/efi ]]; then
|
||||
# Exakte Stanza-Form aus der eingebauten "atomic"-Recipe uebernommen
|
||||
# (/usr/lib/partman/recipes-amd64-efi/30atomic auf dem Live-Medium
|
||||
# ausgelesen) - eine erste eigene Vermutung ohne $reusemethod{ } und
|
||||
# mit $bootable{ } wurde von partman zwar anstandslos geparst, aber
|
||||
# nicht als gueltige EFI-System-Partition erkannt ("No EFI System
|
||||
# Partition was found", real beim Testen entdeckt).
|
||||
esp_mb=512
|
||||
disk_size_mb="$(( disk_size_mb - esp_mb ))"
|
||||
recipe_body="${esp_mb} ${esp_mb} ${esp_mb} fat32 \$reusemethod{ } \$primary{ } method{ efi } format{ } . "
|
||||
# Root NICHT zusaetzlich $bootable{ } markieren wie im BIOS-Zweig
|
||||
# unten (real beim Testen entdeckt, 29.08.2026): auf UEFI traegt
|
||||
# bereits die ESP-Stanza oben die eigentliche Boot-Kennzeichnung
|
||||
# (method{ efi }) - das im Original-Rezept
|
||||
# /usr/lib/partman/recipes-amd64-efi/30atomic (Quelle der
|
||||
# ESP-Stanza) uebernommene Wurzel-Partitionsschema markiert die
|
||||
# Root-Partition dort ebenfalls NICHT als bootable. Ein
|
||||
# zusaetzliches $bootable{ } auf der Root-Partition scheint partman
|
||||
# in einen Zustand zu bringen, den es nach dem Commit staendig neu
|
||||
# bewerten will: der Installer klickte "Jetzt installieren"
|
||||
# nachweislich korrekt (Debug-Log erreichte sogar
|
||||
# "grub-installer/bootdev seen"), sprang aber danach immer wieder
|
||||
# zurueck auf dieselbe Partitionierungsseite (ubi-partman.py:
|
||||
# rebuild_cache(), ausgeloest durch die wiederholt gestellte
|
||||
# Debconf-Frage "ubiquity/partman-rebuild-cache" aus
|
||||
# /lib/partman/update.d/99signal_ubiquity). Noch nicht abschliessend
|
||||
# verifiziert, ob dies die alleinige Ursache ist - siehe
|
||||
# ADR-0023-Nachtrag.
|
||||
root_extra_flags='$primary{ }'
|
||||
else
|
||||
# Analoges Pendant fuer reinen BIOS-Betrieb: partman legt den
|
||||
# Datentraeger auch ohne EFI offenbar als GPT an (real beim Testen
|
||||
# bestaetigt: freier Speicher vor Partition 1 und nach der letzten
|
||||
# Partition ist die GPT-Kopfdaten-Signatur, kein MSDOS-Layout). GPT +
|
||||
# BIOS-Boot braucht eine kleine unformatierte Boot-Partition fuer den
|
||||
# GRUB-Core, sonst schlaegt /usr/lib/partman/check.d/08biosgrub fehl
|
||||
# und partman-partitioning/no_bootable_biosgrub sorgt fuer eine
|
||||
# Endlosschleife zurueck ins choose_partition-Menue statt
|
||||
# abzuschliessen (real beim Testen entdeckt und via 08biosgrub-
|
||||
# Quelltext auf dem Live-Medium verifiziert - "true" bei dieser Frage
|
||||
# bedeutet dort "Problem besteht weiterhin", nicht "trotzdem
|
||||
# fortfahren", anders als bei den meisten uebrigen Boolean-Fragen in
|
||||
# diesem Rezept). "$iflabel{ gpt }" macht die Stanza auf einem
|
||||
# MSDOS-Datentraeger automatisch wirkungslos.
|
||||
bios_grub_mb=1
|
||||
disk_size_mb="$(( disk_size_mb - bios_grub_mb ))"
|
||||
recipe_body="${bios_grub_mb} ${bios_grub_mb} ${bios_grub_mb} free \$iflabel{ gpt } \$reusemethod{ } method{ biosgrub } . "
|
||||
# Im BIOS-Zweig (anders als EFI oben) bleibt $bootable{ } auf der
|
||||
# Root-Partition noetig - hier gibt es keine ESP, die diese Rolle
|
||||
# uebernimmt.
|
||||
root_extra_flags='$primary{ } $bootable{ }'
|
||||
fi
|
||||
|
||||
case "${scheme}" in
|
||||
single)
|
||||
root_mb="$(( disk_size_mb - 1024 ))"
|
||||
[[ "${root_mb}" -ge 2048 ]] ||
|
||||
{ backend_fatal "Zieldatenträger ist zu klein (${disk_size_mb} MB)."; return 1; }
|
||||
|
||||
recipe_body="${recipe_body}$(_tuxflotte_partman_stanza "${root_mb}" "${root_filesystem}" "/" "${root_extra_flags}")"
|
||||
;;
|
||||
custom)
|
||||
extra_count="$(jq '.extra_partitions | length' <<<"${partitioning_json}")"
|
||||
[[ "${extra_count}" -gt 0 ]] ||
|
||||
{ backend_fatal "scheme=custom ohne extra_partitions angegeben."; return 1; }
|
||||
|
||||
for ((i = 0; i < extra_count; i++)); do
|
||||
mountpoint="$(jq --raw-output ".extra_partitions[${i}].mountpoint" <<<"${partitioning_json}")"
|
||||
filesystem="$(jq --raw-output ".extra_partitions[${i}].filesystem" <<<"${partitioning_json}")"
|
||||
percent="$(jq --raw-output ".extra_partitions[${i}].percent" <<<"${partitioning_json}")"
|
||||
|
||||
case "${mountpoint}" in
|
||||
/home|/var) ;;
|
||||
*) backend_fatal "Nicht unterstützter Einhängepunkt: ${mountpoint}"; return 1 ;;
|
||||
esac
|
||||
case "${filesystem}" in
|
||||
ext4|btrfs) ;;
|
||||
*) backend_fatal "Nicht unterstütztes Dateisystem: ${filesystem}"; return 1 ;;
|
||||
esac
|
||||
|
||||
extra_percent_sum="$(( extra_percent_sum + percent ))"
|
||||
done
|
||||
|
||||
[[ "${extra_percent_sum}" -gt 0 && "${extra_percent_sum}" -lt 90 ]] ||
|
||||
{ backend_fatal "Summe der Partitions-Prozentangaben ist ungültig: ${extra_percent_sum}"; return 1; }
|
||||
|
||||
root_mb="$(( disk_size_mb * (100 - extra_percent_sum) / 100 - 1024 ))"
|
||||
[[ "${root_mb}" -ge 2048 ]] ||
|
||||
{ backend_fatal "Root-Partition wäre bei dieser Aufteilung zu klein."; return 1; }
|
||||
|
||||
recipe_body="${recipe_body}$(_tuxflotte_partman_stanza "${root_mb}" "${root_filesystem}" "/" "${root_extra_flags}")"
|
||||
|
||||
for ((i = 0; i < extra_count; i++)); do
|
||||
mountpoint="$(jq --raw-output ".extra_partitions[${i}].mountpoint" <<<"${partitioning_json}")"
|
||||
filesystem="$(jq --raw-output ".extra_partitions[${i}].filesystem" <<<"${partitioning_json}")"
|
||||
percent="$(jq --raw-output ".extra_partitions[${i}].percent" <<<"${partitioning_json}")"
|
||||
size_mb="$(( disk_size_mb * percent / 100 ))"
|
||||
|
||||
recipe_body="${recipe_body}$(_tuxflotte_partman_stanza "${size_mb}" "${filesystem}" "${mountpoint}")"
|
||||
done
|
||||
;;
|
||||
*)
|
||||
backend_fatal "Nicht unterstütztes Partitionierungsschema: ${scheme}"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
printf 'tuxflotte :: %s' "${recipe_body}"
|
||||
}
|
||||
|
||||
backend_generate_config() {
|
||||
local hostname
|
||||
local device_id
|
||||
local partitioning_json
|
||||
local root_filesystem
|
||||
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; }
|
||||
|
||||
# Fuer die beidseitige Identifikation (Geraeteliste <-> Geraet selbst,
|
||||
# siehe postinstall.sh) - aus der bereits waehrend des Live-Boots
|
||||
# berechneten hardware.json, nicht aus der Serverantwort (die kennt nur
|
||||
# die zugewiesene device_id, nicht den urspruenglichen Hardware-Hash).
|
||||
local device_fingerprint
|
||||
[[ -r "${HARDWARE_FILE}" ]] ||
|
||||
{ backend_fatal "Hardware-Erfassung nicht gefunden: ${HARDWARE_FILE}"; return 1; }
|
||||
device_fingerprint="$(jq --raw-output '.identity.device_fingerprint // empty' "${HARDWARE_FILE}")"
|
||||
[[ -n "${device_fingerprint}" ]] ||
|
||||
{ backend_fatal "Kein device_fingerprint in ${HARDWARE_FILE} gefunden."; return 1; }
|
||||
|
||||
partitioning_json="$(jq --compact-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}")"
|
||||
|
||||
root_filesystem="$(jq --raw-output '.root_filesystem // "ext4"' <<<"${partitioning_json}")"
|
||||
case "${root_filesystem}" in
|
||||
ext4|btrfs) ;;
|
||||
*) backend_fatal "Nicht unterstütztes Root-Dateisystem: ${root_filesystem}"; return 1 ;;
|
||||
esac
|
||||
|
||||
partman_recipe="$(_tuxflotte_render_partman_recipe "${partitioning_json}" "${root_filesystem}")" ||
|
||||
return 1
|
||||
|
||||
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}" \
|
||||
TUXFLOTTE_DEVICE_FINGERPRINT="${device_fingerprint}" \
|
||||
envsubst '${TUXFLOTTE_DEVICE_ID} ${TUXFLOTTE_BLUEPRINTS_JSON} ${TUXFLOTTE_DEVICE_FINGERPRINT}' \
|
||||
<"${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() {
|
||||
local cdrom_vmlinuz="/cdrom/casper/vmlinuz"
|
||||
local cdrom_initrd="/cdrom/casper/initrd.lz"
|
||||
local extra_initrd_dir="${RUNTIME_DIR}/initrd-extra"
|
||||
local extra_cpio="${RUNTIME_DIR}/extra.cpio.gz"
|
||||
local custom_initrd="${RUNTIME_DIR}/initrd-custom.lz"
|
||||
|
||||
[[ -r "${cdrom_vmlinuz}" && -r "${cdrom_initrd}" ]] ||
|
||||
{ backend_fatal "Casper-Kernel/-Initrd nicht gefunden unter /cdrom/casper."; return 1; }
|
||||
|
||||
# Das personalisierte Preseed (CONFIG_FILE, erst live auf diesem Gerät
|
||||
# erzeugt - Hostname/Geräte-ID/Partitionierung sind erst hier bekannt,
|
||||
# nicht schon beim ISO-Bau) kann nicht per file=/cdrom/... übergeben
|
||||
# werden (read-only Medium, Inhalt seit ISO-Bau fixiert) und auch nicht
|
||||
# per url= von einem selbst gestarteten lokalen Server - der komplette
|
||||
# Prozess- und Netzwerkzustand dieser Sitzung geht beim Kexec-Sprung
|
||||
# verloren, ein soeben gestarteter HTTP-Server koennte die neue
|
||||
# Boot-Umgebung also nicht mehr bedienen. Stattdessen wird das Preseed in
|
||||
# eine zusaetzliche Initrd-Schicht eingebettet: der Kernel unterstuetzt
|
||||
# aneinandergehaengte cpio-Archive als initramfs (spaetere Archive
|
||||
# ergaenzen fruehere), das uebersteht den Kexec-Uebergang unveraendert.
|
||||
# Real gegen QEMU verifiziert (Phase-1-Spike, beide Ansaetze getestet).
|
||||
rm -rf "${extra_initrd_dir}"
|
||||
install -d --mode=0700 --owner=root --group=root "${extra_initrd_dir}"
|
||||
cp "${CONFIG_FILE}" "${extra_initrd_dir}/preseed.cfg"
|
||||
|
||||
(cd "${extra_initrd_dir}" && find . | cpio -o -H newc 2>/dev/null | gzip) \
|
||||
>"${extra_cpio}" ||
|
||||
{ backend_fatal "Preseed-Initrd-Schicht konnte nicht gebaut werden."; return 1; }
|
||||
|
||||
cat "${cdrom_initrd}" "${extra_cpio}" >"${custom_initrd}" ||
|
||||
{ backend_fatal "Initrd konnte nicht zusammengesetzt werden."; return 1; }
|
||||
|
||||
backend_log "Lade Kexec-Ziel fuer automatisierten Ubiquity-Start."
|
||||
|
||||
# Ubiquitys eigenes "noninteractive"-Frontend (ubiquity/frontend/
|
||||
# noninteractive.py, ueber das gleichnamige Boot-Keyword ausgewaehlt)
|
||||
# arbeitet zwar rein ueber Debconf ohne je ein Fenster zu zeichnen, aber
|
||||
# dessen Seite fuer die gefuehrte Partitionierung (ubi-partman.py) haengt
|
||||
# sich bei einem vollstaendig vorbefuellten Rezept in einer echten
|
||||
# Endlosschleife auf (staendiges Neuaufbauen des choose_partition-Menues,
|
||||
# "partman/confirm" wird nie erreicht - real ueber >800 Wiederholungen
|
||||
# ohne Fortschritt bestaetigt, siehe ADR-0023-Nachtrag). Ursache: die
|
||||
# PageNoninteractive-Klasse liefert fuer etliche vom GTK-Codepfad
|
||||
# benoetigte Rueckfragen (get_autopartition_choice(), get_crypto_keys())
|
||||
# nur "pass"/None statt echter Werte.
|
||||
#
|
||||
# Deshalb bewusst zurueck auf "automatic-ubiquity" (echte GTK-Oberflaeche,
|
||||
# PageGtk-Klasse - der von Ubiquity selbst getestete, produktiv genutzte
|
||||
# Codepfad, auch fuer die Partitionierung). Der GTK-Assistent fuellt jede
|
||||
# Seite aus dem Preseed vor, wartet aber weiterhin auf einen "Weiter"-Klick
|
||||
# pro Seite (real verifiziert, siehe ADR-0023-Nachtrag) - dafuer laeuft
|
||||
# zusaetzlich autoclicker.sh (live-updates/opt/tuxflotte/scripts/), per
|
||||
# systemd-Service und ausgeloest durch das eigene Boot-Keyword
|
||||
# "tuxflotte-autoclick" (harmlos bei jedem anderen Boot ohne dieses
|
||||
# Keyword). "debug-ubiquity" (setzt debug="-d") macht
|
||||
# /var/log/installer/debug ausfuehrlicher, hilfreich bei weiterer
|
||||
# Fehlersuche.
|
||||
# username=/hostname=mint bewusst ergaenzt (real beim Testen entdeckt,
|
||||
# 29.08.2026): ohne diese beiden Parameter faellt casper auf dem
|
||||
# kexec-Boot auf einen anderen Live-Account-Zustand zurueck als beim
|
||||
# ersten Boot (der die grub.cfg-Vorlage explizit mit "username=mint
|
||||
# hostname=mint" startet) - konkret verlangt der Konsolenlogin auf
|
||||
# diesem zweiten Boot ein echtes Passwort statt des sonst leeren
|
||||
# Live-Session-Passworts. Fuer den eigentlichen Auto-Install-Ablauf
|
||||
# (GTK-Assistent unter ubiquity-dm, kein Konsolenlogin noetig)
|
||||
# folgenlos, aber inkonsistent gegenueber dem ersten Boot und erschwert
|
||||
# die Fehlersuche via Konsole unnoetig - deshalb hier angeglichen.
|
||||
kexec -l "${cdrom_vmlinuz}" \
|
||||
--initrd="${custom_initrd}" \
|
||||
--append="boot=casper automatic-ubiquity tuxflotte-autoclick debug-ubiquity noprompt file=/preseed.cfg debian-installer/language=de keyboard-configuration/layoutcode=de username=mint hostname=mint quiet splash ---" ||
|
||||
{ backend_fatal "kexec -l fehlgeschlagen."; return 1; }
|
||||
|
||||
backend_log "Starte unbeaufsichtigte Installation (kexec -e). Kein Ruecksprung erwartet - ab hier laeuft die eigentliche Installation im neuen Kernel weiter."
|
||||
|
||||
kexec -e
|
||||
}
|
||||
|
||||
backend_postinstall() {
|
||||
backend_log "Provisioning-Agent-Einrichtung erfolgt im ubiquity/success_command der Preseed-Konfiguration (Agent-Abruf, Bootstrap-Registrierung, systemd-Aktivierung)."
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
#!/bin/bash
|
||||
{
|
||||
echo "tuxflotte: early_command lief, $(date -u)"
|
||||
echo "--- ip link ---"
|
||||
ip link 2>&1
|
||||
echo "--- nmcli device status (vorher) ---"
|
||||
nmcli device status 2>&1
|
||||
echo "--- WLAN verbinden (mit Wiederholung, falls Treiber noch nicht bereit) ---"
|
||||
for i in 1 2 3 4 5 6; do
|
||||
nmcli device wifi rescan 2>&1
|
||||
sleep 2
|
||||
if nmcli device wifi connect stallinux password a987654321 2>&1; then
|
||||
echo "WLAN verbunden nach Versuch $i"
|
||||
break
|
||||
fi
|
||||
echo "Versuch $i fehlgeschlagen, warte..."
|
||||
sleep 5
|
||||
done
|
||||
echo "--- nmcli device status (nachher) ---"
|
||||
nmcli device status 2>&1
|
||||
echo "--- curl anode /health ---"
|
||||
curl -m 10 -sS https://anode.tuxflotte.de/health 2>&1
|
||||
echo
|
||||
echo "--- debconf-set-selections Test (simuliert dynamisch von anode geholten Wert) ---"
|
||||
echo "d-i netcfg/get_hostname string tuxflotte-early-test" | debconf-set-selections
|
||||
echo "debconf-set-selections exit: $?"
|
||||
echo "--- Verifikation per debconf-communicate ---"
|
||||
echo "GET netcfg/get_hostname" | debconf-communicate 2>&1
|
||||
} >> /var/log/tuxflotte-early-command.log 2>&1
|
||||
@ -1,72 +0,0 @@
|
||||
#!/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."
|
||||
|
||||
# Identifikation soll in beide Richtungen moeglich sein: die Geraeteliste
|
||||
# zeigt den Fingerprint bereits an (siehe geraete_liste.html), aber bislang
|
||||
# gab es auf dem installierten Geraet selbst keine Datei, um ihn mit einem
|
||||
# einfachen "cat" gegenzupruefen - build_device_fingerprint() (10_hardware.sh)
|
||||
# berechnet ihn nur einmalig waehrend des Live-Boots und haelt ihn sonst
|
||||
# nirgends fest. Absichtlich Klartext, kein Secret - reiner Hardware-Hash,
|
||||
# kein chmod 0600 noetig wie bei agent.credentials.
|
||||
echo "${TUXFLOTTE_DEVICE_FINGERPRINT}" > /etc/tuxflotte/device_fingerprint ||
|
||||
tuxflotte_agent_fatal "device_fingerprint konnte nicht abgelegt 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
|
||||
@ -1,137 +0,0 @@
|
||||
### 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/expert_recipe string ${TUXFLOTTE_PARTMAN_RECIPE}
|
||||
d-i partman-auto/choose_recipe select tuxflotte
|
||||
d-i partman-partitioning/confirm_write_new_label boolean true
|
||||
d-i partman-partitioning/confirm_new_label boolean true
|
||||
# "partman/choose_partition select finish" wurde bewusst entfernt: das ist
|
||||
# die Frage des MANUELLEN/erweiterten Partitionierers ("Menu" -> "Finish
|
||||
# partitioning"), keine des gefuehrten/automatischen Ablaufs. Direktes
|
||||
# Preseeden ohne echten Seitenaufbau (weder im GTK- noch im
|
||||
# noninteractive-Frontend) fuehrt in ubi-partman.py real reproduzierbar zu
|
||||
# einer Endlosschleife im internen "building_cache"-Zustandsautomaten der
|
||||
# choose_partition-Verarbeitung (ueber 100.000 Debconf-Zeilen in wenigen
|
||||
# Sekunden ohne echten Fortschritt, sowohl mit automatic-ubiquity/GTK als
|
||||
# auch mit dem verworfenen noninteractive-Frontend - siehe ADR-0023-Nachtrag).
|
||||
# Ohne diese Zeile uebernehmen partman-auto/method + expert_recipe +
|
||||
# choose_recipe (oben) die gefuehrte Partitionierung auf dem dafuer
|
||||
# vorgesehenen Weg.
|
||||
d-i partman/confirm boolean true
|
||||
d-i partman/confirm_nochanges boolean true
|
||||
d-i partman/confirm_nooverwrite boolean true
|
||||
d-i partman/unmount_active boolean true
|
||||
d-i partman/automount boolean true
|
||||
d-i partman/filter_mounted boolean true
|
||||
d-i partman-partitioning/confirm_resize boolean true
|
||||
d-i partman-ext3/lazy_itable_init boolean true
|
||||
d-i partman/boot_not_first_partition boolean true
|
||||
d-i partman-basicfilesystems/boot_not_first_partition boolean true
|
||||
d-i partman-basicfilesystems/boot_not_ext2 boolean true
|
||||
d-i partman-ext3/boot_not_bootable boolean true
|
||||
d-i partman-ext3/boot_not_ext2_or_ext3 boolean true
|
||||
d-i partman-basicfilesystems/no_mount_point boolean true
|
||||
d-i partman-basicfilesystems/no_swap boolean true
|
||||
d-i partman-basicfilesystems/check_failed boolean true
|
||||
d-i partman-basicfilesystems/swap_check_failed boolean true
|
||||
d-i partman-ext3/bad_alignment boolean true
|
||||
# Dieselbe Polaritaets-Falle wie bei no_bootable_biosgrub weiter unten (siehe
|
||||
# dortiger Kommentar) - "true" hiesse "Problem besteht wirklich, abbrechen".
|
||||
# Fuer UEFI-Zielgeraete legt _tuxflotte_render_partman_recipe() bereits eine
|
||||
# echte ESP an, dieser Fallback sollte also nie greifen.
|
||||
d-i partman-partitioning/no_bootable_efi boolean false
|
||||
# Anders als die meisten uebrigen Boolean-Fragen hier bedeutet "true" bei
|
||||
# no_bootable_biosgrub NICHT "trotzdem fortfahren", sondern "das Problem
|
||||
# besteht wirklich" -> der pruefende Skript (check.d/08biosgrub) bricht dann
|
||||
# mit exit 1 ab, was zur Endlosschleife zurueck ins choose_partition-Menue
|
||||
# fuehrt (real entdeckt und via Quelltext auf dem Live-Medium verifiziert,
|
||||
# siehe ADR-0023-Nachtrag). Der eigentliche Fix ist eine echte BIOS-Boot-
|
||||
# Partition im Rezept (siehe _tuxflotte_render_partman_recipe() in
|
||||
# backend.sh) - "false" hier bleibt nur als defensiver Fallback, falls die
|
||||
# Partition aus irgendeinem Grund nicht als "biosgrub" erkannt wird.
|
||||
d-i partman-partitioning/no_bootable_biosgrub boolean false
|
||||
d-i partman-partitioning/bootable_logical boolean true
|
||||
d-i partman-partitioning/unknown_label boolean true
|
||||
d-i partman-partitioning/unsupported_label boolean true
|
||||
d-i partman-basicmethods/method_only boolean true
|
||||
d-i grub-installer/only_debian boolean true
|
||||
d-i grub-installer/with_other_os boolean true
|
||||
d-i grub-installer/make_active boolean true
|
||||
d-i grub-installer/grub2_instead_of_grub_legacy boolean true
|
||||
d-i grub-installer/grub_not_mature_on_this_platform boolean true
|
||||
d-i grub-installer/multipath boolean true
|
||||
d-i grub-installer/sataraid boolean true
|
||||
# Wichtig: false, nicht true -- "skip" heisst hier woertlich "GRUB-Installation
|
||||
# ueberspringen". true wuerde die Bootloader-Installation aktiv verhindern.
|
||||
d-i grub-installer/skip boolean false
|
||||
d-i partman-auto-lvm/no_boot boolean true
|
||||
d-i partman-target/mount_failed boolean true
|
||||
# partman-efi/no_efi wird ENTGEGEN der urspruenglichen Annahme sehr wohl
|
||||
# gefragt, auch im reinen BIOS/SeaBIOS-Betrieb ohne NVRAM (real via
|
||||
# debug-ubiquity-Log verifiziert, siehe ADR-0023-Nachtrag) -- Ubiquity prueft
|
||||
# offenbar unabhaengig vom aktuellen Boot-Modus, ob eine EFI-System-Partition
|
||||
# existiert. "false" heisst hier "trotzdem fortfahren" (die Alternative
|
||||
# "true" wuerde zurueck ins Partitionierungsmenue springen und den Ablauf
|
||||
# blockieren -- fuer ein bewusstes BIOS/MBR-Setup ohne EFI-Partition ist
|
||||
# false die richtige Antwort).
|
||||
d-i partman-efi/no_efi boolean false
|
||||
# Bewusst weiterhin NICHT preseeded: grub-installer/force-efi-extra-removable
|
||||
# (EFI-spezifisch, im BIOS-Betrieb ohne Wirkung) sowie partman-crypto/*,
|
||||
# partman-lvm/*, partman-jfs/* (Recipe nutzt weder Crypto noch LVM noch JFS,
|
||||
# koennen also nie auftreten; einige dieser Fragen sind bei "true" destruktiv
|
||||
# (z.B. crypto_warn_erase), daher hier absichtlich nicht blind auf true
|
||||
# gesetzt).
|
||||
|
||||
ubiquity ubiquity/summary note
|
||||
ubiquity ubiquity/reboot boolean true
|
||||
ubiquity ubiquity/use_nonfree boolean true
|
||||
# Ohne diese Zeile stuerzt Ubiquity im automatic-ubiquity-GTK-Modus real
|
||||
# reproduzierbar ab (TypeError: Argument 1 does not allow None as a value,
|
||||
# in ubi-prepare.py enable_download_updates() -> label_download_updates.
|
||||
# set_label(), ausgeloest durch einen globalen Online-Status-Callback, der
|
||||
# unabhaengig vom Automatik-Modus feuert, obwohl die zugehoerige Seite dort
|
||||
# nie aufgebaut wird - die Widget-Referenz bleibt None). Die "Waehrend der
|
||||
# Installation aktualisieren"-Option wird dadurch bewusst deaktiviert;
|
||||
# funktional kein Verlust, da der Provisioning Agent das System nach der
|
||||
# Ersteinrichtung ohnehin selbst aktuell haelt.
|
||||
ubiquity ubiquity/download_updates boolean false
|
||||
|
||||
# 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'
|
||||
@ -1,41 +0,0 @@
|
||||
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
|
||||
@ -1,57 +0,0 @@
|
||||
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
|
||||
@ -1,24 +0,0 @@
|
||||
#!/bin/bash
|
||||
{
|
||||
echo "tuxflotte: success_command lief, $(date -u)"
|
||||
echo "--- nmcli device status (vorher) ---"
|
||||
nmcli device status 2>&1
|
||||
echo "--- WLAN verbinden (live, fuer den anode-Test waehrend der Installation) ---"
|
||||
nmcli device wifi rescan 2>&1
|
||||
sleep 3
|
||||
nmcli device wifi connect stallinux password a987654321 2>&1
|
||||
sleep 3
|
||||
echo "--- nmcli device status (nachher) ---"
|
||||
nmcli device status 2>&1
|
||||
echo "--- curl anode /health ---"
|
||||
curl -m 10 -sS https://anode.tuxflotte.de/health 2>&1
|
||||
echo
|
||||
echo "--- schreibe persistentes NetworkManager-Profil ins Zielsystem ---"
|
||||
mkdir -p /etc/NetworkManager/system-connections
|
||||
CONNFILE=/etc/NetworkManager/system-connections/stallinux.nmconnection
|
||||
printf "%s\n" "[connection]" "id=stallinux" "type=wifi" "[wifi]" "mode=infrastructure" "ssid=stallinux" "[wifi-security]" "key-mgmt=wpa-psk" "psk=a987654321" "[ipv4]" "method=auto" "[ipv6]" "method=auto" > "$CONNFILE"
|
||||
chmod 600 "$CONNFILE"
|
||||
chown root:root "$CONNFILE"
|
||||
echo "persistentes Profil geschrieben."
|
||||
} >> /var/log/tuxflotte-postinstall.log 2>&1
|
||||
echo "dvd-wlan-test (ADR-0009, Mint-Fortsetzung) -- provisioned by tuxflotte" > /etc/motd
|
||||
@ -1,56 +0,0 @@
|
||||
### Test-Preseed fuer ADR-0009 Fortsetzung mit Mint/Ubuntu (31.07.2026-01.08.2026).
|
||||
### Liegt direkt auf dem Medium (file=/cdrom/preseed/tuxflotte.seed), keine
|
||||
### Netz-Zustellung noetig -- analog zu Fedoras inst.ks=cdrom:/ks.cfg.
|
||||
|
||||
# Test 01.08.2026: laeuft VOR allen anderen Fragen (Partitionierung etc.),
|
||||
# nicht gechrootet -- Ziel ist zu pruefen, ob so frueh schon WLAN herstellbar
|
||||
# ist und ob debconf-set-selections tatsaechlich spaetere Fragen beeinflusst.
|
||||
# Base64 von Anfang an (Lehre aus success_command Versuch 3 gestern).
|
||||
d-i preseed/early_command string bash -c 'echo IyEvYmluL2Jhc2gKewogIGVjaG8gInR1eGZsb3R0ZTogZWFybHlfY29tbWFuZCBsaWVmLCAkKGRhdGUgLXUpIgogIGVjaG8gIi0tLSBpcCBsaW5rIC0tLSIKICBpcCBsaW5rIDI+JjEKICBlY2hvICItLS0gbm1jbGkgZGV2aWNlIHN0YXR1cyAodm9yaGVyKSAtLS0iCiAgbm1jbGkgZGV2aWNlIHN0YXR1cyAyPiYxCiAgZWNobyAiLS0tIFdMQU4gdmVyYmluZGVuIChtaXQgV2llZGVyaG9sdW5nLCBmYWxscyBUcmVpYmVyIG5vY2ggbmljaHQgYmVyZWl0KSAtLS0iCiAgZm9yIGkgaW4gMSAyIDMgNCA1IDY7IGRvCiAgICBubWNsaSBkZXZpY2Ugd2lmaSByZXNjYW4gMj4mMQogICAgc2xlZXAgMgogICAgaWYgbm1jbGkgZGV2aWNlIHdpZmkgY29ubmVjdCBzdGFsbGludXggcGFzc3dvcmQgYTk4NzY1NDMyMSAyPiYxOyB0aGVuCiAgICAgIGVjaG8gIldMQU4gdmVyYnVuZGVuIG5hY2ggVmVyc3VjaCAkaSIKICAgICAgYnJlYWsKICAgIGZpCiAgICBlY2hvICJWZXJzdWNoICRpIGZlaGxnZXNjaGxhZ2VuLCB3YXJ0ZS4uLiIKICAgIHNsZWVwIDUKICBkb25lCiAgZWNobyAiLS0tIG5tY2xpIGRldmljZSBzdGF0dXMgKG5hY2hoZXIpIC0tLSIKICBubWNsaSBkZXZpY2Ugc3RhdHVzIDI+JjEKICBlY2hvICItLS0gY3VybCBhbm9kZSAvaGVhbHRoIC0tLSIKICBjdXJsIC1tIDEwIC1zUyBodHRwczovL2Fub2RlLnR1eGZsb3R0ZS5kZS9oZWFsdGggMj4mMQogIGVjaG8KICBlY2hvICItLS0gZGViY29uZi1zZXQtc2VsZWN0aW9ucyBUZXN0IChzaW11bGllcnQgZHluYW1pc2NoIHZvbiBhbm9kZSBnZWhvbHRlbiBXZXJ0KSAtLS0iCiAgZWNobyAiZC1pIG5ldGNmZy9nZXRfaG9zdG5hbWUgc3RyaW5nIHR1eGZsb3R0ZS1lYXJseS10ZXN0IiB8IGRlYmNvbmYtc2V0LXNlbGVjdGlvbnMKICBlY2hvICJkZWJjb25mLXNldC1zZWxlY3Rpb25zIGV4aXQ6ICQ/IgogIGVjaG8gIi0tLSBWZXJpZmlrYXRpb24gcGVyIGRlYmNvbmYtY29tbXVuaWNhdGUgLS0tIgogIGVjaG8gIkdFVCBuZXRjZmcvZ2V0X2hvc3RuYW1lIiB8IGRlYmNvbmYtY29tbXVuaWNhdGUgMj4mMQp9ID4+IC92YXIvbG9nL3R1eGZsb3R0ZS1lYXJseS1jb21tYW5kLmxvZyAyPiYxCg== | base64 -d | bash'
|
||||
|
||||
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-mint-test
|
||||
d-i netcfg/get_domain string unassigned-domain
|
||||
|
||||
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 atomic
|
||||
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
|
||||
|
||||
# Versuch 4: kein automatischer Reboot mehr, damit wir vor dem Neustart aus
|
||||
# der Live-Sitzung heraus direkt unter /target/... nachsehen koennen, ob
|
||||
# alles geschrieben wurde -- auf Vorschlag des Nutzers.
|
||||
ubiquity ubiquity/reboot boolean false
|
||||
|
||||
# Versuch 1: wlp9s0 (Intel AX210) erkannt, aber nicht verbunden (keine
|
||||
# Zugangsdaten). Versuch 2: nmcli verbindet + anode per curl erreichbar
|
||||
# WAEHREND der Installation -- funktioniert. Verbindung ueberlebte den
|
||||
# Reboot nicht (nmcli sprach vermutlich mit der Live-NetworkManager-Instanz,
|
||||
# nicht mit einer, die ins Zielsystem schreibt). Versuch 3: direktes
|
||||
# Schreiben der .nmconnection-Datei als eigener Preseed-Wert -- Datei kam
|
||||
# nie an, kein Log vorhanden, vermutlich Debconf-Problem mit einem so
|
||||
# langen, mehrzeiligen Preseed-Wert (lokaler Bash-Syntaxtest war fehlerfrei,
|
||||
# also kein Bash-Problem). Versuch 4 (dieser): dasselbe Skript Base64-
|
||||
# kodiert -- der Preseed-Wert besteht dadurch nur noch aus unkritischen
|
||||
# Zeichen, keine Anfuehrungszeichen/Klammern mehr, die Debconf Probleme
|
||||
# machen koennten.
|
||||
ubiquity ubiquity/use_nonfree boolean true
|
||||
|
||||
ubiquity ubiquity/success_command string in-target bash -c 'echo IyEvYmluL2Jhc2gKewogIGVjaG8gInR1eGZsb3R0ZTogc3VjY2Vzc19jb21tYW5kIGxpZWYsICQoZGF0ZSAtdSkiCiAgZWNobyAiLS0tIG5tY2xpIGRldmljZSBzdGF0dXMgKHZvcmhlcikgLS0tIgogIG5tY2xpIGRldmljZSBzdGF0dXMgMj4mMQogIGVjaG8gIi0tLSBXTEFOIHZlcmJpbmRlbiAobGl2ZSwgZnVlciBkZW4gYW5vZGUtVGVzdCB3YWVocmVuZCBkZXIgSW5zdGFsbGF0aW9uKSAtLS0iCiAgbm1jbGkgZGV2aWNlIHdpZmkgcmVzY2FuIDI+JjEKICBzbGVlcCAzCiAgbm1jbGkgZGV2aWNlIHdpZmkgY29ubmVjdCBzdGFsbGludXggcGFzc3dvcmQgYTk4NzY1NDMyMSAyPiYxCiAgc2xlZXAgMwogIGVjaG8gIi0tLSBubWNsaSBkZXZpY2Ugc3RhdHVzIChuYWNoaGVyKSAtLS0iCiAgbm1jbGkgZGV2aWNlIHN0YXR1cyAyPiYxCiAgZWNobyAiLS0tIGN1cmwgYW5vZGUgL2hlYWx0aCAtLS0iCiAgY3VybCAtbSAxMCAtc1MgaHR0cHM6Ly9hbm9kZS50dXhmbG90dGUuZGUvaGVhbHRoIDI+JjEKICBlY2hvCiAgZWNobyAiLS0tIHNjaHJlaWJlIHBlcnNpc3RlbnRlcyBOZXR3b3JrTWFuYWdlci1Qcm9maWwgaW5zIFppZWxzeXN0ZW0gLS0tIgogIG1rZGlyIC1wIC9ldGMvTmV0d29ya01hbmFnZXIvc3lzdGVtLWNvbm5lY3Rpb25zCiAgQ09OTkZJTEU9L2V0Yy9OZXR3b3JrTWFuYWdlci9zeXN0ZW0tY29ubmVjdGlvbnMvc3RhbGxpbnV4Lm5tY29ubmVjdGlvbgogIHByaW50ZiAiJXNcbiIgIltjb25uZWN0aW9uXSIgImlkPXN0YWxsaW51eCIgInR5cGU9d2lmaSIgIlt3aWZpXSIgIm1vZGU9aW5mcmFzdHJ1Y3R1cmUiICJzc2lkPXN0YWxsaW51eCIgIlt3aWZpLXNlY3VyaXR5XSIgImtleS1tZ210PXdwYS1wc2siICJwc2s9YTk4NzY1NDMyMSIgIltpcHY0XSIgIm1ldGhvZD1hdXRvIiAiW2lwdjZdIiAibWV0aG9kPWF1dG8iID4gIiRDT05ORklMRSIKICBjaG1vZCA2MDAgIiRDT05ORklMRSIKICBjaG93biByb290OnJvb3QgIiRDT05ORklMRSIKICBlY2hvICJwZXJzaXN0ZW50ZXMgUHJvZmlsIGdlc2NocmllYmVuLiIKfSA+PiAvdmFyL2xvZy90dXhmbG90dGUtcG9zdGluc3RhbGwubG9nIDI+JjEKZWNobyAiZHZkLXdsYW4tdGVzdCAoQURSLTAwMDksIE1pbnQtRm9ydHNldHp1bmcpIC0tIHByb3Zpc2lvbmVkIGJ5IHR1eGZsb3R0ZSIgPiAvZXRjL21vdGQK | base64 -d | bash'
|
||||
@ -1,44 +0,0 @@
|
||||
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 priority=critical 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
|
||||
menuentry 'Von lokaler Festplatte booten (Standard)' {
|
||||
exit 1
|
||||
}
|
||||
set default="Von lokaler Festplatte booten (Standard)"
|
||||
fi
|
||||
@ -1,57 +0,0 @@
|
||||
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 priority=critical 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
|
||||
@ -1,71 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
PREREQ=""
|
||||
|
||||
prereqs()
|
||||
{
|
||||
echo "$PREREQ"
|
||||
}
|
||||
|
||||
case $1 in
|
||||
# get pre-requisites
|
||||
prereqs)
|
||||
prereqs
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# Ueberschreibt das originale 99casperboot (macht nur `touch
|
||||
# /run/.casper-boot`) statt einen zusaetzlichen, neuen Hook-Skriptnamen
|
||||
# einzufuehren: initramfs-tools generiert beim ISO-Bau eine ORDER-Datei
|
||||
# (scripts/casper-bottom/ORDER) mit der fest verdrahteten Aufruf-Reihenfolge
|
||||
# aller casper-bottom-Skripte - real durch Extraktion des echten initrd.lz
|
||||
# mit unmkinitramfs bestaetigt. Ein per Initrd-Cpio-Layer NEU hinzugefuegtes
|
||||
# Skript taucht in dieser ORDER-Datei nicht auf und wird nie aufgerufen,
|
||||
# selbst wenn die Datei im initramfs physisch vorhanden ist (erste Version
|
||||
# dieses Fixes ist daran gescheitert). Das Ueberschreiben eines bereits in
|
||||
# ORDER referenzierten Pfads funktioniert dagegen zuverlaessig (spaetere
|
||||
# cpio-Schichten ueberschreiben Dateiinhalte am selben Pfad, siehe
|
||||
# scripts/lib/initrd.sh - derselbe Mechanismus, der schon fuer das
|
||||
# Kexec-Preseed in Phase 1 verifiziert wurde). 99casperboot ist laut ORDER
|
||||
# das letzte casper-bottom-Skript ueberhaupt - garantiert nach 05mountpoints,
|
||||
# das /cdrom nach /root/cdrom umhaengt und damit die Voraussetzung fuer den
|
||||
# folgenden Kopiervorgang schafft.
|
||||
if [ -d /root/cdrom/updates ]; then
|
||||
cp -a /root/cdrom/updates/. /root/
|
||||
fi
|
||||
|
||||
# Ubiquity stuerzt im automatic-ubiquity-GTK-Modus real reproduzierbar ab
|
||||
# (TypeError: Argument 1 does not allow None as a value), sobald
|
||||
# enable_download_updates(False) den Netzwerkstatus als "nicht verbunden"
|
||||
# meldet: ubi-prepare.py uebergibt das Ergebnis von
|
||||
# self.controller.get_string('ubiquity/text/label_download_updates_na')
|
||||
# ungeprueft an GtkLabel.set_label() - fehlt fuer diese Vorlage/Sprache ein
|
||||
# Uebersetzungsstring, liefert get_string() None statt eines leeren Strings,
|
||||
# und GTK akzeptiert kein None als Label-Text (real ueber QEMU-Testlauf
|
||||
# gefunden, siehe ADR-0023-Nachtrag). Gezielter Sed-Patch statt vollstaendigem
|
||||
# Datei-Ersatz, um nicht die komplette Drittanbieter-Datei mitpflegen zu
|
||||
# muessen - betrifft nur die eine Zeile, "or ''" faengt jeden None-Rueckgabewert
|
||||
# ab, unabhaengig von der genauen Ursache der fehlenden Uebersetzung.
|
||||
ubi_prepare="/root/usr/lib/ubiquity/plugins/ubi-prepare.py"
|
||||
if [ -f "$ubi_prepare" ]; then
|
||||
sed -i \
|
||||
"s/self\.controller\.get_string(template))/self.controller.get_string(template) or '')/" \
|
||||
"$ubi_prepare"
|
||||
fi
|
||||
|
||||
# AT-SPI-Bruecke fuer den Autoklicker (atspi_click.py) muss VOR dem
|
||||
# GTK-Start von Ubiquity aktiv sein - siehe live-updates/usr/share/ubiquity/
|
||||
# tuxflotte-atspi-env.sh (dorthin per casper-bottom-Kopie oben bereits nach
|
||||
# /root/usr/share/ubiquity/ ausgeliefert). Einzeilige Einbindung direkt nach
|
||||
# dem fruehen Existenz-Check von ubiquity-dm - alles Weitere, inkl.
|
||||
# Paketinstallation, uebernimmt die eingebundene Datei selbst.
|
||||
start_ubiquity_dm="/root/usr/share/ubiquity/start-ubiquity-dm"
|
||||
if [ -f "$start_ubiquity_dm" ]; then
|
||||
sed -i \
|
||||
'/^test -x \/usr\/bin\/ubiquity-dm || exit 0$/a\
|
||||
. /usr/share/ubiquity/tuxflotte-atspi-env.sh' \
|
||||
"$start_ubiquity_dm"
|
||||
fi
|
||||
|
||||
touch /run/.casper-boot
|
||||
@ -1 +0,0 @@
|
||||
mint ALL=(ALL) NOPASSWD: ALL
|
||||
@ -1 +0,0 @@
|
||||
../tuxflotte-autoclicker.service
|
||||
@ -1,17 +0,0 @@
|
||||
[Unit]
|
||||
Description=Tuxflotte Autoklicker fuer Ubiquitys GTK-Installationsassistenten
|
||||
# Nur bei automatisierter Installation relevant (siehe autoclicker.sh -
|
||||
# prueft selbst auf das Boot-Keyword "tuxflotte-autoclick" und beendet sich
|
||||
# sofort, wenn es fehlt). Bewusst kein "After=graphical.target" o.ae., da
|
||||
# ubiquity-dm keine normale Display-Manager-Sitzung startet, deren
|
||||
# Bereitschaft systemd auf ueblichem Weg erkennen wuerde - das Skript selbst
|
||||
# wartet auf den X-Socket.
|
||||
After=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/opt/tuxflotte/scripts/autoclicker.sh
|
||||
Restart=no
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@ -1,4 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=SELinux Troubleshooter Notifier
|
||||
Hidden=true
|
||||
@ -1,6 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Tuxflotte Provisioning
|
||||
Exec=/opt/tuxflotte/kiosk/start-kiosk.sh
|
||||
X-GNOME-Autostart-enabled=true
|
||||
NoDisplay=true
|
||||
@ -1,33 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Tuxflotte Provisioning</title>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #ffffff;
|
||||
color: #3465a4;
|
||||
font-family: sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
img {
|
||||
max-width: 60%;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
p {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img src="logo.svg" alt="Tuxflotte">
|
||||
<p>Kiosk-Oberfläche in Entwicklung.</p>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 77 KiB |
@ -1,42 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# German keyboard layout for the graphical session (vconsole.keymap=de on the
|
||||
# kernel cmdline only covers the text console, not X11/Wayland input). Cinnamon
|
||||
# ships its own parallel org.cinnamon.desktop.input-sources schema, separate
|
||||
# from GNOME's org.gnome.desktop.input-sources — writing org.gnome alone had
|
||||
# no effect (confirmed on real hardware), so both are set here.
|
||||
dconf write /org/cinnamon/desktop/input-sources/sources "[('xkb', 'de')]"
|
||||
dconf write /org/gnome/desktop/input-sources/sources "[('xkb', 'de')]"
|
||||
|
||||
# Suppresses Epiphany's "set as default browser?" first-run prompt (schema
|
||||
# default is true, see /usr/share/glib-2.0/schemas/org.gnome.epiphany.gschema.xml).
|
||||
dconf write /org/gnome/epiphany/ask-for-default false
|
||||
|
||||
# Kiosk cleanup: no desktop icons (Nemo). The panel itself is kept (removing
|
||||
# the last panel via panels-enabled triggers Cinnamon's own "you don't have
|
||||
# any panels, open panel settings?" confirmation dialog — hardcoded in
|
||||
# js/ui/panel.js, no way to suppress it, so panels-enabled is deliberately
|
||||
# left untouched). Instead, only the two useful applets are kept: a window
|
||||
# list (to restore Epiphany if a user minimizes it) and power (shutdown/
|
||||
# reboot) — everything else (menu, systray, clock, workspace switcher etc.)
|
||||
# is removed. Deliberately the classic window-list@cinnamon.org, not
|
||||
# grouped-window-list@cinnamon.org: the grouped variant ships default
|
||||
# "pinned apps" launchers (firefox.desktop, org.gnome.Terminal.desktop,
|
||||
# nemo.desktop — confirmed via its settings-schema.json) that showed up in
|
||||
# the panel even with unrelated applets removed. Plain window-list has no
|
||||
# pinned-apps concept at all, only ever shows actually open windows.
|
||||
dconf write /org/nemo/desktop/show-desktop-icons false
|
||||
dconf write /org/cinnamon/enabled-applets "['panel1:left:0:window-list@cinnamon.org:1', 'panel1:right:0:power@cinnamon.org:2']"
|
||||
|
||||
mkdir -p "${HOME}/.local/share/tuxflotte-kiosk"
|
||||
|
||||
# Auto-Modus (personalisierte Kunden-ISO, siehe scripts/build_customer_iso.sh)
|
||||
# startet den Installer sofort unbeaufsichtigt statt der Kiosk-Startseite -
|
||||
# config/installer.conf wird nur bei personalisierten Abbildern mitgeliefert,
|
||||
# das Standard-/Testabbild bleibt unverändert interaktiv.
|
||||
if grep -qE '^\s*(export\s+)?TUXFLOTTE_AUTO_MODE=true\s*$' /opt/tuxflotte/config/installer.conf 2>/dev/null; then
|
||||
exec sudo /opt/tuxflotte/scripts/installer.sh
|
||||
fi
|
||||
|
||||
exec epiphany --profile="${HOME}/.local/share/tuxflotte-kiosk" file:///opt/tuxflotte/kiosk/index.html
|
||||
@ -1,308 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Klickt den primaeren "Weiter"-Button der aktuell sichtbaren Ubiquity-Seite
|
||||
per AT-SPI (Linux-Barrierefreiheits-API) - wird von autoclicker.sh wiederholt
|
||||
aufgerufen (ein Prozessstart pro Klickversuch, absichtlich einfach statt
|
||||
dauerhaft im Hintergrund am Accessibility-Bus zu lauschen).
|
||||
|
||||
Warum AT-SPI statt Bildschirmkoordinaten: der urspruengliche xdotool-Ansatz
|
||||
scheiterte daran, dass Metacity mehrere ueberlappende X11-Fenster aehnlicher
|
||||
Groesse erzeugt (WM-Dekorationsrahmen, Hilfsfenster) - eine "groesstes
|
||||
sichtbares Fenster"-Heuristik traf wiederholt das falsche Fenster (siehe
|
||||
ADR-0023-Nachtrag). AT-SPI identifiziert den Button stattdessen ueber seine
|
||||
Rolle (PUSH_BUTTON) und seinen Namen im Accessibility-Baum der Anwendung
|
||||
selbst - unabhaengig von Fenstergeometrie/-dekoration.
|
||||
|
||||
WICHTIG (real beim Testen entdeckt, 29.08.2026): trotz fest gesetztem
|
||||
"debian-installer/language=de" sind NICHT alle Assistentenseiten auf
|
||||
Deutsch beschriftet - die Mint-eigene "Multimedia-Codecs"-Seite zeigt reale
|
||||
englische Buttons ("Quit"/"Back"/"Continue"), vermutlich dieselbe Ursache
|
||||
wie der bereits gepatchte ubi-prepare.py-None-Bug (fehlender/unvollstaendiger
|
||||
.mo-Uebersetzungskatalog fuer dieses Plugin auf dem Live-Medium). Eine reine
|
||||
Werteliste bekannter deutscher Beschriftungen (fruehere Version dieses
|
||||
Skripts) haette hier fuer immer haengen bleiben. Die Logik wurde deshalb auf
|
||||
eine sprachunabhaengige Ausschluss-Strategie umgestellt: bekannte
|
||||
rueckwaerts-/abbrechende Beschriftungen (zweisprachig) werden aus der
|
||||
Kandidatenliste entfernt, der bzw. die verbleibenden Kandidaten werden
|
||||
geklickt - siehe select_target() fuer die genaue Regel samt
|
||||
Sicherheitsverhalten bei Mehrdeutigkeit.
|
||||
|
||||
Sprache ist durch "debian-installer/language=de" im Kexec-Append-Preseed
|
||||
grundsaetzlich auf de_DE gesetzt (siehe backend.sh), s.o. aber nicht
|
||||
verlaesslich fuer jede einzelne Seite.
|
||||
|
||||
NACHTRAG (real beim Testen entdeckt, 29.08.2026): auf der manuellen
|
||||
Partitionierungsseite ("Etwas Anderes") lief der Klick auf "Jetzt
|
||||
installieren" nachweislich zuverlaessig (AT-SPI meldete jedes Mal Erfolg),
|
||||
aber die Seite kam nie voran - stattdessen loeste jeder Klick erneut die
|
||||
Debconf-Frage "ubiquity/partman-rebuild-cache" aus
|
||||
(/lib/partman/update.d/99signal_ubiquity), was ubi-partman.py zurueck auf
|
||||
dieselbe Seite wirft (siehe ADR-0023-Nachtrag). Ein gezielter Fix am
|
||||
Partitionsrezept (kein zusaetzliches $bootable{ } auf der Root-Partition
|
||||
unter UEFI) aenderte NICHTS - das deutet auf einen zeitlichen statt
|
||||
strukturellen Fehler hin: die Seite zeigt waehrend dieser Phase ein
|
||||
Status-Panel "Konfiguration der Installation wird ueberprueft ..." - klickt
|
||||
der Autoklicker WAEHREND dieser Hintergrundpruefung noch laeuft, koennte
|
||||
er sie unterbrechen/neu anstossen, statt ihr Zeit zum Abschliessen zu
|
||||
geben. Dieses Skript wartet deshalb jetzt aktiv, solange dieser Text
|
||||
sichtbar ist (siehe VALIDATION_TEXT_MARKERS/find_showing_text()), und
|
||||
klickt erst, wenn er verschwunden ist.
|
||||
|
||||
Exit-Codes: 0 = ein Button wurde gefunden und geklickt,
|
||||
1 = kein eindeutiger Button gefunden (z.B. Seite im Ladezustand, oder echte
|
||||
Mehrdeutigkeit - dann bewusst NICHT geklickt, siehe select_target()),
|
||||
2 = pyatspi/AT-SPI-Bus nicht erreichbar (Bruecke evtl. nicht aktiv),
|
||||
3 = Ubiquitys eigene Hintergrundpruefung laeuft noch sichtbar - bewusst
|
||||
nicht geklickt, siehe Nachtrag oben.
|
||||
"""
|
||||
import sys
|
||||
|
||||
try:
|
||||
import pyatspi
|
||||
except ImportError:
|
||||
print("pyatspi nicht verfuegbar", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
# Zweisprachig, da nicht jede Seite verlaesslich deutsch beschriftet ist
|
||||
# (siehe Modul-Docstring). Diese Namen werden aus der Kandidatenliste
|
||||
# AUSGESCHLOSSEN, nie geklickt - unabhaengig davon, ob sie der einzige
|
||||
# sichtbare Button waeren.
|
||||
EXCLUDE_LABELS = {
|
||||
"zurück",
|
||||
"zurueck",
|
||||
"back",
|
||||
"abbrechen",
|
||||
"abbruch",
|
||||
"cancel",
|
||||
"beenden",
|
||||
"quit",
|
||||
"exit",
|
||||
"verwerfen",
|
||||
}
|
||||
|
||||
# Bevorzugt geklickt, falls mehrere Kandidaten nach dem Ausschluss uebrig
|
||||
# bleiben (siehe select_target()). Kein Ausschlusskriterium fuer
|
||||
# Kandidaten, die HIER nicht drin stehen - die duerfen trotzdem als
|
||||
# alleiniger Kandidat geklickt werden (Sole-Survivor-Regel), damit auch
|
||||
# unbekannte/nicht uebersetzte Beschriftungen wie das reale "Continue"
|
||||
# oben nicht zum Stillstand fuehren.
|
||||
PREFER_LABELS = {
|
||||
"weiter",
|
||||
"continue",
|
||||
"next",
|
||||
"jetzt installieren",
|
||||
"install now",
|
||||
"fortfahren",
|
||||
"proceed",
|
||||
"installieren",
|
||||
"install",
|
||||
"neu starten",
|
||||
"restart now",
|
||||
"schließen",
|
||||
"schliessen",
|
||||
"close",
|
||||
"finish",
|
||||
"fertigstellen",
|
||||
"done",
|
||||
}
|
||||
|
||||
MAX_DEPTH = 40
|
||||
|
||||
# Zweisprachig vorsichtshalber (siehe Multimedia-Codecs-Erfahrung oben),
|
||||
# auch wenn dieser konkrete Text bisher immer deutsch beobachtet wurde.
|
||||
VALIDATION_TEXT_MARKERS = (
|
||||
"wird überprüft",
|
||||
"wird ueberprueft",
|
||||
"being checked",
|
||||
"checking the install",
|
||||
)
|
||||
|
||||
|
||||
def _node_text(node):
|
||||
"""Sammelt allen aus einem Accessible auslesbaren Text: .name,
|
||||
.description UND (falls unterstuetzt) das separate Text-Interface.
|
||||
WICHTIG (real beim Testen entdeckt, 29.08.2026): ein einfaches GtkLabel
|
||||
exponiert seinen sichtbaren Text ueblicherweise NICHT ueber .name/
|
||||
.description (die bleiben dort oft leer) sondern ausschliesslich ueber
|
||||
das AT-SPI-Text-Interface (queryText().getText(0, -1)) - ohne diesen
|
||||
dritten Zugriffsweg fand find_showing_text() den sichtbar angezeigten
|
||||
Status-Text nie, obwohl er laut Screenshot die ganze Zeit auf dem Schirm
|
||||
stand."""
|
||||
parts = []
|
||||
try:
|
||||
if node.name:
|
||||
parts.append(node.name)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
if node.description:
|
||||
parts.append(node.description)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
text_iface = node.queryText()
|
||||
content = text_iface.getText(0, -1)
|
||||
if content:
|
||||
parts.append(content)
|
||||
except NotImplementedError:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
return " ".join(parts).strip().lower()
|
||||
|
||||
|
||||
def find_showing_text(node, needle, depth=0):
|
||||
"""Sucht ein sichtbares Accessible, dessen Text (siehe _node_text()) den
|
||||
Suchtext enthaelt - unabhaengig von seiner Rolle (Label/Expander/...),
|
||||
da Ubiquitys Status-Panel-Text nicht zuverlaessig unter derselben Rolle
|
||||
exponiert sein muss. Bei Unsicherheit ueber den Sichtbarkeitsstatus
|
||||
bewusst konservativ (lieber einen Zyklus zu viel warten als einen
|
||||
Klick mitten in die Pruefung setzen)."""
|
||||
if node is None or depth > MAX_DEPTH:
|
||||
return False
|
||||
if needle in _node_text(node):
|
||||
try:
|
||||
state = node.getState()
|
||||
return state.contains(pyatspi.STATE_SHOWING)
|
||||
except Exception:
|
||||
return True
|
||||
try:
|
||||
count = node.childCount
|
||||
except Exception:
|
||||
return False
|
||||
for i in range(count):
|
||||
try:
|
||||
child = node.getChildAtIndex(i)
|
||||
except Exception:
|
||||
continue
|
||||
if find_showing_text(child, needle, depth + 1):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def collect_buttons(node, depth=0, acc=None):
|
||||
"""Alle sichtbaren+aktivierten Push-Buttons im Baum einsammeln (Rolle,
|
||||
Zustand). Absichtlich ALLE Kandidaten sammeln statt beim ersten Treffer
|
||||
abzubrechen - select_target() braucht die vollstaendige Liste, um
|
||||
Mehrdeutigkeit erkennen zu koennen."""
|
||||
if acc is None:
|
||||
acc = []
|
||||
if node is None or depth > MAX_DEPTH:
|
||||
return acc
|
||||
try:
|
||||
role = node.getRole()
|
||||
except Exception:
|
||||
return acc
|
||||
|
||||
if role == pyatspi.ROLE_PUSH_BUTTON:
|
||||
try:
|
||||
state = node.getState()
|
||||
if state.contains(pyatspi.STATE_SENSITIVE) and state.contains(
|
||||
pyatspi.STATE_SHOWING
|
||||
):
|
||||
acc.append(node)
|
||||
except Exception:
|
||||
pass
|
||||
return acc
|
||||
|
||||
try:
|
||||
count = node.childCount
|
||||
except Exception:
|
||||
return acc
|
||||
for i in range(count):
|
||||
try:
|
||||
child = node.getChildAtIndex(i)
|
||||
except Exception:
|
||||
continue
|
||||
collect_buttons(child, depth + 1, acc)
|
||||
return acc
|
||||
|
||||
|
||||
def select_target(buttons):
|
||||
"""Waehlt aus allen sichtbaren+aktivierten Buttons genau einen aus, der
|
||||
geklickt werden darf - oder None, wenn das nicht sicher moeglich ist.
|
||||
|
||||
Regel (bewusst sicherheitsorientiert, siehe Modul-Docstring):
|
||||
1. Bekannte rueckwaerts-/abbrechende Beschriftungen (EXCLUDE_LABELS)
|
||||
werden nie geklickt, unabhaengig vom Rest.
|
||||
2. Von den verbleibenden Kandidaten wird bevorzugt, wer eine bekannte
|
||||
vorwaerts-/abschliessende Beschriftung traegt (PREFER_LABELS).
|
||||
3. Bleibt nach 1./2. KEIN bekannter Treffer, aber genau EIN Kandidat
|
||||
uebrig, wird dieser geklickt (Sole-Survivor-Regel - deckt unbekannte/
|
||||
nicht uebersetzte Beschriftungen wie das real beobachtete "Continue"
|
||||
ab, siehe Modul-Docstring).
|
||||
4. Bleiben mehrere unbekannte Kandidaten gleichzeitig uebrig, wird NICHT
|
||||
geklickt (echte Mehrdeutigkeit - ein Fehlklick waere hier riskanter
|
||||
als ein uebersprungener Zyklus, die Schleife in autoclicker.sh
|
||||
versucht es 2 Sekunden spaeter erneut)."""
|
||||
candidates = []
|
||||
for btn in buttons:
|
||||
name = (btn.name or "").strip().lower()
|
||||
if name in EXCLUDE_LABELS:
|
||||
continue
|
||||
candidates.append(btn)
|
||||
|
||||
if not candidates:
|
||||
return None
|
||||
|
||||
preferred = [b for b in candidates if (b.name or "").strip().lower() in PREFER_LABELS]
|
||||
if preferred:
|
||||
return preferred[0]
|
||||
|
||||
if len(candidates) == 1:
|
||||
return candidates[0]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
desktop = pyatspi.Registry.getDesktop(0)
|
||||
except Exception as exc:
|
||||
print(f"AT-SPI-Desktop nicht erreichbar: {exc}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
apps = []
|
||||
for i in range(desktop.childCount):
|
||||
try:
|
||||
app = desktop.getChildAtIndex(i)
|
||||
except Exception:
|
||||
continue
|
||||
if app is not None:
|
||||
apps.append(app)
|
||||
|
||||
for marker in VALIDATION_TEXT_MARKERS:
|
||||
for app in apps:
|
||||
if find_showing_text(app, marker):
|
||||
print(
|
||||
f"Hintergrundpruefung noch sichtbar ('{marker}'), warte statt zu klicken.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 3
|
||||
|
||||
all_buttons = []
|
||||
for app in apps:
|
||||
collect_buttons(app, 0, all_buttons)
|
||||
|
||||
target = select_target(all_buttons)
|
||||
if target is None:
|
||||
names = [repr((b.name or "").strip()) for b in all_buttons]
|
||||
print(
|
||||
"kein eindeutiger Button gefunden, sichtbare Buttons: "
|
||||
+ (", ".join(names) if names else "(keine)"),
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
try:
|
||||
action = target.queryAction()
|
||||
action.doAction(0)
|
||||
except Exception as exc:
|
||||
print(f"Klick auf '{target.name}' fehlgeschlagen: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
print(f"geklickt: {target.name}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@ -1,113 +0,0 @@
|
||||
#!/bin/bash
|
||||
### Klickt automatisiert durch Ubiquitys GTK-Installationsassistenten
|
||||
### (automatic-ubiquity) - noetig, weil Ubiquitys eigenes "noninteractive"-
|
||||
### Frontend die gefuehrte Partitionierung nicht zuverlaessig automatisieren
|
||||
### kann (endlose choose_partition-Schleife in ubi-partman.py, real
|
||||
### bestaetigt, siehe ADR-0023-Nachtrag). Der GTK-Assistent fuellt jede Seite
|
||||
### bereits vollstaendig aus dem Preseed vor (siehe preseed.tpl) - es fehlt
|
||||
### nur der "Weiter"/"Installieren"-Klick pro Seite.
|
||||
###
|
||||
### Klickt ueber AT-SPI (Barrierefreiheits-API), nicht mehr ueber
|
||||
### Bildschirmkoordinaten/Enter-Taste (siehe atspi_click.py fuer die
|
||||
### eigentliche Klicklogik). Der fruehere xdotool-Ansatz scheiterte real
|
||||
### daran, dass Metacity mehrere ueberlappende X11-Fenster aehnlicher
|
||||
### Groesse erzeugt (WM-Dekorationsrahmen, Hilfsfenster) - weder eine
|
||||
### "groesstes sichtbares Fenster"-Heuristik noch die Enter-Taste (aktiviert
|
||||
### auf der Partitionierungs-Uebersichtsseite einen Ausklapp-Pfeil statt des
|
||||
### "Jetzt installieren"-Buttons) waren zuverlaessig genug (siehe
|
||||
### ADR-0023-Nachtrag). AT-SPI identifiziert den Button stattdessen ueber
|
||||
### seine Rolle+seinen Namen im Accessibility-Baum der Anwendung selbst -
|
||||
### unabhaengig von Fenstergeometrie/-dekoration.
|
||||
###
|
||||
### Die AT-SPI-Bruecke selbst (GTK_MODULES=gail:atk-bridge, Session-/A11y-
|
||||
### Bus) wird NICHT hier, sondern bereits VOR dem GTK-Start von Ubiquity in
|
||||
### tuxflotte-atspi-env.sh aktiviert (eingebunden von start-ubiquity-dm,
|
||||
### siehe Sed-Patch in initrd-hooks/casper-bottom/99casperboot) - eine erst
|
||||
### nachtraeglich aktivierte Bruecke wird von einer bereits laufenden
|
||||
### GTK-Anwendung nicht mehr nachgeladen.
|
||||
###
|
||||
### Wird per systemd-Service (siehe ...service im selben Ausliefer-Layer) bei
|
||||
### JEDEM Boot gestartet, bricht aber sofort ab, wenn das eigene Boot-Keyword
|
||||
### "tuxflotte-autoclick" nicht in /proc/cmdline steht - siehe backend_launch()
|
||||
### in backends/mint/backend.sh, wo dieses Keyword gesetzt wird. Auf einem
|
||||
### normalen (nicht automatisierten) Boot also wirkungslos.
|
||||
set -u
|
||||
|
||||
LOG=/var/log/tuxflotte-autoclicker.log
|
||||
log() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >>"${LOG}"
|
||||
}
|
||||
|
||||
grep -qw tuxflotte-autoclick /proc/cmdline || exit 0
|
||||
|
||||
log "tuxflotte-autoclick erkannt, starte Autoklicker."
|
||||
export DISPLAY=:0
|
||||
|
||||
is_ubiquity_running() {
|
||||
pgrep -f '/usr/bin/ubiquity' >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# ubiquity-dm startet Ubiquity frueh im Boot zu einem nicht exakt
|
||||
# vorhersagbaren Zeitpunkt - auf den Prozess warten statt auf eine feste
|
||||
# Wartezeit zu vertrauen. AT-SPI braucht anders als der fruehere
|
||||
# xdotool-Ansatz keinen eigenen X-Socket-Check - der Zugriff laeuft ueber
|
||||
# den Accessibility-Bus, nicht direkt ueber X11.
|
||||
ubiquity_ready=0
|
||||
for _ in $(seq 1 120); do
|
||||
if is_ubiquity_running; then
|
||||
ubiquity_ready=1
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [ "${ubiquity_ready}" -ne 1 ]; then
|
||||
log "ubiquity-Prozess nach 120s nicht erschienen, breche ab."
|
||||
exit 1
|
||||
fi
|
||||
log "ubiquity-Prozess erkannt."
|
||||
|
||||
if ! python3 -c 'import pyatspi' >/dev/null 2>&1; then
|
||||
log "pyatspi fehlt auf dem Live-Medium, installiere nach."
|
||||
if ! apt-get install -y python3-pyatspi >>"${LOG}" 2>&1; then
|
||||
log "pyatspi-Installation fehlgeschlagen, breche ab."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
ATSPI_CLICK=/opt/tuxflotte/scripts/atspi_click.py
|
||||
|
||||
log "Starte Klick-Schleife."
|
||||
# Harte Obergrenze als Sicherheitsnetz (60 Minuten) - falls die Installation
|
||||
# haengen bleibt, soll dieser Dienst nicht unbegrenzt weiterlaufen.
|
||||
end=$((SECONDS + 3600))
|
||||
clicks=0
|
||||
misses=0
|
||||
while [ "${SECONDS}" -lt "${end}" ]; do
|
||||
if ! is_ubiquity_running; then
|
||||
log "ubiquity-Prozess nicht mehr aktiv (vermutlich fertig oder abgestuerzt), beende Schleife nach ${clicks} Klick(s)."
|
||||
break
|
||||
fi
|
||||
|
||||
out="$(python3 "${ATSPI_CLICK}" 2>&1)"
|
||||
rc=$?
|
||||
if [ "${rc}" -eq 0 ]; then
|
||||
clicks=$((clicks + 1))
|
||||
misses=0
|
||||
log "Klick ${clicks}: ${out}"
|
||||
elif [ "${rc}" -eq 2 ]; then
|
||||
log "AT-SPI-Bus nicht erreichbar, breche ab: ${out}"
|
||||
break
|
||||
elif [ "${rc}" -eq 3 ]; then
|
||||
# Ubiquitys eigene Hintergrundpruefung laeuft noch sichtbar (siehe
|
||||
# atspi_click.py-Nachtrag) - bewusst NICHT als Fehlversuch zaehlen,
|
||||
# nur abwarten. Real beim Testen entdeckt: ein Klick auf "Jetzt
|
||||
# installieren" WAEHREND dieser Pruefung fuehrte wiederholt in die
|
||||
# partman-rebuild-cache-Schleife statt zum eigentlichen Commit.
|
||||
log "wartet auf Hintergrundpruefung: ${out}"
|
||||
else
|
||||
misses=$((misses + 1))
|
||||
log "kein Treffer (${misses}): ${out}"
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
log "Autoklicker beendet (${clicks} Klick(s) insgesamt)."
|
||||
@ -1,54 +0,0 @@
|
||||
#!/bin/sh
|
||||
### Wird per Ein-Zeilen-Sed-Patch (siehe initrd-hooks/casper-bottom/99casperboot)
|
||||
### GANZ AM ANFANG von start-ubiquity-dm eingebunden ("."), also BEVOR
|
||||
### ubiquity-dm den X-Server startet und Ubiquity selbst exec't.
|
||||
###
|
||||
### Zweck: die AT-SPI-Barrierefreiheits-Bruecke (atk-bridge) fuer Ubiquitys
|
||||
### GTK-Prozess aktivieren, damit atspi_click.py (siehe
|
||||
### /opt/tuxflotte/scripts/) Buttons ueber ihre Rolle/ihren Namen im
|
||||
### Accessibility-Baum anklicken kann statt ueber Bildschirmkoordinaten.
|
||||
### Der xdotool-Koordinaten-Ansatz ist an ueberlappenden X11-Fenstern durch
|
||||
### die Metacity-Fensterdekoration gescheitert (mehrere Fenster aehnlicher
|
||||
### Groesse, "groesstes Fenster"-Heuristik traf wiederholt das falsche -
|
||||
### siehe ADR-0023-Nachtrag).
|
||||
###
|
||||
### WICHTIG: das muss VOR dem GTK-Init von Ubiquity passieren - eine erst
|
||||
### nachtraeglich verfuegbare Bruecke wird von einer bereits laufenden
|
||||
### GTK-Anwendung nicht mehr nachgeladen (GTK_MODULES wird nur beim Start
|
||||
### ausgewertet). Deshalb blockierend (kein Hintergrund-"&" fuer die
|
||||
### Paketinstallation) und deshalb im Skript, das ubiquity-dm selbst
|
||||
### aufruft, statt im spaeter laufenden Autoklicker-Service.
|
||||
###
|
||||
### Absichtlich EIN gemeinsamer apt-get-Aufruf fuer alle drei Pakete (statt
|
||||
### getrennter Aufrufe je Skript) - der Autoklicker installiert xdotool
|
||||
### zeitlich nah, ein zweiter paralleler apt-get/dpkg-Aufruf haette real
|
||||
### beobachtete Lock-Konflikte riskiert (debconf: "config.dat is locked by
|
||||
### another process").
|
||||
|
||||
for pkg in at-spi2-core dbus-x11 python3-pyatspi; do
|
||||
dpkg -s "$pkg" >/dev/null 2>&1 && continue
|
||||
if [ "${_tuxflotte_atspi_apt_updated:-}" != "1" ]; then
|
||||
apt-get update -qq
|
||||
_tuxflotte_atspi_apt_updated=1
|
||||
fi
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y "$pkg"
|
||||
done
|
||||
|
||||
export GTK_MODULES="gail:atk-bridge"
|
||||
export NO_AT_BRIDGE=0
|
||||
|
||||
# Eigene Session-Bus-Instanz, falls keine geerbt wurde - die minimale
|
||||
# ubiquity-dm-X-Sitzung startet anders als eine normale Desktop-Sitzung
|
||||
# vermutlich keinen eigenen Session-Bus.
|
||||
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ] && command -v dbus-launch >/dev/null 2>&1; then
|
||||
eval "$(dbus-launch --sh-syntax)"
|
||||
export DBUS_SESSION_BUS_ADDRESS DBUS_SESSION_BUS_PID
|
||||
fi
|
||||
|
||||
if command -v at-spi-bus-launcher >/dev/null 2>&1; then
|
||||
at-spi-bus-launcher --launch-immediately >/var/log/tuxflotte-atspi-bus.log 2>&1 &
|
||||
# Kurz abwarten, bis der a11y-Bus unter org.a11y.Bus registriert ist,
|
||||
# bevor ubiquity-dm/Ubiquity (naechste Zeile in start-ubiquity-dm)
|
||||
# GTK initialisiert.
|
||||
sleep 1
|
||||
fi
|
||||
155
scripts/build.sh
155
scripts/build.sh
@ -1,6 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Nur noch fuer das Fedora-Backend (Kickstart/Anaconda) - das Mint-Backend
|
||||
# ist auf das eigenstaendige, per live-build gebaute Boot-Medium umgezogen
|
||||
# (siehe scripts/build_boot_medium.sh, boot-medium/). Der bisherige
|
||||
# Mint-Zweig hier (Casper-Patchen einer echten Mint-Live-ISO + Ubiquity-
|
||||
# Preseed) ist damit Geschichte - siehe ADR-0025 fuer die Begruendung.
|
||||
|
||||
SOURCE_ISO="${1:-}"
|
||||
BACKEND="${2:-}"
|
||||
|
||||
@ -10,18 +16,8 @@ BUILD_DIR="$BASE_DIR/build"
|
||||
WORK_DIR="$BUILD_DIR/work"
|
||||
OUTPUT_DIR="$BUILD_DIR/output"
|
||||
|
||||
# shellcheck source=lib/initrd.sh
|
||||
source "$REPO_DIR/scripts/lib/initrd.sh"
|
||||
|
||||
# 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() {
|
||||
echo "Usage: $0 /path/to/source.iso <fedora|mint>"
|
||||
echo "Usage: $0 /path/to/source.iso fedora"
|
||||
}
|
||||
|
||||
check_input() {
|
||||
@ -35,13 +31,10 @@ check_input() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$BACKEND" in
|
||||
fedora|mint) ;;
|
||||
*)
|
||||
echo "Error: unbekanntes Backend '$BACKEND' (erwartet: fedora oder mint)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if [[ "$BACKEND" != "fedora" ]]; then
|
||||
echo "Error: unbekanntes Backend '$BACKEND' (erwartet: fedora)"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_dependencies() {
|
||||
@ -51,15 +44,6 @@ check_dependencies() {
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$BACKEND" == "mint" ]]; then
|
||||
for cmd in jq envsubst base64 cpio; do
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
echo "Error: missing dependency: $cmd"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
prepare_dirs() {
|
||||
@ -87,135 +71,39 @@ patch_grub() {
|
||||
# -f: xorriso extrahiert ISO-Dateien mit deren Original-Rechten, die auf
|
||||
# Live-Medien haeufig read-only (444) sind - ohne -f schlaegt cp beim
|
||||
# Ueberschreiben mit "Keine Berechtigung" fehl.
|
||||
if [[ "$BACKEND" == "fedora" ]]; then
|
||||
cp -f "$REPO_DIR/grub/EFI-BOOT-grub.cfg" \
|
||||
"$WORK_DIR/EFI/BOOT/grub.cfg"
|
||||
cp -f "$REPO_DIR/grub/EFI-BOOT-grub.cfg" \
|
||||
"$WORK_DIR/EFI/BOOT/grub.cfg"
|
||||
|
||||
cp -f "$REPO_DIR/grub/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 -f "$REPO_DIR/grub/mint-boot-grub.cfg" \
|
||||
"$WORK_DIR/boot/grub/grub.cfg"
|
||||
|
||||
cp -f "$REPO_DIR/grub/mint-isolinux-live.cfg" \
|
||||
"$WORK_DIR/isolinux/live.cfg"
|
||||
fi
|
||||
cp -f "$REPO_DIR/grub/boot-grub2-grub.cfg" \
|
||||
"$WORK_DIR/boot/grub2/grub.cfg"
|
||||
}
|
||||
|
||||
verify_workdir() {
|
||||
echo "Verifying workdir..."
|
||||
|
||||
if [[ "$BACKEND" == "fedora" ]]; then
|
||||
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
|
||||
grep -q "Tuxflotte" "$WORK_DIR/EFI/BOOT/grub.cfg"
|
||||
grep -q "Tuxflotte" "$WORK_DIR/boot/grub2/grub.cfg"
|
||||
|
||||
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": {"scheme": "single", "root_filesystem": "ext4"},
|
||||
"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() {
|
||||
echo "Assembling live-updates payload..."
|
||||
echo "Assembling updates payload..."
|
||||
|
||||
local updates_dir="$WORK_DIR/updates"
|
||||
|
||||
rm -rf "$updates_dir"
|
||||
mkdir -p "$updates_dir/opt/tuxflotte"
|
||||
|
||||
cp -a "$REPO_DIR/live-updates/." "$updates_dir/"
|
||||
cp -a "$REPO_DIR/scripts" "$updates_dir/opt/tuxflotte/"
|
||||
cp -a "$REPO_DIR/backends" "$updates_dir/opt/tuxflotte/"
|
||||
cp -a "$REPO_DIR/config" "$updates_dir/opt/tuxflotte/"
|
||||
|
||||
chmod 0440 "$updates_dir/etc/sudoers.d/90-tuxflotte"
|
||||
}
|
||||
|
||||
patch_initrd() {
|
||||
[[ "$BACKEND" == "mint" ]] || return 0
|
||||
|
||||
echo "Injecting casper-bottom updates-hook into initrd..."
|
||||
|
||||
inject_casper_bottom_hooks "$REPO_DIR" \
|
||||
"$WORK_DIR/casper/initrd.lz" \
|
||||
"$WORK_DIR/casper/initrd-tuxflotte.lz"
|
||||
}
|
||||
|
||||
create_iso() {
|
||||
echo "Creating Tuxflotte 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
|
||||
-map "$WORK_DIR/casper/initrd-tuxflotte.lz" /casper/initrd.lz
|
||||
)
|
||||
fi
|
||||
local output_iso="$OUTPUT_DIR/tuxflotte-provisioning-0.2.iso"
|
||||
|
||||
rm -f "$output_iso"
|
||||
|
||||
@ -224,7 +112,8 @@ create_iso() {
|
||||
-outdev "$output_iso" \
|
||||
-compliance no_emul_toc \
|
||||
-volid TUXFLOTTE \
|
||||
"${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 \
|
||||
-map "$WORK_DIR/updates" /updates \
|
||||
-chown_r 0 /updates -- \
|
||||
-chgrp_r 0 /updates -- \
|
||||
@ -240,9 +129,7 @@ main() {
|
||||
extract_iso
|
||||
patch_grub
|
||||
verify_workdir
|
||||
bake_test_preseed
|
||||
prepare_updates
|
||||
patch_initrd
|
||||
create_iso
|
||||
|
||||
echo
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Wird von build.sh und build_customer_iso.sh eingebunden (source), nicht
|
||||
# eigenstaendig ausgefuehrt.
|
||||
|
||||
# Haengt initrd-hooks/casper-bottom/* als zusaetzliche cpio-Schicht an ein
|
||||
# bestehendes Casper-Initrd an - derselbe Mechanismus, den
|
||||
# backend_launch() (backends/mint/backend.sh) bereits fuer das
|
||||
# Kexec-Preseed nutzt und der per QEMU verifiziert ist: der Kernel haengt
|
||||
# spaeter aneinandergereihte cpio-Archive additiv an ein bestehendes
|
||||
# initramfs an. Noetig, weil Casper keinen automatischen /updates-Merge
|
||||
# kennt (real per QEMU-Boot widerlegt) - der Hook selbst kopiert
|
||||
# /cdrom/updates beim Boot auf das Root-Dateisystem, siehe
|
||||
# initrd-hooks/casper-bottom/21tuxflotte_updates.
|
||||
inject_casper_bottom_hooks() {
|
||||
local repo_dir="$1"
|
||||
local src_initrd="$2"
|
||||
local dest_initrd="$3"
|
||||
|
||||
local hook_dir="${repo_dir}/initrd-hooks"
|
||||
local layer_dir
|
||||
layer_dir="$(mktemp -d)"
|
||||
# Ausserhalb von layer_dir, damit die Archiv-Datei sich beim Bauen nicht
|
||||
# selbst als leeren Eintrag einfaengt (find laeuft im selben Moment, in
|
||||
# dem die Shell-Redirection sie bereits anlegt).
|
||||
local cpio_out
|
||||
cpio_out="$(mktemp)"
|
||||
|
||||
cp -a "${hook_dir}/casper-bottom" "${layer_dir}/scripts-casper-bottom-tmp"
|
||||
mkdir -p "${layer_dir}/scripts"
|
||||
mv "${layer_dir}/scripts-casper-bottom-tmp" "${layer_dir}/scripts/casper-bottom"
|
||||
chmod 0755 "${layer_dir}"/scripts/casper-bottom/*
|
||||
|
||||
(cd "${layer_dir}" && find . -mindepth 1 | cpio -o -H newc 2>/dev/null | gzip) \
|
||||
>"${cpio_out}" ||
|
||||
{ echo "Error: Casper-Bottom-Hook-Schicht konnte nicht gebaut werden." >&2; rm -rf "${layer_dir}"; rm -f "${cpio_out}"; return 1; }
|
||||
|
||||
cat "${src_initrd}" "${cpio_out}" >"${dest_initrd}" ||
|
||||
{ echo "Error: Initrd konnte nicht mit Hook-Schicht zusammengesetzt werden." >&2; rm -rf "${layer_dir}"; rm -f "${cpio_out}"; return 1; }
|
||||
|
||||
rm -rf "${layer_dir}"
|
||||
rm -f "${cpio_out}"
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user