G-1: 메신저 Webhook Relay + _send_to_room 실제 httpx 호출 구현 G-2: POST /api/tasks/bulk SR 대량작업 엔드포인트 (최대 100건) G-3: 라이선스 만료 알림 스케줄러 (매일 09:00 KST) G-4: 체험판 upgrade_banner 필드 + license.py 배너 로직 G-5: core/auto_rca.py + incidents/problem auto-rca 엔드포인트 G-6: core/deploy_impact.py + vibe impact-analysis 엔드포인트 G-7: core/ticket_classifier.py + SR 생성 시 AI 분류 + ai-suggestion API G-8: VulnPatchRecord 모델 + vuln_scan 패치추적 4개 엔드포인트 G-9: core/jira_sync.py + gateway Jira/Confluence 연동 엔드포인트 G-10: core/push_notify.py + routers/push.py + PushSubscription 모델 G-11: approvals 다중승인 (위임/서명/기한초과/마감연장) G-12: alembic.ini + migrations/ + cicd/migrate_to_postgres.sh 하네스: guardia-orchestrator 확장기능 Phase 반영 봇명령어: /sr /status /license /bulk 슬래시 명령어 추가 설치스크립트: setup/ (Ubuntu, CentOS, RHEL, Windows) --test 옵션 포함 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
159 lines
6.9 KiB
Bash
159 lines
6.9 KiB
Bash
#!/bin/bash
|
|
# ============================================================
|
|
# GUARDiA SM | db_postgresql_sm.sh
|
|
# 대상: PostgreSQL
|
|
# 파라미터: PG_HOST=localhost PG_PORT=5432 PG_DB=postgres
|
|
# PG_USER=postgres PGPASSWORD=<password>
|
|
# SLOW_QUERY_MS=1000 MAX_CONN_WARN=80
|
|
# ============================================================
|
|
set -euo pipefail
|
|
PG_HOST=${PG_HOST:-localhost}
|
|
PG_PORT=${PG_PORT:-5432}
|
|
PG_DB=${PG_DB:-postgres}
|
|
PG_USER=${PG_USER:-postgres}
|
|
export PGPASSWORD=${PGPASSWORD:-""}
|
|
SLOW_QUERY_MS=${SLOW_QUERY_MS:-1000}
|
|
MAX_CONN_WARN=${MAX_CONN_WARN:-80}
|
|
OK="[OK]"; WARN="[WARN]"; CRIT="[CRIT]"
|
|
SEP="─────────────────────────────────────────"
|
|
RESULT=0
|
|
PSQ="psql -h ${PG_HOST} -p ${PG_PORT} -U ${PG_USER} -d ${PG_DB} -t -A -c"
|
|
|
|
echo "======================================================"
|
|
echo " GUARDiA SM 점검 | PostgreSQL | $(hostname -s)"
|
|
echo " 점검 시각: $(date '+%Y-%m-%d %H:%M:%S %Z')"
|
|
echo "======================================================"
|
|
|
|
# ── 1. 프로세스 ───────────────────────────────────────────
|
|
echo; echo "[$SEP] 1. PostgreSQL 프로세스"
|
|
PG_PROC=$(pgrep -c "postgres" 2>/dev/null || echo 0)
|
|
PG_MASTER=$(pgrep -f "postgres: checkpointer\|postmaster" 2>/dev/null | head -1 || echo "")
|
|
if [ "$PG_PROC" -gt 0 ]; then
|
|
echo " ${OK} PostgreSQL 실행 중 (${PG_PROC}개 프로세스)"
|
|
else
|
|
echo " ${CRIT} PostgreSQL 프로세스 없음"
|
|
RESULT=2
|
|
fi
|
|
|
|
# ── 2. 포트 리스닝 ────────────────────────────────────────
|
|
echo; echo "[$SEP] 2. 포트 리스닝"
|
|
if ss -tlnp 2>/dev/null | grep -q ":${PG_PORT} "; then
|
|
echo " ${OK} 포트 ${PG_PORT} LISTEN"
|
|
else
|
|
echo " ${CRIT} 포트 ${PG_PORT} LISTEN 없음"
|
|
RESULT=2
|
|
fi
|
|
|
|
# psql 접속 테스트
|
|
if command -v psql &>/dev/null; then
|
|
VERSION=$(${PSQ} "SELECT version();" 2>/dev/null | head -1 || echo "접속 실패")
|
|
if echo "$VERSION" | grep -qi "postgresql"; then
|
|
echo " ${OK} DB 접속 성공: $(echo "$VERSION" | head -c 60)..."
|
|
else
|
|
echo " ${CRIT} DB 접속 실패: ${VERSION}"
|
|
RESULT=2
|
|
fi
|
|
else
|
|
echo " ${WARN} psql 클라이언트 없음 — 접속 점검 건너뜀"
|
|
[ $RESULT -lt 1 ] && RESULT=1
|
|
fi
|
|
|
|
# ── 3. 연결 수 ────────────────────────────────────────────
|
|
echo; echo "[$SEP] 3. 연결 현황"
|
|
if command -v psql &>/dev/null && [ "$RESULT" -lt 2 ]; then
|
|
CONN_INFO=$(${PSQ} "
|
|
SELECT
|
|
setting AS max_connections
|
|
FROM pg_settings WHERE name='max_connections';" 2>/dev/null || echo "")
|
|
MAX_CONN=$CONN_INFO
|
|
CURR_CONN=$(${PSQ} "SELECT count(*) FROM pg_stat_activity;" 2>/dev/null || echo 0)
|
|
ACTIVE_CONN=$(${PSQ} "SELECT count(*) FROM pg_stat_activity WHERE state='active';" 2>/dev/null || echo 0)
|
|
IDLE_CONN=$(${PSQ} "SELECT count(*) FROM pg_stat_activity WHERE state='idle';" 2>/dev/null || echo 0)
|
|
echo " 최대 연결 수: ${MAX_CONN}"
|
|
echo " 현재 연결 수: ${CURR_CONN} (active:${ACTIVE_CONN} idle:${IDLE_CONN})"
|
|
if [ -n "$MAX_CONN" ] && [ "$MAX_CONN" -gt 0 ]; then
|
|
CONN_PCT=$(( CURR_CONN * 100 / MAX_CONN ))
|
|
if [ "$CONN_PCT" -ge "$MAX_CONN_WARN" ]; then
|
|
echo " ${WARN} 연결 사용률 ${CONN_PCT}%"
|
|
[ $RESULT -lt 1 ] && RESULT=1
|
|
else
|
|
echo " ${OK} 연결 사용률 ${CONN_PCT}%"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# ── 4. 슬로우 쿼리 ────────────────────────────────────────
|
|
echo; echo "[$SEP] 4. 슬로우 쿼리 (>${SLOW_QUERY_MS}ms)"
|
|
if command -v psql &>/dev/null && [ "$RESULT" -lt 2 ]; then
|
|
SLOW=$(${PSQ} "
|
|
SELECT pid, now() - pg_stat_activity.query_start AS duration,
|
|
left(query, 80) AS query
|
|
FROM pg_stat_activity
|
|
WHERE (now() - pg_stat_activity.query_start) > interval '${SLOW_QUERY_MS} ms'
|
|
AND state = 'active'
|
|
ORDER BY duration DESC
|
|
LIMIT 5;" 2>/dev/null || echo "")
|
|
if [ -n "$SLOW" ]; then
|
|
echo " ${WARN} 슬로우 쿼리 감지:"
|
|
echo "$SLOW" | sed 's/^/ /'
|
|
[ $RESULT -lt 1 ] && RESULT=1
|
|
else
|
|
echo " ${OK} 슬로우 쿼리 없음"
|
|
fi
|
|
fi
|
|
|
|
# ── 5. 잠금(Lock) 대기 ────────────────────────────────────
|
|
echo; echo "[$SEP] 5. 잠금 대기"
|
|
if command -v psql &>/dev/null && [ "$RESULT" -lt 2 ]; then
|
|
LOCK=$(${PSQ} "
|
|
SELECT count(*) FROM pg_stat_activity
|
|
WHERE wait_event_type = 'Lock';" 2>/dev/null || echo 0)
|
|
if [ "$LOCK" -gt 5 ]; then
|
|
echo " ${CRIT} 잠금 대기 ${LOCK}건"
|
|
RESULT=2
|
|
elif [ "$LOCK" -gt 0 ]; then
|
|
echo " ${WARN} 잠금 대기 ${LOCK}건"
|
|
[ $RESULT -lt 1 ] && RESULT=1
|
|
else
|
|
echo " ${OK} 잠금 대기 없음"
|
|
fi
|
|
fi
|
|
|
|
# ── 6. 복제(Replication) 상태 ────────────────────────────
|
|
echo; echo "[$SEP] 6. 복제 상태"
|
|
if command -v psql &>/dev/null && [ "$RESULT" -lt 2 ]; then
|
|
IS_STANDBY=$(${PSQ} "SELECT pg_is_in_recovery();" 2>/dev/null || echo "f")
|
|
if echo "$IS_STANDBY" | grep -q "t"; then
|
|
LAG=$(${PSQ} "SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))::integer;" \
|
|
2>/dev/null || echo "N/A")
|
|
echo " ${OK} 스탠바이 모드 — 복제 지연: ${LAG}초"
|
|
[ "$LAG" -gt 60 ] 2>/dev/null && echo " ${WARN} 복제 지연 과다 (${LAG}s)" && [ $RESULT -lt 1 ] && RESULT=1
|
|
else
|
|
REP_COUNT=$(${PSQ} "SELECT count(*) FROM pg_stat_replication;" 2>/dev/null || echo 0)
|
|
echo " 마스터 모드 — 복제 슬레이브 수: ${REP_COUNT}"
|
|
fi
|
|
fi
|
|
|
|
# ── 7. DB 크기 상위 5개 ──────────────────────────────────
|
|
echo; echo "[$SEP] 7. DB 크기"
|
|
if command -v psql &>/dev/null && [ "$RESULT" -lt 2 ]; then
|
|
${PSQ} "
|
|
SELECT datname,
|
|
pg_size_pretty(pg_database_size(datname)) AS size
|
|
FROM pg_database
|
|
ORDER BY pg_database_size(datname) DESC
|
|
LIMIT 5;" 2>/dev/null | sed 's/^/ /' || true
|
|
fi
|
|
|
|
# ── 요약 ─────────────────────────────────────────────────
|
|
echo
|
|
echo "======================================================"
|
|
case $RESULT in
|
|
0) echo " 최종 결과: ${OK} PostgreSQL 정상" ;;
|
|
1) echo " 최종 결과: ${WARN} 주의 항목 있음" ;;
|
|
2) echo " 최종 결과: ${CRIT} 즉시 조치 필요" ;;
|
|
esac
|
|
echo " 점검 완료: $(date '+%Y-%m-%d %H:%M:%S')"
|
|
echo "======================================================"
|
|
exit $RESULT
|