# 테스트 데이터 정리 가이드 ## 개요 headscale 자동 등록 스크립트 테스트 시 생성되는 데이터를 정리하는 방법 ## 정리해야 할 데이터 1. **farmq.db**: 테스트 약국 데이터 (P0003 이후) 2. **gateway.db**: 테스트 사용자 계정 (ID 5 이후) 3. **Headscale**: 테스트 VPN 노드 --- ## 1. farmq.db 테스트 약국 삭제 ### 수동 삭제 (Python) ```bash cd /srv/headscale-tailscale-replacement/farmq-admin python3 << 'EOF' import sqlite3 conn = sqlite3.connect('farmq.db') cursor = conn.cursor() print('현재 약국 목록:') cursor.execute('SELECT pharmacy_code, pharmacy_name, tailscale_ip FROM pharmacies') for row in cursor.fetchall(): print(f' {row[0]}: {row[1]} - {row[2]}') # P0003~P9999 약국 삭제 (P001, P002, P0001, P0002는 보호) print('\nP0003 이후 약국 삭제 중...') cursor.execute("DELETE FROM pharmacies WHERE pharmacy_code >= 'P0003' AND pharmacy_code <= 'P9999' AND LENGTH(pharmacy_code) = 5") deleted_count = cursor.rowcount conn.commit() print(f'✓ {deleted_count}개 약국 삭제 완료') print('\n남은 약국 목록:') cursor.execute('SELECT pharmacy_code, pharmacy_name, tailscale_ip FROM pharmacies') for row in cursor.fetchall(): print(f' {row[0]}: {row[1]} - {row[2]}') conn.close() EOF ``` ### 특정 약국만 삭제 ```bash cd /srv/headscale-tailscale-replacement/farmq-admin python3 << 'EOF' import sqlite3 conn = sqlite3.connect('farmq.db') cursor = conn.cursor() # 삭제할 약국 코드 지정 pharmacy_codes = ['P0003', 'P0004', 'P0005', 'P0006'] for code in pharmacy_codes: cursor.execute('DELETE FROM pharmacies WHERE pharmacy_code = ?', (code,)) print(f'✓ {code} 삭제 완료') conn.commit() conn.close() EOF ``` --- ## 2. gateway.db 테스트 사용자 삭제 ### 수동 삭제 (Python) ```bash cd /srv/pharmq-gateway python3 << 'EOF' import sqlite3 conn = sqlite3.connect('gateway.db') cursor = conn.cursor() print('현재 사용자 목록:') cursor.execute('SELECT id, username, name, primary_pharmacy_code FROM users') for row in cursor.fetchall(): print(f' ID {row[0]}: {row[1]} ({row[2]}) - {row[3]}') # ID 5 이후 사용자 삭제 (테스트 데이터) print('\nID 5 이후 사용자 삭제 중...') cursor.execute('DELETE FROM pharmacy_members WHERE user_id >= 5') cursor.execute('DELETE FROM users WHERE id >= 5') deleted_count = cursor.rowcount conn.commit() print(f'✓ {deleted_count}명 사용자 삭제 완료') print('\n남은 사용자 목록:') cursor.execute('SELECT id, username, name, primary_pharmacy_code FROM users') for row in cursor.fetchall(): print(f' ID {row[0]}: {row[1]} ({row[2]}) - {row[3]}') conn.close() EOF ``` ### 특정 사용자만 삭제 ```bash cd /srv/pharmq-gateway python3 << 'EOF' import sqlite3 conn = sqlite3.connect('gateway.db') cursor = conn.cursor() # 삭제할 사용자 ID 지정 user_ids = [5, 6, 7, 8] for user_id in user_ids: cursor.execute('DELETE FROM pharmacy_members WHERE user_id = ?', (user_id,)) cursor.execute('DELETE FROM users WHERE id = ?', (user_id,)) print(f'✓ ID {user_id} 삭제 완료') conn.commit() conn.close() EOF ``` --- ## 3. Headscale 테스트 노드 삭제 ### 노드 목록 확인 ```bash docker exec headscale headscale nodes list ``` ### 특정 노드 삭제 (ID 기준) ```bash # 단일 노드 삭제 docker exec headscale headscale nodes delete --identifier --force # 예시: ID 13 삭제 docker exec headscale headscale nodes delete --identifier 13 --force ``` ### 여러 노드 한번에 삭제 ```bash # 삭제할 노드 ID들 NODE_IDS=(13 14 15 16 17 18) for id in "${NODE_IDS[@]}"; do docker exec headscale headscale nodes delete --identifier $id --force echo "✓ Node ID $id 삭제 완료" done ``` ### 특정 이름 패턴 노드 삭제 ```bash # pve-로 시작하는 테스트 노드 찾기 docker exec headscale headscale nodes list | grep "pve-" # 해당 노드들의 ID를 확인한 후 수동으로 삭제 docker exec headscale headscale nodes delete --identifier --force ``` --- ## 자동화 스크립트 ### 통합 정리 스크립트 실행 ```bash bash /srv/install_scripts/pve9-repo-fix/cleanup-test-data.sh ``` **또는 직접 다운로드하여 실행:** ```bash curl -fsSL https://raw.githubusercontent.com/thug0bin/pve9-repo-fix/main/cleanup-test-data.sh | bash ``` --- ## 사용 시나리오 ### 시나리오 1: 전체 테스트 데이터 정리 ```bash # 1. farmq.db 정리 (P0003~P9999, P001/P002 보호) cd /srv/headscale-tailscale-replacement/farmq-admin python3 -c "import sqlite3; conn = sqlite3.connect('farmq.db'); cursor = conn.cursor(); cursor.execute(\"DELETE FROM pharmacies WHERE pharmacy_code >= 'P0003' AND pharmacy_code <= 'P9999' AND LENGTH(pharmacy_code) = 5\"); conn.commit(); print(f'✓ {cursor.rowcount}개 약국 삭제'); conn.close()" # 2. gateway.db 정리 (ID 5 이후) cd /srv/pharmq-gateway python3 -c "import sqlite3; conn = sqlite3.connect('gateway.db'); cursor = conn.cursor(); cursor.execute('DELETE FROM pharmacy_members WHERE user_id >= 5'); cursor.execute('DELETE FROM users WHERE id >= 5'); conn.commit(); print(f'✓ {cursor.rowcount}명 사용자 삭제'); conn.close()" # 3. Headscale 노드 정리 (수동 확인 후) docker exec headscale headscale nodes list # 테스트 노드 ID 확인 후 삭제 ``` ### 시나리오 2: 특정 약국 코드 범위만 정리 ```bash # P0005~P0010 범위만 삭제 cd /srv/headscale-tailscale-replacement/farmq-admin python3 -c "import sqlite3; conn = sqlite3.connect('farmq.db'); cursor = conn.cursor(); cursor.execute(\"DELETE FROM pharmacies WHERE pharmacy_code >= 'P0005' AND pharmacy_code <= 'P0010'\"); conn.commit(); print(f'✓ {cursor.rowcount}개 약국 삭제'); conn.close()" ``` --- ## 주의사항 ⚠️ **운영 데이터 보호** - P001, P002, P0002는 운영 약국이므로 삭제하지 마세요 - ID 1~4 사용자는 운영 계정이므로 삭제하지 마세요 - 삭제 전 반드시 데이터를 확인하세요 ⚠️ **백업 권장** ```bash # farmq.db 백업 cp /srv/headscale-tailscale-replacement/farmq-admin/farmq.db /srv/headscale-tailscale-replacement/farmq-admin/farmq.db.backup # gateway.db 백업 cp /srv/pharmq-gateway/gateway.db /srv/pharmq-gateway/gateway.db.backup ``` ⚠️ **Headscale 노드 삭제** - offline 상태의 노드만 삭제 권장 - online 노드 삭제 시 연결이 끊어집니다 --- ## 트러블슈팅 ### 문제: "database is locked" 에러 **원인**: Flask 서버가 DB를 사용 중 **해결**: ```bash # farmq-admin 재시작 cd /srv/headscale-tailscale-replacement/farmq-admin pkill -f "flask run" source venv/bin/activate flask run --host=0.0.0.0 --port=5001 & # gateway 재시작 cd /srv/pharmq-gateway pkill -f "uvicorn" source venv/bin/activate uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload & ``` ### 문제: Python 스크립트 실행 안 됨 **해결**: 경로 확인 ```bash # 올바른 경로로 이동 cd /srv/headscale-tailscale-replacement/farmq-admin # farmq.db cd /srv/pharmq-gateway # gateway.db ``` --- ## 참고 - farmq.db 위치: `/srv/headscale-tailscale-replacement/farmq-admin/farmq.db` - gateway.db 위치: `/srv/pharmq-gateway/gateway.db` - Headscale: Docker 컨테이너 `headscale` - 약국 코드 형식: P0001~P9999 (P + 4자리 숫자) - 사용자 계정: pharmacy_code 소문자 (예: P0003 → p0003)