#!/bin/bash set -euo pipefail # ============================== # Конфигурация через переменные окружения # ============================== TARGET_DIR="${TARGET_DIR:-/opt/appdata/pihole/etc/dnsmasq.d}" IPSET_CONF="${IPSET_CONF:-/tmp/91-ipset-bbrkn.conf}" RESOLVE_CONF="${RESOLVE_CONF:-/tmp/92-resolve-bbrkn.conf}" DOCKER_CONTAINER="${DOCKER_CONTAINER:-pihole}" # Адрес, на котором слушает Pi-hole DNS (для health check) DNS_LISTEN_ADDR="${DNS_LISTEN_ADDR:-127.0.0.1}" # Домен для проверки DNS после рестарта DNS_CHECK_DOMAIN="${DNS_CHECK_DOMAIN:-google.com}" # Имена назначения (без basename — используем параметрическую подстановку) ipset_name="${IPSET_CONF##*/}" resolve_name="${RESOLVE_CONF##*/}" ipset_dest="$TARGET_DIR/$ipset_name" resolve_dest="$TARGET_DIR/$resolve_name" # Пути к бэкапам (заполняются ниже, нужны для rollback) IPSET_BACKUP="" RESOLVE_BACKUP="" echo "Deploying configuration files to $TARGET_DIR" # ============================== # Проверка входных файлов # ============================== if [ ! -f "$IPSET_CONF" ] || [ ! -f "$RESOLVE_CONF" ]; then echo "Error: one or both config files not found!" exit 1 fi # ============================== # Функция отката: восстанавливает бэкапы и перезапускает контейнер # ============================== rollback() { echo "[ROLLBACK] Restoring previous configuration..." local restored=false if [ -n "$IPSET_BACKUP" ] && [ -f "$IPSET_BACKUP" ]; then cp "$IPSET_BACKUP" "$ipset_dest" echo "[ROLLBACK] Restored $ipset_dest" restored=true fi if [ -n "$RESOLVE_BACKUP" ] && [ -f "$RESOLVE_BACKUP" ]; then cp "$RESOLVE_BACKUP" "$resolve_dest" echo "[ROLLBACK] Restored $resolve_dest" restored=true fi if $restored; then echo "[ROLLBACK] Restarting $DOCKER_CONTAINER with previous config..." docker restart "$DOCKER_CONTAINER" 2>/dev/null || true else echo "[ROLLBACK] No backups found, cannot restore" fi echo "[ROLLBACK] Done" } # ============================== # Бэкап существующих файлов # ============================== ts=$(date +%Y%m%d-%H%M%S) if [ -f "$ipset_dest" ]; then IPSET_BACKUP="${ipset_dest}.backup.${ts}" cp "$ipset_dest" "$IPSET_BACKUP" echo "Backed up $ipset_dest → $IPSET_BACKUP" fi if [ -f "$resolve_dest" ]; then RESOLVE_BACKUP="${resolve_dest}.backup.${ts}" cp "$resolve_dest" "$RESOLVE_BACKUP" echo "Backed up $resolve_dest → $RESOLVE_BACKUP" fi # ============================== # Копирование новых файлов # ============================== cp "$IPSET_CONF" "$TARGET_DIR/" cp "$RESOLVE_CONF" "$TARGET_DIR/" # ============================== # Перезапуск контейнера # ============================== echo "Restarting $DOCKER_CONTAINER container..." docker restart "$DOCKER_CONTAINER" # Ждём запуска — polling через docker inspect вместо sleep + docker ps echo "Waiting for $DOCKER_CONTAINER to be ready (up to 30s)..." ready=false for i in $(seq 1 30); do status=$(docker inspect "$DOCKER_CONTAINER" --format '{{.State.Status}}' 2>/dev/null || echo "missing") if [ "$status" = "running" ]; then ready=true break fi sleep 1 done if ! $ready; then echo "Error: $DOCKER_CONTAINER failed to start after 30s (status: $status)" rollback exit 1 fi echo "$DOCKER_CONTAINER is running" # ============================== # DNS health check # ============================== dns_health_check() { if command -v dig >/dev/null 2>&1; then dig +short +time=3 +tries=2 "@$DNS_LISTEN_ADDR" "$DNS_CHECK_DOMAIN" >/dev/null 2>&1 elif command -v nslookup >/dev/null 2>&1; then nslookup "$DNS_CHECK_DOMAIN" "$DNS_LISTEN_ADDR" >/dev/null 2>&1 else echo "Warning: neither 'dig' nor 'nslookup' found, skipping DNS health check" return 0 fi } echo "Running DNS health check ($DNS_CHECK_DOMAIN via $DNS_LISTEN_ADDR, up to 15 attempts)..." dns_ok=false for i in $(seq 1 15); do if dns_health_check; then dns_ok=true echo "DNS health check passed (attempt $i)" break fi echo " attempt $i failed, retrying in 1s..." sleep 1 done if ! $dns_ok; then echo "Error: DNS health check failed after 15 attempts — Pi-hole not responding on $DNS_LISTEN_ADDR" rollback exit 1 fi # ============================== # Очистка IPSET # ============================== echo "Flushing ipset bbrkn..." ipset flush bbrkn echo "Deployment completed successfully" DOMAIN_COUNT=$(grep -c '^ipset=' "$ipset_dest" || echo "0") echo "Applied configuration for $DOMAIN_COUNT domains"