Update 2025-12-19 20:23:59
This commit is contained in:
166
data/scripts/SP_18EA_MAC_info.py
Normal file
166
data/scripts/SP_18EA_MAC_info.py
Normal file
@@ -0,0 +1,166 @@
|
||||
#!/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)
|
||||
|
||||
# 메모리 / 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"{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}초")
|
||||
Reference in New Issue
Block a user