headscale-tailscale-replace.../test-proxmox-api.py
시골약사 35ecd4748e PharmQ SaaS 구독 서비스 관리 시스템 완전 구현
📋 기획 및 설계:
- PharmQ SaaS 서비스 기획서 작성
- 구독 서비스 라인업 정의 (클라우드PC, AI CCTV, CRM)
- DB 스키마 설계 및 API 아키텍처 설계

🗄️ 데이터베이스 구조:
- service_products: 서비스 상품 마스터 테이블
- pharmacy_subscriptions: 약국별 구독 현황 테이블
- subscription_usage_logs: 서비스 이용 로그 테이블
- billing_history: 결제 이력 테이블
- 샘플 데이터 자동 생성 (21개 구독, 월 118만원 매출)

🔧 백엔드 API 구현:
- 구독 현황 통계 API (/api/subscriptions/stats)
- 약국별 구독 조회 API (/api/pharmacies/subscriptions)
- 구독 상세 정보 API (/api/pharmacy/{id}/subscriptions)
- 구독 생성/해지 API (/api/subscriptions)

🖥️ 프론트엔드 UI 구현:
- 대시보드 구독 현황 카드 (월 매출, 구독 수, 구독률 등)
- 약국 목록에 구독 상태 아이콘 및 월 구독료 표시
- 약국 상세 페이지 구독 서비스 섹션 추가
- 실시간 구독 생성/해지 기능 구현

 주요 특징:
- 서비스별 색상 코딩 및 이모지 아이콘 시스템
- 실시간 업데이트 (구독 생성/해지 즉시 반영)
- 반응형 디자인 (모바일/태블릿 최적화)
- 툴팁 기반 상세 정보 표시

📊 현재 구독 현황:
- 총 월 매출: ₩1,180,000
- 구독 약국: 10/14개 (71.4%)
- AI CCTV: 6개 약국, CRM: 10개 약국, 클라우드PC: 5개 약국

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-11 19:48:12 +09:00

