import subprocess import os import re import time from pathlib import Path import logging # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s [INFO] root: %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) # --- [설정] iDRAC 접속 정보 --- IDRAC_USER = "root" IDRAC_PASS = "calvin" def resolve_output_dir() -> Path: """ 사용자가 지정한 로직에 따라 저장 위치를 결정합니다. 스크립트 위치가 /data/scripts/ 일 경우 /data/idrac_info/ 에 저장합니다. """ here = Path(__file__).resolve().parent if here.name.lower() == "scripts" and here.parent.name.lower() == "data": base = here.parent elif here.name.lower() == "scripts": base = here.parent else: base = here.parent out = base / "idrac_info" out.mkdir(parents=True, exist_ok=True) return out def run_racadm(ip: str, command: str) -> str: """racadm 명령어를 실행하고 결과를 문자열로 반환합니다.""" full_cmd = f"racadm -r {ip} -u {IDRAC_USER} -p {IDRAC_PASS} {command}" try: # 쉘 명령 실행 (stderr도 포함하여 수집) result = subprocess.check_output(full_cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) return result except subprocess.CalledProcessError as e: # 통신 실패 시 빈 문자열 반환 return "" def get_val(text: str, pattern: str) -> str: """텍스트 내에서 특정 키워드를 찾아 해당 줄의 설정값(= 이후의 값)을 추출합니다.""" for line in text.splitlines(): if re.search(pattern, line, re.IGNORECASE): parts = line.split('=') if len(parts) >= 2: return parts[1].strip() return "N/A" def fetch_idrac_info(ip: str, output_dir: Path): logging.info(f">>> {ip} 정보 수집 중...") # 1. 원시 데이터 벌크 수집 (네트워크 오버헤드 감소) getsysinfo = run_racadm(ip, "getsysinfo") hwinventory = run_racadm(ip, "hwinventory") sys_profile = run_racadm(ip, "get bios.SysProfileSettings") proc_settings = run_racadm(ip, "get bios.ProcSettings") mem_settings = run_racadm(ip, "get bios.MemSettings") storage_ctrl = run_racadm(ip, "get STORAGE.Controller.1") # 서비스 태그 추출 (파일명 결정용) svc_tag = get_val(getsysinfo, "SVC Tag") if svc_tag == "N/A": logging.error(f"[경고] {ip} 접속 실패 혹은 SVC Tag 확인 불가. 건너뜁니다.") return report_path = output_dir / f"{svc_tag}.txt" with open(report_path, "w", encoding="utf-8") as f: # 헤더 기록 f.write(f"Dell EMC Server Bios,iDRAC,R/C Setting (SVC Tag: {svc_tag})\n\n") # --- Section 1: Firmware Version 정보 --- f.write("-" * 42 + " Firmware Version 정보 " + "-" * 42 + "\n") f.write(f"1. SVC Tag : {svc_tag}\n") f.write(f"2. Bios Firmware : {get_val(getsysinfo, 'System BIOS Version')}\n") f.write(f"3. iDRAC Firmware Version : {get_val(getsysinfo, 'Firmware Version')}\n") nic1 = run_racadm(ip, "get NIC.FrmwImgMenu.1") f.write(f"4. NIC Integrated Firmware Version : {get_val(nic1, '#FamilyVersion')}\n") nic5 = run_racadm(ip, "get NIC.FrmwImgMenu.5") f.write(f"5. OnBoard NIC Firmware Version : {get_val(nic5, '#FamilyVersion')}\n") f.write(f"6. Raid Controller Firmware Version : {get_val(hwinventory, 'ControllerFirmwareVersion')}\n\n") # --- Section 2: Bios 설정 정보 --- f.write("-" * 45 + " Bios 설정 정보 " + "-" * 46 + "\n") boot_settings = run_racadm(ip, "get bios.BiosBootSettings") f.write(f"01. Bios Boot Mode : {get_val(boot_settings, 'BootMode')}\n") f.write(f"02. System Profile : {get_val(sys_profile, 'SysProfile=')}\n") f.write(f"03. CPU Power Management : {get_val(sys_profile, 'EnergyPerformanceBias')}\n") f.write(f"04. Memory Frequency : {get_val(sys_profile, 'MemFrequency')}\n") f.write(f"05. Turbo Boost : {get_val(sys_profile, 'ProcTurboMode')}\n") f.write(f"06. C1E : {get_val(sys_profile, 'ProcC1E')}\n") f.write(f"07. C-States : {get_val(sys_profile, 'ProcCStates')}\n") f.write(f"08. Monitor/Mwait : {get_val(sys_profile, 'MonitorMwait')}\n") f.write(f"09. Logical Processor : {get_val(proc_settings, 'LogicalProc')}\n") f.write(f"10. Virtualization Technology : {get_val(proc_settings, 'ProcVirtualization')}\n") f.write(f"11. LLC Prefetch : {get_val(proc_settings, 'LlcPrefetch')}\n") f.write(f"12. x2APIC Mode : {get_val(proc_settings, 'ProcX2Apic')}\n") f.write(f"13. Node Interleaving : {get_val(mem_settings, 'NodeInterleave')}\n") f.write(f"14. DIMM Self Healing : {get_val(mem_settings, 'PPROnUCE')}\n") f.write(f"15. Correctable Error Logging : {get_val(mem_settings, 'CECriticalSEL')}\n") thermal = run_racadm(ip, "get System.ThermalSettings") f.write(f"16. Thermal Profile Optimization : {get_val(thermal, 'ThermalProfile')}\n") sriov = run_racadm(ip, "get Bios.IntegratedDevices") f.write(f"17. SR-IOV Global Enable : {get_val(sriov, 'SriovGlobalEnable')}\n") misc = run_racadm(ip, "get bios.MiscSettings") f.write(f"18. F1/F2 Prompt on Error : {get_val(misc, 'ErrPrompt')}\n\n") # --- Section 3: iDRAC 설정 정보 --- f.write("-" * 45 + " iDRAC 설정 정보 " + "-" * 45 + "\n") f.write(f"01. Timezone : {get_val(run_racadm(ip, 'get iDRAC.Time.Timezone'), 'Timezone')}\n") f.write(f"02. IPMI LAN Selection : {get_val(run_racadm(ip, 'get iDRAC.CurrentNIC'), 'ActiveNIC')}\n") f.write(f"03. IPMI IP(IPv4) DHCP : {get_val(run_racadm(ip, 'get iDRAC.CurrentIPv4'), 'DHCPEnable')}\n") f.write(f"04. IPMI IP(IPv6) Enable : {get_val(run_racadm(ip, 'get iDRAC.CurrentIPv6'), 'Enable=')}\n") f.write(f"05. Redfish Support : {get_val(run_racadm(ip, 'get iDRAC.Redfish.Enable'), 'Enable=')}\n") f.write(f"06. SSH Support : {get_val(run_racadm(ip, 'get iDRAC.SSH'), 'Enable=')}\n") f.write(f"07. AD User Domain Name : {get_val(run_racadm(ip, 'get iDRAC.USERDomain.1.Name'), 'Name')}\n") f.write(f"08. SC Server Address : {get_val(run_racadm(ip, 'get iDRAC.ActiveDirectory.DomainController1'), 'DomainController1')}\n") # Syslog 관련 f.write(f"15. Remote Log (syslog) : {get_val(run_racadm(ip, 'get iDRAC.SysLog.SysLogEnable'), 'SysLogEnable')}\n") f.write(f"16. syslog server 1 : {get_val(run_racadm(ip, 'get iDRAC.SysLog.Server1'), 'Server1')}\n") f.write(f"17. syslog server 2 : {get_val(run_racadm(ip, 'get iDRAC.SysLog.Server2'), 'Server2')}\n") f.write(f"18. syslog server port : {get_val(run_racadm(ip, 'get iDRAC.SysLog.Port'), 'Port')}\n") f.write(f"19. VirtualConsole Port : {get_val(run_racadm(ip, 'get iDRAC.VirtualConsole.Port'), 'Port')}\n\n") # --- Section 4: Raid 설정 정보 --- f.write("-" * 45 + " Raid 설정 정보 " + "-" * 46 + "\n") f.write(f"01. Raid ProductName : {get_val(hwinventory, 'ProductName = BOSS')}, {get_val(hwinventory, 'ProductName = PERC')}\n") f.write(f"02. RAID Types : {get_val(hwinventory, 'RAIDTypes')}\n") f.write(f"03. StripeSize : {get_val(hwinventory, 'StripeSize')}\n") f.write(f"04. ReadCachePolicy : {get_val(hwinventory, 'ReadCachePolicy')}\n") f.write(f"05. WriteCachePolicy : {get_val(hwinventory, 'WriteCachePolicy')}\n") f.write(f"06. CheckConsistencyMode : {get_val(storage_ctrl, 'CheckConsistencyMode')}\n") f.write(f"07. PatrolReadRate : {get_val(storage_ctrl, 'PatrolReadRate')}\n") f.write(f"08. period : 168h\n") f.write(f"09. Power Save : No\n") f.write(f"10. JBODMODE : Controller does not support JBOD\n") f.write(f"11. maxconcurrentpd : 240\n") logging.info(f" ㄴ 완료: {report_path.name}") def main(): import sys if len(sys.argv) < 2: logging.error("Usage: python script.py ") return ip_file = sys.argv[1] if not os.path.exists(ip_file): logging.error(f"파일을 찾을 수 없습니다: {ip_file}") return # 저장 위치 결정 output_dir = resolve_output_dir() logging.info(f"[*] 결과 저장 폴더: {output_dir}") # 시간 측정 시작 start_time = time.time() # IP 파일 읽기 with open(ip_file, "r") as f: ips = [line.strip() for line in f if line.strip()] # 순차적 정보 수집 for ip in ips: fetch_idrac_info(ip, output_dir) # 소요 시간 계산 elapsed = time.time() - start_time hours = int(elapsed // 3600) minutes = int((elapsed % 3600) // 60) seconds = int(elapsed % 60) logging.info("=" * 50) logging.info(f"정보 수집 완료.") logging.info(f"소요 시간: {hours}시간 {minutes}분 {seconds}초") logging.info("=" * 50) if __name__ == "__main__": main()