fix: align profile selection and installation confirm with Bereitstellungsvorlage model

20_profile_selection.sh and 25_installation_confirm.sh still spoke the
old flat profile model (.profiles[], .profile.distribution,
.profile.installer.type) that the provisioning server no longer
returns - it now returns .templates[] with workspace/backend objects
(see provisioning-server's Merkmal/Blueprint/Bereitstellungsvorlage
migration). Both modules now read/write
/run/tuxflotte/assignment/template.json against the current
Bereitstellungsvorlage schema, matching 10-interactive-provisioning-flow.md.
This commit is contained in:
Thomas Stallinger 2026-07-18 10:49:42 +02:00
parent f7f8e93c30
commit 3a7549adf1
2 changed files with 65 additions and 56 deletions

View File

@ -6,7 +6,7 @@ readonly SCRIPT_NAME
readonly SERVER_RESPONSE_FILE="/run/tuxflotte/server/response.json" readonly SERVER_RESPONSE_FILE="/run/tuxflotte/server/response.json"
readonly RUNTIME_DIR="/run/tuxflotte/assignment" readonly RUNTIME_DIR="/run/tuxflotte/assignment"
readonly PROFILE_FILE="${RUNTIME_DIR}/profile.json" readonly TEMPLATE_FILE="${RUNTIME_DIR}/template.json"
log() { log() {
printf '[%s] %s\n' "${SCRIPT_NAME}" "$*" printf '[%s] %s\n' "${SCRIPT_NAME}" "$*"
@ -25,7 +25,7 @@ require_root() {
prepare_runtime() { prepare_runtime() {
install -d -m 0700 "${RUNTIME_DIR}" install -d -m 0700 "${RUNTIME_DIR}"
rm -f -- "${PROFILE_FILE}" rm -f -- "${TEMPLATE_FILE}"
} }
validate_server_response() { validate_server_response() {
@ -37,47 +37,53 @@ validate_server_response() {
jq --exit-status ' jq --exit-status '
.success == true .success == true
and (.profiles | type == "array") and (.templates | type == "array")
and (.profiles | length > 0) and (.templates | length > 0)
' "${SERVER_RESPONSE_FILE}" >/dev/null || ' "${SERVER_RESPONSE_FILE}" >/dev/null ||
fatal "Serverantwort enthält keine auswählbaren Profile." fatal "Serverantwort enthält keine auswählbaren Bereitstellungsvorlagen."
} }
show_profiles() { show_templates() {
local index=1 local index=1
local profile local template
log "Verfügbare Provisioning-Profile:" log "Verfügbare Bereitstellungsvorlagen:"
while IFS= read -r profile; do while IFS= read -r template; do
printf '\n' printf '\n'
printf ' %d) %s\n' \ printf ' %d) %s' \
"${index}" \ "${index}" \
"$(jq -r '.label' <<<"${profile}")" "$(jq -r '.label' <<<"${template}")"
printf ' Distribution: %s %s\n' \ if [[ "$(jq -r '.is_default' <<<"${template}")" == "true" ]]; then
"$(jq -r '.distribution' <<<"${profile}")" \ printf ' (Standard)'
"$(jq -r '.version' <<<"${profile}")" fi
printf ' %s\n' \ printf '\n'
"$(jq -r '.description // ""' <<<"${profile}")"
printf ' Workspace: %s\n' \
"$(jq -r '.workspace.name' <<<"${template}")"
printf ' Backend: %s %s\n' \
"$(jq -r '.backend.name' <<<"${template}")" \
"$(jq -r '.backend.version' <<<"${template}")"
((index += 1)) ((index += 1))
done < <(jq -c '.profiles[]' "${SERVER_RESPONSE_FILE}") done < <(jq -c '.templates[]' "${SERVER_RESPONSE_FILE}")
} }
select_profile() { select_template() {
local profile_count local template_count
local selection local selection
profile_count="$(jq '.profiles | length' "${SERVER_RESPONSE_FILE}")" template_count="$(jq '.templates | length' "${SERVER_RESPONSE_FILE}")"
while true; do while true; do
printf '\n' printf '\n'
read -r -p "Profil auswählen [1-${profile_count}]: " selection read -r -p "Bereitstellungsvorlage auswählen [1-${template_count}]: " selection
if [[ "${selection}" =~ ^[0-9]+$ ]] && if [[ "${selection}" =~ ^[0-9]+$ ]] &&
((selection >= 1 && selection <= profile_count)); then ((selection >= 1 && selection <= template_count)); then
break break
fi fi
@ -88,30 +94,32 @@ select_profile() {
--argjson index "$((selection - 1))" \ --argjson index "$((selection - 1))" \
'{ '{
schema_version: 1, schema_version: 1,
profile: .profiles[$index] template: .templates[$index]
}' \ }' \
"${SERVER_RESPONSE_FILE}" >"${PROFILE_FILE}" "${SERVER_RESPONSE_FILE}" >"${TEMPLATE_FILE}"
chmod 0600 "${PROFILE_FILE}" chmod 0600 "${TEMPLATE_FILE}"
jq --exit-status ' jq --exit-status '
.schema_version == 1 .schema_version == 1
and (.profile | type == "object") and (.template | type == "object")
and (.profile.id | type == "string") and (.template.id | type == "string")
and (.profile.id | length > 0) and (.template.id | length > 0)
' "${PROFILE_FILE}" >/dev/null || and (.template.workspace | type == "object")
fatal "Ausgewähltes Profil konnte nicht gültig gespeichert werden." and (.template.backend | type == "object")
' "${TEMPLATE_FILE}" >/dev/null ||
fatal "Ausgewählte Bereitstellungsvorlage konnte nicht gültig gespeichert werden."
log "Profil $(jq -r '.profile.id' "${PROFILE_FILE}") wurde ausgewählt." log "Bereitstellungsvorlage $(jq -r '.template.id' "${TEMPLATE_FILE}") wurde ausgewählt."
log "Profilauswahl wurde unter ${PROFILE_FILE} gespeichert." log "Auswahl wurde unter ${TEMPLATE_FILE} gespeichert."
} }
main() { main() {
require_root require_root
prepare_runtime prepare_runtime
validate_server_response validate_server_response
show_profiles show_templates
select_profile select_template
} }
main "$@" main "$@"

View File

@ -4,7 +4,7 @@ set -Eeuo pipefail
SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")" SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
readonly SCRIPT_NAME readonly SCRIPT_NAME
readonly PROFILE_FILE="/run/tuxflotte/assignment/profile.json" readonly TEMPLATE_FILE="/run/tuxflotte/assignment/template.json"
readonly RUNTIME_DIR="/run/tuxflotte/installation" readonly RUNTIME_DIR="/run/tuxflotte/installation"
readonly STATE_FILE="${RUNTIME_DIR}/state.env" readonly STATE_FILE="${RUNTIME_DIR}/state.env"
@ -34,38 +34,39 @@ prepare_runtime() {
rm -f -- "${STATE_FILE}" rm -f -- "${STATE_FILE}"
} }
validate_profile() { validate_template() {
[[ -r "${PROFILE_FILE}" ]] || [[ -r "${TEMPLATE_FILE}" ]] ||
fatal "Profilauswahl nicht gefunden: ${PROFILE_FILE}" fatal "Bereitstellungsvorlage nicht gefunden: ${TEMPLATE_FILE}"
jq --exit-status ' jq --exit-status '
.schema_version == 1 .schema_version == 1
and (.profile | type == "object") and (.template | type == "object")
and (.profile.id | type == "string") and (.template.id | type == "string")
and (.profile.label | type == "string") and (.template.label | type == "string")
and (.profile.distribution | type == "string") and (.template.workspace.name | type == "string")
and (.profile.version | type == "string") and (.template.backend.name | type == "string")
' "${PROFILE_FILE}" >/dev/null || and (.template.backend.version | type == "string")
fatal "Profilauswahl enthält kein gültiges Profil." ' "${TEMPLATE_FILE}" >/dev/null ||
fatal "Bereitstellungsvorlage enthält keine gültige Auswahl."
} }
show_installation_plan() { show_installation_plan() {
local label local label
local distribution local workspace
local version local backend_name
local installer_type local backend_version
label="$(jq -r '.profile.label' "${PROFILE_FILE}")" label="$(jq -r '.template.label' "${TEMPLATE_FILE}")"
distribution="$(jq -r '.profile.distribution' "${PROFILE_FILE}")" workspace="$(jq -r '.template.workspace.name' "${TEMPLATE_FILE}")"
version="$(jq -r '.profile.version' "${PROFILE_FILE}")" backend_name="$(jq -r '.template.backend.name' "${TEMPLATE_FILE}")"
installer_type="$(jq -r '.profile.installer.type // "unbekannt"' "${PROFILE_FILE}")" backend_version="$(jq -r '.template.backend.version' "${TEMPLATE_FILE}")"
printf '\n' printf '\n'
printf 'Geplanter Installationsvorgang\n' printf 'Geplanter Installationsvorgang\n'
printf '==============================\n\n' printf '==============================\n\n'
printf 'Profil: %s\n' "${label}" printf 'Bereitstellungsvorlage: %s\n' "${label}"
printf 'Distribution: %s %s\n' "${distribution}" "${version}" printf 'Workspace: %s\n' "${workspace}"
printf 'Installer: %s\n' "${installer_type}" printf 'Backend: %s %s\n' "${backend_name}" "${backend_version}"
printf '\n' printf '\n'
printf 'Die eigentliche Installation kann lokale Datenträger verändern.\n' printf 'Die eigentliche Installation kann lokale Datenträger verändern.\n'
printf 'Bis zu dieser Bestätigung wurden keine destruktiven Installationsaktionen gestartet.\n' printf 'Bis zu dieser Bestätigung wurden keine destruktiven Installationsaktionen gestartet.\n'
@ -104,7 +105,7 @@ confirm_installation() {
main() { main() {
require_root require_root
prepare_runtime prepare_runtime
validate_profile validate_template
show_installation_plan show_installation_plan
confirm_installation confirm_installation
} }