#!/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 ") 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()