문제: - cleanup 스크립트가 P0003 이후 삭제 시 P001, P002도 함께 삭제됨 - 문자열 비교 'P001' >= 'P0003'이 true로 평가됨 원인: - SQLite 문자열 비교에서 'P001' < 'P0003'이지만 - 'P002' >= 'P0003'은 false인데, 기존 조건이 잘못됨 해결: - LENGTH(pharmacy_code) = 5 조건 추가 - P0003 <= pharmacy_code <= P9999 범위 명시 - P001, P002 (4자), P0001, P0002 (5자) 모두 보호 변경 파일: - cleanup-test-data.sh: 삭제 쿼리 수정 - CLEANUP_TEST_DATA.md: 문서 업데이트 보호되는 약국: - P001: default 약국 (4자) - P002: 새서울약국 (4자) - P0002: 청춘약국 (5자, 범위 밖) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
259 lines
7.7 KiB
Bash
Executable File
259 lines
7.7 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# ================================
|
|
# 테스트 데이터 정리 스크립트
|
|
# ================================
|
|
#
|
|
# 용도: headscale 자동 등록 테스트 후 생성된 데이터 정리
|
|
# - farmq.db: P0003 이후 약국 삭제
|
|
# - gateway.db: ID 5 이후 사용자 삭제
|
|
# - Headscale: 테스트 노드 삭제 (선택)
|
|
#
|
|
|
|
set -e
|
|
|
|
# ================================
|
|
# 색상 정의
|
|
# ================================
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
WHITE='\033[1;37m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# ================================
|
|
# 헤더 출력
|
|
# ================================
|
|
print_header() {
|
|
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
echo -e "${WHITE}$1${NC}"
|
|
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
}
|
|
|
|
# ================================
|
|
# 1. farmq.db 테스트 약국 삭제
|
|
# ================================
|
|
cleanup_farmq_db() {
|
|
print_header "1. farmq.db 테스트 약국 정리"
|
|
|
|
FARMQ_DB="/srv/headscale-tailscale-replacement/farmq-admin/farmq.db"
|
|
|
|
if [ ! -f "$FARMQ_DB" ]; then
|
|
echo -e "${RED}✗ farmq.db를 찾을 수 없습니다: $FARMQ_DB${NC}"
|
|
return 1
|
|
fi
|
|
|
|
echo -e "${BLUE}현재 약국 목록:${NC}"
|
|
python3 << EOF
|
|
import sqlite3
|
|
conn = sqlite3.connect('$FARMQ_DB')
|
|
cursor = conn.cursor()
|
|
cursor.execute('SELECT pharmacy_code, pharmacy_name, tailscale_ip FROM pharmacies ORDER BY pharmacy_code')
|
|
for row in cursor.fetchall():
|
|
print(f' {row[0]}: {row[1]} - {row[2]}')
|
|
conn.close()
|
|
EOF
|
|
|
|
echo -e "\n${YELLOW}P0003 이후 약국을 삭제하시겠습니까? (y/N)${NC}"
|
|
read -p "> " -r response </dev/tty
|
|
|
|
if [[ "$response" =~ ^[Yy]$ ]]; then
|
|
python3 << EOF
|
|
import sqlite3
|
|
conn = sqlite3.connect('$FARMQ_DB')
|
|
cursor = conn.cursor()
|
|
# P0003~P9999만 삭제 (P001, P002, P0001, P0002는 보호)
|
|
cursor.execute("DELETE FROM pharmacies WHERE pharmacy_code >= 'P0003' AND pharmacy_code <= 'P9999' AND LENGTH(pharmacy_code) = 5")
|
|
deleted_count = cursor.rowcount
|
|
conn.commit()
|
|
conn.close()
|
|
print(f'✓ {deleted_count}개 약국 삭제 완료')
|
|
EOF
|
|
|
|
echo -e "\n${GREEN}남은 약국 목록:${NC}"
|
|
python3 << EOF
|
|
import sqlite3
|
|
conn = sqlite3.connect('$FARMQ_DB')
|
|
cursor = conn.cursor()
|
|
cursor.execute('SELECT pharmacy_code, pharmacy_name, tailscale_ip FROM pharmacies ORDER BY pharmacy_code')
|
|
for row in cursor.fetchall():
|
|
print(f' {row[0]}: {row[1]} - {row[2]}')
|
|
conn.close()
|
|
EOF
|
|
else
|
|
echo -e "${YELLOW}건너뜀${NC}"
|
|
fi
|
|
}
|
|
|
|
# ================================
|
|
# 2. gateway.db 테스트 사용자 삭제
|
|
# ================================
|
|
cleanup_gateway_db() {
|
|
print_header "2. gateway.db 테스트 사용자 정리"
|
|
|
|
GATEWAY_DB="/srv/pharmq-gateway/gateway.db"
|
|
|
|
if [ ! -f "$GATEWAY_DB" ]; then
|
|
echo -e "${RED}✗ gateway.db를 찾을 수 없습니다: $GATEWAY_DB${NC}"
|
|
return 1
|
|
fi
|
|
|
|
echo -e "${BLUE}현재 사용자 목록:${NC}"
|
|
python3 << EOF
|
|
import sqlite3
|
|
conn = sqlite3.connect('$GATEWAY_DB')
|
|
cursor = conn.cursor()
|
|
cursor.execute('SELECT id, username, name, primary_pharmacy_code FROM users ORDER BY id')
|
|
for row in cursor.fetchall():
|
|
print(f' ID {row[0]}: {row[1]} ({row[2]}) - {row[3]}')
|
|
conn.close()
|
|
EOF
|
|
|
|
echo -e "\n${YELLOW}ID 5 이후 사용자를 삭제하시겠습니까? (y/N)${NC}"
|
|
read -p "> " -r response </dev/tty
|
|
|
|
if [[ "$response" =~ ^[Yy]$ ]]; then
|
|
python3 << EOF
|
|
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')
|
|
deleted_count = cursor.rowcount
|
|
conn.commit()
|
|
conn.close()
|
|
print(f'✓ {deleted_count}명 사용자 삭제 완료')
|
|
EOF
|
|
|
|
echo -e "\n${GREEN}남은 사용자 목록:${NC}"
|
|
python3 << EOF
|
|
import sqlite3
|
|
conn = sqlite3.connect('$GATEWAY_DB')
|
|
cursor = conn.cursor()
|
|
cursor.execute('SELECT id, username, name, primary_pharmacy_code FROM users ORDER BY id')
|
|
for row in cursor.fetchall():
|
|
print(f' ID {row[0]}: {row[1]} ({row[2]}) - {row[3]}')
|
|
conn.close()
|
|
EOF
|
|
else
|
|
echo -e "${YELLOW}건너뜀${NC}"
|
|
fi
|
|
}
|
|
|
|
# ================================
|
|
# 3. Headscale 테스트 노드 삭제
|
|
# ================================
|
|
cleanup_headscale_nodes() {
|
|
print_header "3. Headscale 테스트 노드 정리"
|
|
|
|
# Docker 컨테이너 확인
|
|
if ! docker ps | grep -q headscale; then
|
|
echo -e "${RED}✗ Headscale 컨테이너를 찾을 수 없습니다${NC}"
|
|
return 1
|
|
fi
|
|
|
|
echo -e "${BLUE}현재 노드 목록:${NC}"
|
|
docker exec headscale headscale nodes list
|
|
|
|
echo -e "\n${YELLOW}삭제할 노드 ID를 입력하세요 (공백으로 구분, Enter로 건너뛰기):${NC}"
|
|
echo -e "${YELLOW}예: 13 14 15 16${NC}"
|
|
read -p "> " -r node_ids </dev/tty
|
|
|
|
if [ -z "$node_ids" ]; then
|
|
echo -e "${YELLOW}건너뜀${NC}"
|
|
return 0
|
|
fi
|
|
|
|
echo -e "\n${BLUE}노드 삭제 중...${NC}"
|
|
for id in $node_ids; do
|
|
if docker exec headscale headscale nodes delete --identifier "$id" --force 2>/dev/null; then
|
|
echo -e "${GREEN}✓ Node ID $id 삭제 완료${NC}"
|
|
else
|
|
echo -e "${RED}✗ Node ID $id 삭제 실패${NC}"
|
|
fi
|
|
done
|
|
|
|
echo -e "\n${GREEN}남은 노드 목록:${NC}"
|
|
docker exec headscale headscale nodes list
|
|
}
|
|
|
|
# ================================
|
|
# 4. 백업 생성
|
|
# ================================
|
|
create_backup() {
|
|
print_header "백업 생성 (선택)"
|
|
|
|
echo -e "${YELLOW}데이터베이스 백업을 생성하시겠습니까? (y/N)${NC}"
|
|
read -p "> " -r response </dev/tty
|
|
|
|
if [[ "$response" =~ ^[Yy]$ ]]; then
|
|
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
|
|
# farmq.db 백업
|
|
if [ -f "/srv/headscale-tailscale-replacement/farmq-admin/farmq.db" ]; then
|
|
cp /srv/headscale-tailscale-replacement/farmq-admin/farmq.db \
|
|
/srv/headscale-tailscale-replacement/farmq-admin/farmq.db.backup_$TIMESTAMP
|
|
echo -e "${GREEN}✓ farmq.db 백업 생성: farmq.db.backup_$TIMESTAMP${NC}"
|
|
fi
|
|
|
|
# gateway.db 백업
|
|
if [ -f "/srv/pharmq-gateway/gateway.db" ]; then
|
|
cp /srv/pharmq-gateway/gateway.db \
|
|
/srv/pharmq-gateway/gateway.db.backup_$TIMESTAMP
|
|
echo -e "${GREEN}✓ gateway.db 백업 생성: gateway.db.backup_$TIMESTAMP${NC}"
|
|
fi
|
|
else
|
|
echo -e "${YELLOW}백업 건너뜀${NC}"
|
|
fi
|
|
}
|
|
|
|
# ================================
|
|
# 메인 함수
|
|
# ================================
|
|
main() {
|
|
print_header "팜큐(FARMQ) 테스트 데이터 정리"
|
|
|
|
echo -e "${CYAN}이 스크립트는 다음 작업을 수행합니다:${NC}"
|
|
echo -e " 1. farmq.db에서 P0003 이후 약국 삭제"
|
|
echo -e " 2. gateway.db에서 ID 5 이후 사용자 삭제"
|
|
echo -e " 3. Headscale 테스트 노드 삭제 (선택)"
|
|
echo ""
|
|
echo -e "${YELLOW}⚠ 주의: 운영 데이터는 삭제되지 않습니다${NC}"
|
|
echo -e " - 보호되는 약국: P001, P002, P0002"
|
|
echo -e " - 보호되는 사용자: ID 1~4"
|
|
echo ""
|
|
|
|
read -p "계속하시겠습니까? (y/N) " -r response </dev/tty
|
|
if [[ ! "$response" =~ ^[Yy]$ ]]; then
|
|
echo -e "${YELLOW}취소되었습니다${NC}"
|
|
exit 0
|
|
fi
|
|
|
|
# 백업 생성 (선택)
|
|
create_backup
|
|
|
|
echo ""
|
|
|
|
# 1. farmq.db 정리
|
|
cleanup_farmq_db
|
|
|
|
echo ""
|
|
|
|
# 2. gateway.db 정리
|
|
cleanup_gateway_db
|
|
|
|
echo ""
|
|
|
|
# 3. Headscale 노드 정리
|
|
cleanup_headscale_nodes
|
|
|
|
echo ""
|
|
print_header "정리 완료!"
|
|
echo -e "${GREEN}모든 작업이 완료되었습니다.${NC}"
|
|
}
|
|
|
|
# 스크립트 실행
|
|
main "$@"
|