Files
iDRAC_Info/data/scripts/unified/collect_gpu.py
T
2026-05-05 17:14:11 +09:00

124 lines
3.8 KiB
Python

#!/usr/bin/env python3
"""
통합 GPU 시리얼 수집 스크립트
hwinventory에서 Video.Slot 정보 수집
"""
import sys
import os
import re
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
import logging
sys.path.insert(0, str(Path(__file__).parent.parent))
from core.idrac_client import IDRACClient
from core.parsers import InfoParser
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [INFO] root: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
def collect_gpu_for_ip(ip: str, output_dir: Path) -> tuple:
"""단일 IP에 대한 GPU Serial 정보 수집"""
try:
logging.info(f"[{ip}] GPU 정보 수집 시작")
client = IDRACClient(ip)
# 1. Get Service Tag
sysinfo = client.get_sysinfo()
svc_tag = InfoParser.extract_service_tag(sysinfo)
if not svc_tag:
return ip, False, "서비스 태그 추출 실패"
# 2. Get Hardware Inventory
hwinventory = client.get_hwinventory()
# 3. Parse GPU Serials
gpu_map = InfoParser.extract_gpu_serials(hwinventory)
# 4. Write File
output_file = output_dir / f"{svc_tag}.txt"
# 정렬 로직 (Legacy GPU_Serial_v1.py 유지)
def slot_key(k: str):
m = re.search(r"Video\.Slot\.(\d+)-(\d+)", k)
if m:
return (int(m.group(1)), int(m.group(2)))
return (1_000_000, 1_000_000, k)
with output_file.open('w', encoding='utf-8', newline='\n') as f:
f.write(f"{svc_tag}\n")
if not gpu_map:
f.write("No GPU(Video) inventory found or SerialNumber not present.\n")
return ip, True, f"저장: {output_file.name} (GPU 없음)"
# Write individual slots
sorted_keys = sorted(gpu_map.keys(), key=slot_key)
for fqdd in sorted_keys:
serial = gpu_map[fqdd]
f.write(f"{fqdd}: {serial}\n")
# Write summary line
serials_only = [gpu_map[k] for k in sorted_keys if gpu_map[k] != "Not Found"]
if serials_only:
f.write(f"SERIALS: {';'.join(serials_only)}\n")
return ip, True, f"저장: {output_file.name} ({len(serials_only)}개 발견)"
except Exception as e:
logging.error(f"[{ip}] 오류: {e}")
return ip, False, f"오류: {e}"
def main():
if len(sys.argv) < 2:
print("Usage: python collect_gpu.py <ip_file>")
sys.exit(1)
ip_file = Path(sys.argv[1])
if not ip_file.exists():
logging.error(f"IP 파일 없음: {ip_file}")
sys.exit(1)
# 출력 디렉토리
# 출력 디렉토리 (스크립트 위치 기준)
script_dir = Path(__file__).resolve().parent
data_root = script_dir.parent.parent
output_dir = data_root / "temp" / "staging"
output_dir.mkdir(parents=True, exist_ok=True)
# IP 목록 읽기
ips = [line.strip() for line in ip_file.read_text(encoding='utf-8').splitlines() if line.strip()]
if not ips:
logging.error("IP 목록이 비어 있습니다.")
sys.exit(1)
logging.info(f"{len(ips)}대 GPU 정보 수집 시작")
# 병렬 처리
ok, fail = 0, 0
with ThreadPoolExecutor(max_workers=20) as executor:
futures = {executor.submit(collect_gpu_for_ip, ip, output_dir): ip for ip in ips}
for future in futures:
ip, success, msg = future.result()
if success:
logging.info(f"[OK] {ip} - {msg}")
ok += 1
else:
logging.error(f"[FAIL] {ip} - {msg}")
fail += 1
logging.info(f"완료: 성공 {ok}대 / 실패 {fail}")
if __name__ == "__main__":
main()