Files
iDRAC_Info/data/scripts/JP_54EA_MAC_info.py
2025-12-19 20:23:59 +09:00

175 lines
6.0 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
import re
import subprocess
from pathlib import Path
from typing import Optional
import logging
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [INFO] root: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
# ─────────────────────────────────────────────────────────────
# 저장 위치: data/scripts 아래에 있다면 → data/idrac_info 생성
def resolve_output_dir() -> Path:
here = Path(__file__).resolve().parent
base = here.parent if here.name.lower() == "scripts" else here
out = base / "idrac_info"
out.mkdir(parents=True, exist_ok=True)
return out
# ─────────────────────────────────────────────────────────────
# iDRAC 접속 계정
IDRAC_USER = "root"
IDRAC_PASS = "calvin"
def run(cmd: list[str]) -> str:
"""racadm 명령 실행 (stdout 수집)"""
try:
return subprocess.getoutput(" ".join(cmd))
except Exception:
return ""
def parse_single_value(pattern: str, text: str) -> Optional[str]:
"""단일 값 추출용"""
m = re.search(pattern, text, flags=re.IGNORECASE)
return m.group(1).strip() if m else None
def find_mac_by_fqdd(fqdd: str, text: str) -> Optional[str]:
"""
swinventory 출력에서 FQDD = {fqdd} 라인을 찾고,
그 주변(±10줄) 내에서 MAC 주소를 추출.
"""
lines = text.splitlines()
for i, line in enumerate(lines):
if f"FQDD = {fqdd}" in line:
for j in range(max(0, i - 10), min(i + 10, len(lines))):
m = re.search(r"([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})", lines[j])
if m:
return m.group(1)
return None
def extract_vendors(hwinventory: str) -> tuple[str, str]:
"""
[InstanceID: DIMM...] 또는 [InstanceID: Disk.Bay...] 블록 내 Manufacturer 추출
"""
# Memory Vendors
mem_vendors = re.findall(
r"\[InstanceID:\s*DIMM[^\]]*\][^\[]*?Manufacturer\s*=\s*([^\n\r]+)",
hwinventory,
flags=re.IGNORECASE
)
mem_vendors = [v.strip() for v in mem_vendors if v.strip()]
memory = ", ".join(sorted(set(mem_vendors))) if mem_vendors else "Not Found"
# SSD Vendors
ssd_vendors = re.findall(
r"\[InstanceID:\s*Disk\.Bay[^\]]*\][^\[]*?Manufacturer\s*=\s*([^\n\r]+)",
hwinventory,
flags=re.IGNORECASE
)
ssd_vendors = [v.strip() for v in ssd_vendors if v.strip()]
ssd = ", ".join(sorted(set(ssd_vendors))) if ssd_vendors else "Not Found"
return memory, ssd
def fetch_idrac_info_one(ip: str, output_dir: Path) -> None:
"""단일 서버 iDRAC 정보 수집"""
logging.info(f"[+] Collecting iDRAC info from {ip} ...")
getsysinfo = run(["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "getsysinfo"])
hwinventory = run(["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "hwinventory"])
swinventory = run(["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "swinventory"])
# 서비스 태그
svc_tag = parse_single_value(r"SVC\s*Tag\s*=\s*(\S+)", getsysinfo)
if not svc_tag:
logging.error(f"[!] Failed to retrieve SVC Tag for IP: {ip}")
return
# iDRAC MAC
idrac_mac = parse_single_value(r"MAC\s*Address\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
# NIC.Integrated / Onboard MAC
integrated_1 = parse_single_value(r"NIC\.Integrated\.1-1-1\s+Ethernet\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
integrated_2 = parse_single_value(r"NIC\.Integrated\.1-2-1\s+Ethernet\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
onboard_1 = parse_single_value(r"NIC\.Embedded\.1-1-1\s+Ethernet\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
onboard_2 = parse_single_value(r"NIC\.Embedded\.2-1-1\s+Ethernet\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
# NIC Slot별 MAC
NIC_Slot_2_1 = find_mac_by_fqdd("NIC.Slot.2-1-1", swinventory)
NIC_Slot_2_2 = find_mac_by_fqdd("NIC.Slot.2-2-1", swinventory)
NIC_Slot_3_1 = find_mac_by_fqdd("NIC.Slot.3-1-1", swinventory)
NIC_Slot_3_2 = find_mac_by_fqdd("NIC.Slot.3-2-1", swinventory)
# 메모리 / SSD 제조사
memory, ssd = extract_vendors(hwinventory)
# 결과 파일 저장
out_file = output_dir / f"{svc_tag}.txt"
with out_file.open("w", encoding="utf-8", newline="\n") as f:
f.write(f"{svc_tag}\n")
f.write(f"{integrated_1 or ''}\n")
f.write(f"{integrated_2 or ''}\n")
f.write(f"{onboard_1 or ''}\n")
f.write(f"{onboard_2 or ''}\n")
f.write(f"{NIC_Slot_2_1 or ''}\n")
f.write(f"{NIC_Slot_2_2 or ''}\n")
f.write(f"{idrac_mac or ''}\n")
f.write(f"{memory}\n")
f.write(f"{ssd}\n")
logging.info(f"[✔] {svc_tag} ({ip}) info saved.")
def main(ip_file: str) -> None:
ip_path = Path(ip_file)
if not ip_path.is_file():
logging.error(f"[!] IP file {ip_file} does not exist.")
return
output_dir = resolve_output_dir()
ips = [line.strip() for line in ip_path.read_text(encoding="utf-8").splitlines() if line.strip()]
if not ips:
logging.error("[!] No IP addresses found in the file.")
return
for ip in ips:
try:
fetch_idrac_info_one(ip, output_dir)
except Exception as e:
logging.error(f"[!] Error processing {ip}: {e}")
try:
ip_path.unlink(missing_ok=True)
except Exception:
pass
logging.info("\n정보 수집 완료.")
if __name__ == "__main__":
import sys, time
if len(sys.argv) != 2:
logging.error("Usage: python script.py <ip_file>")
sys.exit(1)
start = time.time()
main(sys.argv[1])
end = time.time()
elapsed = int(end - start)
h, m, s = elapsed // 3600, (elapsed % 3600) // 60, elapsed % 60
logging.info(f"수집 완료 시간: {h}시간 {m}{s}")