#!/bin/bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" # shellcheck source=/dev/null set -a [ -f "${SCRIPT_DIR}/env-docker_mailserver" ] && source "${SCRIPT_DIR}/env-docker_mailserver" # _credentials.env is NOT auto-sourced — methods source it explicitly when needed set +a DMS_NAMESPACE="${DMS_NAMESPACE:-mail}" DMS_IMAGE="${DMS_IMAGE:-ghcr.io/docker-mailserver/docker-mailserver:14.0}" DMS_GUI_IMAGE="${DMS_GUI_IMAGE:-audioscavenger/dms-gui:v1.5.7}" DMS_NODE="${DMS_NODE:-}" DMS_LB_IPAM_IP="${DMS_LB_IPAM_IP:-}" DMS_STORAGE_CLASS="${DMS_STORAGE_CLASS:-hcloud-volumes}" DMS_MAIL_DATA_SIZE="${DMS_MAIL_DATA_SIZE:-20Gi}" DMS_HOSTNAME="${DMS_HOSTNAME:-}" DMS_DOMAIN="${DMS_DOMAIN:-}" DMS_TLS_SECRET="${DMS_TLS_SECRET:-docker-mailserver-tls}" # Cloudflare DNS-01 token for cert-manager — required when zot.cert is declared. # Created as Secret in cert-manager namespace, referenced by ClusterIssuer dns01 solver. DMS_CF_DNS_TOKEN="${DMS_CF_DNS_TOKEN:-}" DMS_CF_DNS_SECRET_NAME="${DMS_CF_DNS_SECRET_NAME:-dns-cloudflare}" DMS_SMTP_PORT="${DMS_SMTP_PORT:-25}" DMS_IMAP_PORT="${DMS_IMAP_PORT:-143}" DMS_SMTPS_PORT="${DMS_SMTPS_PORT:-465}" DMS_SUBMISSION_PORT="${DMS_SUBMISSION_PORT:-587}" DMS_IMAPS_PORT="${DMS_IMAPS_PORT:-993}" DMS_GUI_PORT="${DMS_GUI_PORT:-80}" RELAY_HOST="${RELAY_HOST:-}" RELAY_PORT="${RELAY_PORT:-587}" KUBECONFIG="${KUBECONFIG:-/etc/kubernetes/admin.conf}" export KUBECONFIG DMS_NAMESPACE DMS_IMAGE DMS_GUI_IMAGE DMS_NODE DMS_LB_IPAM_IP \ DMS_STORAGE_CLASS DMS_MAIL_DATA_SIZE \ DMS_HOSTNAME DMS_DOMAIN DMS_TLS_SECRET \ DMS_CF_DNS_TOKEN DMS_CF_DNS_SECRET_NAME \ DMS_SMTP_PORT DMS_IMAP_PORT DMS_SMTPS_PORT DMS_SUBMISSION_PORT DMS_IMAPS_PORT DMS_GUI_PORT \ RELAY_HOST RELAY_PORT SCRIPT_DIR source "${SCRIPT_DIR}/docker_mailserver-lib.sh" CMD_TSK="${CMD_TSK:-${1:-install}}" _do_install() { _require_env DMS_HOSTNAME _require_env DMS_DOMAIN _require_env DMS_NODE _require_env DMS_LB_IPAM_IP _require_env RELAY_HOST bash "${SCRIPT_DIR}/run-init.sh" echo "docker-mailserver installed" echo " Admin UI: kubectl port-forward -n $DMS_NAMESPACE svc/docker-mailserver-gui $DMS_GUI_PORT:$DMS_GUI_PORT" } _do_backup() { _require_env BACKUP_DIR local pod timestamp backup_dir pod=$(_pod_name) timestamp=$(date +%Y%m%d_%H%M%S) backup_dir="${BACKUP_DIR}/docker-mailserver_${timestamp}" mkdir -p "$backup_dir" _kubectl exec --namespace "$DMS_NAMESPACE" "$pod" \ --container docker-mailserver -- \ tar czf - /var/mail /var/mail-state /tmp/docker-mailserver > "$backup_dir/mail.tar.gz" echo "Backup written to $backup_dir/mail.tar.gz" } _do_restore() { _require_env BACKUP_FILE local pod pod=$(_pod_name) _kubectl exec --stdin --namespace "$DMS_NAMESPACE" "$pod" \ --container docker-mailserver -- \ tar xzf - -C / < "$BACKUP_FILE" _kubectl rollout restart deployment/docker-mailserver --namespace "$DMS_NAMESPACE" echo "Restore completed from $BACKUP_FILE" } _do_health() { local pod pod=$(_pod_name 2>/dev/null || true) [ -n "$pod" ] || { echo "UNHEALTHY: no docker-mailserver pod in $DMS_NAMESPACE" >&2; exit 1; } if echo QUIT | nc -w 5 "$DMS_LB_IPAM_IP" "${DMS_SMTP_PORT}" 2>/dev/null | grep -q "^220"; then echo "HEALTHY: SMTP port ${DMS_SMTP_PORT} responding" else echo "UNHEALTHY: SMTP port ${DMS_SMTP_PORT} not responding" >&2; exit 1 fi } _do_config() { _kubectl exec --namespace "$DMS_NAMESPACE" "$(_pod_name)" \ --container docker-mailserver -- \ cat /tmp/docker-mailserver/postfix-accounts.cf 2>/dev/null || echo "(no accounts configured)" } case "$CMD_TSK" in install|create) _do_install ;; update) bash "${SCRIPT_DIR}/run-update.sh" ;; delete|destroy) bash "${SCRIPT_DIR}/run-delete.sh" ;; restart) bash "${SCRIPT_DIR}/run-restart.sh" ;; backup) _do_backup ;; restore) _do_restore ;; health|status) _do_health ;; config) _do_config ;; *) echo "Unknown operation: $CMD_TSK" >&2; exit 1 ;; esac