130 lines
4.0 KiB
Python
130 lines
4.0 KiB
Python
"""
|
|
iDRAC 클라이언트 - racadm 명령 실행 및 결과 캐싱
|
|
"""
|
|
from typing import Optional, Dict, Tuple
|
|
import subprocess
|
|
import os
|
|
import logging
|
|
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s [INFO] root: %(message)s',
|
|
datefmt='%Y-%m-%d %H:%M:%S'
|
|
)
|
|
|
|
|
|
class IDRACClient:
|
|
"""
|
|
racadm 명령 실행 및 결과 캐싱을 담당하는 클라이언트
|
|
"""
|
|
|
|
def __init__(self, ip: str, user: str = None, password: str = None):
|
|
"""
|
|
Args:
|
|
ip: iDRAC IP 주소
|
|
user: iDRAC 사용자명 (기본값: 환경변수 IDRAC_USER 또는 'root')
|
|
password: iDRAC 비밀번호 (기본값: 환경변수 IDRAC_PASS 또는 'calvin')
|
|
"""
|
|
self.ip = ip
|
|
self.user = user or os.getenv("IDRAC_USER", "root")
|
|
self.password = password or os.getenv("IDRAC_PASS", "calvin")
|
|
self._cache: Dict[str, str] = {} # 중복 호출 방지 캐시
|
|
|
|
def run_command(self, command: str) -> Tuple[int, str]:
|
|
"""
|
|
racadm 명령 실행
|
|
|
|
Args:
|
|
command: 실행할 racadm 명령 (예: "getsysinfo", "get bios.BiosBootSettings")
|
|
|
|
Returns:
|
|
(return_code, output) 튜플
|
|
"""
|
|
cmd = f"racadm -r {self.ip} -u {self.user} -p {self.password} {command}"
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
cmd,
|
|
shell=True,
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
timeout=30 # 30초 타임아웃
|
|
)
|
|
return result.returncode, result.stdout
|
|
except subprocess.TimeoutExpired:
|
|
logging.error(f"[{self.ip}] 명령 타임아웃: {command}")
|
|
return 1, ""
|
|
except Exception as e:
|
|
logging.error(f"[{self.ip}] 명령 실행 오류: {e}")
|
|
return 1, f"Error: {e}"
|
|
|
|
def get_sysinfo(self) -> str:
|
|
"""
|
|
getsysinfo 명령 실행 (캐싱)
|
|
|
|
Returns:
|
|
getsysinfo 출력 결과
|
|
"""
|
|
if "sysinfo" not in self._cache:
|
|
_, output = self.run_command("getsysinfo")
|
|
self._cache["sysinfo"] = output
|
|
return self._cache["sysinfo"]
|
|
|
|
def get_hwinventory(self) -> str:
|
|
"""
|
|
hwinventory 명령 실행 (캐싱)
|
|
|
|
Returns:
|
|
hwinventory 출력 결과
|
|
"""
|
|
if "hwinventory" not in self._cache:
|
|
_, output = self.run_command("hwinventory")
|
|
self._cache["hwinventory"] = output
|
|
return self._cache["hwinventory"]
|
|
|
|
def get_swinventory(self) -> str:
|
|
"""
|
|
swinventory 명령 실행 (캐싱)
|
|
|
|
Returns:
|
|
swinventory 출력 결과
|
|
"""
|
|
if "swinventory" not in self._cache:
|
|
_, output = self.run_command("swinventory")
|
|
self._cache["swinventory"] = output
|
|
return self._cache["swinventory"]
|
|
|
|
|
|
def get_infiniband_pages(self) -> str:
|
|
"""
|
|
InfiniBand 설정 페이지 목록 조회 (InfiniBand.VndrConfigPage)
|
|
|
|
Returns:
|
|
racadm get InfiniBand.VndrConfigPage 출력
|
|
"""
|
|
if "infiniband_pages" not in self._cache:
|
|
_, output = self.run_command("get InfiniBand.VndrConfigPage")
|
|
self._cache["infiniband_pages"] = output
|
|
return self._cache["infiniband_pages"]
|
|
|
|
def get_infiniband_page_detail(self, page_number: str) -> str:
|
|
"""
|
|
특정 InfiniBand 설정 페이지 상세 조회
|
|
|
|
Args:
|
|
page_number: 페이지 번호 (예: "1")
|
|
|
|
Returns:
|
|
racadm get InfiniBand.VndrConfigPage.{page_number} 출력
|
|
"""
|
|
cache_key = f"infiniband_page_{page_number}"
|
|
if cache_key not in self._cache:
|
|
_, output = self.run_command(f"get InfiniBand.VndrConfigPage.{page_number}")
|
|
self._cache[cache_key] = output
|
|
return self._cache[cache_key]
|
|
|
|
def clear_cache(self):
|
|
"""캐시 초기화"""
|
|
self._cache.clear()
|