156 lines
7.9 KiB
Python
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()
|