#!/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-stalwart" ] && source "${SCRIPT_DIR}/env-stalwart" [ -f "${SCRIPT_DIR}/credentials.env" ] && source "${SCRIPT_DIR}/credentials.env" set +a STALWART_NAMESPACE="${STALWART_NAMESPACE:-mail}" STALWART_IMAGE="${STALWART_IMAGE:-stalwartlabs/mail-server:v0.11.6}" STALWART_NODE="${STALWART_NODE:-}" STALWART_LB_IPAM_IP="${STALWART_LB_IPAM_IP:-}" STALWART_STORAGE_CLASS="${STALWART_STORAGE_CLASS:-hcloud-volumes}" STALWART_STORAGE_SIZE="${STALWART_STORAGE_SIZE:-20Gi}" STALWART_HOSTNAME="${STALWART_HOSTNAME:-}" STALWART_DOMAIN="${STALWART_DOMAIN:-}" STALWART_TLS_SECRET="${STALWART_TLS_SECRET:-stalwart-tls}" STALWART_SMTP_PORT="${STALWART_SMTP_PORT:-25}" STALWART_SUBMISSION_PORT="${STALWART_SUBMISSION_PORT:-587}" STALWART_SMTPS_PORT="${STALWART_SMTPS_PORT:-465}" STALWART_IMAPS_PORT="${STALWART_IMAPS_PORT:-993}" STALWART_HTTP_PORT="${STALWART_HTTP_PORT:-8080}" STALWART_DATA_DIR="${STALWART_DATA_DIR:-/var/lib/stalwart}" RELAY_HOST="${RELAY_HOST:-}" RELAY_PORT="${RELAY_PORT:-587}" KUBECONFIG="${KUBECONFIG:-/etc/kubernetes/admin.conf}" export KUBECONFIG STALWART_NAMESPACE STALWART_IMAGE STALWART_NODE STALWART_LB_IPAM_IP \ STALWART_STORAGE_CLASS STALWART_STORAGE_SIZE STALWART_HOSTNAME STALWART_DOMAIN \ STALWART_TLS_SECRET STALWART_SMTP_PORT STALWART_SUBMISSION_PORT STALWART_SMTPS_PORT \ STALWART_IMAPS_PORT STALWART_HTTP_PORT STALWART_DATA_DIR \ RELAY_HOST RELAY_PORT SCRIPT_DIR source "${SCRIPT_DIR}/stalwart-lib.sh" CMD_TSK="${CMD_TSK:-${1:-install}}" _do_install() { _require_env STALWART_HOSTNAME _require_env STALWART_DOMAIN _require_env STALWART_NODE _require_env STALWART_LB_IPAM_IP _require_env RELAY_HOST bash "${SCRIPT_DIR}/run-init.sh" echo "Stalwart installed — Admin UI: kubectl port-forward -n $STALWART_NAMESPACE svc/stalwart-admin $STALWART_HTTP_PORT:$STALWART_HTTP_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}/stalwart_${timestamp}" mkdir -p "$backup_dir" _kubectl exec --namespace "$STALWART_NAMESPACE" "$pod" -- \ stalwart-mail export --config "${STALWART_DATA_DIR}/data" \ --format=tar > "$backup_dir/data.tar" 2>/dev/null || \ _kubectl exec --namespace "$STALWART_NAMESPACE" "$pod" -- \ tar czf - -C "$STALWART_DATA_DIR" data > "$backup_dir/rocksdb.tar.gz" echo "Backup written to $backup_dir" } _do_restore() { _require_env BACKUP_FILE local pod pod=$(_pod_name) if [[ "$BACKUP_FILE" == *.tar.gz ]]; then _kubectl exec --stdin --namespace "$STALWART_NAMESPACE" "$pod" -- \ tar xzf - -C "$STALWART_DATA_DIR" < "$BACKUP_FILE" else _kubectl exec --stdin --namespace "$STALWART_NAMESPACE" "$pod" -- \ tar xf - -C "$STALWART_DATA_DIR" < "$BACKUP_FILE" fi _kubectl rollout restart deployment/stalwart --namespace "$STALWART_NAMESPACE" echo "Restore completed from $BACKUP_FILE" } _do_health() { local pod pod=$(_pod_name 2>/dev/null || true) [ -n "$pod" ] || { echo "UNHEALTHY: no stalwart pod in $STALWART_NAMESPACE" >&2; exit 1; } if _kubectl exec --namespace "$STALWART_NAMESPACE" "$pod" -- \ sh -c "echo QUIT | nc -w 2 127.0.0.1 ${STALWART_SMTP_PORT}" >/dev/null 2>&1; then echo "HEALTHY: SMTP port ${STALWART_SMTP_PORT} responding" else echo "UNHEALTHY: SMTP port ${STALWART_SMTP_PORT} not responding" >&2; exit 1 fi } _do_config() { _kubectl exec --namespace "$STALWART_NAMESPACE" "$(_pod_name)" -- \ cat /etc/stalwart/config.toml } 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