import os
import subprocess
import time
from dotenv import load_dotenv
from concurrent.futures import ThreadPoolExecutor

# .env 파일 로드
load_dotenv()

# 사용자 이름 및 비밀번호 설정
IDRAC_USER = os.getenv("IDRAC_USER")
IDRAC_PASS = os.getenv("IDRAC_PASS")

# IP 파일 유효성 검사
def validate_ip_file(ip_file_path):
    if not os.path.isfile(ip_file_path):
        raise FileNotFoundError(f"IP 파일 {ip_file_path} 이(가) 존재하지 않습니다.")
    return ip_file_path

# 정보 저장 디렉터리 설정
OUTPUT_DIR = "idrac_info"
os.makedirs(OUTPUT_DIR, exist_ok=True)

# iDRAC 정보를 가져오는 함수 정의
def fetch_idrac_info(ip_address):
    try:
        # 모든 hwinventory 저장
        hwinventory = subprocess.getoutput(f"racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} hwinventory")
        # 모든 샷시 정보 저장
        getsysinfo = subprocess.getoutput(f"racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} getsysinfo")
        # 모든 SysProfileSettings 저장
        SysProfileSettings = subprocess.getoutput(f"racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get bios.SysProfileSettings")
        # ProcessorSettings 저장
        ProcessorSettings = subprocess.getoutput(f"racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get bios.ProcSettings")
        # Memory Settings 저장
        MemorySettings = subprocess.getoutput(f"racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get bios.MemSettings")
        # Raid Settings 저장
        STORAGEController = subprocess.getoutput(f"racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get STORAGE.Controller.1")

        # 서비스 태그 가져오기
        SVC_TAG = get_value(getsysinfo, "SVC Tag")
        if not SVC_TAG:
            raise ValueError(f"IP {ip_address} 에 대한 SVC Tag 가져오기 실패")

        # 출력 파일 작성
        output_file = os.path.join(OUTPUT_DIR, f"{SVC_TAG}.txt")
        with open(output_file, 'a', encoding='utf-8') as f:
            f.write(f"Dell EMC Server Bios,iDRAC,R/C Setting (SVC Tag: {SVC_TAG})\n\n")
            f.write("------------------------------------------Firware Version 정보------------------------------------------\n")
            f.write(f"1. SVC Tag : {SVC_TAG}\n")
            f.write(f"2. Bios Firmware : {get_value(getsysinfo, 'System BIOS Version')}\n")
            f.write(f"3. iDRAC Firmware Version : {get_value(getsysinfo, 'Firmware Version')}\n")
            f.write(f"4. NIC Integrated Firmware Version : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get NIC.FrmwImgMenu.1'), '#FamilyVersion')}\n")
            f.write(f"5. OnBoard NIC Firmware Version : Not Found\n")
            f.write(f"6. Raid Controller Firmware Version : {get_value(hwinventory, 'ControllerFirmwareVersion')}\n\n")
            
            f.write("---------------------------------------------Bios 설정 정보----------------------------------------------\n")
            f.write(f"01. Bios Boot Mode : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get bios.BiosBootSettings'), 'BootMode')}\n")
            f.write(f"02. System Profile Settings - System Profile : {get_value(SysProfileSettings, 'SysProfile=')}\n") 
            f.write(f"03. System Profile Settings - CPU Power Management : {get_value(SysProfileSettings, 'EnergyPerformanceBias')}\n")
            f.write(f"04. System Profile Settings - Memory Frequency : {get_value(SysProfileSettings, 'MemFrequency')}\n")
            f.write(f"05. System Profile Settings - Turbo Boost : {get_value(SysProfileSettings, 'ProcTurboMode')}\n")
            f.write(f"06. System Profile Settings - C1E : {get_value(SysProfileSettings, 'ProcC1E')}\n")
            f.write(f"07. System Profile Settings - C-States : {get_value(SysProfileSettings, 'ProcCStates')}\n")
            f.write(f"08. System Profile Settings - Monitor/Mwait : {get_value(SysProfileSettings, 'MonitorMwait')}\n")
            f.write(f"09. Processor Settings - Logical Processor : {get_value(ProcessorSettings, 'LogicalProc')}\n")
            f.write(f"10. Processor Settings - Virtualization Technology : {get_value(ProcessorSettings, 'ProcVirtualization')}\n")
            f.write(f"11. Processor Settings - LLC Prefetch : {get_value(ProcessorSettings, 'LlcPrefetch')}\n")
            f.write(f"12. Processor Settings - x2APIC Mode : {get_value(ProcessorSettings, 'ProcX2Apic')}\n")
            f.write(f"13. Memory Settings - Node Interleaving : {get_value(MemorySettings, 'NodeInterleave')}\n")
            f.write(f"14. Memory Settings - DIMM Self Healing (Post Package Repair) on Uncorrectable Memory Error : {get_value(MemorySettings, 'PPROnUCE')}\n")
            f.write(f"15. Memory Settings - Correctable Error Logging : {get_value(MemorySettings, 'CECriticalSEL')}\n")
            f.write(f"16. System Settings - Thermal Profile Optimization : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get System.ThermalSettings'), 'ThermalProfile')}\n")
            f.write(f"17. Integrated Devices Settings - SR-IOV Global Enable : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get Bios.IntegratedDevices'), 'SriovGlobalEnable')}\n")
            f.write(f"18. Miscellaneous Settings - F1/F2 Prompt on Error : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get bios.MiscSettings'), 'ErrPrompt')}\n\n")

            f.write("---------------------------------------------iDRAC 설정 정보----------------------------------------------\n")
            f.write(f"01. iDRAC Settings - Timezone : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.Time.Timezone'), 'Timezone')}\n")
            f.write(f"02. iDRAC Settings - IPMI LAN Selection : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.CurrentNIC'), 'ActiveNIC')}\n")
            f.write(f"03. iDRAC Settings - IPMI IP(IPv4) : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.CurrentIPv4'), 'DHCPEnable')}\n")
            f.write(f"04. iDRAC Settings - IPMI IP(IPv6) : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.CurrentIPv6'), 'Enable')}\n")
            f.write(f"05. iDRAC Settings - Redfish Support : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.Redfish.Enable'), 'Enable')}\n")
            f.write(f"06. iDRAC Settings - SSH Support : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.SSH'), 'Enable')}\n")
            f.write(f"07. iDRAC Settings - AD User Domain Name : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.USERDomain.1.Name'), 'Name')}\n")
            f.write(f"08. iDRAC Settings - SC Server Address : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.ActiveDirectory.DomainController1'), 'DomainController1')}\n")
            f.write(f"09. iDRAC Settings - SE AD RoleGroup Name : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.ADGroup.1.Name'), 'Name')}\n")
            f.write(f"10. iDRAC Settings - SE AD RoleGroup Domain : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.ADGroup.1.Domain'), 'Domain')}\n")
            f.write(f"11. iDRAC Settings - SE AD RoleGroup Privilege : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.ADGroup.1.Privilege'), 'Privilege')}\n")
            f.write(f"12. iDRAC Settings - IDC AD RoleGroup Name : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.ADGroup.2.Name'), 'Name')}\n")
            f.write(f"13. iDRAC Settings - IDC AD RoleGroup Domain : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.ADGroup.2.Domain'), 'Domain')}\n")
            f.write(f"14. iDRAC Settings - IDC AD RoleGroup Privilege : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.ADGroup.2.Privilege'), 'Privilege')}\n")
            f.write(f"15. iDRAC Settings - Remote Log (syslog) : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.SysLog.SysLogEnable'), 'SysLogEnable')}\n")
            f.write(f"16. iDRAC Settings - syslog server address 1 : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.SysLog.Server1'), 'Server1')}\n")
            f.write(f"17. iDRAC Settings - syslog server address 2 : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.SysLog.Server2'), 'Server2')}\n")
            f.write(f"18. iDRAC Settings - syslog server port : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.SysLog.Port'), 'Port')}\n")
            f.write(f"19. iDRAC Settings - Remote KVM Nonsecure port : {get_value(subprocess.getoutput(f'racadm -r {ip_address} -u {IDRAC_USER} -p {IDRAC_PASS} get iDRAC.VirtualConsole.Port'), 'Port')}\n\n")
            
            f.write("---------------------------------------------Raid 설정 정보----------------------------------------------\n")
            f.write(f"01. RAID Settings - Raid ProductName : {get_value(hwinventory, 'ProductName = PERC')}\n")
            f.write(f"02. RAID Settings - Raid Types : {get_value(hwinventory, 'RAIDTypes')}\n")
            f.write(f"03. RAID Settings - StripeSize : {get_value(hwinventory, 'StripeSize')}\n")
            f.write(f"04. RAID Settings - ReadCachePolicy : {get_value(hwinventory, 'ReadCachePolicy')}\n")
            f.write(f"05. RAID Settings - WriteCachePolicy : {get_value(hwinventory, 'WriteCachePolicy')}\n")
            f.write(f"06. RAID Settings - CheckConsistencyRate : {get_value(STORAGEController, 'CheckConsistencyRate')}\n")
            f.write(f"07. RAID Settings - PatrolReadMode : {get_value(STORAGEController, '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")

        print(f"IP {ip_address} 에 대한 정보를 {output_file} 에 저장했습니다.")
    except Exception as e:
        print(f"오류 발생: {e}")

# 명령 결과에서 원하는 값 가져오기
def get_value(output, key):
    for line in output.splitlines():
        if key.lower() in line.lower():
            return line.split('=')[1].strip()
    return None

# 시작 시간 기록
start_time = time.time()

# IP 목록 파일을 읽어 병렬로 작업 수행
if __name__ == "__main__":
    import sys
    if len(sys.argv) != 2:
        print(f"Usage: {sys.argv[0]} <ip_file>")
        sys.exit(1)

    ip_file_path = validate_ip_file(sys.argv[1])
    with open(ip_file_path, 'r') as ip_file:
        ip_addresses = ip_file.read().splitlines()

    # 병렬 처리를 위해 ThreadPoolExecutor 사용
    max_workers = 100  # 작업 풀 크기 설정
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        executor.map(fetch_idrac_info, ip_addresses)

# 종료 시간 기록
end_time = time.time()

# 소요 시간 계산
elapsed_time = end_time - start_time
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} 초.")
