guardia-itsm/scripts/sm/search/search_solr_sm.sh
DESKTOP-TKLFCPRython 64c27c3509 feat(itsm): G-1~G-12 확장 기능 + 하네스/봇/설치스크립트 구현
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>
2026-05-29 18:18:52 +09:00

152 lines
6.9 KiB
Bash

#!/bin/bash
# ============================================================
# GUARDiA SM | search_solr_sm.sh
# 대상: Apache Solr (7.x / 8.x / 9.x)
# 파라미터: SOLR_HOME=/opt/solr SOLR_HOST=localhost SOLR_PORT=8983
# SOLR_USER=solr SOLR_PASS=SolrRocks
# QUERY_TIME_WARN=1000
# ============================================================
set -euo pipefail
SOLR_HOME=${SOLR_HOME:-/opt/solr}
SOLR_HOST=${SOLR_HOST:-localhost}
SOLR_PORT=${SOLR_PORT:-8983}
SOLR_USER=${SOLR_USER:-""}
SOLR_PASS=${SOLR_PASS:-""}
QUERY_TIME_WARN=${QUERY_TIME_WARN:-1000}
SOLR_BASE="http://${SOLR_HOST}:${SOLR_PORT}"
OK="[OK]"; WARN="[WARN]"; CRIT="[CRIT]"
SEP="─────────────────────────────────────────"
RESULT=0
_solr() {
local URL="$1"
local AUTH=""
[ -n "$SOLR_USER" ] && AUTH="-u ${SOLR_USER}:${SOLR_PASS}"
curl -sk --max-time 10 $AUTH "${SOLR_BASE}${URL}" 2>/dev/null
}
echo "======================================================"
echo " GUARDiA SM 점검 | Apache Solr | $(hostname -s)"
echo " 점검 시각: $(date '+%Y-%m-%d %H:%M:%S %Z')"
echo "======================================================"
# ── 1. 프로세스 ───────────────────────────────────────────
echo; echo "[$SEP] 1. Solr 프로세스"
SOLR_PROC=$(pgrep -f "solr\|start.jar" 2>/dev/null | wc -l || echo 0)
if [ "$SOLR_PROC" -gt 0 ]; then
SOLR_PID=$(pgrep -f "solr" | head -1)
echo " ${OK} Solr 실행 중 (PID: ${SOLR_PID})"
RSS_MB=$(awk '/VmRSS/{print $2}' /proc/${SOLR_PID}/status 2>/dev/null | \
awk '{printf "%d", $1/1024}' || echo "N/A")
echo " RSS 메모리: ${RSS_MB} MB"
else
echo " ${CRIT} Solr 프로세스 없음"
RESULT=2
fi
# ── 2. 포트 리스닝 ────────────────────────────────────────
echo; echo "[$SEP] 2. 포트 리스닝"
ss -tlnp 2>/dev/null | grep -q ":${SOLR_PORT} " && \
echo " ${OK} 포트 ${SOLR_PORT} LISTEN" || \
{ echo " ${CRIT} 포트 ${SOLR_PORT} LISTEN 없음"; RESULT=2; }
# ── 3. 시스템 정보 ────────────────────────────────────────
echo; echo "[$SEP] 3. Solr 시스템 정보"
if command -v curl &>/dev/null; then
SYS=$(_solr "/solr/admin/info/system?wt=json")
if [ -n "$SYS" ]; then
SOLR_VER=$(echo "$SYS" | python3 -c \
"import sys,json; d=json.load(sys.stdin); print(d.get('lucene',{}).get('solr-spec-version','?'))" 2>/dev/null)
UPTIME=$(echo "$SYS" | python3 -c \
"import sys,json; d=json.load(sys.stdin); ms=d.get('jvm',{}).get('jmx',{}).get('upTimeMS',0); \
h=ms//3600000; m=(ms%3600000)//60000; print(f'{h}h {m}m')" 2>/dev/null || echo "N/A")
echo " ${OK} Solr 버전: ${SOLR_VER}, 가동 시간: ${UPTIME}"
# JVM 힙
HEAP=$(echo "$SYS" | python3 -c \
"import sys,json; d=json.load(sys.stdin); jvm=d.get('jvm',{}).get('memory',{}).get('raw',{}); \
used=jvm.get('used',0)//1048576; max_=jvm.get('max',1)//1048576; \
pct=used*100//max_ if max_>0 else 0; print(f'used={used}MB max={max_}MB ({pct}%)')" 2>/dev/null)
echo " JVM 힙: ${HEAP}"
if echo "$HEAP" | grep -oP '\d+(?=%)' | awk '{exit !($1>=85)}'; then
echo " ${WARN} JVM 힙 사용률 85% 초과"
[ $RESULT -lt 1 ] && RESULT=1
fi
else
echo " ${CRIT} Solr 응답 없음"
RESULT=2
fi
fi
# ── 4. 코어/컬렉션 상태 ─────────────────────────────────
echo; echo "[$SEP] 4. 코어/컬렉션 상태"
if command -v curl &>/dev/null; then
CORES=$(_solr "/solr/admin/cores?wt=json&indexInfo=false")
if [ -n "$CORES" ]; then
CORE_LIST=$(echo "$CORES" | python3 -c "
import sys, json
d = json.load(sys.stdin)
status = d.get('status', {})
for name, info in status.items():
sz = info.get('index', {}).get('sizeInBytes', 0) // 1048576
docs = info.get('index', {}).get('numDocs', 0)
print(f' {name:20s} docs={docs:>10,d} size={sz}MB')
" 2>/dev/null || echo " 파싱 실패")
echo "$CORE_LIST"
CORE_COUNT=$(echo "$CORES" | python3 -c \
"import sys,json; d=json.load(sys.stdin); print(len(d.get('status',{})))" 2>/dev/null)
echo " 총 코어 수: ${CORE_COUNT}"
fi
fi
# ── 5. 쿼리 성능 통계 ────────────────────────────────────
echo; echo "[$SEP] 5. 쿼리 성능 통계"
if command -v curl &>/dev/null; then
# 첫 번째 코어의 성능 지표
FIRST_CORE=$(echo "$CORES" 2>/dev/null | python3 -c \
"import sys,json; d=json.load(sys.stdin); print(list(d.get('status',{}).keys())[0])" 2>/dev/null || echo "")
if [ -n "$FIRST_CORE" ]; then
METRICS=$(_solr "/solr/${FIRST_CORE}/admin/mbeans?stats=true&cat=QUERYHANDLER&wt=json")
AVG_TIME=$(echo "$METRICS" | python3 -c "
import sys, json
d = json.load(sys.stdin)
beans = d.get('solr-mbeans', [])
for i in range(0, len(beans), 2):
if beans[i] == 'QUERYHANDLER':
handlers = beans[i+1] if i+1 < len(beans) else {}
for name, stats in handlers.items():
if '/select' in name:
qs = stats.get('stats', {})
avg = qs.get('avgTimePerRequest', 0)
rpc = qs.get('requests', 0)
print(f' /select: requests={rpc} avg={avg:.1f}ms')
" 2>/dev/null || echo " 쿼리 통계 없음")
echo "$AVG_TIME"
fi
fi
# ── 6. 로그 오류 ─────────────────────────────────────────
echo; echo "[$SEP] 6. 로그 오류"
for LOGDIR in "${SOLR_HOME}/server/logs" "${SOLR_HOME}/logs" "/var/log/solr"; do
if [ -d "$LOGDIR" ]; then
LOGFILE=$(ls -t "${LOGDIR}"/solr.log 2>/dev/null | head -1 || echo "")
if [ -n "$LOGFILE" ] && [ -r "$LOGFILE" ]; then
ERR=$(tail -1000 "$LOGFILE" | grep -cE "ERROR|WARN|Exception" || echo 0)
echo " 최근 오류/경고: ${ERR}건 (${LOGFILE})"
tail -1000 "$LOGFILE" | grep -E "ERROR|WARN" | tail -5 | sed 's/^/ /' || true
fi
break
fi
done
# ── 요약 ─────────────────────────────────────────────────
echo
echo "======================================================"
case $RESULT in
0) echo " 최종 결과: ${OK} Solr 정상" ;;
1) echo " 최종 결과: ${WARN} 주의 항목 있음" ;;
2) echo " 최종 결과: ${CRIT} 즉시 조치 필요" ;;
esac
echo " 점검 완료: $(date '+%Y-%m-%d %H:%M:%S')"
echo "======================================================"
exit $RESULT