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

130 lines
4.4 KiB
Python

import sys
import os
import shutil
import tempfile
import time
import logging
import subprocess
from pathlib import Path
# ─────────────────────────────────────────────
# 설정 (필요하면 .env 등에서 읽어와도 됨)
IDRAC_USER = os.getenv("IDRAC_USER", "root")
IDRAC_PASS = os.getenv("IDRAC_PASS", "calvin")
RACADM = os.getenv("RACADM_PATH", "racadm") # PATH에 있으면 'racadm'
# 로깅
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [INFO] root: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
def read_ip_list(ip_file: Path):
ips = []
for line in ip_file.read_text(encoding="utf-8").splitlines():
s = line.strip()
if s:
ips.append(s)
return ips
def preflight(ip: str) -> tuple[bool, str]:
"""접속/인증/권한 간단 점검: getsysinfo 호출."""
cmd = [RACADM, "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "getsysinfo"]
try:
p = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", shell=False, timeout=30)
if p.returncode != 0:
return False, p.stderr.strip() or p.stdout.strip()
return True, ""
except Exception as e:
return False, str(e)
def safe_xml_path(src: Path) -> Path:
"""
racadm이 경로의 공백/한글을 싫어하는 문제 회피:
임시 폴더에 ASCII 파일명으로 복사해서 사용.
"""
tmp_dir = Path(tempfile.gettempdir()) / "idrac_xml"
tmp_dir.mkdir(parents=True, exist_ok=True)
# ASCII, 공백 제거 파일명
dst_name = "config_" + str(int(time.time())) + ".xml"
dst = tmp_dir / dst_name
shutil.copy2(src, dst)
return dst
def apply_xml(ip: str, xml_path: Path) -> tuple[bool, str]:
"""
racadm XML 적용. 벤더/세대에 따라
'config -f' 또는 'set -t xml -f' 를 씁니다.
일반적으로 최신 iDRAC은 config -f 가 잘 동작합니다.
"""
# 1) 공백/한글 제거된 임시 경로 준비
safe_path = safe_xml_path(xml_path)
# 2) 명령 조립(리스트 인자, shell=False)
# 필요 시 아래 둘 중 하나만 사용하세요.
cmd = [RACADM, "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "set", "-t", "xml", "-f", str(safe_path)]
# 대안:
# cmd = [RACADM, "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "set", "-t", "xml", "-f", str(safe_path)]
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()
stderr = (p.stderr or "").strip()
if p.returncode != 0:
msg = f"racadm 실패 (rc={p.returncode})\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}"
return False, msg
# 일부 버전은 성공해도 stdout만 출력하고 rc=0
return True, stdout or "성공"
except Exception as e:
return False, f"예외: {e}"
finally:
# 임시 XML 제거(필요 시 보관하려면 주석처리)
try:
safe_path.unlink(missing_ok=True)
except Exception:
pass
def main():
if len(sys.argv) != 3:
logging.error("Usage: python 02-set_config.py <ip_file> <xml_file>")
sys.exit(1)
ip_file = Path(sys.argv[1])
xml_file = Path(sys.argv[2])
if not ip_file.is_file():
logging.error("IP 파일을 찾을 수 없습니다: %s", ip_file)
sys.exit(2)
if not xml_file.is_file():
logging.error("XML 파일을 찾을 수 없습니다: %s", xml_file)
sys.exit(3)
ips = read_ip_list(ip_file)
if not ips:
logging.error("IP 목록이 비어있습니다.")
sys.exit(4)
start = time.time()
for ip in ips:
logging.info("%s에 XML 파일 '%s' 설정 적용 중...", ip, xml_file)
ok, why = preflight(ip)
if not ok:
logging.error("%s 사전 점검(getsysinfo) 실패: %s", ip, why)
continue
ok, msg = apply_xml(ip, xml_file)
if ok:
logging.info("%s 설정 성공: %s", ip, msg)
else:
logging.error("%s 설정 실패\n%s", ip, msg)
el = int(time.time() - start)
logging.info("전체 설정 소요 시간: %d 시간, %d 분, %d 초.", el // 3600, (el % 3600) // 60, el % 60)
if __name__ == "__main__":
main()