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, "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("실행 명령(리스트) → %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()
