From 9d5d2b8d9969f1d0d2f9615ba0ad5ac963d34259 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 19 Dec 2025 20:23:59 +0900 Subject: [PATCH] Update 2025-12-19 20:23:59 --- data/scripts/01-settings.py | 18 +- data/scripts/02-set_config.py | 7 +- data/scripts/03-tsr_log.py | 27 +- data/scripts/04-tsr_save.py | 27 +- data/scripts/06-PowerON.py | 27 +- data/scripts/07-PowerOFF.py | 27 +- data/scripts/08-job_delete_all.py | 27 +- data/scripts/09-Log_Viewer.py | 6 +- data/scripts/AMD_Server_Info.py | 206 ++++++++++++ data/scripts/GPU_Serial_v1.py | 20 +- data/scripts/Intel_Server_info.py | 192 +++++++++++ data/scripts/JP_54EA_MAC_info.py | 174 ++++++++++ data/scripts/MAC_info.py | 234 ++++++++++++++ data/scripts/PortGUID.py | 20 +- data/scripts/PortGUID_v1.py | 20 +- data/scripts/SP_18EA_MAC_info.py | 166 ++++++++++ data/scripts/TYPE11_MAC_info.py | 158 ++++++---- data/scripts/TYPE11_Server_info.py | 19 +- data/scripts/TYPE8A_Server_info.sh | 316 ------------------- data/scripts/XE9680_H200_IB_10EA_MAC_info.py | 27 +- data/scripts/collect_idrac_info.py | 27 +- idrac-info.service | 29 ++ 22 files changed, 1302 insertions(+), 472 deletions(-) create mode 100644 data/scripts/AMD_Server_Info.py create mode 100644 data/scripts/Intel_Server_info.py create mode 100644 data/scripts/JP_54EA_MAC_info.py create mode 100644 data/scripts/MAC_info.py create mode 100644 data/scripts/SP_18EA_MAC_info.py delete mode 100644 data/scripts/TYPE8A_Server_info.sh create mode 100644 idrac-info.service diff --git a/data/scripts/01-settings.py b/data/scripts/01-settings.py index 14069a2..18f5ecd 100644 --- a/data/scripts/01-settings.py +++ b/data/scripts/01-settings.py @@ -3,6 +3,14 @@ import subprocess import time from dotenv import load_dotenv from concurrent.futures import ThreadPoolExecutor +import logging + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) # .env 파일 로드 load_dotenv() @@ -99,9 +107,9 @@ def fetch_idrac_info(ip_address): f.write(f"01. RAID Settings - Raid ProductName : {get_value(hwinventory, 'ProductName = PERC')}\n") f.write(f"02. RAID Settings - Raid Types : No-Raid mode\n") - print(f"IP {ip_address} 에 대한 정보를 {output_file} 에 저장했습니다.") + logging.info(f"IP {ip_address} 에 대한 정보를 {output_file} 에 저장했습니다.") except Exception as e: - print(f"오류 발생: {e}") + logging.error(f"오류 발생: {e}") # 명령 결과에서 원하는 값 가져오기 def get_value(output, key): @@ -117,7 +125,7 @@ start_time = time.time() if __name__ == "__main__": import sys if len(sys.argv) != 2: - print(f"Usage: {sys.argv[0]} ") + logging.error(f"Usage: {sys.argv[0]} ") sys.exit(1) ip_file_path = validate_ip_file(sys.argv[1]) @@ -138,5 +146,5 @@ elapsed_hours = int(elapsed_time // 3600) elapsed_minutes = int((elapsed_time % 3600) // 60) elapsed_seconds = int(elapsed_time % 60) -print("정보 수집 완료.") -print(f"수집 완료 시간: {elapsed_hours} 시간, {elapsed_minutes} 분, {elapsed_seconds} 초.") +logging.info("정보 수집 완료.") +logging.info(f"수집 완료 시간: {elapsed_hours} 시간, {elapsed_minutes} 분, {elapsed_seconds} 초.") diff --git a/data/scripts/02-set_config.py b/data/scripts/02-set_config.py index c54d711..6412a85 100644 --- a/data/scripts/02-set_config.py +++ b/data/scripts/02-set_config.py @@ -16,7 +16,8 @@ RACADM = os.getenv("RACADM_PATH", "racadm") # PATH에 있으면 'racadm' # 로깅 logging.basicConfig( level=logging.INFO, - format="%(asctime)s - %(levelname)s - %(message)s" + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' ) def read_ip_list(ip_file: Path): @@ -66,7 +67,7 @@ def apply_xml(ip: str, xml_path: Path) -> tuple[bool, str]: # 대안: # cmd = [RACADM, "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "set", "-t", "xml", "-f", str(safe_path)] - logging.info("실행 명령(리스트) → %s", " ".join(cmd)) + logging.info(f"실행 명령(리스트) → {' '.join(cmd)}") try: p = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", shell=False, timeout=180) stdout = (p.stdout or "").strip() @@ -88,7 +89,7 @@ def apply_xml(ip: str, xml_path: Path) -> tuple[bool, str]: def main(): if len(sys.argv) != 3: - print("Usage: python 02-set_config.py ") + logging.error("Usage: python 02-set_config.py ") sys.exit(1) ip_file = Path(sys.argv[1]) diff --git a/data/scripts/03-tsr_log.py b/data/scripts/03-tsr_log.py index 6f4e6e8..5607686 100644 --- a/data/scripts/03-tsr_log.py +++ b/data/scripts/03-tsr_log.py @@ -4,6 +4,14 @@ import time from dotenv import load_dotenv import sys from multiprocessing import Pool +import logging + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) # 환경 변수 로드 load_dotenv() # .env 파일에서 환경 변수 로드 @@ -14,26 +22,27 @@ IDRAC_USER, IDRAC_PASS = os.getenv("IDRAC_USER"), os.getenv("IDRAC_PASS") # IP 주소 파일 로드 함수 def load_ip_file(ip_file_path): if not os.path.isfile(ip_file_path): - sys.exit(f"IP file {ip_file_path} does not exist.") + logging.error(f"IP file {ip_file_path} does not exist.") + sys.exit(1) with open(ip_file_path, "r") as file: return [line.strip() for line in file if line.strip()] # iDRAC 정보를 가져오는 함수 정의 def fetch_idrac_info(idrac_ip): - print(f"Collecting TSR report for iDRAC IP: {idrac_ip}") + logging.info(f"Collecting TSR report for iDRAC IP: {idrac_ip}") try: result = subprocess.run( ["racadm", "-r", idrac_ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "techsupreport", "collect"], capture_output=True, text=True ) - print( - f"Successfully collected TSR report for {idrac_ip}" - if result.returncode == 0 - else f"Failed to collect TSR report for {idrac_ip}: {result.stderr.strip()}" - ) + if result.returncode == 0: + logging.info(f"Successfully collected TSR report for {idrac_ip}") + else: + logging.error(f"Failed to collect TSR report for {idrac_ip}: {result.stderr.strip()}") + except Exception as e: - print(f"Exception occurred for {idrac_ip}: {e}") + logging.error(f"Exception occurred for {idrac_ip}: {e}") # 메인 함수 if __name__ == "__main__": @@ -48,4 +57,4 @@ if __name__ == "__main__": pool.map(fetch_idrac_info, ip_list) elapsed_time = time.time() - start_time - print(f"설정 완료. 수집 완료 시간: {int(elapsed_time // 3600)} 시간, {int((elapsed_time % 3600) // 60)} 분, {int(elapsed_time % 60)} 초.") \ No newline at end of file + logging.info(f"설정 완료. 수집 완료 시간: {int(elapsed_time // 3600)} 시간, {int((elapsed_time % 3600) // 60)} 분, {int(elapsed_time % 60)} 초.") \ No newline at end of file diff --git a/data/scripts/04-tsr_save.py b/data/scripts/04-tsr_save.py index 0393a76..10bf36b 100644 --- a/data/scripts/04-tsr_save.py +++ b/data/scripts/04-tsr_save.py @@ -3,6 +3,14 @@ import subprocess from dotenv import load_dotenv import sys from multiprocessing import Pool +import logging + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) # 환경 변수 로드 load_dotenv() # .env 파일에서 환경 변수 로드 @@ -16,13 +24,14 @@ OME_PASS = os.getenv("OME_PASS") # IP 주소 파일 로드 및 유효성 검사 def load_ip_file(ip_file_path): if not os.path.isfile(ip_file_path): - sys.exit(f"IP file {ip_file_path} does not exist.") + logging.error(f"IP file {ip_file_path} does not exist.") + sys.exit(1) with open(ip_file_path, "r") as file: return [line.strip() for line in file if line.strip()] # iDRAC 정보를 가져오는 함수 def fetch_idrac_info(idrac_ip): - print(f"Collecting TSR report for iDRAC IP: {idrac_ip}") + logging.info(f"Collecting TSR report for iDRAC IP: {idrac_ip}") try: result = subprocess.run( [ @@ -32,13 +41,13 @@ def fetch_idrac_info(idrac_ip): capture_output=True, text=True ) - print( - f"Successfully collected TSR report for {idrac_ip}" - if result.returncode == 0 - else f"Failed to collect TSR report for {idrac_ip}: {result.stderr.strip()}" - ) + if result.returncode == 0: + logging.info(f"Successfully collected TSR report for {idrac_ip}") + else: + logging.error(f"Failed to collect TSR report for {idrac_ip}: {result.stderr.strip()}") + except Exception as e: - print(f"Exception occurred for {idrac_ip}: {e}") + logging.error(f"Exception occurred for {idrac_ip}: {e}") # 메인 함수 if __name__ == "__main__": @@ -51,4 +60,4 @@ if __name__ == "__main__": with Pool() as pool: pool.map(fetch_idrac_info, ip_list) - print("설정 완료.") + logging.info("설정 완료.") diff --git a/data/scripts/06-PowerON.py b/data/scripts/06-PowerON.py index 39d3df4..9da663c 100644 --- a/data/scripts/06-PowerON.py +++ b/data/scripts/06-PowerON.py @@ -4,6 +4,14 @@ import time from dotenv import load_dotenv import sys from multiprocessing import Pool +import logging + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) # Load environment variables load_dotenv() # Load variables from .env file @@ -14,26 +22,27 @@ IDRAC_USER, IDRAC_PASS = os.getenv("IDRAC_USER"), os.getenv("IDRAC_PASS") # Load IP addresses from file def load_ip_file(ip_file_path): if not os.path.isfile(ip_file_path): - sys.exit(f"IP file {ip_file_path} does not exist.") + logging.error(f"IP file {ip_file_path} does not exist.") + sys.exit(1) with open(ip_file_path, "r") as file: return [line.strip() for line in file if line.strip()] # Power on the server for given iDRAC IP def poweron_idrac_server(idrac_ip): - print(f"Powering on server for iDRAC IP: {idrac_ip}") + logging.info(f"Powering on server for iDRAC IP: {idrac_ip}") try: result = subprocess.run( ["racadm", "-r", idrac_ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "serveraction", "powerup"], capture_output=True, text=True ) - print( - f"Successfully powered on server for {idrac_ip}" - if result.returncode == 0 - else f"Failed to power on server for {idrac_ip}: {result.stderr.strip()}" - ) + if result.returncode == 0: + logging.info(f"Successfully powered on server for {idrac_ip}") + else: + logging.error(f"Failed to power on server for {idrac_ip}: {result.stderr.strip()}") + except Exception as e: - print(f"Exception occurred for {idrac_ip}: {e}") + logging.error(f"Exception occurred for {idrac_ip}: {e}") # Main function if __name__ == "__main__": @@ -48,4 +57,4 @@ if __name__ == "__main__": pool.map(poweron_idrac_server, ip_list) elapsed_time = time.time() - start_time - print(f"Server Power On 완료. 완료 시간: {int(elapsed_time // 3600)} 시간, {int((elapsed_time % 3600) // 60)} 분, {int(elapsed_time % 60)} 초.") \ No newline at end of file + logging.info(f"Server Power On 완료. 완료 시간: {int(elapsed_time // 3600)} 시간, {int((elapsed_time % 3600) // 60)} 분, {int(elapsed_time % 60)} 초.") \ No newline at end of file diff --git a/data/scripts/07-PowerOFF.py b/data/scripts/07-PowerOFF.py index 288e936..23e932c 100644 --- a/data/scripts/07-PowerOFF.py +++ b/data/scripts/07-PowerOFF.py @@ -4,6 +4,14 @@ import time from dotenv import load_dotenv import sys from multiprocessing import Pool +import logging + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) # Load environment variables load_dotenv() # Load variables from .env file @@ -14,26 +22,27 @@ IDRAC_USER, IDRAC_PASS = os.getenv("IDRAC_USER"), os.getenv("IDRAC_PASS") # Load IP addresses from file def load_ip_file(ip_file_path): if not os.path.isfile(ip_file_path): - sys.exit(f"IP file {ip_file_path} does not exist.") + logging.error(f"IP file {ip_file_path} does not exist.") + sys.exit(1) with open(ip_file_path, "r") as file: return [line.strip() for line in file if line.strip()] # Power off the server for given iDRAC IP def poweroff_idrac_server(idrac_ip): - print(f"Powering off server for iDRAC IP: {idrac_ip}") + logging.info(f"Powering off server for iDRAC IP: {idrac_ip}") try: result = subprocess.run( ["racadm", "-r", idrac_ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "serveraction", "powerdown"], capture_output=True, text=True ) - print( - f"Successfully powered off server for {idrac_ip}" - if result.returncode == 0 - else f"Failed to power off server for {idrac_ip}: {result.stderr.strip()}" - ) + if result.returncode == 0: + logging.info(f"Successfully powered off server for {idrac_ip}") + else: + logging.error(f"Failed to power off server for {idrac_ip}: {result.stderr.strip()}") + except Exception as e: - print(f"Exception occurred for {idrac_ip}: {e}") + logging.error(f"Exception occurred for {idrac_ip}: {e}") # Main function if __name__ == "__main__": @@ -48,4 +57,4 @@ if __name__ == "__main__": pool.map(poweroff_idrac_server, ip_list) elapsed_time = time.time() - start_time - print(f"Server Power Off 완료. 완료 시간: {int(elapsed_time // 3600)} 시간, {int((elapsed_time % 3600) // 60)} 분, {int(elapsed_time % 60)} 초.") \ No newline at end of file + logging.info(f"Server Power Off 완료. 완료 시간: {int(elapsed_time // 3600)} 시간, {int((elapsed_time % 3600) // 60)} 분, {int(elapsed_time % 60)} 초.") \ No newline at end of file diff --git a/data/scripts/08-job_delete_all.py b/data/scripts/08-job_delete_all.py index 22353c1..9a20c9e 100644 --- a/data/scripts/08-job_delete_all.py +++ b/data/scripts/08-job_delete_all.py @@ -4,6 +4,14 @@ import time from dotenv import load_dotenv import sys from multiprocessing import Pool +import logging + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) # Load environment variables load_dotenv() # Load variables from .env file @@ -14,26 +22,27 @@ IDRAC_USER, IDRAC_PASS = os.getenv("IDRAC_USER"), os.getenv("IDRAC_PASS") # Load IP addresses from file def load_ip_file(ip_file_path): if not os.path.isfile(ip_file_path): - sys.exit(f"IP file {ip_file_path} does not exist.") + logging.error(f"IP file {ip_file_path} does not exist.") + sys.exit(1) with open(ip_file_path, "r") as file: return [line.strip() for line in file if line.strip()] # Delete all jobs for given iDRAC IP def delete_all_jobs(idrac_ip): - print(f"Deleting all jobs for iDRAC IP: {idrac_ip}") + logging.info(f"Deleting all jobs for iDRAC IP: {idrac_ip}") try: result = subprocess.run( ["racadm", "-r", idrac_ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "jobqueue", "delete", "-i", "ALL"], capture_output=True, text=True ) - print( - f"Successfully deleted all jobs for {idrac_ip}" - if result.returncode == 0 - else f"Failed to delete jobs for {idrac_ip}: {result.stderr.strip()}" - ) + if result.returncode == 0: + logging.info(f"Successfully deleted all jobs for {idrac_ip}") + else: + logging.error(f"Failed to delete jobs for {idrac_ip}: {result.stderr.strip()}") + except Exception as e: - print(f"Exception occurred for {idrac_ip}: {e}") + logging.error(f"Exception occurred for {idrac_ip}: {e}") # Main function if __name__ == "__main__": @@ -48,4 +57,4 @@ if __name__ == "__main__": pool.map(delete_all_jobs, ip_list) elapsed_time = time.time() - start_time - print(f"Job delete 완료. 완료 시간: {int(elapsed_time // 3600)} 시간, {int((elapsed_time % 3600) // 60)} 분, {int(elapsed_time % 60)} 초.") \ No newline at end of file + logging.info(f"Job delete 완료. 완료 시간: {int(elapsed_time // 3600)} 시간, {int((elapsed_time % 3600) // 60)} 분, {int(elapsed_time % 60)} 초.") \ No newline at end of file diff --git a/data/scripts/09-Log_Viewer.py b/data/scripts/09-Log_Viewer.py index d7de63e..5d1cf4c 100644 --- a/data/scripts/09-Log_Viewer.py +++ b/data/scripts/09-Log_Viewer.py @@ -9,7 +9,11 @@ from concurrent.futures import ThreadPoolExecutor load_dotenv() # 로깅 설정 -logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) logger = logging.getLogger(__name__) # 사용자 이름 및 비밀번호 설정 diff --git a/data/scripts/AMD_Server_Info.py b/data/scripts/AMD_Server_Info.py new file mode 100644 index 0000000..a2deda8 --- /dev/null +++ b/data/scripts/AMD_Server_Info.py @@ -0,0 +1,206 @@ +import subprocess +import sys +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: + 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, *args): + """racadm 명령어를 실행하고 결과를 반환합니다.""" + cmd = ["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS] + list(args) + try: + result = subprocess.run(cmd, capture_output=True, text=True, check=True, timeout=30) + return result.stdout + except Exception as e: + # 에러 발생 시 빈 문자열 반환 (스크립트 중단 방지) + return "" + +def extract_value(text, pattern, delimiter='='): + """텍스트에서 특정 키의 값을 추출하고 공백을 제거합니다.""" + for line in text.splitlines(): + if re.search(pattern, line, re.IGNORECASE): + if delimiter in line: + # '=' 기준으로 쪼갠 후 값만 가져와서 공백 제거 + return line.split(delimiter, 1)[1].strip() + return "N/A" + +# ───────────────────────────────────────────────────────────── +# 메인 수집 함수 +def fetch_idrac_info(ip, output_dir): + logging.info(f">>> [{ip}] 데이터 수집 시작...") + + # 1. 원본 데이터 덩어리 가져오기 (API 호출 최소화) + hwinventory = run_racadm(ip, "hwinventory") + getsysinfo = run_racadm(ip, "getsysinfo") + 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 = extract_value(getsysinfo, "SVC Tag") + if svc_tag == "N/A": + logging.error(f"!!! [{ip}] SVC Tag 추출 실패. 작업을 건너뜁니다.") + return + + output_file = output_dir / f"{svc_tag}.txt" + + with open(output_file, "w", encoding="utf-8") as f: + # 헤더 작성 + f.write(f"Dell EMC Server Bios,iDRAC,R/C Setting (SVC Tag: {svc_tag})\n\n") + + # --- 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 : {extract_value(getsysinfo, 'System BIOS Version')}\n") + f.write(f"3. iDRAC Firmware Version : {extract_value(getsysinfo, 'Firmware Version')}\n") + + # NIC 펌웨어 (별도 호출 필요) + nic1 = run_racadm(ip, "get", "NIC.FrmwImgMenu.1") + nic5 = run_racadm(ip, "get", "NIC.FrmwImgMenu.5") + f.write(f"4. NIC Integrated Firmware Version : {extract_value(nic1, '#FamilyVersion')}\n") + f.write(f"5. OnBoard NIC Firmware Version : {extract_value(nic5, '#FamilyVersion')}\n") + f.write(f"6. Raid Controller Firmware Version : {extract_value(hwinventory, 'ControllerFirmwareVersion')}\n\n") + + # --- 2. Bios 설정 정보 --- + f.write("-" * 45 + " Bios 설정 정보 " + "-" * 45 + "\n") + boot_mode = run_racadm(ip, "get", "bios.BiosBootSettings") + f.write(f"01. Bios Boot Mode : {extract_value(boot_mode, 'BootMode')}\n") + f.write(f"02. System Profile Settings - System Profile : {extract_value(sys_profile, 'SysProfile=')}\n") + f.write(f"03. System Profile Settings - CPU Power Management : {extract_value(sys_profile, 'ProcPwrPerf')}\n") + f.write(f"04. System Profile Settings - Memory Frequency : {extract_value(sys_profile, 'MemFrequency')}\n") + f.write(f"05. System Profile Settings - Turbo Boost : {extract_value(sys_profile, 'ProcTurboMode')}\n") + f.write(f"06. System Profile Settings - PCI ASPM L1 Link Power Management : {extract_value(sys_profile, 'PcieAspmL1')}\n") + f.write(f"07. System Profile Settings - C-States : {extract_value(sys_profile, 'ProcCStates')}\n") + f.write(f"08. System Profile Settings - Determinism Slider : {extract_value(sys_profile, 'DeterminismSlider')}\n") + f.write(f"08-2. System Profile Settings - Dynamic Link Width Management (DLWM) : {extract_value(sys_profile, 'DynamicLinkWidthManagement')}\n") + + f.write(f"09. Processor Settings - Logical Processor : {extract_value(proc_settings, 'LogicalProc')}\n") + f.write(f"10. Processor Settings - Virtualization Technology : {extract_value(proc_settings, 'ProcVirtualization')}\n") + f.write(f"11. Processor Settings - NUMA Nodes Per Socket : {extract_value(proc_settings, 'NumaNodesPerSocket')}\n") + f.write(f"12. Processor Settings - x2APIC Mode : {extract_value(proc_settings, 'ProcX2Apic')}\n") + + f.write(f"13. Memory Settings - Dram Refresh Delay : {extract_value(mem_settings, 'DramRefreshDelay')}\n") + f.write(f"14. Memory Settings - DIMM Self Healing (PPR) : {extract_value(mem_settings, 'PPROnUCE')}\n") + f.write(f"15. Memory Settings - Correctable Error Logging : {extract_value(mem_settings, 'CECriticalSEL')}\n") + + thermal = run_racadm(ip, "get", "System.ThermalSettings") + f.write(f"16. System Settings - Thermal Profile Optimization : {extract_value(thermal, 'ThermalProfile')}\n") + + integrated = run_racadm(ip, "get", "Bios.IntegratedDevices") + f.write(f"17. Integrated Devices Settings - SR-IOV Global Enable : {extract_value(integrated, 'SriovGlobalEnable')}\n") + + misc = run_racadm(ip, "get", "bios.MiscSettings") + f.write(f"18. Miscellaneous Settings - F1/F2 Prompt on Error : {extract_value(misc, 'ErrPrompt')}\n\n") + + # --- 3. iDRAC 설정 정보 --- + f.write("-" * 45 + " iDRAC 설정 정보 " + "-" * 45 + "\n") + f.write(f"01. iDRAC Settings - Timezone : {extract_value(run_racadm(ip, 'get', 'iDRAC.Time.Timezone'), 'Timezone')}\n") + f.write(f"02. iDRAC Settings - IPMI LAN Selection : {extract_value(run_racadm(ip, 'get', 'iDRAC.CurrentNIC'), 'ActiveNIC')}\n") + f.write(f"03. iDRAC Settings - IPMI IP(IPv4) : {extract_value(run_racadm(ip, 'get', 'iDRAC.CurrentIPv4'), 'DHCPEnable')}\n") + f.write(f"04. iDRAC Settings - IPMI IP(IPv6) : {extract_value(run_racadm(ip, 'get', 'iDRAC.CurrentIPv6'), 'Enable=')}\n") + f.write(f"05. iDRAC Settings - Redfish Support : {extract_value(run_racadm(ip, 'get', 'iDRAC.Redfish.Enable'), 'Enable=')}\n") + f.write(f"06. iDRAC Settings - SSH Support : {extract_value(run_racadm(ip, 'get', 'iDRAC.SSH'), 'Enable=')}\n") + + # AD 관련 설정 (AD Group 1, 2 포함) + f.write(f"07. iDRAC Settings - AD User Domain Name : {extract_value(run_racadm(ip, 'get', 'iDRAC.USERDomain.1.Name'), 'Name')}\n") + f.write(f"08. iDRAC Settings - SC Server Address : {extract_value(run_racadm(ip, 'get', 'iDRAC.ActiveDirectory.DomainController1'), 'DomainController1')}\n") + f.write(f"09. iDRAC Settings - SE AD RoleGroup Name : {extract_value(run_racadm(ip, 'get', 'iDRAC.ADGroup.1.Name'), 'Name')}\n") + f.write(f"10. iDRAC Settings - SE AD RoleGroup Domain : {extract_value(run_racadm(ip, 'get', 'iDRAC.ADGroup.1.Domain'), 'Domain')}\n") + f.write(f"11. iDRAC Settings - SE AD RoleGroup Privilege : {extract_value(run_racadm(ip, 'get', 'iDRAC.ADGroup.1.Privilege'), 'Privilege')}\n") + f.write(f"12. iDRAC Settings - IDC AD RoleGroup Name : {extract_value(run_racadm(ip, 'get', 'iDRAC.ADGroup.2.Name'), 'Name')}\n") + f.write(f"13. iDRAC Settings - IDC AD RoleGroup Domain : {extract_value(run_racadm(ip, 'get', 'iDRAC.ADGroup.2.Domain'), 'Domain')}\n") + f.write(f"14. iDRAC Settings - IDC AD RoleGroup Privilege : {extract_value(run_racadm(ip, 'get', 'iDRAC.ADGroup.2.Privilege'), 'Privilege')}\n") + + # Syslog 및 기타 + f.write(f"15. iDRAC Settings - Remote Log (syslog) : {extract_value(run_racadm(ip, 'get', 'iDRAC.SysLog.SysLogEnable'), 'SysLogEnable')}\n") + f.write(f"16. iDRAC Settings - syslog server address 1 : {extract_value(run_racadm(ip, 'get', 'iDRAC.SysLog.Server1'), 'Server1')}\n") + f.write(f"17. iDRAC Settings - syslog server address 2 : {extract_value(run_racadm(ip, 'get', 'iDRAC.SysLog.Server2'), 'Server2')}\n") + f.write(f"18. iDRAC Settings - syslog server port : {extract_value(run_racadm(ip, 'get', 'iDRAC.SysLog.Port'), 'Port')}\n") + f.write(f"19. iDRAC Settings - Remote KVM Nonsecure port : {extract_value(run_racadm(ip, 'get', 'iDRAC.VirtualConsole.Port'), 'Port')}\n\n") + + # --- 4. Raid 설정 정보 (주석 해제 버전) --- + f.write("-" * 45 + " Raid 설정 정보 " + "-" * 45 + "\n") + f.write(f"01. RAID Settings - Raid ProductName : {extract_value(hwinventory, 'ProductName = PERC')}\n") + f.write(f"02. RAID Settings - Raid Types : {extract_value(hwinventory, 'RAIDTypes')}\n") + f.write(f"03. RAID Settings - StripeSize : {extract_value(hwinventory, 'StripeSize')}\n") + f.write(f"04. RAID Settings - ReadCachePolicy : {extract_value(hwinventory, 'ReadCachePolicy')}\n") + f.write(f"05. RAID Settings - WriteCachePolicy : {extract_value(hwinventory, 'WriteCachePolicy')}\n") + f.write(f"06. RAID Settings - CheckConsistencyRate : {extract_value(storage_ctrl, 'CheckConsistencyRate')}\n") + f.write(f"07. RAID Settings - PatrolReadMode : {extract_value(storage_ctrl, 'PatrolReadMode')}\n") + f.write(f"08. RAID Settings - period : 168h\n") + f.write(f"09. RAID Settings - Power Save : No\n") + f.write(f"10. RAID Settings - JBODMODE : Controller does not support JBOD\n") + f.write(f"11. RAID Settings - maxconcurrentpd : 240\n") + + logging.info(f"✅ [{ip}] 저장 완료: {output_file.name}") + +# ───────────────────────────────────────────────────────────── +# 실행 흐름 제어 +def main(): + if len(sys.argv) < 2: + logging.error(f"사용법: python {sys.argv[0]} ") + sys.exit(1) + + ip_file = Path(sys.argv[1]) + if not ip_file.exists(): + logging.error(f"오류: IP 파일 '{ip_file}'이 존재하지 않습니다.") + sys.exit(1) + + output_dir = resolve_output_dir() + start_time = time.time() + + # IP 목록 읽기 + with open(ip_file, "r") as f: + ips = [line.strip() for line in f if line.strip()] + + # 각 IP별로 수집 실행 + for ip in ips: + try: + fetch_idrac_info(ip, output_dir) + except Exception as e: + logging.error(f"❌ [{ip}] 처리 중 예외 발생: {e}") + + # 소요 시간 계산 + end_time = time.time() + elapsed = end_time - start_time + hours, rem = divmod(elapsed, 3600) + minutes, seconds = divmod(rem, 60) + + logging.info("="*50) + logging.info("정보 수집 완료.") + logging.info(f"총 소요 시간: {int(hours)}시간 {int(minutes)}분 {int(seconds)}초") + logging.info(f"저장 경로: {output_dir}") + logging.info("="*50) + +if __name__ == "__main__": + main() diff --git a/data/scripts/GPU_Serial_v1.py b/data/scripts/GPU_Serial_v1.py index 1949399..cdd8c3d 100644 --- a/data/scripts/GPU_Serial_v1.py +++ b/data/scripts/GPU_Serial_v1.py @@ -3,9 +3,17 @@ import re import subprocess from pathlib import Path from concurrent.futures import ThreadPoolExecutor, as_completed +import logging from dotenv import load_dotenv, find_dotenv +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) + # ───────────────────────────────────────────────────────────── # .env 자동 탐색 로드 (현재 파일 기준 상위 디렉터리까지 검색) load_dotenv(find_dotenv()) @@ -86,7 +94,7 @@ def fetch_idrac_info(idrac_ip: str, output_dir: Path) -> None: svc_tag = svc_tag_match.group(1) if svc_tag_match else None if not svc_tag: - print(f"Failed to retrieve SVC Tag for IP: {idrac_ip}") + logging.error(f"Failed to retrieve SVC Tag for IP: {idrac_ip}") return # 전체 하드웨어 인벤토리 @@ -125,13 +133,13 @@ def fetch_idrac_info(idrac_ip: str, output_dir: Path) -> None: f.write(f"SERIALS: {';'.join(serials_only)}\n") except Exception as e: - print(f"Error processing IP {idrac_ip}: {e}") + logging.error(f"Error processing IP {idrac_ip}: {e}") def main(ip_file: str) -> None: ip_path = Path(ip_file) if not ip_path.is_file(): - print(f"IP file {ip_file} does not exist.") + logging.error(f"IP file {ip_file} does not exist.") return output_dir = resolve_output_dir() @@ -146,14 +154,14 @@ def main(ip_file: str) -> None: ip = future_to_ip[future] try: future.result() - print(f"✅ Completed: {ip}") + logging.info(f"✅ Completed: {ip}") except Exception as e: - print(f"❌ Error processing {ip}: {e}") + logging.error(f"❌ Error processing {ip}: {e}") if __name__ == "__main__": import sys if len(sys.argv) != 2: - print("Usage: python GPU_Serial_v1.py ") + logging.error("Usage: python GPU_Serial_v1.py ") sys.exit(1) main(sys.argv[1]) diff --git a/data/scripts/Intel_Server_info.py b/data/scripts/Intel_Server_info.py new file mode 100644 index 0000000..3458ac3 --- /dev/null +++ b/data/scripts/Intel_Server_info.py @@ -0,0 +1,192 @@ +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() diff --git a/data/scripts/JP_54EA_MAC_info.py b/data/scripts/JP_54EA_MAC_info.py new file mode 100644 index 0000000..a30dde1 --- /dev/null +++ b/data/scripts/JP_54EA_MAC_info.py @@ -0,0 +1,174 @@ +#!/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 ") + 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}초") diff --git a/data/scripts/MAC_info.py b/data/scripts/MAC_info.py new file mode 100644 index 0000000..b565ba9 --- /dev/null +++ b/data/scripts/MAC_info.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import re +import subprocess +from pathlib import Path +from typing import Optional, List +import logging + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) + +# ───────────────────────────────────────────────────────────── +# 출력 디렉토리 결정 +def resolve_output_dir() -> Path: + here = Path(__file__).resolve().parent + if here.name.lower() == "scripts" and here.parent.name.lower() == "data": + base = here.parent + else: + base = here.parent + + 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 + + +# ───────────────────────────────────────────────────────────── +# NIC MAC 수집 (가변 포트 대응) +def extract_nic_macs(text: str, nic_type: str) -> List[str]: + """ + nic_type: + - 'Integrated' + - 'Embedded' + """ + pattern = re.compile( + rf"NIC\.{nic_type}\.\d+-\d+-\d+.*?([0-9A-Fa-f]{{2}}(?::[0-9A-Fa-f]{{2}}){{5}})", + re.IGNORECASE + ) + return sorted(set(m.group(1) for m in pattern.finditer(text))) + + +# ───────────────────────────────────────────────────────────── +# hwinventory 블록 기반 Manufacturer 추출 (DIMM) +def extract_memory_vendors(hwinventory: str) -> List[str]: + vendors = set() + blocks = re.split(r"\n\s*\n", hwinventory) + + for block in blocks: + if "[InstanceID: DIMM." in block: + m = re.search(r"Manufacturer\s*=\s*(.+)", block, re.IGNORECASE) + if m: + vendors.add(m.group(1).strip()) + + return sorted(vendors) + + +# ───────────────────────────────────────────────────────────── +# BOSS 디스크 Vendor 추출 +def extract_boss_vendors(hwinventory: str) -> List[str]: + vendors = set() + blocks = re.split(r"\n\s*\n", hwinventory) + + for block in blocks: + if "BOSS." in block: + m = re.search(r"Manufacturer\s*=\s*(.+)", block, re.IGNORECASE) + if m: + vendors.add(m.group(1).strip()) + + return sorted(vendors) + + +# ───────────────────────────────────────────────────────────── +# 일반 Disk Vendor (BOSS 제외) +DISK_PREFIXES = [ + "Disk.Bay.", + "Disk.M.2.", + "Disk.Direct.", + "Disk.Slot." +] + + +def extract_disk_vendors_excluding_boss(hwinventory: str) -> List[str]: + vendors = set() + blocks = re.split(r"\n\s*\n", hwinventory) + + for block in blocks: + if "BOSS." in block: + continue + + for prefix in DISK_PREFIXES: + if f"[InstanceID: {prefix}" in block: + m = re.search(r"Manufacturer\s*=\s*(.+)", block, re.IGNORECASE) + if m: + vendors.add(m.group(1).strip()) + + return sorted(vendors) + + +# ───────────────────────────────────────────────────────────── +def fetch_idrac_info_one(ip: str, output_dir: Path) -> None: + getsysinfo = run([ + "racadm", "-r", ip, + "-u", IDRAC_USER, + "-p", IDRAC_PASS, + "getsysinfo" + ]) + + hwinventory = run([ + "racadm", "-r", ip, + "-u", IDRAC_USER, + "-p", IDRAC_PASS, + "hwinventory" + ]) + + # ── Service Tag + svc_tag = parse_single_value(r"SVC\s*Tag\s*=\s*(\S+)", getsysinfo) + if not svc_tag: + logging.error(f"[ERROR] SVC Tag 수집 실패: {ip}") + return + + # ── iDRAC MAC + idrac_mac = parse_single_value( + r"MAC Address\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo + ) + + # ── NIC MAC + integrated_macs = extract_nic_macs(getsysinfo, "Integrated") + embedded_macs = extract_nic_macs(getsysinfo, "Embedded") + + # ── Vendors + memory_vendors = extract_memory_vendors(hwinventory) + disk_vendors = extract_disk_vendors_excluding_boss(hwinventory) + boss_vendors = extract_boss_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") + + for mac in integrated_macs: + f.write(f"{mac}\n") + + for mac in embedded_macs: + f.write(f"{mac}\n") + + f.write(f"{idrac_mac or ''}\n") + + # Memory Vendors + for v in memory_vendors: + f.write(f"{v}\n") + + # Disk Vendors (일반) + for v in disk_vendors: + f.write(f"{v}\n") + + # BOSS Vendors (있을 때만, 벤더명만) + for v in boss_vendors: + f.write(f"{v}\n") + + logging.info(f"[OK] {svc_tag} 수집 완료") + + +# ───────────────────────────────────────────────────────────── +def main(ip_file: str) -> None: + ip_path = Path(ip_file) + if not ip_path.is_file(): + logging.error(f"[ERROR] IP 파일 없음: {ip_file}") + 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("[ERROR] IP 목록이 비어 있습니다.") + return + + for ip in ips: + try: + fetch_idrac_info_one(ip, output_dir) + except Exception as e: + logging.error(f"[ERROR] {ip} 처리 실패: {e}") + + # Bash 스크립트와 동일하게 입력 IP 파일 삭제 + try: + ip_path.unlink(missing_ok=True) + except Exception: + pass + + logging.info("정보 수집 완료.") + + +# ───────────────────────────────────────────────────────────── +if __name__ == "__main__": + import sys + import time + + if len(sys.argv) != 2: + logging.error("Usage: python script.py ") + sys.exit(1) + + start = time.time() + main(sys.argv[1]) + elapsed = int(time.time() - start) + + h, m, s = elapsed // 3600, (elapsed % 3600) // 60, elapsed % 60 + logging.info(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.") diff --git a/data/scripts/PortGUID.py b/data/scripts/PortGUID.py index 1cf108a..8ca8a73 100644 --- a/data/scripts/PortGUID.py +++ b/data/scripts/PortGUID.py @@ -3,6 +3,14 @@ import re import subprocess from dotenv import load_dotenv from concurrent.futures import ThreadPoolExecutor, as_completed +import logging + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) # .env 파일에서 사용자 이름 및 비밀번호 설정 load_dotenv() @@ -18,7 +26,7 @@ def fetch_idrac_info(idrac_ip, output_dir): svc_tag = svc_tag_match.group(1) if svc_tag_match else None if not svc_tag: - print(f"Failed to retrieve SVC Tag for IP: {idrac_ip}") + logging.error(f"Failed to retrieve SVC Tag for IP: {idrac_ip}") return # InfiniBand.VndrConfigPage 목록 가져오기 @@ -58,13 +66,15 @@ def fetch_idrac_info(idrac_ip, output_dir): # 모든 PortGUID를 "GUID: 0x;0x" 형식으로 저장 if hex_guid_list: f.write(f"GUID: {';'.join(hex_guid_list)}\n") + + logging.info(f"✅ Completed: {idrac_ip}") except Exception as e: - print(f"Error processing IP {idrac_ip}: {e}") + logging.error(f"Error processing IP {idrac_ip}: {e}") def main(ip_file): if not os.path.isfile(ip_file): - print(f"IP file {ip_file} does not exist.") + logging.error(f"IP file {ip_file} does not exist.") return output_dir = "/app/idrac_info/idrac_info" @@ -80,12 +90,12 @@ def main(ip_file): try: future.result() except Exception as e: - print(f"Error processing task: {e}") + logging.error(f"Error processing task: {e}") if __name__ == "__main__": import sys if len(sys.argv) != 2: - print("Usage: python script.py ") + logging.error("Usage: python script.py ") sys.exit(1) ip_file = sys.argv[1] diff --git a/data/scripts/PortGUID_v1.py b/data/scripts/PortGUID_v1.py index a6686b3..eb965ed 100644 --- a/data/scripts/PortGUID_v1.py +++ b/data/scripts/PortGUID_v1.py @@ -3,9 +3,17 @@ import re import subprocess from pathlib import Path from concurrent.futures import ThreadPoolExecutor, as_completed +import logging from dotenv import load_dotenv, find_dotenv +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) + # ───────────────────────────────────────────────────────────── # .env 자동 탐색 로드 (현재 파일 기준 상위 디렉터리까지 검색) load_dotenv(find_dotenv()) @@ -47,7 +55,7 @@ def fetch_idrac_info(idrac_ip: str, output_dir: Path) -> None: svc_tag = svc_tag_match.group(1) if svc_tag_match else None if not svc_tag: - print(f"Failed to retrieve SVC Tag for IP: {idrac_ip}") + logging.error(f"Failed to retrieve SVC Tag for IP: {idrac_ip}") return # InfiniBand.VndrConfigPage 목록 가져오기 @@ -110,13 +118,13 @@ def fetch_idrac_info(idrac_ip: str, output_dir: Path) -> None: f.write(f"GUID: {';'.join(hex_guid_list)}\n") except Exception as e: - print(f"Error processing IP {idrac_ip}: {e}") + logging.error(f"Error processing IP {idrac_ip}: {e}") def main(ip_file: str) -> None: ip_path = Path(ip_file) if not ip_path.is_file(): - print(f"IP file {ip_file} does not exist.") + logging.error(f"IP file {ip_file} does not exist.") return output_dir = resolve_output_dir() # ← 여기서 OS 무관 저장 위치 확정 (data/idrac_info) @@ -133,15 +141,15 @@ def main(ip_file: str) -> None: ip = future_to_ip[future] try: future.result() - print(f"✅ Completed: {ip}") + logging.info(f"Completed: {ip}") except Exception as e: - print(f"❌ Error processing {ip}: {e}") + logging.error(f"Error processing {ip}: {e}") if __name__ == "__main__": import sys if len(sys.argv) != 2: - print("Usage: python script.py ") + logging.error("Usage: python script.py ") sys.exit(1) main(sys.argv[1]) diff --git a/data/scripts/SP_18EA_MAC_info.py b/data/scripts/SP_18EA_MAC_info.py new file mode 100644 index 0000000..4bc226f --- /dev/null +++ b/data/scripts/SP_18EA_MAC_info.py @@ -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 ") + 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}초") diff --git a/data/scripts/TYPE11_MAC_info.py b/data/scripts/TYPE11_MAC_info.py index 70ad37c..3fcb18b 100644 --- a/data/scripts/TYPE11_MAC_info.py +++ b/data/scripts/TYPE11_MAC_info.py @@ -6,37 +6,43 @@ 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 -# 그 외 위치여도 이 파일의 상위 폴더에 idrac_info 생성 +# 저장 위치 결정 def resolve_output_dir() -> Path: - here = Path(__file__).resolve().parent # 예: .../data/scripts + here = Path(__file__).resolve().parent if here.name.lower() == "scripts" and here.parent.name.lower() == "data": - base = here.parent # 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 # ───────────────────────────────────────────────────────────── -# 사용자 이름 및 비밀번호 (Bash 스크립트와 동일하게 하드코딩) +# iDRAC 계정 IDRAC_USER = "root" IDRAC_PASS = "calvin" def run(cmd: list[str]) -> str: - """racadm 호출을 간단히 실행 (stdout만 수집)""" + """racadm 명령 실행 (stdout만 반환)""" try: - # join하여 getoutput로 호출 (Bash와 비슷한 동작) return subprocess.getoutput(" ".join(cmd)) - except Exception as e: - return f"" # 실패 시 빈 문자열 + except Exception: + return "" def parse_single_value(pattern: str, text: str) -> Optional[str]: @@ -44,61 +50,81 @@ def parse_single_value(pattern: str, text: str) -> Optional[str]: return m.group(1).strip() if m else None -def parse_mac_list_from_lines(text: str, fqdd_key: str) -> Optional[str]: +# ───────────────────────────────────────────────────────────── +# hwinventory 블록 기반 Manufacturer 추출 (핵심 수정 부분) +def extract_manufacturers(hwinventory: str, instance_prefix: str) -> list[str]: """ - 특정 FQDD 라인을 찾아 MAC 주소를 반환하는 간단한 도우미. - (Bash의 grep/awk 파이프를 정규표현식으로 대체) + instance_prefix: + - 'DIMM.' → 메모리 + - 'Disk.Bay.' → 디스크 """ - # MAC 주소 패턴 - mac_pat = r"([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})" - # 해당 FQDD 문자열이 포함된 줄과 가까운 곳에서 MAC을 찾는 간단한 방식 - # (원 스크립트는 awk로 이전 줄을 보는 등 상세하지만 여기선 단순화) - block_pat = rf"{re.escape(fqdd_key)}.*?{mac_pat}" - m = re.search(block_pat, text, flags=re.IGNORECASE | re.DOTALL) - if m: - return m.group(1) - # 라인 전체에서 MAC만 스캔하는 fallback - m2 = re.search(mac_pat, text, flags=re.IGNORECASE) - return m2.group(1) if m2 else None + vendors = [] + + blocks = re.split(r"\n\s*\n", hwinventory) + for block in blocks: + if f"[InstanceID: {instance_prefix}" in block: + m = re.search(r"Manufacturer\s*=\s*(.+)", block, re.IGNORECASE) + if m: + vendors.append(m.group(1).strip()) + + return vendors def fetch_idrac_info_one(ip: str, output_dir: Path) -> None: - # getsysinfo / hwinventory 호출 - getsysinfo = run(["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "getsysinfo"]) - hwinventory = run(["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "hwinventory"]) + getsysinfo = run([ + "racadm", "-r", ip, + "-u", IDRAC_USER, + "-p", IDRAC_PASS, + "getsysinfo" + ]) - # 서비스 태그 + hwinventory = run([ + "racadm", "-r", ip, + "-u", IDRAC_USER, + "-p", IDRAC_PASS, + "hwinventory" + ]) + + # ── Service Tag svc_tag = parse_single_value(r"SVC\s*Tag\s*=\s*(\S+)", getsysinfo) if not svc_tag: - print(f"Failed to retrieve SVC Tag for IP: {ip}") + logging.error(f"[ERROR] SVC Tag 수집 실패: {ip}") return - # iDRAC MAC - idrac_mac = parse_single_value(r"MAC Address\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo) + # ── iDRAC MAC + idrac_mac = parse_single_value( + r"MAC Address\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo + ) - # NIC.Integrated MAC (1-1-1, 1-2-1) - integrated_1 = parse_single_value(r"NIC\.Integrated\.1-1-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})", - getsysinfo) - integrated_2 = parse_single_value(r"NIC\.Integrated\.1-2-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})", - getsysinfo) + # ── Integrated NIC + integrated_1 = parse_single_value( + r"NIC\.Integrated\.1-1-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})", + getsysinfo + ) + integrated_2 = parse_single_value( + r"NIC\.Integrated\.1-2-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})", + getsysinfo + ) - # Onboard MAC (Embedded 1-1-1, 2-1-1) - onboard_1 = parse_single_value(r"NIC\.Embedded\.1-1-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})", - getsysinfo) - onboard_2 = parse_single_value(r"NIC\.Embedded\.2-1-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})", - getsysinfo) + # ── Embedded NIC + onboard_1 = parse_single_value( + r"NIC\.Embedded\.1-1-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})", + getsysinfo + ) + onboard_2 = parse_single_value( + r"NIC\.Embedded\.2-1-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})", + getsysinfo + ) - # 벤더(메모리/SSD) 첫 글자 모음 (원 스크립트는 uniq+sort+cut -c1) - # 여기서는 Manufacturer= 값을 수집해 첫 글자만 취합 후 중복 제거. - mem_vendors = re.findall(r"DIMM.*?Manufacturer\s*=\s*(.+)", hwinventory, flags=re.IGNORECASE) - mem_vendors = [v.strip() for v in mem_vendors if v.strip()] - memory = "".join(sorted(set(v[0] for v in mem_vendors if v))) + # ───────────────────────────────────────────── + # Memory / Disk Vendor (수정 완료) + mem_vendors = sorted(set(extract_manufacturers(hwinventory, "DIMM."))) + ssd_vendors = sorted(set(extract_manufacturers(hwinventory, "Disk.Bay."))) - ssd_vendors = re.findall(r"Disk\.Bay.*?Manufacturer\s*=\s*(.+)", hwinventory, flags=re.IGNORECASE) - ssd_vendors = [v.strip() for v in ssd_vendors if v.strip()] - ssd = "".join(sorted(set(v[0] for v in ssd_vendors if v))) + memory = "\n".join(mem_vendors) + ssd = "\n".join(ssd_vendors) - # 파일 저장 + # ── 결과 파일 저장 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") @@ -110,47 +136,53 @@ def fetch_idrac_info_one(ip: str, output_dir: Path) -> None: f.write(f"{memory}\n") f.write(f"{ssd}\n") + logging.info(f"[OK] {svc_tag} 수집 완료") + def main(ip_file: str) -> None: ip_path = Path(ip_file) if not ip_path.is_file(): - print(f"IP file {ip_file} does not exist.") + logging.error(f"[ERROR] IP 파일 없음: {ip_file}") return output_dir = resolve_output_dir() - # Bash 스크립트는 파일 전체를 cat 하여 '하나의 IP'로 사용했지만, - # 여기서는 줄 단위로 모두 처리(한 줄만 있어도 동일하게 동작). - ips = [line.strip() for line in ip_path.read_text(encoding="utf-8").splitlines() if line.strip()] + ips = [ + line.strip() + for line in ip_path.read_text(encoding="utf-8").splitlines() + if line.strip() + ] + if not ips: - print("No IP addresses found in the file.") + logging.error("[ERROR] IP 목록이 비어 있습니다.") return - # 순차 처리 (필요하면 ThreadPoolExecutor로 병렬화 가능) for ip in ips: try: fetch_idrac_info_one(ip, output_dir) except Exception as e: - print(f"Error processing {ip}: {e}") + logging.error(f"[ERROR] {ip} 처리 실패: {e}") - # 원본 Bash는 마지막에 입력 파일 삭제: rm -f $IP_FILE + # 원본 Bash 스크립트 동작 유지 try: ip_path.unlink(missing_ok=True) except Exception: pass - print("정보 수집 완료.") + logging.info("정보 수집 완료.") if __name__ == "__main__": - import sys, time + import sys + import time + if len(sys.argv) != 2: - print("Usage: python script.py ") + logging.error("Usage: python script.py ") sys.exit(1) start = time.time() main(sys.argv[1]) - end = time.time() - elapsed = int(end - start) + elapsed = int(time.time() - start) + h, m, s = elapsed // 3600, (elapsed % 3600) // 60, elapsed % 60 - print(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.") + logging.info(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.") diff --git a/data/scripts/TYPE11_Server_info.py b/data/scripts/TYPE11_Server_info.py index d4f3feb..0e4ff6d 100644 --- a/data/scripts/TYPE11_Server_info.py +++ b/data/scripts/TYPE11_Server_info.py @@ -6,7 +6,14 @@ import re import time import subprocess 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' +) # ───────────────────────────────────────────────────────────── # 저장 위치: 이 파일이 data/scripts/ 아래 있으면 → data/idrac_info @@ -168,7 +175,7 @@ def fetch_idrac_info(ip: str, output_dir: Path) -> None: r"Port") if not svc_tag: - print(f"Failed to retrieve SVC Tag for IP: {ip}") + logging.error(f"Failed to retrieve SVC Tag for IP: {ip}") return out_file = output_dir / f"{svc_tag}.txt" @@ -227,7 +234,7 @@ def fetch_idrac_info(ip: str, output_dir: Path) -> None: def main(ip_file: str) -> None: ip_path = Path(ip_file) if not ip_path.is_file(): - print(f"Usage: python script.py \nIP file {ip_file} does not exist.") + logging.error(f"Usage: python script.py \nIP file {ip_file} does not exist.") return output_dir = resolve_output_dir() @@ -237,7 +244,7 @@ def main(ip_file: str) -> None: lines = [ln.strip() for ln in ip_path.read_text(encoding="utf-8", errors="ignore").splitlines()] ip = next((ln for ln in lines if ln), None) if not ip: - print("No IP address found in the file.") + logging.error("No IP address found in the file.") return start = time.time() @@ -252,13 +259,13 @@ def main(ip_file: str) -> None: elapsed = int(end - start) h, m, s = elapsed // 3600, (elapsed % 3600) // 60, elapsed % 60 - print("정보 수집 완료.") - print(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.") + logging.info("정보 수집 완료.") + logging.info(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.") if __name__ == "__main__": import sys if len(sys.argv) != 2: - print("Usage: python script.py ") + logging.error("Usage: python script.py ") sys.exit(1) main(sys.argv[1]) \ No newline at end of file diff --git a/data/scripts/TYPE8A_Server_info.sh b/data/scripts/TYPE8A_Server_info.sh deleted file mode 100644 index e8db4ea..0000000 --- a/data/scripts/TYPE8A_Server_info.sh +++ /dev/null @@ -1,316 +0,0 @@ -#!/bin/bash - -# 사용자 이름 및 비밀번호 설정 -IDRAC_USER="root" -IDRAC_PASS="calvin" - -# IP 주소 파일 경로 인자 받기 -if [ -z "$1" ]; then - echo "Usage: $0 " - exit 1 -fi - -IP_FILE=$1 - -if [ ! -f "$IP_FILE" ]; then - echo "IP file $IP_FILE does not exist." - exit 1 -fi - -# 정보 저장 디렉터리 설정 -OUTPUT_DIR="idrac_info" -mkdir -p $OUTPUT_DIR - -# iDRAC 정보를 가져오는 함수 정의 -fetch_idrac_info() { - local IDRAC_IP=$(cat $IP_FILE) - - # 모든 hwinventory 저장 - local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory) - # 모든 샷시 정보 저장 - local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo) - # 모든 SysProfileSettings 저장 - local SysProfileSettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.SysProfileSettings) - # ProcessorSettings 저장 - local ProcessorSettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.ProcSettings) - # Memory Settings 저장 - local MemorySettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.MemSettings) - # Raid Settings 저장 - local STORAGEController=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get STORAGE.Controller.1) - - # 서비스 태그 가져오기 - local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # Bios Firmware Version 확인 - local Bios_firmware=$(echo "$getsysinfo" | grep -i "System BIOS Version" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Firmware Version 확인 - local iDRAC_firmware=$(echo "$getsysinfo" | grep -i "Firmware Version" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # Intel NIC Firmware Version 확인 - local Intel_NIC_firmware=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get NIC.FrmwImgMenu.1 | grep -i "#FamilyVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # OnBoard NIC Firmware Version 확인 - local Onboard_NIC_firmware=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get NIC.FrmwImgMenu.5 | grep -i "#FamilyVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # R/C Firmware Version 확인 - local Raid_firmware=$(echo "$hwinventory" | grep -i "ControllerFirmwareVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # Bios 설정 Boot Mode 확인 - local Bios_BootMode=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.BiosBootSettings | grep -i "BootMode" | awk -F '=' '{print $2}' | tr -d '[:space:]') - - # Bios SysProfileSettings 설정 정보 확인 - local SysProFileSettings_info1=$(echo "$SysProfileSettings" | grep -i "SysProfile=" | awk -F '=' '{print $2}' | tr -d '[:space:]') - local SysProFileSettings_info2=$(echo "$SysProfileSettings" | grep -i "ProcPwrPerf" | awk -F '=' '{print $2}' | tr -d '[:space:]') - local SysProFileSettings_info3=$(echo "$SysProfileSettings" | grep -i "MemFrequency" | awk -F '=' '{print $2}' | tr -d '[:space:]') - local SysProFileSettings_info4=$(echo "$SysProfileSettings" | grep -i "ProcTurboMode" | awk -F '=' '{print $2}' | tr -d '[:space:]') - local SysProFileSettings_info5=$(echo "$SysProfileSettings" | grep -i "PcieAspmL1" | awk -F '=' '{print $2}' | tr -d '[:space:]') - local SysProFileSettings_info6=$(echo "$SysProfileSettings" | grep -i "ProcCStates" | awk -F '=' '{print $2}' | tr -d '[:space:]') - local SysProFileSettings_info7=$(echo "$SysProfileSettings" | grep -i "DeterminismSlider" | awk -F '=' '{print $2}' | tr -d '[:space:]') - local SysProFileSettings_info8=$(echo "$SysProfileSettings" | grep -i "DynamicLinkWidthManagement" | awk -F '=' '{print $2}' | tr -d '[:space:]') - - # Processor Settings - Logical Processor - local ProcessorSettings_info1=$(echo "$ProcessorSettings" | grep -i "LogicalProc" | awk -F '=' '{print $2}' | tr -d '[:space:]') - local ProcessorSettings_info2=$(echo "$ProcessorSettings" | grep -i "ProcVirtualization" | awk -F '=' '{print $2}' | tr -d '[:space:]') - local ProcessorSettings_info3=$(echo "$ProcessorSettings" | grep -i "NumaNodesPerSocket" | awk -F '=' '{print $2}' | tr -d '[:space:]') - local ProcessorSettings_info4=$(echo "$ProcessorSettings" | grep -i "ProcX2Apic" | awk -F '=' '{print $2}' | tr -d '[:space:]') - - # Memory Settings - Node Interleaving - local MemorySettings_info1=$(echo "$MemorySettings" | grep -i "DramRefreshDelay" | awk -F '=' '{print $2}' | tr -d '[:space:]') - local MemorySettings_info2=$(echo "$MemorySettings" | grep -i "PPROnUCE" | awk -F '=' '{print $2}' | tr -d '[:space:]') - local MemorySettings_info3=$(echo "$MemorySettings" | grep -i "CECriticalSEL" | awk -F '=' '{print $2}' | tr -d '[:space:]') - - # System Settings - Thermal Profile Optimization - local SystemSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get System.ThermalSettings | grep -i "ThermalProfile" | awk -F '=' '{print $2}') - # Integrated Devices Settings - SR-IOV Global Enable - local IntegratedDevicesSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get Bios.IntegratedDevices | grep -i "SriovGlobalEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # Miscellaneous Settings - F1/F2 Prompt on Error - local IMiscellaneousSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.MiscSettings | grep -i "ErrPrompt" | awk -F '=' '{print $2}' | tr -d '[:space:]') - - # iDRAC Settings - Timezone - local iDRAC_Settings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.Time.Timezone | grep -i "Timezone" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - IPMI LAN Selection - local iDRAC_Settings_info2=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentNIC | grep -i "ActiveNIC" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - IPMI IP(IPv4) - local iDRAC_Settings_info3=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentIPv4 | grep -i "DHCPEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - IPMI IP(IPv6) - local iDRAC_Settings_info4=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentIPv6 | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - Redfish Support - local iDRAC_Settings_info5=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.Redfish.Enable | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - SSH Support - local iDRAC_Settings_info6=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SSH | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - AD User Domain Name - local iDRAC_Settings_info7=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.USERDomain.1.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - SC Server Address - local iDRAC_Settings_info8=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ActiveDirectory.DomainController1 | grep -i "DomainController1" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - SE AD RoleGroup Name - local iDRAC_Settings_info9=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - SE AD RoleGroup Dome인 - local iDRAC_Settings_info10=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Domain | grep -i "Domain" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - SE AD RoleGroup Privilege - local iDRAC_Settings_info11=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Privilege | grep -i "Privilege" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - IDC AD RoleGroup name - local iDRAC_Settings_info12=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - IDC AD RoleGroup Dome인 - local iDRAC_Settings_info13=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Domain | grep -i "Domain" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - IDC AD RoleGroup Privilege - local iDRAC_Settings_info14=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Privilege | grep -i "Privilege" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - Remote Log (syslog) - local iDRAC_Settings_info15=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.SysLogEnable | grep -i "SysLogEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - syslog server address 1 - local iDRAC_Settings_info16=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Server1 | grep -i "Server1" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - syslog server address 2 - local iDRAC_Settings_info17=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Server2 | grep -i "Server2" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - syslog server port - local iDRAC_Settings_info18=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Port | grep -i "Port" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # iDRAC Settings - VirtualConsole Port - local iDRAC_Settings_info19=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.VirtualConsole.Port | grep -i "Port" | awk -F '=' '{print $2}' | tr -d '[:space:]') - - # RAID Settings - ProductName - local RAID_info0=$(echo "$hwinventory" | grep -i "ProductName = PERC" | awk -F '=' '{print $2}') - # RAID Settings - RAIDType - local RAID_info1=$(echo "$hwinventory" | grep -i "RAIDTypes" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # RAID Settings - StripeSize - local RAID_info2=$(echo "$hwinventory" | grep -i "StripeSize" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # RAID Settings - ReadCachePolicy - local RAID_info3=$(echo "$hwinventory" | grep -i "ReadCachePolicy" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # RAID Settings - WriteCachePolicy - local RAID_info4=$(echo "$hwinventory" | grep -i "WriteCachePolicy" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # RAID Settings - PatrolReadRate - local RAID_info5=$(echo "$STORAGEController" | grep -i "CheckConsistencyRate" | awk -F '=' '{print $2}' | tr -d '[:space:]') - # RAID Settings - PatrolReadRate - local RAID_info6=$(echo "$STORAGEController" | grep -i "PatrolReadMode" | awk -F '=' '{print $2}' | tr -d '[:space:]') - - # 서비스 태그가 존재하는지 확인 - if [ -z "$SVC_TAG" ]; then - echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP" - return - fi - - local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt" - echo "Dell EMC Server Bios,iDRAC,R/C Setting (SVC Tag: $SVC_TAG)" | tee -a "$OUTPUT_FILE" - echo -e "\n" >> "$OUTPUT_FILE" - echo "------------------------------------------Firware Version 정보------------------------------------------" >> "$OUTPUT_FILE" - # SVC Tag 확인 - echo "1. SVC Tag : $SVC_TAG" >> "$OUTPUT_FILE" - - # Bios Firmware Version 확인 - echo "2. Bios Firmware : $Bios_firmware" >> "$OUTPUT_FILE" - - # iDRAC Firmware Version 확인 - echo "3. iDRAC Firmware Version : $iDRAC_firmware" >> "$OUTPUT_FILE" - - # Intel NIC Firmware Version 확인 - echo "4. NIC Integrated Firmware Version : $Intel_NIC_firmware" >> "$OUTPUT_FILE" - - # OnBoard NIC Firmware Version 확인 - echo "5. OnBoard NIC Firmware Version : $Onboard_NIC_firmware" >> "$OUTPUT_FILE" - - # Raid Controller Firmware Version 확인 - echo "6. Raid Controller Firmware Version : $Raid_firmware" >> "$OUTPUT_FILE" - echo -e "\n" >> "$OUTPUT_FILE" - - echo "---------------------------------------------Bios 설정 정보----------------------------------------------" >> "$OUTPUT_FILE" - # bios Boot Mode 확인 - echo "01. Bios Boot Mode : $Bios_BootMode" >> "$OUTPUT_FILE" - - # SysProfileSettings - System Profile - echo "02. System Profile Settings - System Profile : $SysProFileSettings_info1" >> "$OUTPUT_FILE" - - # SysProfileSettings - CPU Power Management - echo "03. System Profile Settings - CPU Power Management : $SysProFileSettings_info2" >> "$OUTPUT_FILE" - - # SysProfileSettings - Memory Frequency - echo "04. System Profile Settings - Memory Frequency : $SysProFileSettings_info3" >> "$OUTPUT_FILE" - - # SysProfileSettings - Turbo Boost - echo "05. System Profile Settings - Turbo Boost : $SysProFileSettings_info4" >> "$OUTPUT_FILE" - - # SysProfileSettings - C1E - echo "06. System Profile Settings - PCI ASPM L1 Link Power Management : $SysProFileSettings_info5" >> "$OUTPUT_FILE" - - # SysProfileSettings - C-States - echo "07. System Profile Settings - C-States : $SysProFileSettings_info6" >> "$OUTPUT_FILE" - - # SysProfileSettings - Determinism Slider - echo "08. System Profile Settings - Determinism Slider : $SysProFileSettings_info7" >> "$OUTPUT_FILE" - - # SysProfileSettings - Dynamic Link Width Management (DLWM) - echo "08. System Profile Settings - Dynamic Link Width Management (DLWM) : $SysProFileSettings_info8" >> "$OUTPUT_FILE" - - # Processor Settings - Logical Processor - echo "09. Processor Settings - Logical Processor : $ProcessorSettings_info1" >> "$OUTPUT_FILE" - - # Processor Settings - Virtualization Technology - echo "10. Processor Settings - Virtualization Technology : $ProcessorSettings_info2" >> "$OUTPUT_FILE" - - # Processor Settings - NUMA Nodes Per Socket - echo "11. Processor Settings - NUMA Nodes Per Socket : $ProcessorSettings_info3" >> "$OUTPUT_FILE" - - # Processor Settings - x2APIC Mode - echo "12. Processor Settings - x2APIC Mode : $ProcessorSettings_info4" >> "$OUTPUT_FILE" - - # Memory Settings - Dram Refresh Delayg - echo "13. Memory Settings - Dram Refresh Delay : $MemorySettings_info1" >> "$OUTPUT_FILE" - - # Memory Settings - DIMM Self Healing (Post Package Repair) on Uncorrectable Memory Error - echo "14. Memory Settings - DIMM Self Healing (Post Package Repair) on Uncorrectable Memory Error : $MemorySettings_info2" >> "$OUTPUT_FILE" - - # Memory Settings - Correctable Error Logging - echo "15. Memory Settings - Correctable Error Logging : $MemorySettings_info3" >> "$OUTPUT_FILE" - - # System Settings - Thermal Profile Optimization - echo "16. System Settings - Thermal Profile Optimization : $SystemSettings_info1" >> "$OUTPUT_FILE" - - # Integrated Devices Settings - SR-IOV Global Enable - echo "17. Integrated Devices Settings - SR-IOV Global Enable : $IntegratedDevicesSettings_info1" >> "$OUTPUT_FILE" - - # Miscellaneous Settings - F1/F2 Prompt on Error - echo "18. Miscellaneous Settings - F1/F2 Prompt on Error : $IMiscellaneousSettings_info1" >> "$OUTPUT_FILE" - echo -e "\n" >> "$OUTPUT_FILE" - - echo "---------------------------------------------iDRAC 설정 정보----------------------------------------------" >> "$OUTPUT_FILE" - # iDRAC Settings - Timezone - echo "01. iDRAC Settings - Timezone : $iDRAC_Settings_info1" >> "$OUTPUT_FILE" - # iDRAC Settings - IPMI LAN Selection - echo "02. iDRAC Settings - IPMI LAN Selection : $iDRAC_Settings_info2" >> "$OUTPUT_FILE" - # iDRAC Settings - IPMI IP(IPv4) - echo "03. iDRAC Settings - IPMI IP(IPv4) : $iDRAC_Settings_info3" >> "$OUTPUT_FILE" - # iDRAC Settings - IPMI IP(IPv6) - echo "04. iDRAC Settings - IPMI IP(IPv6) : $iDRAC_Settings_info4" >> "$OUTPUT_FILE" - # iDRAC Settings - Redfish Support - echo "05. iDRAC Settings - Redfish Support : $iDRAC_Settings_info5" >> "$OUTPUT_FILE" - # iDRAC Settings - SSH Support - echo "06. iDRAC Settings - SSH Support : $iDRAC_Settings_info6" >> "$OUTPUT_FILE" - # iDRAC Settings - AD User Domain Name - echo "07. iDRAC Settings - AD User Domain Name : $iDRAC_Settings_info7" >> "$OUTPUT_FILE" - # iDRAC Settings - SC Server Address - echo "08. iDRAC Settings - SC Server Address : $iDRAC_Settings_info8" >> "$OUTPUT_FILE" - # iDRAC Settings - SE AD RoleGroup Name - echo "09. iDRAC Settings - SE AD RoleGroup Name : $iDRAC_Settings_info9" >> "$OUTPUT_FILE" - # iDRAC Settings - SE AD RoleGroup Dome인 - echo "10. iDRAC Settings - SE AD RoleGroup Dome인 : $iDRAC_Settings_info10" >> "$OUTPUT_FILE" - # iDRAC Settings - SE AD RoleGroup Privilege - echo "11. iDRAC Settings - SE AD RoleGroup Privilege : $iDRAC_Settings_info11" >> "$OUTPUT_FILE" - # iDRAC Settings - SE IDC RoleGroup Name - echo "12. iDRAC Settings - IDC AD RoleGroup Name : $iDRAC_Settings_info12" >> "$OUTPUT_FILE" - # iDRAC Settings - SE IDC RoleGroup Dome인 - echo "13. iDRAC Settings - IDC AD RoleGroup Domain : $iDRAC_Settings_info13" >> "$OUTPUT_FILE" - # iDRAC Settings - SE IDC RoleGroup Dome인 - echo "14. iDRAC Settings - IDC AD RoleGroup Privilege : $iDRAC_Settings_info14" >> "$OUTPUT_FILE" - # iDRAC Settings - Remote Log (syslog) - echo "15. iDRAC Settings - Remote Log (syslog) : $iDRAC_Settings_info15" >> "$OUTPUT_FILE" - # iDRAC Settings - Remote Log (syslog) - echo "16. iDRAC Settings - syslog server address 1 : $iDRAC_Settings_info16" >> "$OUTPUT_FILE" - # iDRAC Settings - Remote Log (syslog) - echo "17. iDRAC Settings - syslog server address 2 : $iDRAC_Settings_info17" >> "$OUTPUT_FILE" - # iDRAC Settings - syslog server port - echo "18. iDRAC Settings - syslog server port : $iDRAC_Settings_info18" >> "$OUTPUT_FILE" - # iDRAC Settings - Remote KVM Nonsecure port - echo "19. iDRAC Settings - Remote KVM Nonsecure port : $iDRAC_Settings_info19" >> "$OUTPUT_FILE" - echo -e "\n" >> "$OUTPUT_FILE" - - # echo "---------------------------------------------Raid 설정 정보----------------------------------------------" >> "$OUTPUT_FILE" - # RAID Settings - Raid Types - #echo "01. RAID Settings - Raid ProductName : $RAID_info0" >> "$OUTPUT_FILE" - # RAID Settings - Raid Types - #echo "02. RAID Settings - Raid Typest : $RAID_info1" >> "$OUTPUT_FILE" - # RAID Settings - StripeSize - #echo "03. RAID Settings - StripeSize : $RAID_info2" >> "$OUTPUT_FILE" - # RAID Settings - ReadCachePolicy - #echo "04. RAID Settings - ReadCachePolicy : $RAID_info3" >> "$OUTPUT_FILE" - # RAID Settings - ReadCachePolicy - #echo "05. RAID Settings - WriteCachePolicy : $RAID_info4" >> "$OUTPUT_FILE" - # RAID Settings - CheckConsistencyRate - #echo "06. RAID Settings - CheckConsistencyRate : $RAID_info5" >> "$OUTPUT_FILE" - # RAID Settings - PatrolReadMode - #echo "07. RAID Settings - PatrolReadMode : $RAID_info6" >> "$OUTPUT_FILE" - # RAID Settings - period - #echo "08. RAID Settings - period : 168h" >> "$OUTPUT_FILE" - # RAID Settings - Power Save - #echo "09. RAID Settings - Power Save : No" >> "$OUTPUT_FILE" - # RAID Settings - JBODMODE - #echo "10. RAID Settings - JBODMODE : Controller does not support JBOD" >> "$OUTPUT_FILE" - # RAID Settings - maxconcurrentpd - #echo "11. RAID Settings - maxconcurrentpd : 240" >> "$OUTPUT_FILE" - - # 임시 파일 삭제 - rm -f $IP_FILE -} - -export -f fetch_idrac_info -export IDRAC_USER -export IDRAC_PASS -export OUTPUT_DIR - -# 시작 시간 기록 -START_TIME=$(date +%s) - -# IP 목록 파일을 읽어 병렬로 작업 수행 -fetch_idrac_info - -# 종료 시간 기록 -END_TIME=$(date +%s) - -# 소요 시간 계산 -ELAPSED_TIME=$(($END_TIME - $START_TIME)) -ELAPSED_HOURS=$(($ELAPSED_TIME / 3600)) -ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60)) -ELAPSED_SECONDS=$(($ELAPSED_TIME % 60)) - -echo "정보 수집 완료." -echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초." diff --git a/data/scripts/XE9680_H200_IB_10EA_MAC_info.py b/data/scripts/XE9680_H200_IB_10EA_MAC_info.py index 009fa20..2a9d64b 100644 --- a/data/scripts/XE9680_H200_IB_10EA_MAC_info.py +++ b/data/scripts/XE9680_H200_IB_10EA_MAC_info.py @@ -10,6 +10,14 @@ import sys import time from pathlib import Path from typing import Dict, Optional, Tuple, List +import logging + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) # ===== 설정: 기본 계정/비밀번호 (환경변수로 덮어쓰기 가능) ===== IDRAC_USER = os.getenv("IDRAC_USER", "root") @@ -190,17 +198,17 @@ def main(): ip_file = Path(args.ip_file) if not ip_file.exists(): - print(f"IP 파일이 존재하지 않습니다: {ip_file}", file=sys.stderr) + logging.error(f"IP 파일이 존재하지 않습니다: {ip_file}") sys.exit(1) with ip_file.open("r", encoding="utf-8") as f: ips = [ln.strip() for ln in f if ln.strip()] if not ips: - print("IP 목록이 비어 있습니다.", file=sys.stderr) + logging.error("IP 목록이 비어 있습니다.") sys.exit(1) - print(f"[시작] 총 {len(ips)}대, workers={args.workers}, IDRAC_USER={IDRAC_USER}") + logging.info(f"[시작] 총 {len(ips)}대, workers={args.workers}, IDRAC_USER={IDRAC_USER}") t0 = time.time() ok = 0 @@ -214,20 +222,23 @@ def main(): try: _ip, success, msg = fut.result() prefix = "[OK] " if success else "[FAIL] " - print(prefix + ip + " - " + msg) + if success: + logging.info(prefix + ip + " - " + msg) + else: + logging.error(prefix + ip + " - " + msg) ok += int(success) fail += int(not success) except Exception as e: - print(f"[EXC] {ip} - {e}", file=sys.stderr) + logging.error(f"[EXC] {ip} - {e}") fail += 1 dt = int(time.time() - t0) h, r = divmod(dt, 3600) m, s = divmod(r, 60) - print("\n정보 수집 완료.") - print(f"성공 {ok}대 / 실패 {fail}대") - print(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.") + logging.info("\n정보 수집 완료.") + logging.info(f"성공 {ok}대 / 실패 {fail}대") + logging.info(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.") if __name__ == "__main__": main() \ No newline at end of file diff --git a/data/scripts/collect_idrac_info.py b/data/scripts/collect_idrac_info.py index 5cb2b1e..778ff62 100644 --- a/data/scripts/collect_idrac_info.py +++ b/data/scripts/collect_idrac_info.py @@ -10,6 +10,14 @@ import sys import time from pathlib import Path from typing import Dict, Optional, Tuple, List +import logging + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [INFO] root: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) # ===== 설정: 기본 계정/비밀번호 (환경변수로 덮어쓰기 가능) ===== IDRAC_USER = os.getenv("IDRAC_USER", "root") @@ -189,17 +197,17 @@ def main(): ip_file = Path(args.ip_file) if not ip_file.exists(): - print(f"IP 파일이 존재하지 않습니다: {ip_file}", file=sys.stderr) + logging.error(f"IP 파일이 존재하지 않습니다: {ip_file}") sys.exit(1) with ip_file.open("r", encoding="utf-8") as f: ips = [ln.strip() for ln in f if ln.strip()] if not ips: - print("IP 목록이 비어 있습니다.", file=sys.stderr) + logging.error("IP 목록이 비어 있습니다.") sys.exit(1) - print(f"[시작] 총 {len(ips)}대, workers={args.workers}, IDRAC_USER={IDRAC_USER}") + logging.info(f"[시작] 총 {len(ips)}대, workers={args.workers}, IDRAC_USER={IDRAC_USER}") t0 = time.time() ok = 0 @@ -213,20 +221,23 @@ def main(): try: _ip, success, msg = fut.result() prefix = "[OK] " if success else "[FAIL] " - print(prefix + ip + " - " + msg) + if success: + logging.info(prefix + ip + " - " + msg) + else: + logging.error(prefix + ip + " - " + msg) ok += int(success) fail += int(not success) except Exception as e: - print(f"[EXC] {ip} - {e}", file=sys.stderr) + logging.error(f"[EXC] {ip} - {e}") fail += 1 dt = int(time.time() - t0) h, r = divmod(dt, 3600) m, s = divmod(r, 60) - print("\n정보 수집 완료.") - print(f"성공 {ok}대 / 실패 {fail}대") - print(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.") + logging.info("\n정보 수집 완료.") + logging.info(f"성공 {ok}대 / 실패 {fail}대") + logging.info(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.") if __name__ == "__main__": main() \ No newline at end of file diff --git a/idrac-info.service b/idrac-info.service new file mode 100644 index 0000000..8c1acd9 --- /dev/null +++ b/idrac-info.service @@ -0,0 +1,29 @@ +[Unit] +Description=iDRAC Info Web Service +After=network.target + +[Service] +# 실행할 사용자 (보안을 위해 root 대신 전용 계정 권장, 예: idrac) +User=root +Group=root + +# 프로젝트 루트 디렉토리 (서버 환경에 맞게 수정 필요) +WorkingDirectory=/data/app/idrac_info_new + +# 가상환경의 python 실행 및 app.py 호출 +# ExecStart= +ExecStart=/bin/bash -c '/data/app/idrac_info_new/venv/bin/python /data/app/idrac_info_new/app.py' + +# 환경 변수 설정 (필요 시 수정) +Environment="FLASK_HOST=0.0.0.0" +Environment="FLASK_PORT=5000" +Environment="FLASK_DEBUG=false" +# Werkzeug 리로더 끄기 (프로덕션 모드) - Systemd에서는 이 설정이 오히려 오류(KeyError)를 유발하므로 제거 +# Environment="WERKZEUG_RUN_MAIN=true" + +# 프로세스 종료 시 자동 재시작 +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target