#!/usr/bin/env python3 """서버에서 직접 라이선스 API 테스트 (paramiko exec)""" import paramiko, time, sys, json HOST = '101.79.17.164'; USER = 'root'; PASS = '1q2w3e!Q' client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(HOST, username=USER, password=PASS, timeout=15) def ssh(label, cmd, timeout=20): print(f'\n[{label}]') chan = client.get_transport().open_session() chan.set_combine_stderr(True) chan.exec_command(cmd) start = time.time() while not chan.exit_status_ready(): if chan.recv_ready(): sys.stdout.buffer.write(chan.recv(4096)); sys.stdout.flush() if time.time() - start > timeout: break time.sleep(0.2) while chan.recv_ready(): sys.stdout.buffer.write(chan.recv(4096)) sys.stdout.flush() rc = chan.recv_exit_status() print(f' exit={rc}') return rc # 테스트 스크립트 서버에 업로드 test_script = r"""#!/usr/bin/env python3 import urllib.request, urllib.parse, json BASE = 'http://localhost:8001' RESULTS = [] def api(method, path, data=None, token=None): url = f'{BASE}{path}' body = json.dumps(data).encode() if data else None req = urllib.request.Request(url, data=body, method=method) req.add_header('Content-Type', 'application/json') if token: req.add_header('Authorization', f'Bearer {token}') try: resp = urllib.request.urlopen(req, timeout=10) return json.loads(resp.read()), resp.status except urllib.error.HTTPError as e: return json.loads(e.read()), e.code except Exception as ex: return {'error': str(ex)}, 0 def test(name, fn): try: r = fn(); ok = True except Exception as e: r = str(e); ok = False RESULTS.append((name, ok, r)) print(f'{"OK" if ok else "FAIL"} {name}: {str(r)[:80]}') return r if ok else None print('=== GUARDiA 라이선스 API 테스트 ===') # T1 로그인 params = urllib.parse.urlencode({'username':'admin','password':'Admin@zioinfo2026!'}) req = urllib.request.Request(f'{BASE}/api/auth/login', data=params.encode(), method='POST') req.add_header('Content-Type', 'application/x-www-form-urlencoded') resp = urllib.request.urlopen(req, timeout=10) TOKEN = json.loads(resp.read()).get('access_token','') print(f'TOKEN: {TOKEN[:20]}...\n') # T2 현재 상태 test('T2 현재 라이선스 상태', lambda: api('GET', '/api/license/status', token=TOKEN)[0].get('message')) # T3 체험 발급 (이미 있으면 Skip) cur, _ = api('GET', '/api/license/status', token=TOKEN) if not cur.get('activated'): def t3(): r,s = api('POST','/api/license/trial',{'customer':'지오정보기술 체험판','days':7},token=TOKEN) return f'HTTP {s}: {r.get("message",r.get("detail","?"))}' test('T3 체험 라이선스 발급 (7일)', t3) else: RESULTS.append(('T3 체험 라이선스 발급','SKIP','이미 활성화됨')) print('SKIP T3 체험 라이선스 발급: 이미 활성화됨') # T4 활성화 후 상태 def t4(): r,_ = api('GET','/api/license/status',token=TOKEN) return f"valid={r.get('valid')}, edition={r.get('edition')}, days={r.get('days_remaining')}" test('T4 활성화 후 상태 확인', t4) # T5 이력 조회 def t5(): r,s = api('GET','/api/license/history',token=TOKEN) cnt = len(r) if isinstance(r,list) else '?' return f'HTTP {s}: {cnt}건' test('T5 라이선스 이력 조회', t5) # T6 잘못된 키 검증 def t6(): r,s = api('POST','/api/license/verify',{'license_key':'invalid_test_key'},token=TOKEN) return f'HTTP {s}: {r.get("detail",r.get("message","?"))[:50]}' test('T6 잘못된 키 검증 (400/422 예상)', t6) # T7 Manager UI import urllib.request as ur try: resp2 = ur.urlopen('http://localhost:8090/', timeout=5) ui_status = resp2.status except Exception as ex: ui_status = str(ex) test('T7 Manager UI 접속', lambda: f'HTTP {ui_status}') # T8 Manager API try: resp3 = ur.urlopen('http://localhost:8002/health', timeout=5) api_status = json.loads(resp3.read()).get('status','?') except Exception as ex: api_status = str(ex) test('T8 Manager Backend', lambda: api_status) # 결과 요약 print(f'\n{"="*55}') passed = sum(1 for _,ok,_ in RESULTS if ok is True or ok=='SKIP') print(f'테스트 결과: {passed}/{len(RESULTS)} PASS') for name,ok,detail in RESULTS: icon = '✅' if ok is True else ('⏭️' if ok=='SKIP' else '❌') print(f' {icon} {name}') print('='*55) """ sftp = client.open_sftp() with sftp.open('/tmp/test_license.py', 'w') as f: f.write(test_script) sftp.close() ssh('라이선스 테스트 실행', 'python3 /tmp/test_license.py 2>&1', timeout=30) client.close()