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