Custom-Partitionierungsschema (extra_partitions) im Golden-Image-Deployment

image_deploy_partition_custom()/_format_custom()/_mount_custom() sowie eine
um extra_partitions erweiterte image_deploy_write_fstab() ergaenzen das
bisherige starre ESP+Root-Layout um eine variable Anzahl zusaetzlicher
Partitionen (Mountpoint/Prozentanteil-der-Gesamtplatte/Dateisystem), ohne
das bestehende scheme:"single" in irgendeiner Weise zu veraendern (eigene
Funktionen statt Erweiterung der bestehenden).

Alle drei Backends (mint/debian/ubuntu-image) verzweigen in backend_launch()
auf das Schema aus der Bereitstellungsvorlage und validieren extra_partitions
zusaetzlich defensiv in backend_validate() (Prozentsumme, doppelte
Mountpoints, Dateisystem-Whitelist ext4/btrfs - zfs/Fedora bewusst nicht).

Gegenstueck (API+GUI+DB) ist in provisioning-server/kundenplattform bereits
committet. Teil von platform-docs/roadmap/e2e-testrunde-lokale-
adressierung.md Phase 3.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DWKevK2QUK5tsGmqfSD6Yy
This commit is contained in:
adminandClaude Sonnet 5 committed 2026-09-19 14:57:59 +02:00
1 parent 5bc8d108a6
commit 020aa66bfa
7 files changed
+534 -70

No files matched your search

