update
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user