222 lines
7.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Proxmox VE API 테스트 스크립트
사용법: python test-proxmox-api.py <proxmox-ip> [root-password]
"""
import requests
import json
import sys
import urllib3
from urllib.parse import quote_plus
# SSL 경고 무시
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def test_api_token_method(host, token):
"""API Token 방식 테스트"""
print("🔑 API Token 방식 테스트...")
headers = {
'Authorization': f'PVEAPIToken={token}'
}
try:
response = requests.get(
f'https://{host}:443/api2/json/version',
headers=headers,
verify=False,
timeout=10
)
if response.status_code == 200:
version_info = response.json()['data']
print(f"✅ API Token 인증 성공!")
print(f" Proxmox Version: {version_info['version']}")
print(f" Release: {version_info['release']}")
return True
else:
print(f"❌ API Token 인증 실패: {response.status_code}")
print(f" 응답: {response.text}")
return False
except Exception as e:
print(f"❌ API Token 연결 실패: {e}")
return False
def test_session_method(host, username, password):
"""세션 쿠키 방식 테스트"""
print("🍪 세션 쿠키 방식 테스트...")
# 1단계: 로그인하여 티켓 획득
login_data = {
'username': username,
'password': password
}
try:
response = requests.post(
f'https://{host}:443/api2/json/access/ticket',
data=login_data,
verify=False,
timeout=10
)
if response.status_code != 200:
print(f"❌ 로그인 실패: {response.status_code}")
print(f" 응답: {response.text}")
return False, None, None
data = response.json()['data']
ticket = data['ticket']
csrf_token = data['CSRFPreventionToken']
print("✅ 로그인 성공!")
print(f" 티켓: {ticket[:20]}...")
print(f" CSRF: {csrf_token}")
return True, ticket, csrf_token
except Exception as e:
print(f"❌ 로그인 연결 실패: {e}")
return False, None, None
def test_vm_list_api(host, ticket=None, csrf_token=None, api_token=None):
"""VM 목록 조회 API 테스트"""
print("\n📋 VM 목록 조회 API 테스트...")
if api_token:
headers = {'Authorization': f'PVEAPIToken={api_token}'}
cookies = None
else:
headers = {'CSRFPreventionToken': csrf_token}
cookies = {'PVEAuthCookie': ticket}
try:
response = requests.get(
f'https://{host}:443/api2/json/cluster/resources?type=vm',
headers=headers,
cookies=cookies,
verify=False,
timeout=10
)
if response.status_code == 200:
vms = response.json()['data']
print(f"✅ VM 목록 조회 성공! (총 {len(vms)}개)")
for vm in vms:
status_icon = "🟢" if vm.get('status') == 'running' else "🔴"
print(f" {status_icon} VM {vm.get('vmid')}: {vm.get('name', 'N/A')} ({vm.get('status', 'unknown')})")
return True, vms
else:
print(f"❌ VM 목록 조회 실패: {response.status_code}")
print(f" 응답: {response.text}")
return False, []
except Exception as e:
print(f"❌ VM 목록 API 연결 실패: {e}")
return False, []
def test_vnc_proxy_api(host, node, vmid, ticket=None, csrf_token=None, api_token=None):
"""VNC 프록시 티켓 생성 테스트"""
print(f"\n🖥️ VNC 프록시 API 테스트 (VM {vmid})...")
if api_token:
headers = {'Authorization': f'PVEAPIToken={api_token}'}
cookies = None
else:
headers = {'CSRFPreventionToken': csrf_token}
cookies = {'PVEAuthCookie': ticket}
data = {'websocket': '1'}
try:
response = requests.post(
f'https://{host}:443/api2/json/nodes/{node}/qemu/{vmid}/vncproxy',
headers=headers,
cookies=cookies,
data=data,
verify=False,
timeout=10
)
if response.status_code == 200:
vnc_data = response.json()['data']
print("✅ VNC 프록시 티켓 생성 성공!")
print(f" 포트: {vnc_data['port']}")
print(f" 티켓: {vnc_data['ticket'][:20]}...")
# WebSocket URL 생성
encoded_ticket = quote_plus(vnc_data['ticket'])
ws_url = f"wss://{host}:443/api2/json/nodes/{node}/qemu/{vmid}/vncwebsocket?port={vnc_data['port']}&vncticket={encoded_ticket}"
print(f" WebSocket URL: {ws_url[:80]}...")
return True, vnc_data
else:
print(f"❌ VNC 프록시 생성 실패: {response.status_code}")
print(f" 응답: {response.text}")
return False, None
except Exception as e:
print(f"❌ VNC 프록시 API 연결 실패: {e}")
return False, None
def main():
if len(sys.argv) < 2:
print("사용법: python test-proxmox-api.py <proxmox-ip> [root-password] [api-token]")
print()
print("예시:")
print(" python test-proxmox-api.py 100.64.0.1 mypassword")
print(" python test-proxmox-api.py 100.64.0.1 '' root@pam!token=uuid")
sys.exit(1)
host = sys.argv[1]
password = sys.argv[2] if len(sys.argv) > 2 else None
api_token = sys.argv[3] if len(sys.argv) > 3 else None
print("=" * 60)
print(f"🚀 Proxmox API 테스트 - {host}")
print("=" * 60)
# API Token 방식 테스트
if api_token:
success = test_api_token_method(host, api_token)
if success:
# VM 목록 테스트
vm_success, vms = test_vm_list_api(host, api_token=api_token)
# 실행 중인 VM이 있으면 VNC 테스트
if vm_success and vms:
running_vm = next((vm for vm in vms if vm.get('status') == 'running'), None)
if running_vm:
test_vnc_proxy_api(host, running_vm['node'], running_vm['vmid'], api_token=api_token)
else:
print("⚠️ 실행 중인 VM이 없어 VNC 테스트를 건너뜁니다.")
# 패스워드 방식 테스트
elif password:
login_success, ticket, csrf_token = test_session_method(host, 'root@pam', password)
if login_success:
# VM 목록 테스트
vm_success, vms = test_vm_list_api(host, ticket, csrf_token)
# 실행 중인 VM이 있으면 VNC 테스트
if vm_success and vms:
running_vm = next((vm for vm in vms if vm.get('status') == 'running'), None)
if running_vm:
test_vnc_proxy_api(host, running_vm['node'], running_vm['vmid'], ticket, csrf_token)
else:
print("⚠️ 실행 중인 VM이 없어 VNC 테스트를 건너뜁니다.")
else:
print("❌ 패스워드 또는 API 토큰을 제공해주세요.")
sys.exit(1)
print("\n" + "=" * 60)
print("✅ 테스트 완료!")
if __name__ == '__main__':
main()