+63 -10
View File
@@ -152,10 +152,31 @@ backend_validate() {
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
{ backend_fatal "Installationszeitliche Vorgaben fehlen oder sind ungültig."; return 1; }
# Phase 3 (siehe platform-docs/roadmap/e2e-testrunde-lokale-
# adressierung.md) ergaenzt "custom" (extra_partitions fuer /home,
# /var, /usr, ...) neben dem bisherigen "single"-Schema. zfs/Fedora
# bewusst nicht abgedeckt.
local scheme
scheme="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning.scheme // "single"' "${RUNTIME_BLUEPRINT_FILE}")"
[[ "${scheme}" == "single" ]] ||
{ backend_fatal "Partitionierungsschema '${scheme}' wird von diesem Backend noch nicht unterstützt (nur 'single')."; return 1; }
case "${scheme}" in
single) ;;
custom)
jq --exit-status '
.runtime_blueprint.installation_directives.partitioning.extra_partitions as $extra
| ($extra | type == "array")
and (($extra | map(.mountpoint) | length) == ($extra | map(.mountpoint) | unique | length))
and (($extra | map(.percent) | add // 0) < 100)
and all($extra[]; (.mountpoint | type == "string") and (.mountpoint | startswith("/")))
and all($extra[]; (.percent | type == "number") and .percent > 0)
and all($extra[]; .filesystem == "ext4" or .filesystem == "btrfs")
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
{ backend_fatal "Partitionierungsschema 'custom': extra_partitions ist ungültig (Mountpoints/Prozente/Dateisystem prüfen)."; return 1; }
;;
*)
backend_fatal "Partitionierungsschema '${scheme}' wird von diesem Backend nicht unterstützt (nur 'single'/'custom')."
return 1
;;
esac
local target_disk_rank
target_disk_rank="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning.target_disk_rank // 1' "${RUNTIME_BLUEPRINT_FILE}")"
@@ -173,6 +194,7 @@ backend_validate() {
backend_generate_config() {
local hostname device_id device_fingerprint
local root_filesystem partitioning_json blueprints_json target_disk_rank
local scheme extra_partitions_json
[[ -r "${SERVER_RESPONSE_FILE}" ]] ||
{ backend_fatal "Serverantwort nicht gefunden: ${SERVER_RESPONSE_FILE}"; return 1; }
@@ -202,6 +224,11 @@ backend_generate_config() {
# hier nur noch reine Extraktion.
target_disk_rank="$(jq --raw-output '.target_disk_rank // 1' <<<"${partitioning_json}")"
# Bereits in backend_validate() strukturell geprueft (bei scheme:"custom") -
# hier nur noch reine Extraktion.
scheme="$(jq --raw-output '.scheme // "single"' <<<"${partitioning_json}")"
extra_partitions_json="$(jq --compact-output '.extra_partitions // []' <<<"${partitioning_json}")"
blueprints_json="$(jq --compact-output '.runtime_blueprint.blueprints' "${RUNTIME_BLUEPRINT_FILE}")"
jq --null-input \
@@ -210,6 +237,8 @@ backend_generate_config() {
--arg device_fingerprint "${device_fingerprint}" \
--arg root_filesystem "${root_filesystem}" \
--argjson target_disk_rank "${target_disk_rank}" \
--arg scheme "${scheme}" \
--argjson extra_partitions "${extra_partitions_json}" \
--argjson blueprints "${blueprints_json}" \
'{
hostname: $hostname,
@@ -217,6 +246,8 @@ backend_generate_config() {
device_fingerprint: $device_fingerprint,
root_filesystem: $root_filesystem,
target_disk_rank: $target_disk_rank,
scheme: $scheme,
extra_partitions: $extra_partitions,
blueprints: $blueprints
}' > "${CONFIG_FILE}" ||
{ backend_fatal "Konfigurationsdatei konnte nicht erzeugt werden."; return 1; }
@@ -228,6 +259,7 @@ backend_generate_config() {
backend_launch() {
local disk is_efi root_fs boot_part root_part target_disk_rank
local scheme extra_partitions_json partition_result=""
target_disk_rank="$(jq --raw-output '.target_disk_rank // 1' "${CONFIG_FILE}")"
disk="$(_debian_image_detect_target_disk "${target_disk_rank}")"
@@ -238,18 +270,34 @@ backend_launch() {
backend_log "Zieldatenträger: ${disk} (Firmware: $([ "${is_efi}" = true ] && echo UEFI || echo BIOS))"
root_fs="$(jq --raw-output '.root_filesystem' "${CONFIG_FILE}")"
scheme="$(jq --raw-output '.scheme // "single"' "${CONFIG_FILE}")"
extra_partitions_json="$(jq --compact-output '.extra_partitions // []' "${CONFIG_FILE}")"
backend_log "Partitioniere ${disk}"
# Reihenfolge "root_part boot_part" (nicht umgekehrt) - siehe
# image_deploy_partition() in image_deploy.sh fuer die Begruendung.
read -r root_part boot_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
return 1
backend_log "Partitioniere ${disk} (Schema: ${scheme})"
if [[ "${scheme}" == "custom" ]]; then
partition_result="$(image_deploy_partition_custom "${disk}" "${is_efi}" "${extra_partitions_json}")" || return 1
boot_part="$(jq --raw-output '.boot_part' <<<"${partition_result}")"
root_part="$(jq --raw-output '.root_part' <<<"${partition_result}")"
else
# Reihenfolge "root_part boot_part" (nicht umgekehrt) - siehe
# image_deploy_partition() in image_deploy.sh fuer die Begruendung.
read -r root_part boot_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
return 1
fi
backend_log "Formatiere Partitionen"
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_format_custom "${boot_part}" "${root_part}" "${root_fs}" "${partition_result}" || return 1
else
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
fi
backend_log "Mounte unter ${TARGET_DIR}"
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_mount_custom "${TARGET_DIR}" "${boot_part}" "${root_part}" "${partition_result}" || return 1
else
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
fi
if [[ -f "${NETWORK_PROFILE_EXPORT}" ]]; then
backend_log "Übernehme WLAN-/Netzwerkverbindungsprofil ins Zielsystem"
@@ -267,7 +315,12 @@ backend_launch() {
fi
backend_log "Schreibe fstab"
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" \
"$(jq --compact-output '.extra_partitions' <<<"${partition_result}")" || return 1
else
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
fi
backend_log "Binde /dev, /proc, /sys ein"
image_deploy_bind_mounts "${TARGET_DIR}" MOUNT_STACK || return 1
+63 -15
View File
@@ -163,15 +163,31 @@ backend_validate() {
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
{ backend_fatal "Installationszeitliche Vorgaben fehlen oder sind ungültig."; return 1; }
# Phase 2 deckt bewusst nur das einfache Schema ab (ESP/biosgrub +
# eine Root-Partition, siehe image_deploy_partition()) - "custom" mit
# extra_partitions (/home, /var) ist noch nicht auf die neue
# parted-basierte Mechanik uebertragen. Klarer Fehler statt stiller
# Fehlinterpretation.
# Phase 3 (siehe platform-docs/roadmap/e2e-testrunde-lokale-
# adressierung.md) ergaenzt "custom" (extra_partitions fuer /home,
# /var, /usr, ...) neben dem bisherigen "single"-Schema. zfs/Fedora
# bewusst nicht abgedeckt.
local scheme
scheme="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning.scheme // "single"' "${RUNTIME_BLUEPRINT_FILE}")"
[[ "${scheme}" == "single" ]] ||
{ backend_fatal "Partitionierungsschema '${scheme}' wird von diesem Backend noch nicht unterstützt (nur 'single')."; return 1; }
case "${scheme}" in
single) ;;
custom)
jq --exit-status '
.runtime_blueprint.installation_directives.partitioning.extra_partitions as $extra
| ($extra | type == "array")
and (($extra | map(.mountpoint) | length) == ($extra | map(.mountpoint) | unique | length))
and (($extra | map(.percent) | add // 0) < 100)
and all($extra[]; (.mountpoint | type == "string") and (.mountpoint | startswith("/")))
and all($extra[]; (.percent | type == "number") and .percent > 0)
and all($extra[]; .filesystem == "ext4" or .filesystem == "btrfs")
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
{ backend_fatal "Partitionierungsschema 'custom': extra_partitions ist ungültig (Mountpoints/Prozente/Dateisystem prüfen)."; return 1; }
;;
*)
backend_fatal "Partitionierungsschema '${scheme}' wird von diesem Backend nicht unterstützt (nur 'single'/'custom')."
return 1
;;
esac
local target_disk_rank
target_disk_rank="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning.target_disk_rank // 1' "${RUNTIME_BLUEPRINT_FILE}")"
@@ -189,6 +205,7 @@ backend_validate() {
backend_generate_config() {
local hostname device_id device_fingerprint
local root_filesystem partitioning_json blueprints_json target_disk_rank
local scheme extra_partitions_json
[[ -r "${SERVER_RESPONSE_FILE}" ]] ||
{ backend_fatal "Serverantwort nicht gefunden: ${SERVER_RESPONSE_FILE}"; return 1; }
@@ -218,6 +235,11 @@ backend_generate_config() {
# hier nur noch reine Extraktion.
target_disk_rank="$(jq --raw-output '.target_disk_rank // 1' <<<"${partitioning_json}")"
# Bereits in backend_validate() strukturell geprueft (bei scheme:"custom") -
# hier nur noch reine Extraktion.
scheme="$(jq --raw-output '.scheme // "single"' <<<"${partitioning_json}")"
extra_partitions_json="$(jq --compact-output '.extra_partitions // []' <<<"${partitioning_json}")"
blueprints_json="$(jq --compact-output '.runtime_blueprint.blueprints' "${RUNTIME_BLUEPRINT_FILE}")"
jq --null-input \
@@ -226,6 +248,8 @@ backend_generate_config() {
--arg device_fingerprint "${device_fingerprint}" \
--arg root_filesystem "${root_filesystem}" \
--argjson target_disk_rank "${target_disk_rank}" \
--arg scheme "${scheme}" \
--argjson extra_partitions "${extra_partitions_json}" \
--argjson blueprints "${blueprints_json}" \
'{
hostname: $hostname,
@@ -233,6 +257,8 @@ backend_generate_config() {
device_fingerprint: $device_fingerprint,
root_filesystem: $root_filesystem,
target_disk_rank: $target_disk_rank,
scheme: $scheme,
extra_partitions: $extra_partitions,
blueprints: $blueprints
}' > "${CONFIG_FILE}" ||
{ backend_fatal "Konfigurationsdatei konnte nicht erzeugt werden."; return 1; }
@@ -244,6 +270,7 @@ backend_generate_config() {
backend_launch() {
local disk is_efi root_fs boot_part root_part target_disk_rank
local scheme extra_partitions_json partition_result=""
target_disk_rank="$(jq --raw-output '.target_disk_rank // 1' "${CONFIG_FILE}")"
disk="$(_mint_image_detect_target_disk "${target_disk_rank}")"
@@ -254,18 +281,34 @@ backend_launch() {
backend_log "Zieldatenträger: ${disk} (Firmware: $([ "${is_efi}" = true ] && echo UEFI || echo BIOS))"
root_fs="$(jq --raw-output '.root_filesystem' "${CONFIG_FILE}")"
scheme="$(jq --raw-output '.scheme // "single"' "${CONFIG_FILE}")"
extra_partitions_json="$(jq --compact-output '.extra_partitions // []' "${CONFIG_FILE}")"
backend_log "Partitioniere ${disk}"
# Reihenfolge "root_part boot_part" (nicht umgekehrt) - siehe
# image_deploy_partition() in image_deploy.sh fuer die Begruendung.
read -r root_part boot_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
return 1
backend_log "Partitioniere ${disk} (Schema: ${scheme})"
if [[ "${scheme}" == "custom" ]]; then
partition_result="$(image_deploy_partition_custom "${disk}" "${is_efi}" "${extra_partitions_json}")" || return 1
boot_part="$(jq --raw-output '.boot_part' <<<"${partition_result}")"
root_part="$(jq --raw-output '.root_part' <<<"${partition_result}")"
else
# Reihenfolge "root_part boot_part" (nicht umgekehrt) - siehe
# image_deploy_partition() in image_deploy.sh fuer die Begruendung.
read -r root_part boot_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
return 1
fi
backend_log "Formatiere Partitionen"
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_format_custom "${boot_part}" "${root_part}" "${root_fs}" "${partition_result}" || return 1
else
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
fi
backend_log "Mounte unter ${TARGET_DIR}"
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_mount_custom "${TARGET_DIR}" "${boot_part}" "${root_part}" "${partition_result}" || return 1
else
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
fi
# Live gefunden (01.09.2026, echter Hardware-Test): export_connection_profile()
# in 05_network.sh legt das aktive WLAN-/Ethernet-Profil zwar geschuetzt unter
@@ -295,7 +338,12 @@ backend_launch() {
fi
backend_log "Schreibe fstab"
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" \
"$(jq --compact-output '.extra_partitions' <<<"${partition_result}")" || return 1
else
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
fi
backend_log "Binde /dev, /proc, /sys ein"
image_deploy_bind_mounts "${TARGET_DIR}" MOUNT_STACK || return 1
+63 -10
View File
@@ -158,10 +158,31 @@ backend_validate() {
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
{ backend_fatal "Installationszeitliche Vorgaben fehlen oder sind ungültig."; return 1; }
# Phase 3 (siehe platform-docs/roadmap/e2e-testrunde-lokale-
# adressierung.md) ergaenzt "custom" (extra_partitions fuer /home,
# /var, /usr, ...) neben dem bisherigen "single"-Schema. zfs/Fedora
# bewusst nicht abgedeckt.
local scheme
scheme="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning.scheme // "single"' "${RUNTIME_BLUEPRINT_FILE}")"
[[ "${scheme}" == "single" ]] ||
{ backend_fatal "Partitionierungsschema '${scheme}' wird von diesem Backend noch nicht unterstützt (nur 'single')."; return 1; }
case "${scheme}" in
single) ;;
custom)
jq --exit-status '
.runtime_blueprint.installation_directives.partitioning.extra_partitions as $extra
| ($extra | type == "array")
and (($extra | map(.mountpoint) | length) == ($extra | map(.mountpoint) | unique | length))
and (($extra | map(.percent) | add // 0) < 100)
and all($extra[]; (.mountpoint | type == "string") and (.mountpoint | startswith("/")))
and all($extra[]; (.percent | type == "number") and .percent > 0)
and all($extra[]; .filesystem == "ext4" or .filesystem == "btrfs")
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
{ backend_fatal "Partitionierungsschema 'custom': extra_partitions ist ungültig (Mountpoints/Prozente/Dateisystem prüfen)."; return 1; }
;;
*)
backend_fatal "Partitionierungsschema '${scheme}' wird von diesem Backend nicht unterstützt (nur 'single'/'custom')."
return 1
;;
esac
local target_disk_rank
target_disk_rank="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning.target_disk_rank // 1' "${RUNTIME_BLUEPRINT_FILE}")"
@@ -179,6 +200,7 @@ backend_validate() {
backend_generate_config() {
local hostname device_id device_fingerprint
local root_filesystem partitioning_json blueprints_json target_disk_rank
local scheme extra_partitions_json
[[ -r "${SERVER_RESPONSE_FILE}" ]] ||
{ backend_fatal "Serverantwort nicht gefunden: ${SERVER_RESPONSE_FILE}"; return 1; }
@@ -208,6 +230,11 @@ backend_generate_config() {
# hier nur noch reine Extraktion.
target_disk_rank="$(jq --raw-output '.target_disk_rank // 1' <<<"${partitioning_json}")"
# Bereits in backend_validate() strukturell geprueft (bei scheme:"custom") -
# hier nur noch reine Extraktion.
scheme="$(jq --raw-output '.scheme // "single"' <<<"${partitioning_json}")"
extra_partitions_json="$(jq --compact-output '.extra_partitions // []' <<<"${partitioning_json}")"
blueprints_json="$(jq --compact-output '.runtime_blueprint.blueprints' "${RUNTIME_BLUEPRINT_FILE}")"
jq --null-input \
@@ -216,6 +243,8 @@ backend_generate_config() {
--arg device_fingerprint "${device_fingerprint}" \
--arg root_filesystem "${root_filesystem}" \
--argjson target_disk_rank "${target_disk_rank}" \
--arg scheme "${scheme}" \
--argjson extra_partitions "${extra_partitions_json}" \
--argjson blueprints "${blueprints_json}" \
'{
hostname: $hostname,
@@ -223,6 +252,8 @@ backend_generate_config() {
device_fingerprint: $device_fingerprint,
root_filesystem: $root_filesystem,
target_disk_rank: $target_disk_rank,
scheme: $scheme,
extra_partitions: $extra_partitions,
blueprints: $blueprints
}' > "${CONFIG_FILE}" ||
{ backend_fatal "Konfigurationsdatei konnte nicht erzeugt werden."; return 1; }
@@ -234,6 +265,7 @@ backend_generate_config() {
backend_launch() {
local disk is_efi root_fs boot_part root_part target_disk_rank
local scheme extra_partitions_json partition_result=""
target_disk_rank="$(jq --raw-output '.target_disk_rank // 1' "${CONFIG_FILE}")"
disk="$(_ubuntu_image_detect_target_disk "${target_disk_rank}")"
@@ -244,18 +276,34 @@ backend_launch() {
backend_log "Zieldatenträger: ${disk} (Firmware: $([ "${is_efi}" = true ] && echo UEFI || echo BIOS))"
root_fs="$(jq --raw-output '.root_filesystem' "${CONFIG_FILE}")"
scheme="$(jq --raw-output '.scheme // "single"' "${CONFIG_FILE}")"
extra_partitions_json="$(jq --compact-output '.extra_partitions // []' "${CONFIG_FILE}")"
backend_log "Partitioniere ${disk}"
# Reihenfolge "root_part boot_part" (nicht umgekehrt) - siehe
# image_deploy_partition() in image_deploy.sh fuer die Begruendung.
read -r root_part boot_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
return 1
backend_log "Partitioniere ${disk} (Schema: ${scheme})"
if [[ "${scheme}" == "custom" ]]; then
partition_result="$(image_deploy_partition_custom "${disk}" "${is_efi}" "${extra_partitions_json}")" || return 1
boot_part="$(jq --raw-output '.boot_part' <<<"${partition_result}")"
root_part="$(jq --raw-output '.root_part' <<<"${partition_result}")"
else
# Reihenfolge "root_part boot_part" (nicht umgekehrt) - siehe
# image_deploy_partition() in image_deploy.sh fuer die Begruendung.
read -r root_part boot_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
return 1
fi
backend_log "Formatiere Partitionen"
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_format_custom "${boot_part}" "${root_part}" "${root_fs}" "${partition_result}" || return 1
else
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
fi
backend_log "Mounte unter ${TARGET_DIR}"
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_mount_custom "${TARGET_DIR}" "${boot_part}" "${root_part}" "${partition_result}" || return 1
else
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
fi
if [[ -f "${NETWORK_PROFILE_EXPORT}" ]]; then
backend_log "Übernehme WLAN-/Netzwerkverbindungsprofil ins Zielsystem"
@@ -273,7 +321,12 @@ backend_launch() {
fi
backend_log "Schreibe fstab"
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" \
"$(jq --compact-output '.extra_partitions' <<<"${partition_result}")" || return 1
else
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
fi
backend_log "Binde /dev, /proc, /sys ein"
image_deploy_bind_mounts "${TARGET_DIR}" MOUNT_STACK || return 1
@@ -152,10 +152,31 @@ backend_validate() {
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
{ backend_fatal "Installationszeitliche Vorgaben fehlen oder sind ungültig."; return 1; }
# Phase 3 (siehe platform-docs/roadmap/e2e-testrunde-lokale-
# adressierung.md) ergaenzt "custom" (extra_partitions fuer /home,
# /var, /usr, ...) neben dem bisherigen "single"-Schema. zfs/Fedora
# bewusst nicht abgedeckt.
local scheme
scheme="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning.scheme // "single"' "${RUNTIME_BLUEPRINT_FILE}")"
[[ "${scheme}" == "single" ]] ||
{ backend_fatal "Partitionierungsschema '${scheme}' wird von diesem Backend noch nicht unterstützt (nur 'single')."; return 1; }
case "${scheme}" in
single) ;;
custom)
jq --exit-status '
.runtime_blueprint.installation_directives.partitioning.extra_partitions as $extra
| ($extra | type == "array")
and (($extra | map(.mountpoint) | length) == ($extra | map(.mountpoint) | unique | length))
and (($extra | map(.percent) | add // 0) < 100)
and all($extra[]; (.mountpoint | type == "string") and (.mountpoint | startswith("/")))
and all($extra[]; (.percent | type == "number") and .percent > 0)
and all($extra[]; .filesystem == "ext4" or .filesystem == "btrfs")
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
{ backend_fatal "Partitionierungsschema 'custom': extra_partitions ist ungültig (Mountpoints/Prozente/Dateisystem prüfen)."; return 1; }
;;
*)
backend_fatal "Partitionierungsschema '${scheme}' wird von diesem Backend nicht unterstützt (nur 'single'/'custom')."
return 1
;;
esac
local target_disk_rank
target_disk_rank="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning.target_disk_rank // 1' "${RUNTIME_BLUEPRINT_FILE}")"
@@ -173,6 +194,7 @@ backend_validate() {
backend_generate_config() {
local hostname device_id device_fingerprint
local root_filesystem partitioning_json blueprints_json target_disk_rank
local scheme extra_partitions_json
[[ -r "${SERVER_RESPONSE_FILE}" ]] ||
{ backend_fatal "Serverantwort nicht gefunden: ${SERVER_RESPONSE_FILE}"; return 1; }
@@ -202,6 +224,11 @@ backend_generate_config() {
# hier nur noch reine Extraktion.
target_disk_rank="$(jq --raw-output '.target_disk_rank // 1' <<<"${partitioning_json}")"
# Bereits in backend_validate() strukturell geprueft (bei scheme:"custom") -
# hier nur noch reine Extraktion.
scheme="$(jq --raw-output '.scheme // "single"' <<<"${partitioning_json}")"
extra_partitions_json="$(jq --compact-output '.extra_partitions // []' <<<"${partitioning_json}")"
blueprints_json="$(jq --compact-output '.runtime_blueprint.blueprints' "${RUNTIME_BLUEPRINT_FILE}")"
jq --null-input \
@@ -210,6 +237,8 @@ backend_generate_config() {
--arg device_fingerprint "${device_fingerprint}" \
--arg root_filesystem "${root_filesystem}" \
--argjson target_disk_rank "${target_disk_rank}" \
--arg scheme "${scheme}" \
--argjson extra_partitions "${extra_partitions_json}" \
--argjson blueprints "${blueprints_json}" \
'{
hostname: $hostname,
@@ -217,6 +246,8 @@ backend_generate_config() {
device_fingerprint: $device_fingerprint,
root_filesystem: $root_filesystem,
target_disk_rank: $target_disk_rank,
scheme: $scheme,
extra_partitions: $extra_partitions,
blueprints: $blueprints
}' > "${CONFIG_FILE}" ||
{ backend_fatal "Konfigurationsdatei konnte nicht erzeugt werden."; return 1; }
@@ -228,6 +259,7 @@ backend_generate_config() {
backend_launch() {
local disk is_efi root_fs boot_part root_part target_disk_rank
local scheme extra_partitions_json partition_result=""
target_disk_rank="$(jq --raw-output '.target_disk_rank // 1' "${CONFIG_FILE}")"
disk="$(_debian_image_detect_target_disk "${target_disk_rank}")"
@@ -238,18 +270,34 @@ backend_launch() {
backend_log "Zieldatenträger: ${disk} (Firmware: $([ "${is_efi}" = true ] && echo UEFI || echo BIOS))"
root_fs="$(jq --raw-output '.root_filesystem' "${CONFIG_FILE}")"
scheme="$(jq --raw-output '.scheme // "single"' "${CONFIG_FILE}")"
extra_partitions_json="$(jq --compact-output '.extra_partitions // []' "${CONFIG_FILE}")"
backend_log "Partitioniere ${disk}"
# Reihenfolge "root_part boot_part" (nicht umgekehrt) - siehe
# image_deploy_partition() in image_deploy.sh fuer die Begruendung.
read -r root_part boot_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
return 1
backend_log "Partitioniere ${disk} (Schema: ${scheme})"
if [[ "${scheme}" == "custom" ]]; then
partition_result="$(image_deploy_partition_custom "${disk}" "${is_efi}" "${extra_partitions_json}")" || return 1
boot_part="$(jq --raw-output '.boot_part' <<<"${partition_result}")"
root_part="$(jq --raw-output '.root_part' <<<"${partition_result}")"
else
# Reihenfolge "root_part boot_part" (nicht umgekehrt) - siehe
# image_deploy_partition() in image_deploy.sh fuer die Begruendung.
read -r root_part boot_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
return 1
fi
backend_log "Formatiere Partitionen"
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_format_custom "${boot_part}" "${root_part}" "${root_fs}" "${partition_result}" || return 1
else
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
fi
backend_log "Mounte unter ${TARGET_DIR}"
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_mount_custom "${TARGET_DIR}" "${boot_part}" "${root_part}" "${partition_result}" || return 1
else
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
fi
if [[ -f "${NETWORK_PROFILE_EXPORT}" ]]; then
backend_log "Übernehme WLAN-/Netzwerkverbindungsprofil ins Zielsystem"
@@ -267,7 +315,12 @@ backend_launch() {
fi
backend_log "Schreibe fstab"
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" \
"$(jq --compact-output '.extra_partitions' <<<"${partition_result}")" || return 1
else
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
fi
backend_log "Binde /dev, /proc, /sys ein"
image_deploy_bind_mounts "${TARGET_DIR}" MOUNT_STACK || return 1
@@ -163,15 +163,31 @@ backend_validate() {
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
{ backend_fatal "Installationszeitliche Vorgaben fehlen oder sind ungültig."; return 1; }
# Phase 2 deckt bewusst nur das einfache Schema ab (ESP/biosgrub +
# eine Root-Partition, siehe image_deploy_partition()) - "custom" mit
# extra_partitions (/home, /var) ist noch nicht auf die neue
# parted-basierte Mechanik uebertragen. Klarer Fehler statt stiller
# Fehlinterpretation.
# Phase 3 (siehe platform-docs/roadmap/e2e-testrunde-lokale-
# adressierung.md) ergaenzt "custom" (extra_partitions fuer /home,
# /var, /usr, ...) neben dem bisherigen "single"-Schema. zfs/Fedora
# bewusst nicht abgedeckt.
local scheme
scheme="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning.scheme // "single"' "${RUNTIME_BLUEPRINT_FILE}")"
[[ "${scheme}" == "single" ]] ||
{ backend_fatal "Partitionierungsschema '${scheme}' wird von diesem Backend noch nicht unterstützt (nur 'single')."; return 1; }
case "${scheme}" in
single) ;;
custom)
jq --exit-status '
.runtime_blueprint.installation_directives.partitioning.extra_partitions as $extra
| ($extra | type == "array")
and (($extra | map(.mountpoint) | length) == ($extra | map(.mountpoint) | unique | length))
and (($extra | map(.percent) | add // 0) < 100)
and all($extra[]; (.mountpoint | type == "string") and (.mountpoint | startswith("/")))
and all($extra[]; (.percent | type == "number") and .percent > 0)
and all($extra[]; .filesystem == "ext4" or .filesystem == "btrfs")
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
{ backend_fatal "Partitionierungsschema 'custom': extra_partitions ist ungültig (Mountpoints/Prozente/Dateisystem prüfen)."; return 1; }
;;
*)
backend_fatal "Partitionierungsschema '${scheme}' wird von diesem Backend nicht unterstützt (nur 'single'/'custom')."
return 1
;;
esac
local target_disk_rank
target_disk_rank="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning.target_disk_rank // 1' "${RUNTIME_BLUEPRINT_FILE}")"
@@ -189,6 +205,7 @@ backend_validate() {
backend_generate_config() {
local hostname device_id device_fingerprint
local root_filesystem partitioning_json blueprints_json target_disk_rank
local scheme extra_partitions_json
[[ -r "${SERVER_RESPONSE_FILE}" ]] ||
{ backend_fatal "Serverantwort nicht gefunden: ${SERVER_RESPONSE_FILE}"; return 1; }
@@ -218,6 +235,11 @@ backend_generate_config() {
# hier nur noch reine Extraktion.
target_disk_rank="$(jq --raw-output '.target_disk_rank // 1' <<<"${partitioning_json}")"
# Bereits in backend_validate() strukturell geprueft (bei scheme:"custom") -
# hier nur noch reine Extraktion.
scheme="$(jq --raw-output '.scheme // "single"' <<<"${partitioning_json}")"
extra_partitions_json="$(jq --compact-output '.extra_partitions // []' <<<"${partitioning_json}")"
blueprints_json="$(jq --compact-output '.runtime_blueprint.blueprints' "${RUNTIME_BLUEPRINT_FILE}")"
jq --null-input \
@@ -226,6 +248,8 @@ backend_generate_config() {
--arg device_fingerprint "${device_fingerprint}" \
--arg root_filesystem "${root_filesystem}" \
--argjson target_disk_rank "${target_disk_rank}" \
--arg scheme "${scheme}" \
--argjson extra_partitions "${extra_partitions_json}" \
--argjson blueprints "${blueprints_json}" \
'{
hostname: $hostname,
@@ -233,6 +257,8 @@ backend_generate_config() {
device_fingerprint: $device_fingerprint,
root_filesystem: $root_filesystem,
target_disk_rank: $target_disk_rank,
scheme: $scheme,
extra_partitions: $extra_partitions,
blueprints: $blueprints
}' > "${CONFIG_FILE}" ||
{ backend_fatal "Konfigurationsdatei konnte nicht erzeugt werden."; return 1; }
@@ -244,6 +270,7 @@ backend_generate_config() {
backend_launch() {
local disk is_efi root_fs boot_part root_part target_disk_rank
local scheme extra_partitions_json partition_result=""
target_disk_rank="$(jq --raw-output '.target_disk_rank // 1' "${CONFIG_FILE}")"
disk="$(_mint_image_detect_target_disk "${target_disk_rank}")"
@@ -254,18 +281,34 @@ backend_launch() {
backend_log "Zieldatenträger: ${disk} (Firmware: $([ "${is_efi}" = true ] && echo UEFI || echo BIOS))"
root_fs="$(jq --raw-output '.root_filesystem' "${CONFIG_FILE}")"
scheme="$(jq --raw-output '.scheme // "single"' "${CONFIG_FILE}")"
extra_partitions_json="$(jq --compact-output '.extra_partitions // []' "${CONFIG_FILE}")"
backend_log "Partitioniere ${disk}"
# Reihenfolge "root_part boot_part" (nicht umgekehrt) - siehe
# image_deploy_partition() in image_deploy.sh fuer die Begruendung.
read -r root_part boot_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
return 1
backend_log "Partitioniere ${disk} (Schema: ${scheme})"
if [[ "${scheme}" == "custom" ]]; then
partition_result="$(image_deploy_partition_custom "${disk}" "${is_efi}" "${extra_partitions_json}")" || return 1
boot_part="$(jq --raw-output '.boot_part' <<<"${partition_result}")"
root_part="$(jq --raw-output '.root_part' <<<"${partition_result}")"
else
# Reihenfolge "root_part boot_part" (nicht umgekehrt) - siehe
# image_deploy_partition() in image_deploy.sh fuer die Begruendung.
read -r root_part boot_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
return 1
fi
backend_log "Formatiere Partitionen"
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_format_custom "${boot_part}" "${root_part}" "${root_fs}" "${partition_result}" || return 1
else
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
fi
backend_log "Mounte unter ${TARGET_DIR}"
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_mount_custom "${TARGET_DIR}" "${boot_part}" "${root_part}" "${partition_result}" || return 1
else
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
fi
# Live gefunden (01.09.2026, echter Hardware-Test): export_connection_profile()
# in 05_network.sh legt das aktive WLAN-/Ethernet-Profil zwar geschuetzt unter
@@ -295,7 +338,12 @@ backend_launch() {
fi
backend_log "Schreibe fstab"
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" \
"$(jq --compact-output '.extra_partitions' <<<"${partition_result}")" || return 1
else
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
fi
backend_log "Binde /dev, /proc, /sys ein"
image_deploy_bind_mounts "${TARGET_DIR}" MOUNT_STACK || return 1
@@ -158,10 +158,31 @@ backend_validate() {
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
{ backend_fatal "Installationszeitliche Vorgaben fehlen oder sind ungültig."; return 1; }
# Phase 3 (siehe platform-docs/roadmap/e2e-testrunde-lokale-
# adressierung.md) ergaenzt "custom" (extra_partitions fuer /home,
# /var, /usr, ...) neben dem bisherigen "single"-Schema. zfs/Fedora
# bewusst nicht abgedeckt.
local scheme
scheme="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning.scheme // "single"' "${RUNTIME_BLUEPRINT_FILE}")"
[[ "${scheme}" == "single" ]] ||
{ backend_fatal "Partitionierungsschema '${scheme}' wird von diesem Backend noch nicht unterstützt (nur 'single')."; return 1; }
case "${scheme}" in
single) ;;
custom)
jq --exit-status '
.runtime_blueprint.installation_directives.partitioning.extra_partitions as $extra
| ($extra | type == "array")
and (($extra | map(.mountpoint) | length) == ($extra | map(.mountpoint) | unique | length))
and (($extra | map(.percent) | add // 0) < 100)
and all($extra[]; (.mountpoint | type == "string") and (.mountpoint | startswith("/")))
and all($extra[]; (.percent | type == "number") and .percent > 0)
and all($extra[]; .filesystem == "ext4" or .filesystem == "btrfs")
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
{ backend_fatal "Partitionierungsschema 'custom': extra_partitions ist ungültig (Mountpoints/Prozente/Dateisystem prüfen)."; return 1; }
;;
*)
backend_fatal "Partitionierungsschema '${scheme}' wird von diesem Backend nicht unterstützt (nur 'single'/'custom')."
return 1
;;
esac
local target_disk_rank
target_disk_rank="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning.target_disk_rank // 1' "${RUNTIME_BLUEPRINT_FILE}")"
@@ -179,6 +200,7 @@ backend_validate() {
backend_generate_config() {
local hostname device_id device_fingerprint
local root_filesystem partitioning_json blueprints_json target_disk_rank
local scheme extra_partitions_json
[[ -r "${SERVER_RESPONSE_FILE}" ]] ||
{ backend_fatal "Serverantwort nicht gefunden: ${SERVER_RESPONSE_FILE}"; return 1; }
@@ -208,6 +230,11 @@ backend_generate_config() {
# hier nur noch reine Extraktion.
target_disk_rank="$(jq --raw-output '.target_disk_rank // 1' <<<"${partitioning_json}")"
# Bereits in backend_validate() strukturell geprueft (bei scheme:"custom") -
# hier nur noch reine Extraktion.
scheme="$(jq --raw-output '.scheme // "single"' <<<"${partitioning_json}")"
extra_partitions_json="$(jq --compact-output '.extra_partitions // []' <<<"${partitioning_json}")"
blueprints_json="$(jq --compact-output '.runtime_blueprint.blueprints' "${RUNTIME_BLUEPRINT_FILE}")"
jq --null-input \
@@ -216,6 +243,8 @@ backend_generate_config() {
--arg device_fingerprint "${device_fingerprint}" \
--arg root_filesystem "${root_filesystem}" \
--argjson target_disk_rank "${target_disk_rank}" \
--arg scheme "${scheme}" \
--argjson extra_partitions "${extra_partitions_json}" \
--argjson blueprints "${blueprints_json}" \
'{
hostname: $hostname,
@@ -223,6 +252,8 @@ backend_generate_config() {
device_fingerprint: $device_fingerprint,
root_filesystem: $root_filesystem,
target_disk_rank: $target_disk_rank,
scheme: $scheme,
extra_partitions: $extra_partitions,
blueprints: $blueprints
}' > "${CONFIG_FILE}" ||
{ backend_fatal "Konfigurationsdatei konnte nicht erzeugt werden."; return 1; }
@@ -234,6 +265,7 @@ backend_generate_config() {
backend_launch() {
local disk is_efi root_fs boot_part root_part target_disk_rank
local scheme extra_partitions_json partition_result=""
target_disk_rank="$(jq --raw-output '.target_disk_rank // 1' "${CONFIG_FILE}")"
disk="$(_ubuntu_image_detect_target_disk "${target_disk_rank}")"
@@ -244,18 +276,34 @@ backend_launch() {
backend_log "Zieldatenträger: ${disk} (Firmware: $([ "${is_efi}" = true ] && echo UEFI || echo BIOS))"
root_fs="$(jq --raw-output '.root_filesystem' "${CONFIG_FILE}")"
scheme="$(jq --raw-output '.scheme // "single"' "${CONFIG_FILE}")"
extra_partitions_json="$(jq --compact-output '.extra_partitions // []' "${CONFIG_FILE}")"
backend_log "Partitioniere ${disk}"
# Reihenfolge "root_part boot_part" (nicht umgekehrt) - siehe
# image_deploy_partition() in image_deploy.sh fuer die Begruendung.
read -r root_part boot_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
return 1
backend_log "Partitioniere ${disk} (Schema: ${scheme})"
if [[ "${scheme}" == "custom" ]]; then
partition_result="$(image_deploy_partition_custom "${disk}" "${is_efi}" "${extra_partitions_json}")" || return 1
boot_part="$(jq --raw-output '.boot_part' <<<"${partition_result}")"
root_part="$(jq --raw-output '.root_part' <<<"${partition_result}")"
else
# Reihenfolge "root_part boot_part" (nicht umgekehrt) - siehe
# image_deploy_partition() in image_deploy.sh fuer die Begruendung.
read -r root_part boot_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
return 1
fi
backend_log "Formatiere Partitionen"
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_format_custom "${boot_part}" "${root_part}" "${root_fs}" "${partition_result}" || return 1
else
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
fi
backend_log "Mounte unter ${TARGET_DIR}"
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_mount_custom "${TARGET_DIR}" "${boot_part}" "${root_part}" "${partition_result}" || return 1
else
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
fi
if [[ -f "${NETWORK_PROFILE_EXPORT}" ]]; then
backend_log "Übernehme WLAN-/Netzwerkverbindungsprofil ins Zielsystem"
@@ -273,7 +321,12 @@ backend_launch() {
fi
backend_log "Schreibe fstab"
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
if [[ "${scheme}" == "custom" ]]; then
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" \
"$(jq --compact-output '.extra_partitions' <<<"${partition_result}")" || return 1
else
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
fi
backend_log "Binde /dev, /proc, /sys ein"
image_deploy_bind_mounts "${TARGET_DIR}" MOUNT_STACK || return 1
+156
View File
@@ -145,6 +145,145 @@ image_deploy_partition() {
fi
}
# Partitionierung fuer scheme:"custom" (Bereitstellungsvorlage.partitioning,
# siehe platform-docs/roadmap/e2e-testrunde-lokale-adressierung.md Phase 3):
# ESP/biosgrub wie image_deploy_partition(), danach je einen "extra
# partition"-Eintrag aus extra_partitions_json (kompaktes JSON-Array
# [{"mountpoint":"/home","percent":20,"filesystem":"ext4"}, ...]), Root
# nimmt den verbleibenden Rest. Prozentangaben sind bewusst Anteile der
# GESAMTEN Platte (nicht des nach ESP verbleibenden Rests) - "20% fuer
# /home" bedeutet 20% der Plattengroesse, parted interpretiert "X%" in
# mkpart ohnehin relativ zur Gesamtgroesse des Datentraegers, nicht zum
# vorherigen Partitionsende. Eigene Funktion statt Erweiterung von
# image_deploy_partition() - komplett andere Partitionsanzahl/-logik,
# und das bestehende (viel genutzte) single-Schema soll dadurch keinerlei
# Verhaltensaenderung/Risiko erfahren.
#
# Gibt ein JSON-Objekt auf stdout aus:
# {"boot_part": "...", "root_part": "...",
# "extra_partitions": [{"mountpoint": "/home", "device": "...", "filesystem": "ext4"}, ...]}
image_deploy_partition_custom() {
local disk="$1"
local is_efi="$2"
local extra_partitions_json="$3"
_image_deploy_release_disk "${disk}"
if ! parted --script "${disk}" mklabel gpt; then
image_deploy_log "parted meldete einen Fehler beim Anlegen der Partitionstabelle auf ${disk} (haeufig: eine alte Partition war noch belegt) - pruefe, ob der Kernel die neue Tabelle trotzdem uebernimmt."
fi
_image_deploy_settle_partitions "${disk}" ||
{ image_deploy_fatal "Kernel konnte die neue Partitionstabelle auf ${disk} auch nach mehreren Versuchen nicht uebernehmen."; return 1; }
parted --script "${disk}" print 2>/dev/null | grep -q "Partition Table: gpt" ||
{ image_deploy_fatal "Nach dem Partitionieren liegt kein gueltiges GPT-Label auf ${disk} vor."; return 1; }
local part_num=1 cursor boot_part=""
if [[ "${is_efi}" == "true" ]]; then
parted --script "${disk}" mkpart ESP fat32 1MiB 513MiB &&
parted --script "${disk}" set 1 esp on ||
{ image_deploy_fatal "ESP-Partitionierung fehlgeschlagen auf ${disk}"; return 1; }
boot_part="$(image_deploy_partition_path "${disk}" 1)"
cursor="513MiB"
else
parted --script "${disk}" mkpart biosgrub 1MiB 2MiB &&
parted --script "${disk}" set 1 bios_grub on ||
{ image_deploy_fatal "biosgrub-Partitionierung fehlgeschlagen auf ${disk}"; return 1; }
cursor="2MiB"
fi
local extra_partitions_result="[]"
local mountpoint percent filesystem name cumulative_percent=0 device entry
while IFS= read -r entry; do
[[ -n "${entry}" ]] || continue
part_num=$((part_num + 1))
mountpoint="$(jq --raw-output '.mountpoint' <<<"${entry}")"
percent="$(jq --raw-output '.percent' <<<"${entry}")"
filesystem="$(jq --raw-output '.filesystem' <<<"${entry}")"
# Partitionsname aus Mountpoint ableiten ("/home" -> "home",
# "/var/lib" -> "var-lib") - rein kosmetisch (parted-Label), hat
# keine funktionale Bedeutung.
name="$(sed -e 's#^/##' -e 's#/#-#g' <<<"${mountpoint}")"
cumulative_percent=$((cumulative_percent + percent))
parted --script "${disk}" mkpart "${name}" "${filesystem}" "${cursor}" "${cumulative_percent}%" ||
{ image_deploy_fatal "Partitionierung von ${mountpoint} (${percent}%) fehlgeschlagen auf ${disk}"; return 1; }
cursor="${cumulative_percent}%"
device="$(image_deploy_partition_path "${disk}" "${part_num}")"
extra_partitions_result="$(jq --compact-output \
--arg mountpoint "${mountpoint}" --arg device "${device}" --arg filesystem "${filesystem}" \
'. + [{mountpoint: $mountpoint, device: $device, filesystem: $filesystem}]' \
<<<"${extra_partitions_result}")"
done < <(jq --compact-output '.[]' <<<"${extra_partitions_json}")
part_num=$((part_num + 1))
parted --script "${disk}" mkpart root ext4 "${cursor}" 100% ||
{ image_deploy_fatal "Root-Partitionierung fehlgeschlagen auf ${disk}"; return 1; }
local root_part
root_part="$(image_deploy_partition_path "${disk}" "${part_num}")"
_image_deploy_settle_partitions "${disk}" ||
{ image_deploy_fatal "Kernel konnte die neuen Partitionen auf ${disk} nicht uebernehmen."; return 1; }
[[ -z "${boot_part}" || -b "${boot_part}" ]] && [[ -b "${root_part}" ]] ||
{ image_deploy_fatal "Partitionen nach partprobe nicht gefunden (${boot_part}, ${root_part})"; return 1; }
jq --null-input --compact-output \
--arg boot_part "${boot_part}" --arg root_part "${root_part}" \
--argjson extra_partitions "${extra_partitions_result}" \
'{boot_part: $boot_part, root_part: $root_part, extra_partitions: $extra_partitions}'
}
# Formatiert boot_part/root_part wie image_deploy_format(), zusaetzlich
# jede Extra-Partition mit ihrem eigenen Dateisystem (aus dem stdout-JSON
# von image_deploy_partition_custom()).
image_deploy_format_custom() {
local boot_part="$1"
local root_part="$2"
local root_fs="$3"
local partition_result="$4"
image_deploy_format "${boot_part}" "${root_part}" "${root_fs}" || return 1
local device filesystem entry
while IFS= read -r entry; do
[[ -n "${entry}" ]] || continue
device="$(jq --raw-output '.device' <<<"${entry}")"
filesystem="$(jq --raw-output '.filesystem' <<<"${entry}")"
case "${filesystem}" in
ext4) mkfs.ext4 -F -L "$(basename "${device}")" "${device}" ;;
btrfs) mkfs.btrfs -f -L "$(basename "${device}")" "${device}" ;;
*) image_deploy_fatal "Nicht unterstuetztes Dateisystem: ${filesystem}"; return 1 ;;
esac || { image_deploy_fatal "mkfs auf ${device} fehlgeschlagen"; return 1; }
done < <(jq --compact-output '.extra_partitions[]' <<<"${partition_result}")
}
# Mountet root/ESP wie image_deploy_mount(), zusaetzlich jede Extra-
# Partition unter ihrem Mountpoint innerhalb von target - VOR dem Golden-
# Image-Extract, damit das entpackte Archiv direkt auf den richtigen
# Partitionen landet statt hinterher umkopiert werden zu muessen.
image_deploy_mount_custom() {
local target="$1"
local boot_part="$2"
local root_part="$3"
local partition_result="$4"
image_deploy_mount "${target}" "${boot_part}" "${root_part}" || return 1
local device mountpoint entry
while IFS= read -r entry; do
[[ -n "${entry}" ]] || continue
device="$(jq --raw-output '.device' <<<"${entry}")"
mountpoint="$(jq --raw-output '.mountpoint' <<<"${entry}")"
install -d "${target}${mountpoint}" ||
{ image_deploy_fatal "Mountpunkt ${target}${mountpoint} konnte nicht angelegt werden"; return 1; }
mount "${device}" "${target}${mountpoint}" ||
{ image_deploy_fatal "${device} konnte nicht auf ${target}${mountpoint} gemountet werden"; return 1; }
done < <(jq --compact-output '.extra_partitions[]' <<<"${partition_result}")
}
image_deploy_format() {
local boot_part="$1"
local root_part="$2"
@@ -354,11 +493,16 @@ image_deploy_install_network_profile() {
{ image_deploy_fatal "Verbindungsprofil konnte nicht nach ${dest_dir} kopiert werden"; return 1; }
}
# extra_partitions_json (5. Parameter, optional): kompaktes JSON-Array wie
# von image_deploy_partition_custom() zurueckgegeben
# ([{"mountpoint":...,"device":...,"filesystem":...}, ...]) - Default "[]",
# damit bestehende Aufrufer (scheme:"single") unveraendert bleiben.
image_deploy_write_fstab() {
local target="$1"
local boot_part="$2"
local root_part="$3"
local root_fs="$4"
local extra_partitions_json="${5:-[]}"
local root_uuid
root_uuid="$(blkid -s UUID -o value "${root_part}")"
@@ -375,6 +519,18 @@ image_deploy_write_fstab() {
{ image_deploy_fatal "Keine UUID fuer ${boot_part} gefunden"; return 1; }
echo "UUID=${boot_uuid} /boot/efi vfat umask=0077 0 1"
fi
local device mountpoint filesystem uuid entry
while IFS= read -r entry; do
[[ -n "${entry}" ]] || continue
device="$(jq --raw-output '.device' <<<"${entry}")"
mountpoint="$(jq --raw-output '.mountpoint' <<<"${entry}")"
filesystem="$(jq --raw-output '.filesystem' <<<"${entry}")"
uuid="$(blkid -s UUID -o value "${device}")"
[[ -n "${uuid}" ]] ||
{ image_deploy_fatal "Keine UUID fuer ${device} gefunden"; return 1; }
echo "UUID=${uuid} ${mountpoint} ${filesystem} defaults 0 2"
done < <(jq --compact-output '.[]' <<<"${extra_partitions_json}")
} > "${target}/etc/fstab"
}