init: first commit
This commit is contained in:
210
backup_pg.sh
Executable file
210
backup_pg.sh
Executable file
@@ -0,0 +1,210 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Configuration
|
||||||
|
#######################################
|
||||||
|
DBS=("sirh" "inventory" "ferme")
|
||||||
|
|
||||||
|
PGHOST="localhost"
|
||||||
|
PGPORT="5432"
|
||||||
|
PGUSER="backup_liot"
|
||||||
|
PGPASSWORD="backup_liot"
|
||||||
|
|
||||||
|
IA_SSH="malio-b@192.168.0.179"
|
||||||
|
IA_BASE_DIR="/home/malio-b/backups"
|
||||||
|
|
||||||
|
SSH_KEY="/home/malio/.ssh/id_ed25519_backup"
|
||||||
|
SSH_OPTS=(-i "$SSH_KEY" -o IdentitiesOnly=yes -o BatchMode=yes -o ConnectTimeout=10)
|
||||||
|
|
||||||
|
LOG_DIR="/var/log/pg_backup"
|
||||||
|
mkdir -p "$LOG_DIR"
|
||||||
|
|
||||||
|
TS="$(date +'%Y-%m-%d_%H-%M-%S')"
|
||||||
|
BACKUP_DIR_NAME="backup_${TS}"
|
||||||
|
LOG_FILE="${LOG_DIR}/${BACKUP_DIR_NAME}.log"
|
||||||
|
|
||||||
|
TMP_DIR="/tmp/pg_dump_${BACKUP_DIR_NAME}"
|
||||||
|
mkdir -p "$TMP_DIR"
|
||||||
|
|
||||||
|
exec > >(tee -a "$LOG_FILE") 2>&1
|
||||||
|
log() { echo "---- $(date +'%Y-%m-%d %H:%M:%S') ---- $*"; }
|
||||||
|
|
||||||
|
export PGPASSWORD
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Discord (Webhook)
|
||||||
|
#######################################
|
||||||
|
DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/1478503102888935506/YCtJM09QZiKNMiCe5u7vCQb52VcLjHAd9wwEsKNltlJVcy7sKvoMTOJkvEKOOrk-Wpkh"
|
||||||
|
|
||||||
|
discord_ping() {
|
||||||
|
local details="${1:-}"
|
||||||
|
|
||||||
|
[[ -z "${DISCORD_WEBHOOK_URL:-}" ]] && return 0
|
||||||
|
|
||||||
|
local color dumps_display users_display
|
||||||
|
if [[ -n "${DUMPS_OK:-}" && -n "${USERS_OK:-}" ]]; then
|
||||||
|
color="🟢"
|
||||||
|
else
|
||||||
|
color="🔴"
|
||||||
|
fi
|
||||||
|
|
||||||
|
dumps_display=$([[ -n "${DUMPS_OK:-}" ]] && echo "✅" || echo "❌")
|
||||||
|
users_display=$([[ -n "${USERS_OK:-}" ]] && echo "✅" || echo "❌")
|
||||||
|
|
||||||
|
local msg="**@here BACKUP BDD RECETTE ${color}**\n"
|
||||||
|
msg+="Name: ${BACKUP_DIR_NAME}\n"
|
||||||
|
msg+="Dumps transfer: ${dumps_display}\n"
|
||||||
|
msg+="Users transfer: ${users_display}\n"
|
||||||
|
[[ -n "$details" ]] && msg+="Details: $details"
|
||||||
|
|
||||||
|
curl -fsS -H "Content-Type: application/json" \
|
||||||
|
-d "{\"content\":\"$msg\"}" \
|
||||||
|
"$DISCORD_WEBHOOK_URL" >/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Statuts init
|
||||||
|
#######################################
|
||||||
|
DUMPS_OK=true
|
||||||
|
USERS_OK=true
|
||||||
|
DUMP_ERRORS=""
|
||||||
|
USER_ERRORS=""
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Lock (évite 2 backups en même temps)
|
||||||
|
#######################################
|
||||||
|
LOCK_DIR="/tmp/pg_multi_dump_stream.lock.d"
|
||||||
|
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
|
||||||
|
log "ERROR: Backup déjà en cours (lock: $LOCK_DIR)"
|
||||||
|
DUMPS_OK=
|
||||||
|
USERS_OK=
|
||||||
|
discord_ping "Lock exists: $LOCK_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
trap 'rm -rf "$LOCK_DIR"' EXIT
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Remote dir
|
||||||
|
#######################################
|
||||||
|
REMOTE_DIR="${IA_BASE_DIR}/${BACKUP_DIR_NAME}"
|
||||||
|
|
||||||
|
log "Starting backup process"
|
||||||
|
log "Remote directory: ${REMOTE_DIR}"
|
||||||
|
|
||||||
|
log "Creating remote directory"
|
||||||
|
if ! ssh "${SSH_OPTS[@]}" "$IA_SSH" "mkdir -p '${REMOTE_DIR}'"; then
|
||||||
|
log "ERROR: Création dossier distant impossible: ${REMOTE_DIR}"
|
||||||
|
DUMPS_OK=
|
||||||
|
USERS_OK=
|
||||||
|
discord_ping "Remote mkdir KO: ${REMOTE_DIR}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Export PostgreSQL roles (no passwords)
|
||||||
|
#######################################
|
||||||
|
ROLES_FILE="${TMP_DIR}/roles_${TS}.sql"
|
||||||
|
log "Exporting PostgreSQL roles"
|
||||||
|
|
||||||
|
set +e
|
||||||
|
psql -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" -d postgres -Atq <<'SQL' > "$ROLES_FILE"
|
||||||
|
SELECT
|
||||||
|
format(
|
||||||
|
'DO $$ BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = %L) THEN
|
||||||
|
CREATE ROLE %I;
|
||||||
|
END IF;
|
||||||
|
END $$;',
|
||||||
|
rolname, rolname
|
||||||
|
)
|
||||||
|
FROM pg_roles
|
||||||
|
WHERE rolname !~ '^pg_'
|
||||||
|
ORDER BY rolname;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
format(
|
||||||
|
'ALTER ROLE %I WITH %s%s%s%s%s%s%s%s;',
|
||||||
|
rolname,
|
||||||
|
CASE WHEN rolsuper THEN 'SUPERUSER ' ELSE 'NOSUPERUSER ' END,
|
||||||
|
CASE WHEN rolinherit THEN 'INHERIT ' ELSE 'NOINHERIT ' END,
|
||||||
|
CASE WHEN rolcreaterole THEN 'CREATEROLE ' ELSE 'NOCREATEROLE ' END,
|
||||||
|
CASE WHEN rolcreatedb THEN 'CREATEDB ' ELSE 'NOCREATEDB ' END,
|
||||||
|
CASE WHEN rolcanlogin THEN 'LOGIN ' ELSE 'NOLOGIN ' END,
|
||||||
|
CASE WHEN rolreplication THEN 'REPLICATION ' ELSE 'NOREPLICATION ' END,
|
||||||
|
CASE WHEN rolbypassrls THEN 'BYPASSRLS ' ELSE 'NOBYPASSRLS ' END,
|
||||||
|
'CONNECTION LIMIT ' || rolconnlimit
|
||||||
|
)
|
||||||
|
FROM pg_roles
|
||||||
|
WHERE rolname !~ '^pg_'
|
||||||
|
ORDER BY rolname;
|
||||||
|
SQL
|
||||||
|
RET=$?
|
||||||
|
if [[ $RET -ne 0 ]]; then
|
||||||
|
USERS_OK=
|
||||||
|
USER_ERRORS+="roles_export "
|
||||||
|
log "ERROR: Users export failed"
|
||||||
|
else
|
||||||
|
log "Roles export completed: $ROLES_FILE"
|
||||||
|
fi
|
||||||
|
set -e
|
||||||
|
|
||||||
|
log "Sending roles file to IA server"
|
||||||
|
set +e
|
||||||
|
scp "${SSH_OPTS[@]}" "$ROLES_FILE" "$IA_SSH:${REMOTE_DIR}/"
|
||||||
|
RET=$?
|
||||||
|
if [[ $RET -ne 0 ]]; then
|
||||||
|
USERS_OK=
|
||||||
|
USER_ERRORS+="roles_scp "
|
||||||
|
log "ERROR: Users transfer failed (roles file)"
|
||||||
|
else
|
||||||
|
log "Roles transfer completed"
|
||||||
|
fi
|
||||||
|
set -e
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Dump des bases + transfert (continue même si KO)
|
||||||
|
#######################################
|
||||||
|
set +e
|
||||||
|
for DB in "${DBS[@]}"; do
|
||||||
|
FILE="${TMP_DIR}/${DB}_${TS}.dump"
|
||||||
|
|
||||||
|
log "Dumping database: $DB"
|
||||||
|
pg_dump -h "$PGHOST" -p "$PGPORT" -U "$PGUSER" -Fc --no-owner --no-acl -d "$DB" -f "$FILE"
|
||||||
|
RET=$?
|
||||||
|
if [[ $RET -ne 0 ]]; then
|
||||||
|
DUMPS_OK=
|
||||||
|
DUMP_ERRORS+="${DB} "
|
||||||
|
log "ERROR: Dump failed for $DB"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
log "Dump completed: $FILE"
|
||||||
|
|
||||||
|
log "Sending dump to IA server"
|
||||||
|
scp "${SSH_OPTS[@]}" "$FILE" "$IA_SSH:${REMOTE_DIR}/"
|
||||||
|
RET=$?
|
||||||
|
if [[ $RET -ne 0 ]]; then
|
||||||
|
DUMPS_OK=
|
||||||
|
DUMP_ERRORS+="${DB}(scp) "
|
||||||
|
log "ERROR: Transfer failed for $DB"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
log "Transfer completed for $DB"
|
||||||
|
done
|
||||||
|
set -e
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Nettoyage
|
||||||
|
#######################################
|
||||||
|
log "Cleaning temporary files"
|
||||||
|
rm -rf "$TMP_DIR"
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Envoi message Discord (final)
|
||||||
|
#######################################
|
||||||
|
DETAILS=""
|
||||||
|
[[ -z "${DUMPS_OK:-}" ]] && DETAILS+="Dumps KO: ${DUMP_ERRORS} "
|
||||||
|
[[ -z "${USERS_OK:-}" ]] && DETAILS+="Users KO: ${USER_ERRORS} "
|
||||||
|
discord_ping "$DETAILS"
|
||||||
|
|
||||||
|
log "Backup finished"
|
||||||
147
check_statut_recette.sh
Executable file
147
check_statut_recette.sh
Executable file
@@ -0,0 +1,147 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -u
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Sites à vérifier
|
||||||
|
#######################################
|
||||||
|
SITES=(
|
||||||
|
"ferme.malio-dev.fr"
|
||||||
|
"sirh.malio-dev.fr"
|
||||||
|
"inventory.malio-dev.fr"
|
||||||
|
)
|
||||||
|
|
||||||
|
SCHEME="http"
|
||||||
|
CONNECT_TIMEOUT=3
|
||||||
|
MAX_TIME=8
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Logs
|
||||||
|
#######################################
|
||||||
|
LOG_DIR="/var/log/app_health"
|
||||||
|
mkdir -p "$LOG_DIR"
|
||||||
|
LOG_FILE="${LOG_DIR}/app_health_$(date +'%Y-%m-%d').log"
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Discord
|
||||||
|
#######################################
|
||||||
|
DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/1478379245842600007/tSxi3G6PbCn89pOdeqK34LR7c-GhXfT-lSCPolwBywJXcpa3ihL8rN4QRwsTjF6SS3w0"
|
||||||
|
|
||||||
|
discord_ping() {
|
||||||
|
local site="$1"
|
||||||
|
local status="$2"
|
||||||
|
local detail="$3"
|
||||||
|
|
||||||
|
[[ -z "${DISCORD_WEBHOOK_URL:-}" ]] && return 0
|
||||||
|
|
||||||
|
local color icon
|
||||||
|
|
||||||
|
if [[ "$status" == "OK" ]]; then
|
||||||
|
color="🟢"
|
||||||
|
icon="✅"
|
||||||
|
else
|
||||||
|
color="🔴"
|
||||||
|
icon="❌"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local msg="**CHECK APP RECETTE $color**\n"
|
||||||
|
msg+="Application: ${site}\n"
|
||||||
|
msg+="Status: ${icon}\n"
|
||||||
|
msg+="Details: ${detail}"
|
||||||
|
|
||||||
|
curl -fsS -H "Content-Type: application/json" \
|
||||||
|
-d "{\"content\":\"$msg\"}" \
|
||||||
|
"$DISCORD_WEBHOOK_URL" >/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Logging
|
||||||
|
#######################################
|
||||||
|
log_line() {
|
||||||
|
# 2026-03-04 14:12:33 | LEVEL | site | message
|
||||||
|
printf "%s | %s | %s | %s\n" \
|
||||||
|
"$(date +'%Y-%m-%d %H:%M:%S')" "$1" "$2" "$3" | tee -a "$LOG_FILE"
|
||||||
|
|
||||||
|
# Envoi Discord par application
|
||||||
|
discord_ping "$2" "$1" "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# DNS
|
||||||
|
#######################################
|
||||||
|
dns_ok() {
|
||||||
|
getent hosts "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Check application
|
||||||
|
#######################################
|
||||||
|
check_site() {
|
||||||
|
|
||||||
|
local host="$1"
|
||||||
|
local url="${SCHEME}://${host}/"
|
||||||
|
|
||||||
|
if ! dns_ok "$host"; then
|
||||||
|
log_line "DOWN" "$host" "Résolution impossible (getent hosts)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local http_code curl_exit stderr
|
||||||
|
|
||||||
|
stderr="$(mktemp)"
|
||||||
|
|
||||||
|
http_code="$(
|
||||||
|
curl -sS -o /dev/null \
|
||||||
|
-w '%{http_code}' \
|
||||||
|
--connect-timeout "$CONNECT_TIMEOUT" \
|
||||||
|
--max-time "$MAX_TIME" \
|
||||||
|
"$url" 2>"$stderr"
|
||||||
|
)"
|
||||||
|
|
||||||
|
curl_exit=$?
|
||||||
|
|
||||||
|
if [ $curl_exit -ne 0 ]; then
|
||||||
|
local err
|
||||||
|
err="$(head -n 1 "$stderr" | tr -d '\r')"
|
||||||
|
rm -f "$stderr"
|
||||||
|
|
||||||
|
log_line "DOWN" "$host" "curl exit=$curl_exit : ${err:-"(aucun)"}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$stderr"
|
||||||
|
|
||||||
|
if [[ "$http_code" =~ ^[0-9]{3}$ ]]; then
|
||||||
|
if [ "$http_code" -ge 200 ] && [ "$http_code" -le 399 ]; then
|
||||||
|
log_line "OK" "$host" "HTTP $http_code"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_line "DOWN" "$host" "HTTP $http_code (erreur appli)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_line "DOWN" "$host" "Code HTTP inattendu: $http_code"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Main
|
||||||
|
#######################################
|
||||||
|
main() {
|
||||||
|
|
||||||
|
local failures=0
|
||||||
|
|
||||||
|
for site in "${SITES[@]}"; do
|
||||||
|
if ! check_site "$site"; then
|
||||||
|
failures=$((failures + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$failures" -gt 0 ]; then
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user