diff --git a/script/database-backup/.env.example b/script/database-backup/.env.example index 72b6168..5d0ca2e 100644 --- a/script/database-backup/.env.example +++ b/script/database-backup/.env.example @@ -1,8 +1,8 @@ -DATABASE_HOST=10.0.10.80 +DATABASE_HOST=127.0.0.1 DATABASE_PORT=5432 DATABASE_USER=postgres DATABASE_PASSWORD=masterkey -DATABASE_NAME=herbario_prod +DATABASE_NAME=herbario_dev # Google Drive (Dados reais que você gerou) GDRIVE_TOKEN={"access_token":"SEU_ACCESS_TOKEN_AQUI","token_type":"Bearer","refresh_token":"SEU_REFRESH_TOKEN_AQUI","expiry":"2026-01-01T00:00:00Z"} @@ -14,3 +14,15 @@ RETENTION_DAILY=5 RETENTION_WEEKLY=4 CRON_SCHEDULE="0 2 * * *" TZ=America/Sao_Paulo + +# SMTP (notificação de falha do backup) +SMTP_HOST=smtp.gmail.com +SMTP_PORT=587 +SMTP_USER="seu-email@gmail.com" +SMTP_PASS="sua-senha-de-app-de-16-digitos" +SMTP_FROM="Sistema HCF " + +# Destinatários do alerta (1 ou mais, separados por vírgula) +NOTIFY_EMAIL_TO=ops@exemplo.com,curadoria@exemplo.com +# Desliga notificação sem remover config (default: true) +NOTIFY_EMAIL_ENABLED=true diff --git a/script/database-backup/Dockerfile b/script/database-backup/Dockerfile index d36c3d9..3c266da 100644 --- a/script/database-backup/Dockerfile +++ b/script/database-backup/Dockerfile @@ -9,7 +9,8 @@ RUN \ curl \ ca-certificates \ rclone \ - gzip && \ + gzip \ + msmtp && \ curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/postgresql.gpg && \ echo "deb [signed-by=/usr/share/keyrings/postgresql.gpg] https://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \ apt-get update && \ @@ -17,7 +18,6 @@ RUN \ postgresql-client-18 && \ apt-get remove -y \ curl \ - ca-certificates \ gnupg && \ rm -rf /var/lib/apt/lists/* diff --git a/script/database-backup/README.md b/script/database-backup/README.md index 6794a98..2d1e0f8 100644 --- a/script/database-backup/README.md +++ b/script/database-backup/README.md @@ -10,7 +10,7 @@ Arquitetura: Fluxo: -`cron -> backup.sh -> pg_dump -Fp -> gzip -> rclone copy -> retenção` +`cron -> backup.sh -> pg_dump -Fp -> gzip -> rclone copy -> retenção (-> notificação por e-mail em caso de falha)` ## Formato do backup @@ -37,6 +37,23 @@ Veja `.env.example` para o contrato completo. - `RETENTION_WEEKLY` (default: `4`) - `CRON_SCHEDULE` (ex.: `0 2 * * *`) - `TZ` (ex.: `America/Sao_Paulo`) +- `SMTP_HOST` +- `SMTP_PORT` +- `SMTP_USER` +- `SMTP_PASS` +- `SMTP_FROM` +- `NOTIFY_EMAIL_TO` (1 ou mais e-mails separados por vírgula) +- `NOTIFY_EMAIL_ENABLED` (default: `true`) + +## Notificação de falha + +O container instala e configura o cliente `msmtp` (via `/etc/msmtprc`, gerado no `entrypoint.sh` a partir das variáveis `SMTP_*`). + +- O `backup.sh` captura toda a sua saída em um log temporário e usa um `trap ERR` para detectar qualquer falha (`pg_dump`, `rclone`, retenção, etc.). +- Em caso de falha, um e-mail é enviado via `msmtp` para todos os endereços listados em `NOTIFY_EMAIL_TO` (separados por vírgula), com assunto, horário (`TZ`) e as últimas linhas do log. +- Em caso de sucesso, nenhum e-mail é enviado. +- `NOTIFY_EMAIL_ENABLED=false` desliga a notificação sem precisar remover as demais variáveis. +- Se o próprio envio do e-mail falhar (SMTP fora do ar, credenciais inválidas etc.), isso é apenas logado — o script continua terminando com o código de saída original da falha do backup (a notificação nunca mascara o erro real). ## Política de retenção diff --git a/script/database-backup/backup.sh b/script/database-backup/backup.sh index 0d2b0c5..2451937 100644 --- a/script/database-backup/backup.sh +++ b/script/database-backup/backup.sh @@ -2,6 +2,55 @@ set -euo pipefail +LOG_FILE=$(mktemp) +exec > >(tee -a "${LOG_FILE}") 2>&1 + +notify_failure() { + local exit_code=$1 + local line_no=$2 + + if [ "${NOTIFY_EMAIL_ENABLED:-true}" != "true" ]; then + return 0 + fi + + if [ -z "${NOTIFY_EMAIL_TO:-}" ]; then + echo "NOTIFY_EMAIL_TO não configurado, pulando notificação por e-mail" >&2 + return 0 + fi + + IFS=',' read -ra RAW_RECIPIENTS <<< "${NOTIFY_EMAIL_TO}" + local recipients=() + for r in "${RAW_RECIPIENTS[@]}"; do + r="$(echo -n "$r" | xargs)" + [ -n "$r" ] && recipients+=("$r") + done + + if [ "${#recipients[@]}" -eq 0 ]; then + echo "Nenhum destinatário válido em NOTIFY_EMAIL_TO" >&2 + return 0 + fi + + local subject="[FALHA] Backup do banco ${DATABASE_NAME} - $(date '+%Y-%m-%d %H:%M:%S') (${TZ:-UTC})" + + { + echo "Subject: ${subject}" + echo "From: ${SMTP_FROM}" + echo "To: $(IFS=,; echo "${recipients[*]}")" + echo "Content-Type: text/plain; charset=UTF-8" + echo + echo "Falha no backup do banco: ${DATABASE_NAME}" + echo "Horário da tentativa: $(date '+%Y-%m-%d %H:%M:%S') (${TZ:-UTC})" + echo "Código de saída: ${exit_code} (linha ${line_no})" + echo + echo "Últimas linhas do log:" + tail -n 50 "${LOG_FILE}" 2>/dev/null || echo "(log indisponível)" + } | msmtp "${recipients[@]}" || echo "Falha ao enviar e-mail de notificação via msmtp" >&2 + + return 0 +} + +trap 'notify_failure $? $LINENO' ERR + TIMESTAMP=$(date +%s) FILE_NAME="${DATABASE_NAME}_${TIMESTAMP}.sql.gz" TMP_FILE="/tmp/${FILE_NAME}" diff --git a/script/database-backup/docker-compose.yml b/script/database-backup/docker-compose.yml index a04f164..05a4988 100644 --- a/script/database-backup/docker-compose.yml +++ b/script/database-backup/docker-compose.yml @@ -3,6 +3,8 @@ services: image: database-backup:local container_name: database-backup build: . + extra_hosts: + - "host.docker.internal:host-gateway" environment: # PostgreSQL DATABASE_HOST: "${DATABASE_HOST}" @@ -20,3 +22,12 @@ services: CRON_SCHEDULE: "${CRON_SCHEDULE}" TZ: "${TZ}" + + # SMTP / Notificações + SMTP_HOST: "${SMTP_HOST}" + SMTP_PORT: "${SMTP_PORT}" + SMTP_USER: "${SMTP_USER}" + SMTP_PASS: "${SMTP_PASS}" + SMTP_FROM: "${SMTP_FROM}" + NOTIFY_EMAIL_TO: "${NOTIFY_EMAIL_TO}" + NOTIFY_EMAIL_ENABLED: "${NOTIFY_EMAIL_ENABLED}" diff --git a/script/database-backup/entrypoint.sh b/script/database-backup/entrypoint.sh index ad6176c..3777e92 100644 --- a/script/database-backup/entrypoint.sh +++ b/script/database-backup/entrypoint.sh @@ -10,9 +10,26 @@ token = ${GDRIVE_TOKEN} root_folder_id = ${GDRIVE_FOLDER_ID} EOF +echo "Configurando msmtp..." +cat < /etc/msmtprc +defaults +auth on +tls on +tls_trust_file /etc/ssl/certs/ca-certificates.crt +logfile /var/log/msmtp.log + +account default +host ${SMTP_HOST} +port ${SMTP_PORT} +from ${SMTP_USER} +user ${SMTP_USER} +password ${SMTP_PASS} +EOF +chmod 600 /etc/msmtprc + echo "Configuring cron job with schedule: $CRON_SCHEDULE ($TZ)" -printenv | grep -E "^(DATABASE_|GDRIVE_|RETENTION_|CRON_SCHEDULE|TZ)" >> /etc/environment +printenv | grep -E "^(DATABASE_|GDRIVE_|RETENTION_|CRON_SCHEDULE|TZ|SMTP_|NOTIFY_)" >> /etc/environment echo "$CRON_SCHEDULE /backup.sh 1> /proc/1/fd/1 2> /proc/1/fd/2" | crontab -