Drei Betriebsskripte fuer Linux, im Auslieferungspaket neben den Programmen. setup.sh richtet eine Anlage vollstaendig ein: PostgreSQL auf Wunsch mit (apt/dnf/yum/zypper/pacman), Dienstkonto, Verschluesselungsschluessel, Schema, erster Administrator, gehaertetes Repository, gehaertete systemd-Einheit. Jeder Schritt vermerkt, was er angelegt hat; bricht der Lauf ab, wird genau das zurueckgebaut und nichts sonst. Eine bestehende Installation wird nicht ueberschrieben — dafuer gibt es update.sh, und der Unterschied ist, dass ein Update vorher sichert. update.sh haelt die Reihenfolge ein, um die es geht: sichern, anhalten, tauschen, migrieren, starten, pruefen. Kommt der Dienst danach nicht hoch, holt es die vorige Fassung zurueck. Ohne pg_dump wird gar nicht erst begonnen — ohne Sicherung gibt es nach einer misslungenen Migration keinen Weg zurueck. Repository und Verschluesselungsschluessel bleiben unberuehrt. uninstall.sh entfernt standardmaessig NUR Dienst und Programme. Datenbank, Repository und Konfiguration bleiben liegen; jede dieser Loeschungen verlangt ein woertlich getipptes Bestaetigungswort an einem Terminal. Ein Deinstallationsskript, das nebenbei die Backups mitnimmt, vernichtet genau das, wofuer jemand jahrelang Speicher bezahlt hat. Gegen Debian 12 im Container gefahren — Installation, Anmeldung, Repository eingetragen, Loeschschutz gemessen (advisory auf overlayfs, richtig), echter Sicherungslauf, Update mit unveraendertem Bestand, beide Abbauarten. Drei Fehler dabei gefunden und behoben, alle derselben Art: - "tr </dev/urandom | head -c 32" und "psql | grep -q": Der frueh geschlossene Pipe schickt dem Schreiber SIGPIPE, und mit "set -o pipefail" bricht das Skript mitten in der Einrichtung ab, ohne erkennbaren Grund. - update.sh las die laufende Fassung mit "grep -o" aus der Antwort von /health/ready. Die enthaelt gar kein Versionsfeld; grep endet mit 1, und das Skript nahm ein GELUNGENES Update wieder zurueck — wegen einer Zeile, die nur der Ausgabe dient. Dazu: SYNCOVA_ADMIN_PASSWORD stand in der Doku und existiert nicht — das Passwort kommt ueber die Standardeingabe. Und "syncova-repo break-lock" fehlte zwar nicht mehr, aber der Test auf die Uebereinstimmung der drei Skripte ist neu: Drei Skripte, die sich ueber den Installationsort uneinig sind, ergeben eine Anlage, die sich nicht mehr entfernen laesst. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
460 lines
18 KiB
Bash
Executable File
460 lines
18 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Entfernt Syncova Backups von einem Server.
|
|
#
|
|
# **Standardmaessig bleiben die Daten liegen.** Entfernt werden Dienst und
|
|
# Programme; Datenbank, Repository und Konfiguration bleiben, wo sie sind.
|
|
#
|
|
# Der Grund ist der Gegenstand dieser Software: Ein Deinstallationsskript, das
|
|
# nebenbei die Backups mitnimmt, vernichtet genau das, wofuer jemand jahrelang
|
|
# Speicher bezahlt hat — und zwar in dem Moment, in dem er am wenigsten damit
|
|
# rechnet.
|
|
#
|
|
# ./uninstall.sh Dienst und Programme
|
|
# ./uninstall.sh --mit-konfiguration zusaetzlich /etc/syncova
|
|
# ./uninstall.sh --mit-datenbank zusaetzlich die Datenbank
|
|
# ./uninstall.sh --mit-repository zusaetzlich das Repository
|
|
# ./uninstall.sh --alles alle drei
|
|
#
|
|
# Jeder der drei Schalter verlangt eine getippte Bestaetigung. Ein Kennzeichen
|
|
# in einem Skript reicht nicht aus.
|
|
|
|
set -euo pipefail
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Feste Orte — gleichlautend in setup.sh und update.sh
|
|
# ---------------------------------------------------------------------------
|
|
|
|
readonly installationRoot="/opt/syncova"
|
|
readonly configurationDirectory="/etc/syncova"
|
|
readonly configurationFile="${configurationDirectory}/syncova.env"
|
|
readonly serviceName="syncova-api"
|
|
readonly serviceUnitFile="/etc/systemd/system/${serviceName}.service"
|
|
readonly serviceAccount="syncova"
|
|
readonly backupDirectory="/var/backups/syncova"
|
|
readonly previousReleaseRoot="${installationRoot}.vorherige"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Ausgabe
|
|
# ---------------------------------------------------------------------------
|
|
|
|
if [[ -t 1 ]]; then
|
|
readonly colorReset=$'\033[0m'
|
|
readonly colorBold=$'\033[1m'
|
|
readonly colorRed=$'\033[31m'
|
|
readonly colorGreen=$'\033[32m'
|
|
readonly colorYellow=$'\033[33m'
|
|
else
|
|
readonly colorReset='' colorBold='' colorRed='' colorGreen='' colorYellow=''
|
|
fi
|
|
|
|
writeStep() { printf '%s==>%s %s\n' "${colorBold}" "${colorReset}" "$1"; }
|
|
writeDetail() { printf ' %s\n' "$1"; }
|
|
writeSuccess() { printf ' %s✓%s %s\n' "${colorGreen}" "${colorReset}" "$1"; }
|
|
writeWarning() { printf ' %s!%s %s\n' "${colorYellow}" "${colorReset}" "$1" >&2; }
|
|
|
|
abortWithMessage() {
|
|
printf '\n%sAbbruch:%s %s\n' "${colorRed}${colorBold}" "${colorReset}" "$1" >&2
|
|
exit 1
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Schalter
|
|
# ---------------------------------------------------------------------------
|
|
|
|
removeConfiguration="nein"
|
|
removeDatabase="nein"
|
|
removeRepository="nein"
|
|
removeServiceAccount="nein"
|
|
|
|
showUsage() {
|
|
cat <<'USAGE'
|
|
Verwendung:
|
|
uninstall.sh [Schalter]
|
|
|
|
Ohne Schalter werden entfernt:
|
|
- der Dienst syncova-api
|
|
- die Programme unter /opt/syncova
|
|
|
|
Es bleiben liegen:
|
|
- die Datenbank mit Auftraegen, Laeufen und Wiederherstellungspunkten
|
|
- das Repository mit den Sicherungen selbst
|
|
- die Konfiguration samt Verschluesselungsschluessel
|
|
|
|
Zusaetzliche Schalter (jeder verlangt eine getippte Bestaetigung):
|
|
--mit-konfiguration Entfernt /etc/syncova — DARIN LIEGT DER SCHLUESSEL
|
|
--mit-datenbank Entfernt die Datenbank
|
|
--mit-repository Entfernt das Repository — DAS SIND DIE BACKUPS
|
|
--mit-dienstkonto Entfernt das Dienstkonto syncova
|
|
--alles Alle vier
|
|
--hilfe Diese Uebersicht
|
|
USAGE
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--mit-konfiguration) removeConfiguration="ja"; shift ;;
|
|
--mit-datenbank) removeDatabase="ja"; shift ;;
|
|
--mit-repository) removeRepository="ja"; shift ;;
|
|
--mit-dienstkonto) removeServiceAccount="ja"; shift ;;
|
|
--alles)
|
|
removeConfiguration="ja"; removeDatabase="ja"
|
|
removeRepository="ja"; removeServiceAccount="ja"; shift ;;
|
|
--hilfe|-h|--help) showUsage; exit 0 ;;
|
|
*) showUsage >&2; abortWithMessage "unbekannter Schalter: $1" ;;
|
|
esac
|
|
done
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Bestandsaufnahme
|
|
# ---------------------------------------------------------------------------
|
|
|
|
printf '\n%sSyncova Backups — Deinstallation%s\n\n' "${colorBold}" "${colorReset}"
|
|
|
|
if [[ "$(id -u)" -ne 0 ]]; then
|
|
abortWithMessage "Dieses Skript braucht root-Rechte (sudo ./uninstall.sh)."
|
|
fi
|
|
|
|
writeStep "Was ist vorhanden?"
|
|
|
|
foundAnything="nein"
|
|
|
|
installedVersion=""
|
|
if [[ -x "${installationRoot}/bin/syncova-api" ]]; then
|
|
installedVersion="$("${installationRoot}/bin/syncova-api" --version 2>/dev/null | awk '{print $2}')"
|
|
writeDetail "Programme ${installationRoot} (${installedVersion:-Version unbekannt})"
|
|
foundAnything="ja"
|
|
fi
|
|
|
|
if [[ -f "${serviceUnitFile}" ]]; then
|
|
serviceState="$(systemctl is-active "${serviceName}" 2>/dev/null || echo 'gestoppt')"
|
|
writeDetail "Dienst ${serviceName} (${serviceState})"
|
|
foundAnything="ja"
|
|
fi
|
|
|
|
# Die Konfiguration wird gelesen, um Datenbank und Repository zu finden. Sie
|
|
# enthaelt Geheimnisse; ausgegeben wird nichts davon.
|
|
databaseName="" ; databaseUser="" ; databaseHost="" ; databasePort=""
|
|
if [[ -f "${configurationFile}" ]]; then
|
|
set -a
|
|
# shellcheck disable=SC1090
|
|
. "${configurationFile}"
|
|
set +a
|
|
|
|
databaseName="${SYNCOVA_DB_NAME:-}"
|
|
databaseUser="${SYNCOVA_DB_USER:-}"
|
|
databaseHost="${SYNCOVA_DB_HOST:-127.0.0.1}"
|
|
databasePort="${SYNCOVA_DB_PORT:-5432}"
|
|
|
|
writeDetail "Konfiguration ${configurationFile}"
|
|
foundAnything="ja"
|
|
fi
|
|
|
|
# Repositories aus der Datenbank ermitteln — es koennen mehrere sein, und ihr
|
|
# Ort steht nicht in der Konfiguration.
|
|
knownRepositoryPaths=()
|
|
if [[ -n "${databaseName}" ]] && command -v psql >/dev/null 2>&1; then
|
|
while IFS= read -r repositoryLocation; do
|
|
[[ -n "${repositoryLocation}" ]] && knownRepositoryPaths+=("${repositoryLocation}")
|
|
done < <(PGPASSWORD="${SYNCOVA_DB_PASSWORD:-}" psql -h "${databaseHost}" -p "${databasePort}" \
|
|
-U "${databaseUser}" -d "${databaseName}" -tAc \
|
|
"SELECT location FROM repositories ORDER BY name" 2>/dev/null || true)
|
|
fi
|
|
|
|
if [[ -n "${databaseName}" ]]; then
|
|
backupCount=""
|
|
if command -v psql >/dev/null 2>&1; then
|
|
backupCount="$(PGPASSWORD="${SYNCOVA_DB_PASSWORD:-}" psql -h "${databaseHost}" -p "${databasePort}" \
|
|
-U "${databaseUser}" -d "${databaseName}" -tAc \
|
|
"SELECT COUNT(*) FROM backups WHERE deleted_at IS NULL" 2>/dev/null || true)"
|
|
fi
|
|
|
|
writeDetail "Datenbank ${databaseName}@${databaseHost}:${databasePort}${backupCount:+ (${backupCount} Wiederherstellungspunkte)}"
|
|
foundAnything="ja"
|
|
fi
|
|
|
|
for repositoryLocation in "${knownRepositoryPaths[@]}"; do
|
|
repositorySize=""
|
|
[[ -d "${repositoryLocation}" ]] && repositorySize="$(du -sh "${repositoryLocation}" 2>/dev/null | awk '{print $1}')"
|
|
writeDetail "Repository ${repositoryLocation}${repositorySize:+ (${repositorySize})}"
|
|
foundAnything="ja"
|
|
done
|
|
|
|
if [[ -d "${backupDirectory}" ]]; then
|
|
writeDetail "Sicherungen ${backupDirectory} (Datenbankabzuege der Updates)"
|
|
fi
|
|
|
|
if [[ "${foundAnything}" != "ja" ]]; then
|
|
printf '\n Es ist keine Installation zu finden.\n\n'
|
|
exit 0
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Was passiert
|
|
# ---------------------------------------------------------------------------
|
|
|
|
printf '\n'
|
|
writeStep "Was entfernt wird"
|
|
|
|
writeDetail "Dienst und Programme"
|
|
|
|
[[ "${removeConfiguration}" == "ja" ]] && writeDetail "Konfiguration ${configurationDirectory}"
|
|
[[ "${removeDatabase}" == "ja" ]] && writeDetail "Datenbank ${databaseName}"
|
|
[[ "${removeRepository}" == "ja" ]] && writeDetail "Repositories (siehe oben)"
|
|
[[ "${removeServiceAccount}" == "ja" ]] && writeDetail "Dienstkonto ${serviceAccount}"
|
|
|
|
printf '\n'
|
|
writeStep "Was liegen bleibt"
|
|
|
|
[[ "${removeConfiguration}" != "ja" ]] && writeDetail "Konfiguration ${configurationDirectory} — enthaelt den Verschluesselungsschluessel"
|
|
[[ "${removeDatabase}" != "ja" ]] && writeDetail "Datenbank ${databaseName:-(keine gefunden)}"
|
|
[[ "${removeRepository}" != "ja" ]] && {
|
|
if [[ ${#knownRepositoryPaths[@]} -eq 0 ]]; then
|
|
writeDetail "Repositories — keine gefunden"
|
|
else
|
|
for repositoryLocation in "${knownRepositoryPaths[@]}"; do
|
|
writeDetail "Repository ${repositoryLocation} — die Sicherungen selbst"
|
|
done
|
|
fi
|
|
}
|
|
[[ -d "${backupDirectory}" ]] && writeDetail "Sicherungen ${backupDirectory}"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Bestaetigungen
|
|
#
|
|
# Je gefaehrlicher, desto laenger das zu tippende Wort. Ein Kennzeichen in einem
|
|
# Skript soll nicht genuegen, um Backups zu vernichten.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# requireTypedConfirmation verlangt ein woertlich getipptes Wort.
|
|
requireTypedConfirmation() {
|
|
local confirmationWord="$1" questionText="$2" enteredValue=""
|
|
|
|
if [[ ! -t 0 ]]; then
|
|
abortWithMessage "Diese Handlung verlangt eine Bestaetigung an einem Terminal.
|
|
In einem Skript ist sie bewusst nicht moeglich."
|
|
fi
|
|
|
|
printf '\n'
|
|
printf ' %s%s%s\n' "${colorRed}${colorBold}" "${questionText}" "${colorReset}"
|
|
read -r -p " Tippen Sie '${confirmationWord}' zum Bestaetigen: " enteredValue
|
|
|
|
if [[ "${enteredValue}" != "${confirmationWord}" ]]; then
|
|
abortWithMessage "Nicht bestaetigt. Es wurde nichts entfernt."
|
|
fi
|
|
}
|
|
|
|
if [[ "${removeRepository}" == "ja" ]]; then
|
|
printf '\n'
|
|
printf ' %s┌──────────────────────────────────────────────────────────────┐%s\n' "${colorRed}${colorBold}" "${colorReset}"
|
|
printf ' %s│ DAS REPOSITORY ENTHAELT DIE SICHERUNGEN SELBST │%s\n' "${colorRed}${colorBold}" "${colorReset}"
|
|
printf ' %s└──────────────────────────────────────────────────────────────┘%s\n' "${colorRed}${colorBold}" "${colorReset}"
|
|
printf '\n'
|
|
writeDetail "Nach dem Entfernen gibt es keinen Wiederherstellungspunkt mehr."
|
|
writeDetail "Kein Rueckweg, keine zweite Kopie, kein Papierkorb."
|
|
writeDetail ""
|
|
writeDetail "Ein gehaertetes Repository laesst sich nicht einfach loeschen; das"
|
|
writeDetail "Skript hebt dafuer den Aufbewahrungsschutz auf. Genau davor schuetzt"
|
|
writeDetail "dieser Schutz normalerweise."
|
|
|
|
requireTypedConfirmation "SICHERUNGEN VERNICHTEN" \
|
|
"Sollen die Sicherungen unwiederbringlich entfernt werden?"
|
|
fi
|
|
|
|
if [[ "${removeDatabase}" == "ja" ]]; then
|
|
requireTypedConfirmation "DATENBANK LOESCHEN" \
|
|
"Auftraege, Laeufe, Wiederherstellungspunkte und das Auditprotokoll gehen verloren."
|
|
fi
|
|
|
|
if [[ "${removeConfiguration}" == "ja" ]]; then
|
|
printf '\n'
|
|
writeDetail "In ${configurationFile} steht der Verschluesselungsschluessel."
|
|
writeDetail "Ohne ihn sind verschluesselte Sicherungen nicht mehr lesbar — auch"
|
|
writeDetail "die, die anderswo liegen."
|
|
writeDetail ""
|
|
writeDetail "Sichern Sie ihn jetzt, falls noch nicht geschehen:"
|
|
writeDetail " grep SYNCOVA_ENCRYPTION_KEYS ${configurationFile}"
|
|
|
|
requireTypedConfirmation "SCHLUESSEL VERWERFEN" \
|
|
"Soll die Konfiguration samt Schluessel entfernt werden?"
|
|
fi
|
|
|
|
if [[ "${removeConfiguration}" != "ja" && "${removeDatabase}" != "ja" && \
|
|
"${removeRepository}" != "ja" ]]; then
|
|
if [[ -t 0 ]]; then
|
|
printf '\n'
|
|
read -r -p " Dienst und Programme entfernen? [j/N]: " proceedAnswer
|
|
[[ "${proceedAnswer}" =~ ^[jJyY] ]] || { printf '\n Abgebrochen.\n\n'; exit 0; }
|
|
fi
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 1. Dienst
|
|
# ---------------------------------------------------------------------------
|
|
|
|
printf '\n'
|
|
writeStep "Dienst"
|
|
|
|
if systemctl is-active --quiet "${serviceName}" 2>/dev/null; then
|
|
systemctl stop "${serviceName}"
|
|
writeSuccess "Dienst angehalten"
|
|
fi
|
|
|
|
if systemctl is-enabled --quiet "${serviceName}" 2>/dev/null; then
|
|
systemctl disable "${serviceName}" >/dev/null 2>&1 || true
|
|
fi
|
|
|
|
if [[ -f "${serviceUnitFile}" ]]; then
|
|
rm -f "${serviceUnitFile}"
|
|
systemctl daemon-reload
|
|
writeSuccess "Diensteinheit entfernt"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 2. Repositories
|
|
#
|
|
# Vor den Programmen, weil das Aufheben des Aufbewahrungsschutzes das Werkzeug
|
|
# aus dem Paket braucht.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
if [[ "${removeRepository}" == "ja" ]] && [[ ${#knownRepositoryPaths[@]} -gt 0 ]]; then
|
|
printf '\n'
|
|
writeStep "Repositories"
|
|
|
|
for repositoryLocation in "${knownRepositoryPaths[@]}"; do
|
|
[[ -d "${repositoryLocation}" ]] || continue
|
|
|
|
# Der Aufbewahrungsschutz muss Datei fuer Datei aufgehoben werden. Eine
|
|
# rekursive Aufhebungsfunktion gibt es im Produktivcode ausdruecklich
|
|
# nicht — sie waere genau das Werkzeug, das ein Angreifer sucht.
|
|
if command -v chattr >/dev/null 2>&1; then
|
|
find "${repositoryLocation}" -type f -exec chattr -i {} + 2>/dev/null || true
|
|
fi
|
|
|
|
if rm -rf "${repositoryLocation}" 2>/dev/null; then
|
|
writeSuccess "Entfernt: ${repositoryLocation}"
|
|
else
|
|
writeWarning "Nicht vollstaendig entfernt: ${repositoryLocation}"
|
|
writeDetail " Der Aufbewahrungsschutz greift noch. Von Hand:"
|
|
writeDetail " chattr -R -i '${repositoryLocation}' && rm -rf '${repositoryLocation}'"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 3. Programme
|
|
# ---------------------------------------------------------------------------
|
|
|
|
printf '\n'
|
|
writeStep "Programme"
|
|
|
|
for programRoot in "${installationRoot}" "${previousReleaseRoot}"; do
|
|
if [[ -d "${programRoot}" ]]; then
|
|
rm -rf "${programRoot}"
|
|
writeSuccess "Entfernt: ${programRoot}"
|
|
fi
|
|
done
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 4. Datenbank
|
|
# ---------------------------------------------------------------------------
|
|
|
|
if [[ "${removeDatabase}" == "ja" ]] && [[ -n "${databaseName}" ]]; then
|
|
printf '\n'
|
|
writeStep "Datenbank"
|
|
|
|
# Ohne Pipe zu grep: Der frueh geschlossene Pipe schickt psql ein SIGPIPE,
|
|
# und mit "set -o pipefail" braeche das Skript mitten im Abraeumen ab.
|
|
existingDatabase="$(su - postgres -c "psql -tAc \"SELECT 1 FROM pg_database WHERE datname='${databaseName}'\"" 2>/dev/null || true)"
|
|
|
|
if [[ "${existingDatabase}" == "1" ]]; then
|
|
# WITH (FORCE) trennt bestehende Verbindungen. Ohne den Zusatz
|
|
# scheitert das Loeschen an einer einzigen offenen Sitzung.
|
|
if su - postgres -c "psql -v ON_ERROR_STOP=1 -c \"DROP DATABASE IF EXISTS ${databaseName} WITH (FORCE)\"" >/dev/null 2>&1; then
|
|
writeSuccess "Datenbank ${databaseName} entfernt"
|
|
else
|
|
writeWarning "Die Datenbank liess sich nicht entfernen."
|
|
writeDetail " Von Hand: sudo -u postgres dropdb --force ${databaseName}"
|
|
fi
|
|
|
|
if [[ -n "${databaseUser}" ]]; then
|
|
# Kein "A && B || C": Scheitert B, liefe auch C — und der Betreiber
|
|
# bekaeme beide Meldungen zugleich.
|
|
if su - postgres -c "psql -c \"DROP ROLE IF EXISTS ${databaseUser}\"" >/dev/null 2>&1; then
|
|
writeSuccess "Datenbankkonto ${databaseUser} entfernt"
|
|
else
|
|
writeDetail "Das Datenbankkonto ${databaseUser} blieb (es gehoert womoeglich anderen Datenbanken)."
|
|
fi
|
|
fi
|
|
else
|
|
writeDetail "Die Datenbank ${databaseName} ist von hier aus nicht erreichbar."
|
|
writeDetail "Bei einer entfernten Datenbank entfernen Sie sie dort."
|
|
fi
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 5. Konfiguration
|
|
# ---------------------------------------------------------------------------
|
|
|
|
if [[ "${removeConfiguration}" == "ja" ]] && [[ -d "${configurationDirectory}" ]]; then
|
|
printf '\n'
|
|
writeStep "Konfiguration"
|
|
|
|
rm -rf "${configurationDirectory}"
|
|
writeSuccess "Entfernt: ${configurationDirectory}"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 6. Dienstkonto
|
|
# ---------------------------------------------------------------------------
|
|
|
|
if [[ "${removeServiceAccount}" == "ja" ]] && id "${serviceAccount}" >/dev/null 2>&1; then
|
|
printf '\n'
|
|
writeStep "Dienstkonto"
|
|
|
|
if userdel "${serviceAccount}" 2>/dev/null; then
|
|
writeSuccess "Dienstkonto ${serviceAccount} entfernt"
|
|
else
|
|
writeWarning "Das Dienstkonto liess sich nicht entfernen (gehoeren ihm noch Dateien?)."
|
|
fi
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Abschluss
|
|
# ---------------------------------------------------------------------------
|
|
|
|
printf '\n%sDie Deinstallation ist abgeschlossen.%s\n\n' "${colorGreen}${colorBold}" "${colorReset}"
|
|
|
|
remainingItems=()
|
|
[[ "${removeConfiguration}" != "ja" && -d "${configurationDirectory}" ]] && \
|
|
remainingItems+=("${configurationDirectory} — Konfiguration samt Verschluesselungsschluessel")
|
|
[[ "${removeDatabase}" != "ja" && -n "${databaseName}" ]] && \
|
|
remainingItems+=("Datenbank ${databaseName} auf ${databaseHost}:${databasePort}")
|
|
if [[ "${removeRepository}" != "ja" ]]; then
|
|
for repositoryLocation in "${knownRepositoryPaths[@]}"; do
|
|
[[ -d "${repositoryLocation}" ]] && remainingItems+=("${repositoryLocation} — die Sicherungen")
|
|
done
|
|
fi
|
|
[[ -d "${backupDirectory}" ]] && remainingItems+=("${backupDirectory} — Datenbankabzuege frueherer Updates")
|
|
|
|
if [[ ${#remainingItems[@]} -gt 0 ]]; then
|
|
printf '%sEs bleibt liegen:%s\n\n' "${colorBold}" "${colorReset}"
|
|
for remainingItem in "${remainingItems[@]}"; do
|
|
printf ' %s\n' "${remainingItem}"
|
|
done
|
|
printf '\n'
|
|
printf 'Das ist Absicht. Eine spaetere Neuinstallation findet diese Daten wieder;\n'
|
|
printf 'ein Skript, das sie nebenbei mitnimmt, vernichtet genau das, wofuer\n'
|
|
printf 'jemand jahrelang Speicher bezahlt hat.\n\n'
|
|
|
|
if [[ "${removeConfiguration}" != "ja" && -f "${configurationFile}" ]]; then
|
|
printf '%sSichern Sie den Verschluesselungsschluessel, bevor Sie den Server%s\n' \
|
|
"${colorYellow}${colorBold}" "${colorReset}"
|
|
printf '%sabraeumen — ohne ihn sind verschluesselte Sicherungen unlesbar:%s\n\n' \
|
|
"${colorYellow}${colorBold}" "${colorReset}"
|
|
printf ' grep SYNCOVA_ENCRYPTION_KEYS %s\n\n' "${configurationFile}"
|
|
fi
|
|
else
|
|
printf 'Es wurde alles entfernt.\n\n'
|
|
fi
|