Initial commit
This commit is contained in:
128
data/scripts/02-set_config.py
Normal file
128
data/scripts/02-set_config.py
Normal file
@@ -0,0 +1,128 @@
|
||||
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 - %(levelname)s - %(message)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, "config", "-f", str(safe_path)]
|
||||
# 대안:
|
||||
# cmd = [RACADM, "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "set", "-t", "xml", "-f", str(safe_path)]
|
||||
|
||||
logging.info("실행 명령(리스트) → %s", " ".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:
|
||||
print("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()
|
||||
Reference in New Issue
Block a user