zioinfo-mail/scripts/check/full_deployment_check.py
DESKTOP-TKLFCPR\ython 371f77e7ab
Some checks are pending
GUARDiA CI / Python Lint & Import Test (push) Waiting to run
GUARDiA CI / Validate Install Scripts (push) Waiting to run
GUARDiA CI / PR Validation Summary (push) Blocked by required conditions
fix(enhance-v4): APK QR 버그 수정 + 웹메일 라우터 수정
2026-06-02 20:23:55 +09:00

156 lines
7.9 KiB
Python

"""전체 배포 상태 종합 검증"""
import paramiko, sys, json, base64, time
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
c = paramiko.SSHClient(); c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=15)
sftp = c.open_sftp()
G = base64.b64encode(b'zio:Zio@Admin2026!').decode()
J = 'http://127.0.0.1:9080'
JA = 'admin:Admin@2026!'
def run(cmd, timeout=15):
_, o, _ = c.exec_command(cmd, timeout=timeout)
return o.read().decode('utf-8','replace').strip()
def ok(v): return '' if v else ''
results = {}
print('=' * 60)
print('GUARDiA 전체 배포 상태 검증')
print('=' * 60)
# ── 1. 서비스 상태 ─────────────────────────────────────────
print('\n■ 1. 서비스 상태')
services = {
'GUARDiA ITSM (9001)': 'guardia',
'홈페이지 (8082)': 'zioinfo',
'Manager (8090)': 'guardia-manager',
'Webhook (9999)': 'zioinfo-deploy',
'Jenkins (9080)': 'jenkins',
'zioinfo-mail (8026)': 'zioinfo-mail',
'Gitea (9003)': 'gitea',
}
for name, svc in services.items():
status = run(f'systemctl is-active {svc} 2>/dev/null')
print(f' {ok(status=="active")} {name}: {status}')
# ── 2. ITSM API 엔드포인트 ──────────────────────────────────
print('\n■ 2. GUARDiA ITSM API')
api_info = run(
'curl -sf http://localhost:9001/openapi.json 2>/dev/null | '
'python3 -c "import sys,json; d=json.load(sys.stdin); paths=d[\'paths\']; '
'adv=[p for p in paths if any(k in p for k in [\'/api/ocr\',\'/api/docflow\',\'/api/autodiscovery\',\'/api/nlquery\',\'/api/drift\',\'/api/kpi\',\'/api/multicloud\'])]; '
'print(f\'전체: {len(paths)}개 | OCR+확장: {len(adv)}개\')" 2>/dev/null || echo "API 확인 불가"'
)
print(f'{api_info}')
# 주요 신규 기능 엔드포인트 확인
key_paths = ['/api/ocr/parse', '/api/docflow/brand-contract', '/api/nlquery/ask',
'/api/drift/scan/{server_id}', '/api/kpi/dashboard', '/api/autodiscovery/scan',
'/api/multicloud/providers', '/api/narasajang/bids']
existing = run(
'curl -sf http://localhost:9001/openapi.json 2>/dev/null | '
'python3 -c "import sys,json; d=json.load(sys.stdin)[\'paths\']; print(\'|\'.join(d.keys()))" 2>/dev/null'
)
for path in key_paths:
exists = path in existing
print(f' {ok(exists)} {path}')
# ── 3. DB 테이블 ────────────────────────────────────────────
print('\n■ 3. 신규 DB 테이블')
db_check = """
import asyncio, sys
sys.path.insert(0, '/opt/guardia/app')
from database import engine
from sqlalchemy import text
TABLES = [
'tb_upstage_ocr_config', 'tb_ocr_history', 'tb_doc_workflow_job', 'tb_doc_template',
'tb_discovery_scan_job', 'tb_cmdb_autodiscovery', 'tb_service_dependency',
'tb_query_history', 'tb_assistant_session', 'tb_golden_config', 'tb_drift_result',
'tb_multicloud_config', 'tb_kpi_definition', 'tb_kpi_value',
'tb_jira_config', 'tb_slack_config', 'tb_tenant_branding',
'tb_narasajang_config', 'tb_network_zone', 'tb_procurement_record',
'tb_learning_run', 'tb_container_alert_rule', 'tb_aws_config',
]
async def check():
ok_cnt = fail_cnt = 0
async with engine.connect() as conn:
for t in TABLES:
try:
await conn.execute(text(f"SELECT 1 FROM {t} LIMIT 0"))
ok_cnt += 1
except:
fail_cnt += 1
print(f" MISS: {t}")
print(f" DB 테이블: {ok_cnt}/{len(TABLES)}개 정상")
asyncio.run(check())
"""
with sftp.open('/tmp/dbchk.py', 'w') as f: f.write(db_check)
print(run('cd /opt/guardia/app && /opt/guardia/venv/bin/python3 /tmp/dbchk.py 2>&1; rm /tmp/dbchk.py', timeout=20))
# ── 4. 홈페이지 ─────────────────────────────────────────────
print('\n■ 4. 홈페이지 (zioinfo.co.kr)')
www_files = run('ls /var/www/zioinfo/assets/*.js 2>/dev/null | wc -l')
www_date = run('stat /var/www/zioinfo/index.html 2>/dev/null | grep Modify | cut -d" " -f2,3')
guardia_js = run('ls /var/www/zioinfo/assets/GuardiaDetail*.js 2>/dev/null | sort | tail -1 | xargs ls -lh 2>/dev/null')
print(f' ✅ 정적 파일: {www_files}')
print(f' ✅ index.html: {www_date}')
print(f' ✅ GuardiaDetail: {guardia_js}')
homepage_ok = run('curl -sf -o /dev/null -w "%{http_code}" https://zioinfo.co.kr/ -L 2>/dev/null || echo "0"')
print(f' {ok(homepage_ok in ("200","301","302"))} HTTP: {homepage_ok}')
# ── 5. Manager ──────────────────────────────────────────────
print('\n■ 5. GUARDiA Manager (8090)')
mgr_date = run('stat /var/www/manager/index.html 2>/dev/null | grep Modify | cut -d" " -f2,3')
mgr_files = run('ls /var/www/manager/assets/*.js 2>/dev/null | wc -l')
print(f' ✅ 정적 파일: {mgr_files}개 | index.html: {mgr_date}')
# ── 6. zioinfo-mail ─────────────────────────────────────────
print('\n■ 6. 웹메일 (mail:8025, API:8026)')
mail_health = run('curl -sf http://localhost:8026/health 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin).get(\'status\'))" 2>/dev/null || echo "응답없음"')
mail_www = run('ls /var/www/mail/assets/*.js 2>/dev/null | wc -l')
print(f' {ok(mail_health=="ok")} API health: {mail_health}')
print(f' ✅ 프론트엔드: {mail_www}개 JS 파일')
# ── 7. Jenkins CI/CD ────────────────────────────────────────
print('\n■ 7. Jenkins CI/CD (9080)')
jenkins_jobs = run(
f'curl -sf -u "{JA}" {J}/api/json 2>/dev/null | '
'python3 -c "import sys,json; d=json.load(sys.stdin); jobs=d[\'jobs\']; '
'blue=sum(1 for j in jobs if j[\'color\']==\'blue\'); '
'print(f\'{blue}/{len(jobs)}개 blue\')" 2>/dev/null || echo "확인불가"'
)
print(f' ✅ Jenkins jobs: {jenkins_jobs}')
# ── 8. Gitea repos ──────────────────────────────────────────
print('\n■ 8. Gitea 저장소 현황')
for repo in ['zioinfo-web', 'guardia-itsm', 'guardia-manager', 'guardia-messenger', 'guardia-docs', 'zioinfo-mail']:
commit = run(
f'curl -sf "http://127.0.0.1:9003/api/v1/repos/zio/{repo}/commits?limit=1" '
f'-H "Authorization: Basic {G}" 2>/dev/null | '
'python3 -c "import sys,json; c=json.load(sys.stdin)[0]; print(c[\'sha\'][:8], c[\'commit\'][\'message\'][:45])" 2>/dev/null || echo "확인불가"'
)
print(f'{repo}: {commit}')
# ── 9. Webhook 배포 서버 ────────────────────────────────────
print('\n■ 9. Webhook 배포 서버')
webhook_repos = run("grep -c 'elif repo ==' /opt/zioinfo/deploy_server.py 2>/dev/null || echo 0")
webhook_port = run('ss -tlnp | grep 9999 2>/dev/null | head -1')
print(f' ✅ 지원 repo: {webhook_repos}')
print(f' {ok("9999" in webhook_port)} 포트 9999: {"LISTEN" if "9999" in webhook_port else "없음"}')
# ── 요약 ────────────────────────────────────────────────────
print('\n' + '=' * 60)
print('■ 종합 요약')
print('=' * 60)
print(f' ITSM: {api_info}')
print(f' 서비스: 7개 중 {"7" if all(run(f"systemctl is-active {s} 2>/dev/null")=="active" for s in services.values()) else "일부"} active')
print(f' 홈페이지: www {www_files}개 파일')
print(f' 웹메일: API {mail_health}')
print(f' CI/CD: Jenkins {jenkins_jobs}')
sftp.close(); c.close()