#!/usr/bin/env bash set -Eeuo pipefail SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)" # shellcheck disable=SC1091 source "${SCRIPT_DIR}/lib/common.sh" SCRIPT_NAME="restore-configs.sh" CATEGORIES=() LIST_CATEGORIES=false usage() { cat </dev/null 2>&1; then report "${SCRIPT_NAME}" "users" "sudoers-perms" "fix" "changed" "sudoers ownership and permissions normalized" "" return 0 fi note_failure "${SCRIPT_NAME}" "users" "sudoers-perms" "fix" "visudo validation failed after permission normalization" return 1 } maybe_restore() { local category="$1" item="$2" src="$3" dst="$4" local prompt_text="Restore ${category}/${item} -> ${dst}?" if ! prompt_yes_no "${prompt_text}" yes; then report "${SCRIPT_NAME}" "${category}" "${item}" "restore" "skipped" "operator skipped" "" return 0 fi restore_path "${SCRIPT_NAME}" "${category}" "${item}" "${src}" "${dst}" || true } category_enabled() { local want="$1" x for x in "${CATEGORIES[@]}"; do [[ "${x}" == "${want}" ]] && return 0 done return 1 } restore_system_basics() { local base="${PUBLIC_DIR}/system" [[ -d "${base}" ]] || { mark_manual "${SCRIPT_NAME}" "system-basics" "db" "missing ${base}"; return 0; } if ! prompt_yes_no "Restore category 'system-basics'?" yes; then report "${SCRIPT_NAME}" "system-basics" "category" "restore" "skipped" "operator skipped category" "" return 0 fi maybe_restore "system-basics" "etc-hostname" "${base}/etc-hostname" "/etc/hostname" maybe_restore "system-basics" "etc-hosts" "${base}/etc-hosts" "/etc/hosts" maybe_restore "system-basics" "etc-environment" "${base}/etc-environment" "/etc/environment" maybe_restore "system-basics" "locale.gen" "${base}/locale.gen" "/etc/locale.gen" maybe_restore "system-basics" "timezone" "${base}/timezone" "/etc/timezone" if [[ -f "${base}/etc-hostname" ]]; then local captured_hostname captured_hostname="$(head -n1 "${base}/etc-hostname" 2>/dev/null || true)" if [[ -n "${captured_hostname}" ]]; then if prompt_yes_no "Apply captured hostname now?" yes; then if [[ ${DRY_RUN} == true ]]; then printf '[dry] hostnamectl set-hostname %s\n' "${captured_hostname}" else hostnamectl set-hostname "${captured_hostname}" || note_failure "${SCRIPT_NAME}" "system-basics" "hostnamectl" "set" "hostnamectl failed" fi report "${SCRIPT_NAME}" "system-basics" "hostnamectl" "set" "changed" "${captured_hostname}" "" else report "${SCRIPT_NAME}" "system-basics" "hostnamectl" "set" "skipped" "operator skipped hostnamectl" "" fi fi fi } restore_users() { local base="${PUBLIC_DIR}/users" [[ -d "${base}" ]] || { mark_manual "${SCRIPT_NAME}" "users" "db" "missing ${base}"; return 0; } if ! prompt_yes_no "Restore category 'users'?" yes; then report "${SCRIPT_NAME}" "users" "category" "restore" "skipped" "operator skipped category" "" return 0 fi maybe_restore "users" "sudoers" "${base}/sudoers" "/etc/sudoers" maybe_restore "users" "sudoers.d" "${base}/sudoers.d" "/etc/sudoers.d" fix_sudoers_perms || true maybe_restore "users" "shells" "${base}/shells" "/etc/shells" maybe_restore "users" "login.defs" "${base}/login.defs" "/etc/login.defs" } restore_ssh() { local pub_users="${PUBLIC_DIR}/users" local sec_ssh="${SECRET_DIR}/ssh" if ! prompt_yes_no "Restore category 'ssh'?" yes; then report "${SCRIPT_NAME}" "ssh" "category" "restore" "skipped" "operator skipped category" "" return 0 fi if prompt_yes_no "Restore ssh/sshd_config -> /etc/ssh/sshd_config?" yes; then restore_path "${SCRIPT_NAME}" "ssh" "sshd_config" \ "${pub_users}/sshd_config" "/etc/ssh/sshd_config" \ 0644 root root || true else report "${SCRIPT_NAME}" "ssh" "sshd_config" "restore" "skipped" "operator skipped" "" fi if prompt_yes_no "Restore ssh/sshd_config.d -> /etc/ssh/sshd_config.d?" yes; then restore_path "${SCRIPT_NAME}" "ssh" "sshd_config.d" \ "${pub_users}/sshd_config.d" "/etc/ssh/sshd_config.d" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown -R root:root /etc/ssh/sshd_config.d\n' printf '[dry] find /etc/ssh/sshd_config.d -type d -exec chmod 0755 {} +\n' printf '[dry] find /etc/ssh/sshd_config.d -type f -exec chmod 0644 {} +\n' else if [[ -d /etc/ssh/sshd_config.d ]]; then chown -R root:root /etc/ssh/sshd_config.d 2>/dev/null || true find /etc/ssh/sshd_config.d -type d -exec chmod 0755 {} + 2>/dev/null || true find /etc/ssh/sshd_config.d -type f -exec chmod 0644 {} + 2>/dev/null || true fi fi report "${SCRIPT_NAME}" "ssh" "sshd_config.d-metadata" "restore" "changed" \ "normalized /etc/ssh/sshd_config.d ownership=root:root dirs=0755 files=0644" "" else report "${SCRIPT_NAME}" "ssh" "sshd_config.d" "restore" "skipped" "operator skipped" "" fi if [[ "${ROLE}" == "replacement" || "${ROLE}" == "hardware" ]]; then if [[ -d "${sec_ssh}/etc-ssh" ]]; then if prompt_yes_no "Restore SSH host keys from secret DB?" no; then restore_path "${SCRIPT_NAME}" "ssh" "host-keys" \ "${sec_ssh}/etc-ssh" "/etc/ssh" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown root:root /etc/ssh\n' printf '[dry] chmod 0755 /etc/ssh\n' printf '[dry] find /etc/ssh -maxdepth 1 -type f -name '\''ssh_host_*_key'\'' -exec chown root:root {} +\n' printf '[dry] find /etc/ssh -maxdepth 1 -type f -name '\''ssh_host_*_key'\'' -exec chmod 0600 {} +\n' printf '[dry] find /etc/ssh -maxdepth 1 -type f -name '\''ssh_host_*_key.pub'\'' -exec chown root:root {} +\n' printf '[dry] find /etc/ssh -maxdepth 1 -type f -name '\''ssh_host_*_key.pub'\'' -exec chmod 0644 {} +\n' else chown root:root /etc/ssh 2>/dev/null || true chmod 0755 /etc/ssh 2>/dev/null || true find /etc/ssh -maxdepth 1 -type f -name 'ssh_host_*_key' -exec chown root:root {} + 2>/dev/null || true find /etc/ssh -maxdepth 1 -type f -name 'ssh_host_*_key' -exec chmod 0600 {} + 2>/dev/null || true find /etc/ssh -maxdepth 1 -type f -name 'ssh_host_*_key.pub' -exec chown root:root {} + 2>/dev/null || true find /etc/ssh -maxdepth 1 -type f -name 'ssh_host_*_key.pub' -exec chmod 0644 {} + 2>/dev/null || true fi report "${SCRIPT_NAME}" "ssh" "host-keys-metadata" "restore" "changed" \ "normalized SSH host key ownership=root:root private=0600 public=0644" "" else report "${SCRIPT_NAME}" "ssh" "host-keys" "restore" "skipped" "operator skipped host keys" "" fi fi else report "${SCRIPT_NAME}" "ssh" "host-keys" "restore" "skipped" "lab role: host keys not restored" "" fi if [[ -d "${sec_ssh}/user-lukasz" ]]; then if prompt_yes_no "Restore lukasz user SSH material from secret DB?" no; then restore_path "${SCRIPT_NAME}" "ssh" "user-lukasz" \ "${sec_ssh}/user-lukasz" "/home/lukasz/.ssh" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown -R lukasz:lukasz /home/lukasz/.ssh\n' printf '[dry] chmod 700 /home/lukasz/.ssh\n' printf '[dry] find /home/lukasz/.ssh -maxdepth 1 -type f -exec chmod 600 {} +\n' else chown -R lukasz:lukasz /home/lukasz/.ssh 2>/dev/null || true chmod 700 /home/lukasz/.ssh 2>/dev/null || true find /home/lukasz/.ssh -maxdepth 1 -type f -exec chmod 600 {} + 2>/dev/null || true fi report "${SCRIPT_NAME}" "ssh" "user-lukasz-metadata" "restore" "changed" \ "normalized /home/lukasz/.ssh ownership=lukasz:lukasz dir=0700 files=0600" "" else report "${SCRIPT_NAME}" "ssh" "user-lukasz" "restore" "skipped" "operator skipped user ssh material" "" fi fi if have_cmd sshd; then if [[ ${DRY_RUN} == true ]]; then printf '[dry] sshd -t\n' report "${SCRIPT_NAME}" "ssh" "validate" "check" "ok" "dry-run only" "" else if sshd -t; then report "${SCRIPT_NAME}" "ssh" "validate" "check" "ok" "sshd config validates" "" systemctl restart ssh >/dev/null 2>&1 || true else note_failure "${SCRIPT_NAME}" "ssh" "validate" "check" "sshd validation failed" fi fi fi } restore_network() { local base="${PUBLIC_DIR}/network" [[ -d "${base}" ]] || { mark_manual "${SCRIPT_NAME}" "network" "db" "missing ${base}"; return 0; } if ! prompt_yes_no "Restore category 'network'? This can disrupt connectivity." no; then report "${SCRIPT_NAME}" "network" "category" "restore" "skipped" "operator skipped category" "" return 0 fi if [[ "${ROLE}" == "lab" ]]; then manual_line="lab role: full network restore intentionally skipped" report "${SCRIPT_NAME}" "network" "category" "manual" "manual" "${manual_line}" "" return 0 fi maybe_restore "network" "etc-network" "${base}/etc-network" "/etc/network" maybe_restore "network" "etc-netplan" "${base}/etc-netplan" "/etc/netplan" maybe_restore "network" "systemd-network" "${base}/systemd-network" "/etc/systemd/network" maybe_restore "network" "nsswitch.conf" "${base}/nsswitch.conf" "/etc/nsswitch.conf" maybe_restore "network" "hosts.allow" "${base}/hosts.allow" "/etc/hosts.allow" maybe_restore "network" "hosts.deny" "${base}/hosts.deny" "/etc/hosts.deny" } restore_dns() { local base="${PUBLIC_DIR}/dns" [[ -d "${base}" ]] || { mark_manual "${SCRIPT_NAME}" "dns" "db" "missing ${base}"; return 0; } if ! prompt_yes_no "Restore category 'dns'? This can disrupt resolver state." no; then report "${SCRIPT_NAME}" "dns" "category" "restore" "skipped" "operator skipped category" "" return 0 fi if [[ "${ROLE}" == "lab" ]]; then report "${SCRIPT_NAME}" "dns" "category" "manual" "manual" "lab role: DNS restore intentionally skipped" "" return 0 fi maybe_restore "dns" "dnsmasq.conf" "${base}/dnsmasq.conf" "/etc/dnsmasq.conf" maybe_restore "dns" "dnsmasq.d" "${base}/dnsmasq.d" "/etc/dnsmasq.d" maybe_restore "dns" "etc-unbound" "${base}/etc-unbound" "/etc/unbound" maybe_restore "dns" "resolv.conf" "${base}/resolv.conf" "/etc/resolv.conf" } restore_firewall() { local base="${PUBLIC_DIR}/firewall" [[ -d "${base}" ]] || { mark_manual "${SCRIPT_NAME}" "firewall" "db" "missing ${base}"; return 0; } if ! prompt_yes_no "Restore category 'firewall'? This can disrupt connectivity." no; then report "${SCRIPT_NAME}" "firewall" "category" "restore" "skipped" "operator skipped category" "" return 0 fi if [[ "${ROLE}" == "lab" ]]; then report "${SCRIPT_NAME}" "firewall" "category" "manual" "manual" "lab role: firewall restore intentionally skipped" "" return 0 fi maybe_restore "firewall" "nftables.conf" "${base}/nftables.conf" "/etc/nftables.conf" maybe_restore "firewall" "nftables.d" "${base}/nftables.d" "/etc/nftables.d" if [[ ${DRY_RUN} == false && -f /etc/nftables.conf ]] && have_cmd nft; then nft -c -f /etc/nftables.conf >/dev/null 2>&1 || note_failure "${SCRIPT_NAME}" "firewall" "validate" "check" "nftables config validation failed" fi } restore_nginx() { local base="${PUBLIC_DIR}/nginx/etc-nginx" [[ -d "${base}" ]] || { mark_manual "${SCRIPT_NAME}" "nginx" "db" "missing ${base}"; return 0; } if ! prompt_yes_no "Restore category 'nginx'?" no; then report "${SCRIPT_NAME}" "nginx" "category" "restore" "skipped" "operator skipped category" "" return 0 fi maybe_restore "nginx" "etc-nginx" "${base}" "/etc/nginx" if [[ "${ROLE}" == "lab" ]]; then if [[ ${DRY_RUN} == true ]]; then printf '[dry] sanitize /etc/nginx for lab role\n' printf '[dry] rm -rf /etc/nginx/nginx\n' printf '[dry] find /etc/nginx -maxdepth 1 -type d -name '\''sites-available.bak.*'\'' -exec rm -rf {} +\n' printf '[dry] rm -f /etc/nginx/sites-enabled/*\n' printf '[dry] ln -sf ../sites-available/default /etc/nginx/sites-enabled/default\n' else rm -rf /etc/nginx/nginx 2>/dev/null || true find /etc/nginx -maxdepth 1 -type d -name 'sites-available.bak.*' -exec rm -rf {} + 2>/dev/null || true mkdir -p /etc/nginx/sites-enabled find /etc/nginx/sites-enabled -mindepth 1 -maxdepth 1 -exec rm -f {} + 2>/dev/null || true if [[ -e /etc/nginx/sites-available/default ]]; then ln -sf ../sites-available/default /etc/nginx/sites-enabled/default fi fi report "${SCRIPT_NAME}" "nginx" "lab-sanitize" "restore" "changed" \ "lab role: dropped captured production sites-enabled and restored only default site" "" fi } restore_mariadb() { local base="${PUBLIC_DIR}/mariadb/etc-mysql" [[ -d "${base}" ]] || { mark_manual "${SCRIPT_NAME}" "mariadb" "db" "missing ${base}"; return 0; } if ! prompt_yes_no "Restore category 'mariadb'?" no; then report "${SCRIPT_NAME}" "mariadb" "category" "restore" "skipped" "operator skipped category" "" return 0 fi if prompt_yes_no "Restore mariadb/etc-mysql -> /etc/mysql?" yes; then restore_path "${SCRIPT_NAME}" "mariadb" "etc-mysql" "${base}" "/etc/mysql" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown -R root:root /etc/mysql\n' printf '[dry] find /etc/mysql -type d -exec chmod 0755 {} +\n' printf '[dry] find /etc/mysql -type f -exec chmod 0644 {} +\n' else if [[ -d /etc/mysql ]]; then chown -R root:root /etc/mysql 2>/dev/null || true find /etc/mysql -type d -exec chmod 0755 {} + 2>/dev/null || true find /etc/mysql -type f -exec chmod 0644 {} + 2>/dev/null || true fi fi report "${SCRIPT_NAME}" "mariadb" "metadata" "restore" "changed" \ "normalized /etc/mysql ownership=root:root dirs=0755 files=0644" "" else report "${SCRIPT_NAME}" "mariadb" "etc-mysql" "restore" "skipped" "operator skipped" "" fi } restore_prosody() { local pub_base="${PUBLIC_DIR}/prosody/etc-prosody" local sec_base="${SECRET_DIR}/prosody/etc-prosody" local base="" local label="" if ! prompt_yes_no "Restore category 'prosody'?" no; then report "${SCRIPT_NAME}" "prosody" "category" "restore" "skipped" "operator skipped category" "" return 0 fi if [[ -d "${sec_base}" ]]; then base="${sec_base}" label="etc-prosody(secret)" elif [[ -d "${pub_base}" ]]; then base="${pub_base}" label="etc-prosody(public)" else mark_manual "${SCRIPT_NAME}" "prosody" "db" "missing public/secret prosody config" return 0 fi if prompt_yes_no "Restore prosody/${label} -> /etc/prosody?" yes; then restore_path "${SCRIPT_NAME}" "prosody" "${label}" "${base}" "/etc/prosody" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown -R root:root /etc/prosody\n' printf '[dry] find /etc/prosody -type d -exec chmod 0755 {} +\n' printf '[dry] find /etc/prosody -type f -exec chmod 0644 {} +\n' printf '[dry] find /etc/prosody/certs -type f -exec chmod 0640 {} + 2>/dev/null || true\n' else chown -R root:root /etc/prosody 2>/dev/null || true find /etc/prosody -type d -exec chmod 0755 {} + 2>/dev/null || true find /etc/prosody -type f -exec chmod 0644 {} + 2>/dev/null || true [[ -d /etc/prosody/certs ]] && find /etc/prosody/certs -type f -exec chmod 0640 {} + 2>/dev/null || true fi report "${SCRIPT_NAME}" "prosody" "metadata" "restore" "changed" \ "normalized /etc/prosody ownership=root:root dirs=0755 files=0644 certs=0640" "" else report "${SCRIPT_NAME}" "prosody" "${label}" "restore" "skipped" "operator skipped" "" fi } restore_tor() { local pub_base="${PUBLIC_DIR}/tor" local sec_base="${SECRET_DIR}/tor" if ! prompt_yes_no "Restore category 'tor'?" no; then report "${SCRIPT_NAME}" "tor" "category" "restore" "skipped" "operator skipped category" "" return 0 fi if prompt_yes_no "Restore tor/torrc -> /etc/tor/torrc?" yes; then restore_path "${SCRIPT_NAME}" "tor" "torrc" \ "${pub_base}/torrc" "/etc/tor/torrc" \ 0644 root root || true else report "${SCRIPT_NAME}" "tor" "torrc" "restore" "skipped" "operator skipped" "" fi if prompt_yes_no "Restore tor/torrc.d -> /etc/tor/torrc.d?" yes; then restore_path "${SCRIPT_NAME}" "tor" "torrc.d" \ "${pub_base}/torrc.d" "/etc/tor/torrc.d" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown -R root:root /etc/tor/torrc.d\n' printf '[dry] find /etc/tor/torrc.d -type d -exec chmod 0755 {} +\n' printf '[dry] find /etc/tor/torrc.d -type f -exec chmod 0644 {} +\n' else if [[ -d /etc/tor/torrc.d ]]; then chown -R root:root /etc/tor/torrc.d 2>/dev/null || true find /etc/tor/torrc.d -type d -exec chmod 0755 {} + 2>/dev/null || true find /etc/tor/torrc.d -type f -exec chmod 0644 {} + 2>/dev/null || true fi fi report "${SCRIPT_NAME}" "tor" "torrc.d-metadata" "restore" "changed" \ "normalized /etc/tor/torrc.d ownership=root:root dirs=0755 files=0644" "" else report "${SCRIPT_NAME}" "tor" "torrc.d" "restore" "skipped" "operator skipped" "" fi if [[ "${ROLE}" == "replacement" && -d "${sec_base}/var-lib-tor" ]]; then if prompt_yes_no "Restore tor/var-lib-tor -> /var/lib/tor?" no; then restore_path "${SCRIPT_NAME}" "tor" "var-lib-tor" \ "${sec_base}/var-lib-tor" "/var/lib/tor" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown -R debian-tor:debian-tor /var/lib/tor\n' printf '[dry] find /var/lib/tor -type d -exec chmod 0700 {} +\n' printf '[dry] find /var/lib/tor -type f -exec chmod 0600 {} +\n' else if [[ -d /var/lib/tor ]]; then chown -R debian-tor:debian-tor /var/lib/tor 2>/dev/null || true find /var/lib/tor -type d -exec chmod 0700 {} + 2>/dev/null || true find /var/lib/tor -type f -exec chmod 0600 {} + 2>/dev/null || true fi fi report "${SCRIPT_NAME}" "tor" "var-lib-tor-metadata" "restore" "changed" \ "normalized /var/lib/tor ownership=debian-tor:debian-tor dirs=0700 files=0600" "" else report "${SCRIPT_NAME}" "tor" "var-lib-tor" "restore" "skipped" "operator skipped" "" fi else report "${SCRIPT_NAME}" "tor" "identity" "restore" "skipped" "tor private data not restored in this role" "" fi } restore_i2pd() { local pub_base="${PUBLIC_DIR}/i2pd" local sec_base="${SECRET_DIR}/i2pd" if ! prompt_yes_no "Restore category 'i2pd'?" no; then report "${SCRIPT_NAME}" "i2pd" "category" "restore" "skipped" "operator skipped category" "" return 0 fi if prompt_yes_no "Restore i2pd/etc-i2pd -> /etc/i2pd?" yes; then restore_path "${SCRIPT_NAME}" "i2pd" "etc-i2pd" \ "${pub_base}/etc-i2pd" "/etc/i2pd" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown -R root:root /etc/i2pd\n' printf '[dry] find /etc/i2pd -type d -exec chmod 0755 {} +\n' printf '[dry] find /etc/i2pd -type f -exec chmod 0644 {} +\n' else if [[ -d /etc/i2pd ]]; then chown -R root:root /etc/i2pd 2>/dev/null || true find /etc/i2pd -type d -exec chmod 0755 {} + 2>/dev/null || true find /etc/i2pd -type f -exec chmod 0644 {} + 2>/dev/null || true fi fi report "${SCRIPT_NAME}" "i2pd" "etc-i2pd-metadata" "restore" "changed" \ "normalized /etc/i2pd ownership=root:root dirs=0755 files=0644" "" else report "${SCRIPT_NAME}" "i2pd" "etc-i2pd" "restore" "skipped" "operator skipped" "" fi if [[ "${ROLE}" == "replacement" && -d "${sec_base}/var-lib-i2pd" ]]; then if prompt_yes_no "Restore i2pd/var-lib-i2pd -> /var/lib/i2pd?" no; then restore_path "${SCRIPT_NAME}" "i2pd" "var-lib-i2pd" \ "${sec_base}/var-lib-i2pd" "/var/lib/i2pd" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown -R i2pd:i2pd /var/lib/i2pd\n' printf '[dry] find /var/lib/i2pd -type d -exec chmod 0700 {} +\n' printf '[dry] find /var/lib/i2pd -type f -exec chmod 0600 {} +\n' else if [[ -d /var/lib/i2pd ]]; then chown -R i2pd:i2pd /var/lib/i2pd 2>/dev/null || true find /var/lib/i2pd -type d -exec chmod 0700 {} + 2>/dev/null || true find /var/lib/i2pd -type f -exec chmod 0600 {} + 2>/dev/null || true fi fi report "${SCRIPT_NAME}" "i2pd" "var-lib-i2pd-metadata" "restore" "changed" \ "normalized /var/lib/i2pd ownership=i2pd:i2pd dirs=0700 files=0600" "" else report "${SCRIPT_NAME}" "i2pd" "var-lib-i2pd" "restore" "skipped" "operator skipped" "" fi else report "${SCRIPT_NAME}" "i2pd" "identity" "restore" "skipped" "i2pd private data not restored in this role" "" fi } restore_docker() { local pub_base="${PUBLIC_DIR}/docker" local sec_base="${SECRET_DIR}/docker" if ! prompt_yes_no "Restore category 'docker'?" no; then report "${SCRIPT_NAME}" "docker" "category" "restore" "skipped" "operator skipped category" "" return 0 fi if prompt_yes_no "Restore docker/daemon.json -> /etc/docker/daemon.json?" yes; then restore_path "${SCRIPT_NAME}" "docker" "daemon.json" \ "${pub_base}/daemon.json" "/etc/docker/daemon.json" \ 0644 root root || true else report "${SCRIPT_NAME}" "docker" "daemon.json" "restore" "skipped" "operator skipped" "" fi if [[ -d "${sec_base}/compose-full" ]]; then report "${SCRIPT_NAME}" "docker" "compose-full" "manual" "manual" \ "compose files available in secret DB; restore manually per stack" "" fi } restore_monitoring() { if ! prompt_yes_no "Restore category 'monitoring'?" no; then report "${SCRIPT_NAME}" "monitoring" "category" "restore" "skipped" "operator skipped category" "" return 0 fi if [[ -d "${PUBLIC_DIR}/prometheus/etc-prometheus" ]]; then if prompt_yes_no "Restore monitoring/prometheus -> /etc/prometheus?" yes; then restore_path "${SCRIPT_NAME}" "monitoring" "prometheus" \ "${PUBLIC_DIR}/prometheus/etc-prometheus" "/etc/prometheus" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown -R root:root /etc/prometheus\n' printf '[dry] find /etc/prometheus -type d -exec chmod 0755 {} +\n' printf '[dry] find /etc/prometheus -type f -exec chmod 0644 {} +\n' else [[ -d /etc/prometheus ]] && chown -R root:root /etc/prometheus 2>/dev/null || true [[ -d /etc/prometheus ]] && find /etc/prometheus -type d -exec chmod 0755 {} + 2>/dev/null || true [[ -d /etc/prometheus ]] && find /etc/prometheus -type f -exec chmod 0644 {} + 2>/dev/null || true fi report "${SCRIPT_NAME}" "monitoring" "prometheus-metadata" "restore" "changed" \ "normalized /etc/prometheus ownership=root:root dirs=0755 files=0644" "" else report "${SCRIPT_NAME}" "monitoring" "prometheus" "restore" "skipped" "operator skipped" "" fi fi if [[ -f "${PUBLIC_DIR}/prometheus/node-exporter-defaults" ]]; then if prompt_yes_no "Restore monitoring/prometheus-node-exporter -> /etc/default/prometheus-node-exporter?" yes; then restore_path "${SCRIPT_NAME}" "monitoring" "prometheus-node-exporter" \ "${PUBLIC_DIR}/prometheus/node-exporter-defaults" \ "/etc/default/prometheus-node-exporter" \ 0644 root root || true else report "${SCRIPT_NAME}" "monitoring" "prometheus-node-exporter" "restore" "skipped" "operator skipped" "" fi fi if [[ -d "${PUBLIC_DIR}/loki/etc-loki" ]]; then if prompt_yes_no "Restore monitoring/loki -> /etc/loki?" yes; then restore_path "${SCRIPT_NAME}" "monitoring" "loki" \ "${PUBLIC_DIR}/loki/etc-loki" "/etc/loki" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown -R root:root /etc/loki\n' printf '[dry] find /etc/loki -type d -exec chmod 0755 {} +\n' printf '[dry] find /etc/loki -type f -exec chmod 0644 {} +\n' else [[ -d /etc/loki ]] && chown -R root:root /etc/loki 2>/dev/null || true [[ -d /etc/loki ]] && find /etc/loki -type d -exec chmod 0755 {} + 2>/dev/null || true [[ -d /etc/loki ]] && find /etc/loki -type f -exec chmod 0644 {} + 2>/dev/null || true fi report "${SCRIPT_NAME}" "monitoring" "loki-metadata" "restore" "changed" \ "normalized /etc/loki ownership=root:root dirs=0755 files=0644" "" else report "${SCRIPT_NAME}" "monitoring" "loki" "restore" "skipped" "operator skipped" "" fi fi if [[ -d "${PUBLIC_DIR}/grafana/etc-grafana" ]]; then if prompt_yes_no "Restore monitoring/grafana -> /etc/grafana?" yes; then restore_path "${SCRIPT_NAME}" "monitoring" "grafana" \ "${PUBLIC_DIR}/grafana/etc-grafana" "/etc/grafana" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown -R root:root /etc/grafana\n' printf '[dry] find /etc/grafana -type d -exec chmod 0755 {} +\n' printf '[dry] find /etc/grafana -type f -exec chmod 0644 {} +\n' else [[ -d /etc/grafana ]] && chown -R root:root /etc/grafana 2>/dev/null || true [[ -d /etc/grafana ]] && find /etc/grafana -type d -exec chmod 0755 {} + 2>/dev/null || true [[ -d /etc/grafana ]] && find /etc/grafana -type f -exec chmod 0644 {} + 2>/dev/null || true fi report "${SCRIPT_NAME}" "monitoring" "grafana-metadata" "restore" "changed" \ "normalized /etc/grafana ownership=root:root dirs=0755 files=0644" "" else report "${SCRIPT_NAME}" "monitoring" "grafana" "restore" "skipped" "operator skipped" "" fi fi if [[ -d "${SECRET_DIR}/alloy/etc-alloy" ]]; then if prompt_yes_no "Restore monitoring/alloy -> /etc/alloy?" yes; then restore_path "${SCRIPT_NAME}" "monitoring" "alloy" \ "${SECRET_DIR}/alloy/etc-alloy" "/etc/alloy" || true if [[ ${DRY_RUN} == true ]]; then printf '[dry] chown -R root:root /etc/alloy\n' printf '[dry] find /etc/alloy -type d -exec chmod 0755 {} +\n' printf '[dry] find /etc/alloy -type f -exec chmod 0644 {} +\n' else [[ -d /etc/alloy ]] && chown -R root:root /etc/alloy 2>/dev/null || true [[ -d /etc/alloy ]] && find /etc/alloy -type d -exec chmod 0755 {} + 2>/dev/null || true [[ -d /etc/alloy ]] && find /etc/alloy -type f -exec chmod 0644 {} + 2>/dev/null || true fi report "${SCRIPT_NAME}" "monitoring" "alloy-metadata" "restore" "changed" \ "normalized /etc/alloy ownership=root:root dirs=0755 files=0644" "" else report "${SCRIPT_NAME}" "monitoring" "alloy" "restore" "skipped" "operator skipped" "" fi fi } for category in "${CATEGORIES[@]}"; do log "processing category: ${category}" case "${category}" in system-basics) restore_system_basics ;; users) restore_users ;; ssh) restore_ssh ;; network) restore_network ;; dns) restore_dns ;; firewall) restore_firewall ;; nginx) restore_nginx ;; mariadb) restore_mariadb ;; postfix) restore_postfix ;; prosody) restore_prosody ;; tor) restore_tor ;; i2pd) restore_i2pd ;; docker) restore_docker ;; monitoring) restore_monitoring ;; *) note_failure "${SCRIPT_NAME}" "category" "${category}" "restore" "unknown category" ;; esac done set_state restore_configs done report "${SCRIPT_NAME}" "run" "finish" "exit" "ok" "completed" "" log "${SCRIPT_NAME}: done; report=${REPORT_FILE}"