Compare commits
No commits in common. "086917deece353c29d34a35b15f3a54be18d7717" and "f7f8e93c3021dc3b58571f0d5a132d1c5eb47e93" have entirely different histories.
086917deec
...
f7f8e93c30
@ -1,133 +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="fedora"
|
|
||||||
|
|
||||||
BACKEND_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
KICKSTART_TEMPLATE="${BACKEND_DIR}/kickstart.tpl"
|
|
||||||
|
|
||||||
RUNTIME_BLUEPRINT_FILE="/run/tuxflotte/runtime/runtime_blueprint.json"
|
|
||||||
SERVER_RESPONSE_FILE="/run/tuxflotte/server/response.json"
|
|
||||||
|
|
||||||
RUNTIME_DIR="/run/tuxflotte/backend"
|
|
||||||
CONFIG_FILE="${RUNTIME_DIR}/config"
|
|
||||||
|
|
||||||
backend_log() {
|
|
||||||
printf '[backend:%s] %s\n' "${BACKEND_KEY}" "$*" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
backend_fatal() {
|
|
||||||
printf '[backend:%s] FEHLER: %s\n' "${BACKEND_KEY}" "$*" >&2
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
backend_init() {
|
|
||||||
for cmd in jq envsubst; do
|
|
||||||
command -v "${cmd}" >/dev/null 2>&1 ||
|
|
||||||
{ backend_fatal "Benötigtes Werkzeug fehlt: ${cmd}"; return 1; }
|
|
||||||
done
|
|
||||||
|
|
||||||
[[ -r "${KICKSTART_TEMPLATE}" ]] ||
|
|
||||||
{ backend_fatal "Kickstart-Template nicht gefunden: ${KICKSTART_TEMPLATE}"; return 1; }
|
|
||||||
|
|
||||||
install -d \
|
|
||||||
--mode=0700 \
|
|
||||||
--owner=root \
|
|
||||||
--group=root \
|
|
||||||
"${RUNTIME_DIR}"
|
|
||||||
|
|
||||||
rm -f -- "${CONFIG_FILE}"
|
|
||||||
|
|
||||||
backend_log "Initialisiert."
|
|
||||||
}
|
|
||||||
|
|
||||||
backend_validate() {
|
|
||||||
[[ -r "${RUNTIME_BLUEPRINT_FILE}" ]] ||
|
|
||||||
{ backend_fatal "Runtime Blueprint nicht gefunden: ${RUNTIME_BLUEPRINT_FILE}"; return 1; }
|
|
||||||
|
|
||||||
jq --exit-status \
|
|
||||||
--arg backend_key "${BACKEND_KEY}" \
|
|
||||||
'.runtime_blueprint.backend_id == $backend_key' \
|
|
||||||
"${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
|
|
||||||
{ backend_fatal "Runtime Blueprint ist nicht für Backend '${BACKEND_KEY}' aufgelöst."; return 1; }
|
|
||||||
|
|
||||||
jq --exit-status '
|
|
||||||
.runtime_blueprint.installation_directives
|
|
||||||
| (.disk_encryption | type == "boolean")
|
|
||||||
and (.partitioning | type == "string")
|
|
||||||
and (.secure_boot_required | type == "boolean")
|
|
||||||
' "${RUNTIME_BLUEPRINT_FILE}" >/dev/null ||
|
|
||||||
{ backend_fatal "Installationszeitliche Vorgaben fehlen oder sind ungültig."; return 1; }
|
|
||||||
|
|
||||||
backend_log "Runtime Blueprint ist gültig für Backend '${BACKEND_KEY}'."
|
|
||||||
}
|
|
||||||
|
|
||||||
backend_generate_config() {
|
|
||||||
local hostname
|
|
||||||
local disk_encryption
|
|
||||||
local partitioning
|
|
||||||
local secure_boot_required
|
|
||||||
local partitioning_command
|
|
||||||
local blueprints_json
|
|
||||||
|
|
||||||
[[ -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; }
|
|
||||||
|
|
||||||
disk_encryption="$(jq --raw-output '.runtime_blueprint.installation_directives.disk_encryption' "${RUNTIME_BLUEPRINT_FILE}")"
|
|
||||||
partitioning="$(jq --raw-output '.runtime_blueprint.installation_directives.partitioning' "${RUNTIME_BLUEPRINT_FILE}")"
|
|
||||||
secure_boot_required="$(jq --raw-output '.runtime_blueprint.installation_directives.secure_boot_required' "${RUNTIME_BLUEPRINT_FILE}")"
|
|
||||||
|
|
||||||
case "${partitioning}" in
|
|
||||||
default)
|
|
||||||
if [[ "${disk_encryption}" == "true" ]]; then
|
|
||||||
partitioning_command="autopart --encrypted"
|
|
||||||
else
|
|
||||||
partitioning_command="autopart"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
backend_fatal "Nicht unterstützte Partitionierungsvorgabe: ${partitioning}"
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [[ "${secure_boot_required}" == "true" ]]; then
|
|
||||||
backend_log "Hinweis: secure_boot_required=true wird derzeit nicht in der Kickstart-Konfiguration durchgesetzt (Phase 1)."
|
|
||||||
fi
|
|
||||||
|
|
||||||
blueprints_json="$(jq --compact-output '.runtime_blueprint.blueprints' "${RUNTIME_BLUEPRINT_FILE}")"
|
|
||||||
|
|
||||||
TUXFLOTTE_HOSTNAME="${hostname}" \
|
|
||||||
TUXFLOTTE_PARTITIONING_COMMAND="${partitioning_command}" \
|
|
||||||
TUXFLOTTE_BLUEPRINTS_JSON="${blueprints_json}" \
|
|
||||||
envsubst '${TUXFLOTTE_HOSTNAME} ${TUXFLOTTE_PARTITIONING_COMMAND} ${TUXFLOTTE_BLUEPRINTS_JSON}' \
|
|
||||||
<"${KICKSTART_TEMPLATE}" >"${CONFIG_FILE}"
|
|
||||||
|
|
||||||
chmod 0600 "${CONFIG_FILE}"
|
|
||||||
|
|
||||||
[[ -s "${CONFIG_FILE}" ]] ||
|
|
||||||
{ backend_fatal "Erzeugte Konfigurationsdatei ist leer: ${CONFIG_FILE}"; return 1; }
|
|
||||||
|
|
||||||
if grep -q '\${TUXFLOTTE_' "${CONFIG_FILE}"; then
|
|
||||||
backend_fatal "Erzeugte Konfigurationsdatei enthält nicht aufgelöste Platzhalter."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
backend_log "Konfiguration erzeugt: ${CONFIG_FILE}"
|
|
||||||
}
|
|
||||||
|
|
||||||
backend_launch() {
|
|
||||||
backend_log "Phase 1: Start des nativen Installers ist noch nicht aktiv."
|
|
||||||
backend_log "Erzeugte Konfiguration liegt bereit unter: ${CONFIG_FILE}"
|
|
||||||
}
|
|
||||||
|
|
||||||
backend_postinstall() {
|
|
||||||
backend_log "Phase 1: Vorbereitung des Provisioning-Agent erfolgt bereits im %post-Abschnitt der Kickstart-Konfiguration."
|
|
||||||
}
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
#version=DEVEL
|
|
||||||
|
|
||||||
text
|
|
||||||
reboot
|
|
||||||
|
|
||||||
lang de_DE.UTF-8
|
|
||||||
keyboard de
|
|
||||||
timezone Europe/Berlin --utc
|
|
||||||
|
|
||||||
# Lab-Bootstrap-Zugangsdaten. Ersetzt ein noch fehlendes Secret-Reference-Modell
|
|
||||||
# (siehe 09-data-model-v1.md) und darf nicht als Produktionsmechanismus gelten.
|
|
||||||
rootpw --plaintext test123
|
|
||||||
user --name=tuxflotte --groups=wheel --password=test123
|
|
||||||
|
|
||||||
network --bootproto=dhcp --activate --hostname=${TUXFLOTTE_HOSTNAME}
|
|
||||||
|
|
||||||
zerombr
|
|
||||||
clearpart --all --initlabel
|
|
||||||
${TUXFLOTTE_PARTITIONING_COMMAND}
|
|
||||||
|
|
||||||
firewall --enabled
|
|
||||||
selinux --enforcing
|
|
||||||
|
|
||||||
bootloader --location=mbr
|
|
||||||
|
|
||||||
%packages
|
|
||||||
@core
|
|
||||||
vim
|
|
||||||
curl
|
|
||||||
git
|
|
||||||
ansible-core
|
|
||||||
%end
|
|
||||||
|
|
||||||
%post
|
|
||||||
cat > /etc/motd <<'EOF'
|
|
||||||
Provisioned by tuxflotte
|
|
||||||
|
|
||||||
https://tuxflotte.de
|
|
||||||
EOF
|
|
||||||
|
|
||||||
localectl set-locale LANG=de_DE.UTF-8
|
|
||||||
localectl set-keymap de
|
|
||||||
localectl set-x11-keymap de
|
|
||||||
|
|
||||||
mkdir -p /etc/tuxflotte
|
|
||||||
|
|
||||||
cat > /etc/tuxflotte/runtime_blueprint.json <<'RUNTIME_BLUEPRINT_EOF'
|
|
||||||
${TUXFLOTTE_BLUEPRINTS_JSON}
|
|
||||||
RUNTIME_BLUEPRINT_EOF
|
|
||||||
|
|
||||||
# Der Provisioning Agent existiert noch nicht als Build-Artefakt.
|
|
||||||
# Anwendung der obigen Blueprints per Ansible-Pull erfolgt erst nach dessen Implementierung.
|
|
||||||
echo "tuxflotte: Runtime Blueprint unter /etc/tuxflotte/runtime_blueprint.json hinterlegt." >> /var/log/tuxflotte-postinstall.log
|
|
||||||
echo "tuxflotte: Provisioning-Agent-Installation ist noch nicht implementiert (Phase 1)." >> /var/log/tuxflotte-postinstall.log
|
|
||||||
%end
|
|
||||||
@ -76,8 +76,6 @@ case "${TUXFLOTTE_INSTALLATION_CONFIRMED:-}" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
run_module "$SCRIPT_DIR/modules/30_runtime_blueprint.sh" "always"
|
|
||||||
run_module "$SCRIPT_DIR/modules/40_backend.sh" "always"
|
|
||||||
run_module "$SCRIPT_DIR/modules/20_storage.sh" "dry-run-safe"
|
run_module "$SCRIPT_DIR/modules/20_storage.sh" "dry-run-safe"
|
||||||
run_module "$SCRIPT_DIR/modules/99_finish.sh" "always"
|
run_module "$SCRIPT_DIR/modules/99_finish.sh" "always"
|
||||||
|
|
||||||
|
|||||||
@ -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 TEMPLATE_FILE="${RUNTIME_DIR}/template.json"
|
readonly PROFILE_FILE="${RUNTIME_DIR}/profile.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 -- "${TEMPLATE_FILE}"
|
rm -f -- "${PROFILE_FILE}"
|
||||||
}
|
}
|
||||||
|
|
||||||
validate_server_response() {
|
validate_server_response() {
|
||||||
@ -37,53 +37,47 @@ validate_server_response() {
|
|||||||
|
|
||||||
jq --exit-status '
|
jq --exit-status '
|
||||||
.success == true
|
.success == true
|
||||||
and (.templates | type == "array")
|
and (.profiles | type == "array")
|
||||||
and (.templates | length > 0)
|
and (.profiles | length > 0)
|
||||||
' "${SERVER_RESPONSE_FILE}" >/dev/null ||
|
' "${SERVER_RESPONSE_FILE}" >/dev/null ||
|
||||||
fatal "Serverantwort enthält keine auswählbaren Bereitstellungsvorlagen."
|
fatal "Serverantwort enthält keine auswählbaren Profile."
|
||||||
}
|
}
|
||||||
|
|
||||||
show_templates() {
|
show_profiles() {
|
||||||
local index=1
|
local index=1
|
||||||
local template
|
local profile
|
||||||
|
|
||||||
log "Verfügbare Bereitstellungsvorlagen:"
|
log "Verfügbare Provisioning-Profile:"
|
||||||
|
|
||||||
while IFS= read -r template; do
|
while IFS= read -r profile; do
|
||||||
printf '\n'
|
printf '\n'
|
||||||
printf ' %d) %s' \
|
printf ' %d) %s\n' \
|
||||||
"${index}" \
|
"${index}" \
|
||||||
"$(jq -r '.label' <<<"${template}")"
|
"$(jq -r '.label' <<<"${profile}")"
|
||||||
|
|
||||||
if [[ "$(jq -r '.is_default' <<<"${template}")" == "true" ]]; then
|
printf ' Distribution: %s %s\n' \
|
||||||
printf ' (Standard)'
|
"$(jq -r '.distribution' <<<"${profile}")" \
|
||||||
fi
|
"$(jq -r '.version' <<<"${profile}")"
|
||||||
|
|
||||||
printf '\n'
|
printf ' %s\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 '.templates[]' "${SERVER_RESPONSE_FILE}")
|
done < <(jq -c '.profiles[]' "${SERVER_RESPONSE_FILE}")
|
||||||
}
|
}
|
||||||
|
|
||||||
select_template() {
|
select_profile() {
|
||||||
local template_count
|
local profile_count
|
||||||
local selection
|
local selection
|
||||||
|
|
||||||
template_count="$(jq '.templates | length' "${SERVER_RESPONSE_FILE}")"
|
profile_count="$(jq '.profiles | length' "${SERVER_RESPONSE_FILE}")"
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
printf '\n'
|
printf '\n'
|
||||||
read -r -p "Bereitstellungsvorlage auswählen [1-${template_count}]: " selection
|
read -r -p "Profil auswählen [1-${profile_count}]: " selection
|
||||||
|
|
||||||
if [[ "${selection}" =~ ^[0-9]+$ ]] &&
|
if [[ "${selection}" =~ ^[0-9]+$ ]] &&
|
||||||
((selection >= 1 && selection <= template_count)); then
|
((selection >= 1 && selection <= profile_count)); then
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -94,32 +88,30 @@ select_template() {
|
|||||||
--argjson index "$((selection - 1))" \
|
--argjson index "$((selection - 1))" \
|
||||||
'{
|
'{
|
||||||
schema_version: 1,
|
schema_version: 1,
|
||||||
template: .templates[$index]
|
profile: .profiles[$index]
|
||||||
}' \
|
}' \
|
||||||
"${SERVER_RESPONSE_FILE}" >"${TEMPLATE_FILE}"
|
"${SERVER_RESPONSE_FILE}" >"${PROFILE_FILE}"
|
||||||
|
|
||||||
chmod 0600 "${TEMPLATE_FILE}"
|
chmod 0600 "${PROFILE_FILE}"
|
||||||
|
|
||||||
jq --exit-status '
|
jq --exit-status '
|
||||||
.schema_version == 1
|
.schema_version == 1
|
||||||
and (.template | type == "object")
|
and (.profile | type == "object")
|
||||||
and (.template.id | type == "string")
|
and (.profile.id | type == "string")
|
||||||
and (.template.id | length > 0)
|
and (.profile.id | length > 0)
|
||||||
and (.template.workspace | type == "object")
|
' "${PROFILE_FILE}" >/dev/null ||
|
||||||
and (.template.backend | type == "object")
|
fatal "Ausgewähltes Profil konnte nicht gültig gespeichert werden."
|
||||||
' "${TEMPLATE_FILE}" >/dev/null ||
|
|
||||||
fatal "Ausgewählte Bereitstellungsvorlage konnte nicht gültig gespeichert werden."
|
|
||||||
|
|
||||||
log "Bereitstellungsvorlage $(jq -r '.template.id' "${TEMPLATE_FILE}") wurde ausgewählt."
|
log "Profil $(jq -r '.profile.id' "${PROFILE_FILE}") wurde ausgewählt."
|
||||||
log "Auswahl wurde unter ${TEMPLATE_FILE} gespeichert."
|
log "Profilauswahl wurde unter ${PROFILE_FILE} gespeichert."
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
require_root
|
require_root
|
||||||
prepare_runtime
|
prepare_runtime
|
||||||
validate_server_response
|
validate_server_response
|
||||||
show_templates
|
show_profiles
|
||||||
select_template
|
select_profile
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|||||||
@ -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 TEMPLATE_FILE="/run/tuxflotte/assignment/template.json"
|
readonly PROFILE_FILE="/run/tuxflotte/assignment/profile.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,39 +34,38 @@ prepare_runtime() {
|
|||||||
rm -f -- "${STATE_FILE}"
|
rm -f -- "${STATE_FILE}"
|
||||||
}
|
}
|
||||||
|
|
||||||
validate_template() {
|
validate_profile() {
|
||||||
[[ -r "${TEMPLATE_FILE}" ]] ||
|
[[ -r "${PROFILE_FILE}" ]] ||
|
||||||
fatal "Bereitstellungsvorlage nicht gefunden: ${TEMPLATE_FILE}"
|
fatal "Profilauswahl nicht gefunden: ${PROFILE_FILE}"
|
||||||
|
|
||||||
jq --exit-status '
|
jq --exit-status '
|
||||||
.schema_version == 1
|
.schema_version == 1
|
||||||
and (.template | type == "object")
|
and (.profile | type == "object")
|
||||||
and (.template.id | type == "string")
|
and (.profile.id | type == "string")
|
||||||
and (.template.label | type == "string")
|
and (.profile.label | type == "string")
|
||||||
and (.template.workspace.name | type == "string")
|
and (.profile.distribution | type == "string")
|
||||||
and (.template.backend.name | type == "string")
|
and (.profile.version | type == "string")
|
||||||
and (.template.backend.version | type == "string")
|
' "${PROFILE_FILE}" >/dev/null ||
|
||||||
' "${TEMPLATE_FILE}" >/dev/null ||
|
fatal "Profilauswahl enthält kein gültiges Profil."
|
||||||
fatal "Bereitstellungsvorlage enthält keine gültige Auswahl."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
show_installation_plan() {
|
show_installation_plan() {
|
||||||
local label
|
local label
|
||||||
local workspace
|
local distribution
|
||||||
local backend_name
|
local version
|
||||||
local backend_version
|
local installer_type
|
||||||
|
|
||||||
label="$(jq -r '.template.label' "${TEMPLATE_FILE}")"
|
label="$(jq -r '.profile.label' "${PROFILE_FILE}")"
|
||||||
workspace="$(jq -r '.template.workspace.name' "${TEMPLATE_FILE}")"
|
distribution="$(jq -r '.profile.distribution' "${PROFILE_FILE}")"
|
||||||
backend_name="$(jq -r '.template.backend.name' "${TEMPLATE_FILE}")"
|
version="$(jq -r '.profile.version' "${PROFILE_FILE}")"
|
||||||
backend_version="$(jq -r '.template.backend.version' "${TEMPLATE_FILE}")"
|
installer_type="$(jq -r '.profile.installer.type // "unbekannt"' "${PROFILE_FILE}")"
|
||||||
|
|
||||||
printf '\n'
|
printf '\n'
|
||||||
printf 'Geplanter Installationsvorgang\n'
|
printf 'Geplanter Installationsvorgang\n'
|
||||||
printf '==============================\n\n'
|
printf '==============================\n\n'
|
||||||
printf 'Bereitstellungsvorlage: %s\n' "${label}"
|
printf 'Profil: %s\n' "${label}"
|
||||||
printf 'Workspace: %s\n' "${workspace}"
|
printf 'Distribution: %s %s\n' "${distribution}" "${version}"
|
||||||
printf 'Backend: %s %s\n' "${backend_name}" "${backend_version}"
|
printf 'Installer: %s\n' "${installer_type}"
|
||||||
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'
|
||||||
@ -105,7 +104,7 @@ confirm_installation() {
|
|||||||
main() {
|
main() {
|
||||||
require_root
|
require_root
|
||||||
prepare_runtime
|
prepare_runtime
|
||||||
validate_template
|
validate_profile
|
||||||
show_installation_plan
|
show_installation_plan
|
||||||
confirm_installation
|
confirm_installation
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,119 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -Eeuo pipefail
|
|
||||||
|
|
||||||
SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
|
|
||||||
readonly SCRIPT_NAME
|
|
||||||
|
|
||||||
readonly NETWORK_STATE="/run/tuxflotte/network/state.env"
|
|
||||||
readonly SERVER_RESPONSE_FILE="/run/tuxflotte/server/response.json"
|
|
||||||
readonly TEMPLATE_FILE="/run/tuxflotte/assignment/template.json"
|
|
||||||
|
|
||||||
readonly RUNTIME_DIR="/run/tuxflotte/runtime"
|
|
||||||
readonly RESOLVE_REQUEST_FILE="${RUNTIME_DIR}/resolve_request.json"
|
|
||||||
readonly BLUEPRINT_FILE="${RUNTIME_DIR}/runtime_blueprint.json"
|
|
||||||
|
|
||||||
log() {
|
|
||||||
printf '[%s] %s\n' "${SCRIPT_NAME}" "$*" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal() {
|
|
||||||
printf '[%s] FEHLER: %s\n' "${SCRIPT_NAME}" "$*" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
require_root() {
|
|
||||||
if [[ "${EUID}" -ne 0 ]]; then
|
|
||||||
fatal "Das Runtime-Blueprint-Modul muss als root ausgeführt werden."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
prepare_runtime_directory() {
|
|
||||||
install -d \
|
|
||||||
--mode=0700 \
|
|
||||||
--owner=root \
|
|
||||||
--group=root \
|
|
||||||
"${RUNTIME_DIR}"
|
|
||||||
|
|
||||||
rm -f -- "${RESOLVE_REQUEST_FILE}" "${BLUEPRINT_FILE}"
|
|
||||||
}
|
|
||||||
|
|
||||||
validate_inputs() {
|
|
||||||
[[ -r "${NETWORK_STATE}" ]] ||
|
|
||||||
fatal "Netzwerkstatus nicht gefunden: ${NETWORK_STATE}"
|
|
||||||
|
|
||||||
[[ -r "${SERVER_RESPONSE_FILE}" ]] ||
|
|
||||||
fatal "Serverantwort nicht gefunden: ${SERVER_RESPONSE_FILE}"
|
|
||||||
|
|
||||||
jq --exit-status '.device.id | type == "string" and length > 0' \
|
|
||||||
"${SERVER_RESPONSE_FILE}" >/dev/null ||
|
|
||||||
fatal "Serverantwort enthält keine gültige Geräte-ID."
|
|
||||||
|
|
||||||
[[ -r "${TEMPLATE_FILE}" ]] ||
|
|
||||||
fatal "Bereitstellungsvorlage nicht gefunden: ${TEMPLATE_FILE}"
|
|
||||||
|
|
||||||
jq --exit-status '.template.id | type == "string" and length > 0' \
|
|
||||||
"${TEMPLATE_FILE}" >/dev/null ||
|
|
||||||
fatal "Bereitstellungsvorlage enthält keine gültige ID."
|
|
||||||
}
|
|
||||||
|
|
||||||
build_resolve_request() {
|
|
||||||
jq \
|
|
||||||
--null-input \
|
|
||||||
--slurpfile response "${SERVER_RESPONSE_FILE}" \
|
|
||||||
'{ device_id: $response[0].device.id }' \
|
|
||||||
>"${RESOLVE_REQUEST_FILE}"
|
|
||||||
|
|
||||||
chmod 0600 "${RESOLVE_REQUEST_FILE}"
|
|
||||||
}
|
|
||||||
|
|
||||||
send_resolve_request() {
|
|
||||||
local server_url
|
|
||||||
local template_id
|
|
||||||
|
|
||||||
# shellcheck disable=SC1090
|
|
||||||
source "${NETWORK_STATE}"
|
|
||||||
|
|
||||||
server_url="${TUXFLOTTE_SERVER_URL%/health}"
|
|
||||||
template_id="$(jq --raw-output '.template.id' "${TEMPLATE_FILE}")"
|
|
||||||
|
|
||||||
curl \
|
|
||||||
--silent \
|
|
||||||
--show-error \
|
|
||||||
--fail \
|
|
||||||
--location \
|
|
||||||
--header 'Content-Type: application/json' \
|
|
||||||
--data-binary "@${RESOLVE_REQUEST_FILE}" \
|
|
||||||
--output "${BLUEPRINT_FILE}" \
|
|
||||||
"${server_url}/api/v1/templates/${template_id}/resolve" ||
|
|
||||||
fatal "Runtime Blueprint konnte nicht aufgelöst werden."
|
|
||||||
|
|
||||||
chmod 0600 "${BLUEPRINT_FILE}"
|
|
||||||
|
|
||||||
jq --exit-status . "${BLUEPRINT_FILE}" >/dev/null ||
|
|
||||||
fatal "Antwort auf die Runtime-Blueprint-Anfrage enthält kein gültiges JSON."
|
|
||||||
|
|
||||||
jq --exit-status '.success == true' "${BLUEPRINT_FILE}" >/dev/null ||
|
|
||||||
fatal "$(jq -r '.message // "Provisioning-Server hat die Auflösung abgelehnt."' "${BLUEPRINT_FILE}")"
|
|
||||||
|
|
||||||
jq --exit-status '
|
|
||||||
.runtime_blueprint
|
|
||||||
| (.workspace_id | type == "string")
|
|
||||||
and (.backend_id | type == "string")
|
|
||||||
and (.blueprints | type == "array")
|
|
||||||
and (.installation_directives | type == "object")
|
|
||||||
' "${BLUEPRINT_FILE}" >/dev/null ||
|
|
||||||
fatal "Runtime Blueprint enthält keine gültige Zielbeschreibung."
|
|
||||||
|
|
||||||
log "Runtime Blueprint für Backend $(jq -r '.runtime_blueprint.backend_id' "${BLUEPRINT_FILE}") erzeugt."
|
|
||||||
log "Runtime Blueprint wurde unter ${BLUEPRINT_FILE} gespeichert."
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
require_root
|
|
||||||
prepare_runtime_directory
|
|
||||||
validate_inputs
|
|
||||||
build_resolve_request
|
|
||||||
send_resolve_request
|
|
||||||
}
|
|
||||||
|
|
||||||
main "$@"
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -Eeuo pipefail
|
|
||||||
|
|
||||||
SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
|
|
||||||
readonly SCRIPT_NAME
|
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
readonly SCRIPT_DIR
|
|
||||||
BACKENDS_DIR="$(cd "${SCRIPT_DIR}/../../backends" && pwd)"
|
|
||||||
readonly BACKENDS_DIR
|
|
||||||
|
|
||||||
readonly ORCHESTRATOR_BLUEPRINT_FILE="/run/tuxflotte/runtime/runtime_blueprint.json"
|
|
||||||
|
|
||||||
log() {
|
|
||||||
printf '[%s] %s\n' "${SCRIPT_NAME}" "$*" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
fatal() {
|
|
||||||
printf '[%s] FEHLER: %s\n' "${SCRIPT_NAME}" "$*" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
require_root() {
|
|
||||||
if [[ "${EUID}" -ne 0 ]]; then
|
|
||||||
fatal "Das Backend-Modul muss als root ausgeführt werden."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
load_backend() {
|
|
||||||
local backend_id
|
|
||||||
local backend_script
|
|
||||||
|
|
||||||
[[ -r "${ORCHESTRATOR_BLUEPRINT_FILE}" ]] ||
|
|
||||||
fatal "Runtime Blueprint nicht gefunden: ${ORCHESTRATOR_BLUEPRINT_FILE}"
|
|
||||||
|
|
||||||
backend_id="$(jq --raw-output '.runtime_blueprint.backend_id // empty' "${ORCHESTRATOR_BLUEPRINT_FILE}")"
|
|
||||||
[[ -n "${backend_id}" ]] ||
|
|
||||||
fatal "Runtime Blueprint enthält keine gültige Backend-ID."
|
|
||||||
|
|
||||||
backend_script="${BACKENDS_DIR}/${backend_id}/backend.sh"
|
|
||||||
[[ -r "${backend_script}" ]] ||
|
|
||||||
fatal "Kein Backend für '${backend_id}' gefunden: ${backend_script}"
|
|
||||||
|
|
||||||
log "Lade Backend '${backend_id}' aus ${backend_script}"
|
|
||||||
|
|
||||||
# shellcheck disable=SC1090
|
|
||||||
source "${backend_script}"
|
|
||||||
}
|
|
||||||
|
|
||||||
run_lifecycle() {
|
|
||||||
local step
|
|
||||||
|
|
||||||
for step in backend_init backend_validate backend_generate_config backend_launch backend_postinstall; do
|
|
||||||
declare -f "${step}" >/dev/null ||
|
|
||||||
fatal "Backend implementiert erforderliche Funktion nicht: ${step}"
|
|
||||||
|
|
||||||
log "Führe ${step}() aus."
|
|
||||||
|
|
||||||
"${step}" ||
|
|
||||||
fatal "${step}() ist fehlgeschlagen."
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
require_root
|
|
||||||
load_backend
|
|
||||||
run_lifecycle
|
|
||||||
}
|
|
||||||
|
|
||||||
main "$@"
|
|
||||||
Loading…
x
Reference in New Issue
Block a user