Initial project upload
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
from dotenv import load_dotenv
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import logging
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
# .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
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
# data/scripts/ -> data/temp/staging
|
||||
OUTPUT_DIR = os.path.join(BASE_DIR, "..", "temp", "staging")
|
||||
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 : No-Raid mode\n")
|
||||
|
||||
logging.info(f"IP {ip_address} 에 대한 정보를 {output_file} 에 저장했습니다.")
|
||||
except Exception as e:
|
||||
logging.error(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:
|
||||
logging.error(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)
|
||||
|
||||
logging.info("정보 수집 완료.")
|
||||
logging.info(f"수집 완료 시간: {elapsed_hours} 시간, {elapsed_minutes} 분, {elapsed_seconds} 초.")
|
||||
@@ -0,0 +1,129 @@
|
||||
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()
|
||||
@@ -0,0 +1,105 @@
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
import logging
|
||||
from dotenv import load_dotenv
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
# .env 파일 로드
|
||||
load_dotenv()
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
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
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
OUTPUT_DIR = os.path.join(BASE_DIR, "..", "temp", "staging")
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
# iDRAC 정보를 가져오는 함수
|
||||
def fetch_idrac_info(idrac_ip):
|
||||
try:
|
||||
logger.info(f"{idrac_ip}에 대한 샷시 정보 가져오는 중...")
|
||||
getsysinfo_command = [
|
||||
"racadm", "-r", idrac_ip,
|
||||
"-u", IDRAC_USER,
|
||||
"-p", IDRAC_PASS,
|
||||
"getsysinfo"
|
||||
]
|
||||
getsysinfo_result = subprocess.run(getsysinfo_command, capture_output=True, text=True)
|
||||
getsysinfo = getsysinfo_result.stdout
|
||||
|
||||
svc_tag = ""
|
||||
for line in getsysinfo.splitlines():
|
||||
if "SVC Tag" in line:
|
||||
svc_tag = line.split('=')[1].strip()
|
||||
break
|
||||
|
||||
if not svc_tag:
|
||||
logger.error(f"IP: {idrac_ip}에 대한 SVC Tag 가져오기 실패")
|
||||
return
|
||||
|
||||
logger.info(f"{idrac_ip}에 대한 서버 Log 가져오는 중...")
|
||||
viewerlog_command = [
|
||||
"racadm", "-r", idrac_ip,
|
||||
"-u", IDRAC_USER,
|
||||
"-p", IDRAC_PASS,
|
||||
"getsel"
|
||||
]
|
||||
viewerlog_result = subprocess.run(viewerlog_command, capture_output=True, text=True)
|
||||
viewerlog = viewerlog_result.stdout
|
||||
|
||||
output_file = os.path.join(OUTPUT_DIR, f"{svc_tag}.txt")
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write(f"Dell Server Log Viewer (SVC Tag: {svc_tag})\n\n")
|
||||
f.write("------------------------------------------Log Viewer------------------------------------------\n")
|
||||
f.write(f"1. SVC Tag : {svc_tag}\n")
|
||||
f.write(f"{viewerlog}\n")
|
||||
|
||||
logger.info(f"{idrac_ip}에 대한 로그 정보가 {output_file}에 저장되었습니다.")
|
||||
except Exception as e:
|
||||
logger.error(f"설정 중 오류 발생: {e}")
|
||||
|
||||
# 소요 시간 계산 함수
|
||||
def calculate_elapsed_time(start_time):
|
||||
elapsed_time = time.time() - start_time
|
||||
hours, remainder = divmod(elapsed_time, 3600)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
logger.info(f"전체 작업 소요 시간: {int(hours)} 시간, {int(minutes)} 분, {int(seconds)} 초.")
|
||||
|
||||
# 메인 함수
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
logger.error(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 = [line.strip() for line in ip_file if line.strip()]
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
# 병렬 처리를 위해 ThreadPoolExecutor 사용
|
||||
max_workers = 100 # 병렬 작업 수 설정
|
||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||
executor.map(fetch_idrac_info, ip_addresses)
|
||||
|
||||
calculate_elapsed_time(start_time)
|
||||
@@ -0,0 +1,206 @@
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
import time
|
||||
from pathlib import Path
|
||||
import logging
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# iDRAC 접속 설정
|
||||
IDRAC_USER = "root"
|
||||
IDRAC_PASS = "calvin"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 저장 위치 결정
|
||||
def resolve_output_dir() -> Path:
|
||||
here = Path(__file__).resolve().parent
|
||||
if here.name.lower() == "scripts" and here.parent.name.lower() == "data":
|
||||
base = here.parent
|
||||
elif here.name.lower() == "scripts":
|
||||
base = here.parent
|
||||
else:
|
||||
base = here.parent
|
||||
|
||||
out = base / "temp" / "staging"
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
return out
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 유틸리티 함수
|
||||
def run_racadm(ip, *args):
|
||||
"""racadm 명령어를 실행하고 결과를 반환합니다."""
|
||||
cmd = ["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS] + list(args)
|
||||
try:
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, check=True, timeout=30)
|
||||
return result.stdout
|
||||
except Exception as e:
|
||||
# 에러 발생 시 빈 문자열 반환 (스크립트 중단 방지)
|
||||
return ""
|
||||
|
||||
def extract_value(text, pattern, delimiter='='):
|
||||
"""텍스트에서 특정 키의 값을 추출하고 공백을 제거합니다."""
|
||||
for line in text.splitlines():
|
||||
if re.search(pattern, line, re.IGNORECASE):
|
||||
if delimiter in line:
|
||||
# '=' 기준으로 쪼갠 후 값만 가져와서 공백 제거
|
||||
return line.split(delimiter, 1)[1].strip()
|
||||
return "N/A"
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 메인 수집 함수
|
||||
def fetch_idrac_info(ip, output_dir):
|
||||
logging.info(f">>> [{ip}] 데이터 수집 시작...")
|
||||
|
||||
# 1. 원본 데이터 덩어리 가져오기 (API 호출 최소화)
|
||||
hwinventory = run_racadm(ip, "hwinventory")
|
||||
getsysinfo = run_racadm(ip, "getsysinfo")
|
||||
sys_profile = run_racadm(ip, "get", "bios.SysProfileSettings")
|
||||
proc_settings = run_racadm(ip, "get", "bios.ProcSettings")
|
||||
mem_settings = run_racadm(ip, "get", "bios.MemSettings")
|
||||
storage_ctrl = run_racadm(ip, "get", "STORAGE.Controller.1")
|
||||
|
||||
# 서비스 태그 확인 (파일명 결정용)
|
||||
svc_tag = extract_value(getsysinfo, "SVC Tag")
|
||||
if svc_tag == "N/A":
|
||||
logging.error(f"!!! [{ip}] SVC Tag 추출 실패. 작업을 건너뜁니다.")
|
||||
return
|
||||
|
||||
output_file = output_dir / f"{svc_tag}.txt"
|
||||
|
||||
with open(output_file, "w", encoding="utf-8") as f:
|
||||
# 헤더 작성
|
||||
f.write(f"Dell EMC Server Bios,iDRAC,R/C Setting (SVC Tag: {svc_tag})\n\n")
|
||||
|
||||
# --- 1. Firmware Version 정보 ---
|
||||
f.write("-" * 42 + " Firmware Version 정보 " + "-" * 42 + "\n")
|
||||
f.write(f"1. SVC Tag : {svc_tag}\n")
|
||||
f.write(f"2. Bios Firmware : {extract_value(getsysinfo, 'System BIOS Version')}\n")
|
||||
f.write(f"3. iDRAC Firmware Version : {extract_value(getsysinfo, 'Firmware Version')}\n")
|
||||
|
||||
# NIC 펌웨어 (별도 호출 필요)
|
||||
nic1 = run_racadm(ip, "get", "NIC.FrmwImgMenu.1")
|
||||
nic5 = run_racadm(ip, "get", "NIC.FrmwImgMenu.5")
|
||||
f.write(f"4. NIC Integrated Firmware Version : {extract_value(nic1, '#FamilyVersion')}\n")
|
||||
f.write(f"5. OnBoard NIC Firmware Version : {extract_value(nic5, '#FamilyVersion')}\n")
|
||||
f.write(f"6. Raid Controller Firmware Version : {extract_value(hwinventory, 'ControllerFirmwareVersion')}\n\n")
|
||||
|
||||
# --- 2. Bios 설정 정보 ---
|
||||
f.write("-" * 45 + " Bios 설정 정보 " + "-" * 45 + "\n")
|
||||
boot_mode = run_racadm(ip, "get", "bios.BiosBootSettings")
|
||||
f.write(f"01. Bios Boot Mode : {extract_value(boot_mode, 'BootMode')}\n")
|
||||
f.write(f"02. System Profile Settings - System Profile : {extract_value(sys_profile, 'SysProfile=')}\n")
|
||||
f.write(f"03. System Profile Settings - CPU Power Management : {extract_value(sys_profile, 'ProcPwrPerf')}\n")
|
||||
f.write(f"04. System Profile Settings - Memory Frequency : {extract_value(sys_profile, 'MemFrequency')}\n")
|
||||
f.write(f"05. System Profile Settings - Turbo Boost : {extract_value(sys_profile, 'ProcTurboMode')}\n")
|
||||
f.write(f"06. System Profile Settings - PCI ASPM L1 Link Power Management : {extract_value(sys_profile, 'PcieAspmL1')}\n")
|
||||
f.write(f"07. System Profile Settings - C-States : {extract_value(sys_profile, 'ProcCStates')}\n")
|
||||
f.write(f"08. System Profile Settings - Determinism Slider : {extract_value(sys_profile, 'DeterminismSlider')}\n")
|
||||
f.write(f"08-2. System Profile Settings - Dynamic Link Width Management (DLWM) : {extract_value(sys_profile, 'DynamicLinkWidthManagement')}\n")
|
||||
|
||||
f.write(f"09. Processor Settings - Logical Processor : {extract_value(proc_settings, 'LogicalProc')}\n")
|
||||
f.write(f"10. Processor Settings - Virtualization Technology : {extract_value(proc_settings, 'ProcVirtualization')}\n")
|
||||
f.write(f"11. Processor Settings - NUMA Nodes Per Socket : {extract_value(proc_settings, 'NumaNodesPerSocket')}\n")
|
||||
f.write(f"12. Processor Settings - x2APIC Mode : {extract_value(proc_settings, 'ProcX2Apic')}\n")
|
||||
|
||||
f.write(f"13. Memory Settings - Dram Refresh Delay : {extract_value(mem_settings, 'DramRefreshDelay')}\n")
|
||||
f.write(f"14. Memory Settings - DIMM Self Healing (PPR) : {extract_value(mem_settings, 'PPROnUCE')}\n")
|
||||
f.write(f"15. Memory Settings - Correctable Error Logging : {extract_value(mem_settings, 'CECriticalSEL')}\n")
|
||||
|
||||
thermal = run_racadm(ip, "get", "System.ThermalSettings")
|
||||
f.write(f"16. System Settings - Thermal Profile Optimization : {extract_value(thermal, 'ThermalProfile')}\n")
|
||||
|
||||
integrated = run_racadm(ip, "get", "Bios.IntegratedDevices")
|
||||
f.write(f"17. Integrated Devices Settings - SR-IOV Global Enable : {extract_value(integrated, 'SriovGlobalEnable')}\n")
|
||||
|
||||
misc = run_racadm(ip, "get", "bios.MiscSettings")
|
||||
f.write(f"18. Miscellaneous Settings - F1/F2 Prompt on Error : {extract_value(misc, 'ErrPrompt')}\n\n")
|
||||
|
||||
# --- 3. iDRAC 설정 정보 ---
|
||||
f.write("-" * 45 + " iDRAC 설정 정보 " + "-" * 45 + "\n")
|
||||
f.write(f"01. iDRAC Settings - Timezone : {extract_value(run_racadm(ip, 'get', 'iDRAC.Time.Timezone'), 'Timezone')}\n")
|
||||
f.write(f"02. iDRAC Settings - IPMI LAN Selection : {extract_value(run_racadm(ip, 'get', 'iDRAC.CurrentNIC'), 'ActiveNIC')}\n")
|
||||
f.write(f"03. iDRAC Settings - IPMI IP(IPv4) : {extract_value(run_racadm(ip, 'get', 'iDRAC.CurrentIPv4'), 'DHCPEnable')}\n")
|
||||
f.write(f"04. iDRAC Settings - IPMI IP(IPv6) : {extract_value(run_racadm(ip, 'get', 'iDRAC.CurrentIPv6'), 'Enable=')}\n")
|
||||
f.write(f"05. iDRAC Settings - Redfish Support : {extract_value(run_racadm(ip, 'get', 'iDRAC.Redfish.Enable'), 'Enable=')}\n")
|
||||
f.write(f"06. iDRAC Settings - SSH Support : {extract_value(run_racadm(ip, 'get', 'iDRAC.SSH'), 'Enable=')}\n")
|
||||
|
||||
# AD 관련 설정 (AD Group 1, 2 포함)
|
||||
f.write(f"07. iDRAC Settings - AD User Domain Name : {extract_value(run_racadm(ip, 'get', 'iDRAC.USERDomain.1.Name'), 'Name')}\n")
|
||||
f.write(f"08. iDRAC Settings - SC Server Address : {extract_value(run_racadm(ip, 'get', 'iDRAC.ActiveDirectory.DomainController1'), 'DomainController1')}\n")
|
||||
f.write(f"09. iDRAC Settings - SE AD RoleGroup Name : {extract_value(run_racadm(ip, 'get', 'iDRAC.ADGroup.1.Name'), 'Name')}\n")
|
||||
f.write(f"10. iDRAC Settings - SE AD RoleGroup Domain : {extract_value(run_racadm(ip, 'get', 'iDRAC.ADGroup.1.Domain'), 'Domain')}\n")
|
||||
f.write(f"11. iDRAC Settings - SE AD RoleGroup Privilege : {extract_value(run_racadm(ip, 'get', 'iDRAC.ADGroup.1.Privilege'), 'Privilege')}\n")
|
||||
f.write(f"12. iDRAC Settings - IDC AD RoleGroup Name : {extract_value(run_racadm(ip, 'get', 'iDRAC.ADGroup.2.Name'), 'Name')}\n")
|
||||
f.write(f"13. iDRAC Settings - IDC AD RoleGroup Domain : {extract_value(run_racadm(ip, 'get', 'iDRAC.ADGroup.2.Domain'), 'Domain')}\n")
|
||||
f.write(f"14. iDRAC Settings - IDC AD RoleGroup Privilege : {extract_value(run_racadm(ip, 'get', 'iDRAC.ADGroup.2.Privilege'), 'Privilege')}\n")
|
||||
|
||||
# Syslog 및 기타
|
||||
f.write(f"15. iDRAC Settings - Remote Log (syslog) : {extract_value(run_racadm(ip, 'get', 'iDRAC.SysLog.SysLogEnable'), 'SysLogEnable')}\n")
|
||||
f.write(f"16. iDRAC Settings - syslog server address 1 : {extract_value(run_racadm(ip, 'get', 'iDRAC.SysLog.Server1'), 'Server1')}\n")
|
||||
f.write(f"17. iDRAC Settings - syslog server address 2 : {extract_value(run_racadm(ip, 'get', 'iDRAC.SysLog.Server2'), 'Server2')}\n")
|
||||
f.write(f"18. iDRAC Settings - syslog server port : {extract_value(run_racadm(ip, 'get', 'iDRAC.SysLog.Port'), 'Port')}\n")
|
||||
f.write(f"19. iDRAC Settings - Remote KVM Nonsecure port : {extract_value(run_racadm(ip, 'get', 'iDRAC.VirtualConsole.Port'), 'Port')}\n\n")
|
||||
|
||||
# --- 4. Raid 설정 정보 (주석 해제 버전) ---
|
||||
f.write("-" * 45 + " Raid 설정 정보 " + "-" * 45 + "\n")
|
||||
f.write(f"01. RAID Settings - Raid ProductName : {extract_value(hwinventory, 'ProductName = PERC')}\n")
|
||||
f.write(f"02. RAID Settings - Raid Types : {extract_value(hwinventory, 'RAIDTypes')}\n")
|
||||
f.write(f"03. RAID Settings - StripeSize : {extract_value(hwinventory, 'StripeSize')}\n")
|
||||
f.write(f"04. RAID Settings - ReadCachePolicy : {extract_value(hwinventory, 'ReadCachePolicy')}\n")
|
||||
f.write(f"05. RAID Settings - WriteCachePolicy : {extract_value(hwinventory, 'WriteCachePolicy')}\n")
|
||||
f.write(f"06. RAID Settings - CheckConsistencyRate : {extract_value(storage_ctrl, 'CheckConsistencyRate')}\n")
|
||||
f.write(f"07. RAID Settings - PatrolReadMode : {extract_value(storage_ctrl, '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")
|
||||
|
||||
logging.info(f"✅ [{ip}] 저장 완료: {output_file.name}")
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 실행 흐름 제어
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
logging.error(f"사용법: python {sys.argv[0]} <ip_file>")
|
||||
sys.exit(1)
|
||||
|
||||
ip_file = Path(sys.argv[1])
|
||||
if not ip_file.exists():
|
||||
logging.error(f"오류: IP 파일 '{ip_file}'이 존재하지 않습니다.")
|
||||
sys.exit(1)
|
||||
|
||||
output_dir = resolve_output_dir()
|
||||
start_time = time.time()
|
||||
|
||||
# IP 목록 읽기
|
||||
with open(ip_file, "r") as f:
|
||||
ips = [line.strip() for line in f if line.strip()]
|
||||
|
||||
# 각 IP별로 수집 실행
|
||||
for ip in ips:
|
||||
try:
|
||||
fetch_idrac_info(ip, output_dir)
|
||||
except Exception as e:
|
||||
logging.error(f"❌ [{ip}] 처리 중 예외 발생: {e}")
|
||||
|
||||
# 소요 시간 계산
|
||||
end_time = time.time()
|
||||
elapsed = end_time - start_time
|
||||
hours, rem = divmod(elapsed, 3600)
|
||||
minutes, seconds = divmod(rem, 60)
|
||||
|
||||
logging.info("="*50)
|
||||
logging.info("정보 수집 완료.")
|
||||
logging.info(f"총 소요 시간: {int(hours)}시간 {int(minutes)}분 {int(seconds)}초")
|
||||
logging.info(f"저장 경로: {output_dir}")
|
||||
logging.info("="*50)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,167 @@
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
import logging
|
||||
|
||||
from dotenv import load_dotenv, find_dotenv
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# .env 자동 탐색 로드 (현재 파일 기준 상위 디렉터리까지 검색)
|
||||
load_dotenv(find_dotenv())
|
||||
|
||||
IDRAC_USER = os.getenv("IDRAC_USER")
|
||||
IDRAC_PASS = os.getenv("IDRAC_PASS")
|
||||
|
||||
|
||||
def resolve_output_dir() -> Path:
|
||||
"""
|
||||
실행 위치와 무관하게 결과를 data/idrac_info 밑으로 저장.
|
||||
- 스크립트가 data/scripts/ 에 있다면 → data/idrac_info
|
||||
- 그 외 위치라도 → (스크립트 상위 폴더)/idrac_info
|
||||
"""
|
||||
here = Path(__file__).resolve().parent # .../data/scripts 또는 다른 폴더
|
||||
# case 1: .../data/scripts → data/idrac_info
|
||||
if here.name.lower() == "scripts" and here.parent.name.lower() == "data":
|
||||
base = here.parent # data
|
||||
# case 2: .../scripts (상위가 data가 아닐 때도 상위 폴더를 base로 사용)
|
||||
elif here.name.lower() == "scripts":
|
||||
base = here.parent
|
||||
# case 3: 일반적인 경우: 현재 파일의 상위 폴더
|
||||
else:
|
||||
base = here.parent
|
||||
|
||||
out = base / "temp" / "staging"
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
return out
|
||||
|
||||
|
||||
def parse_gpu_serials_from_hwinventory(hwinv_text: str) -> dict:
|
||||
"""
|
||||
iDRAC hwinventory 전체 텍스트에서 GPU(Video.Slot.*) 블록을 찾아
|
||||
{FQDD(or InstanceID): SerialNumber} 딕셔너리로 반환.
|
||||
블록은 빈 줄로 구분되어 있다고 가정.
|
||||
"""
|
||||
results = {}
|
||||
|
||||
# 빈 줄 기준 블록 분할(여러 개의 개행을 하나의 경계로)
|
||||
blocks = re.split(r"\n\s*\n", hwinv_text, flags=re.MULTILINE)
|
||||
|
||||
for block in blocks:
|
||||
# GPU(Video) 블록만 처리
|
||||
if not re.search(r"\[?InstanceID:\s*Video\.Slot\.", block):
|
||||
continue
|
||||
|
||||
# FQDD 우선, 없으면 [InstanceID: ...]에서 추출
|
||||
fqdd = None
|
||||
m_fqdd = re.search(r"^FQDD\s*=\s*([^\r\n]+)", block, flags=re.MULTILINE)
|
||||
if m_fqdd:
|
||||
fqdd = m_fqdd.group(1).strip()
|
||||
else:
|
||||
m_hdr = re.search(r"\[InstanceID:\s*(Video\.Slot\.[^\]\r\n]+)\]", block)
|
||||
if m_hdr:
|
||||
fqdd = m_hdr.group(1).strip()
|
||||
|
||||
if not fqdd:
|
||||
# 안전장치: Description에 FQDD가 암시되는 경우가 있으나 보통 필요 없음
|
||||
continue
|
||||
|
||||
# SerialNumber 추출
|
||||
m_sn = re.search(r"^SerialNumber\s*=\s*([^\r\n]+)", block, flags=re.MULTILINE)
|
||||
serial = m_sn.group(1).strip() if m_sn else "Not Found"
|
||||
|
||||
results[fqdd] = serial
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def fetch_idrac_info(idrac_ip: str, output_dir: Path) -> None:
|
||||
try:
|
||||
# 서비스 태그 가져오기 (get 제외)
|
||||
cmd_getsysinfo = [
|
||||
"racadm", "-r", idrac_ip, "-u", IDRAC_USER or "", "-p", IDRAC_PASS or "", "getsysinfo"
|
||||
]
|
||||
getsysinfo = subprocess.getoutput(" ".join(cmd_getsysinfo))
|
||||
svc_tag_match = re.search(r"SVC Tag\s*=\s*(\S+)", getsysinfo)
|
||||
svc_tag = svc_tag_match.group(1) if svc_tag_match else None
|
||||
|
||||
if not svc_tag:
|
||||
logging.error(f"Failed to retrieve SVC Tag for IP: {idrac_ip}")
|
||||
return
|
||||
|
||||
# 전체 하드웨어 인벤토리
|
||||
cmd_hwinv = [
|
||||
"racadm", "-r", idrac_ip, "-u", IDRAC_USER or "", "-p", IDRAC_PASS or "", "hwinventory"
|
||||
]
|
||||
hwinv_text = subprocess.getoutput(" ".join(cmd_hwinv))
|
||||
|
||||
gpu_map = parse_gpu_serials_from_hwinventory(hwinv_text)
|
||||
|
||||
# 결과 저장 파일 (SVC Tag 기준)
|
||||
output_file = output_dir / f"{svc_tag}.txt"
|
||||
with output_file.open("w", encoding="utf-8", newline="\n") as f:
|
||||
# 헤더: 서비스 태그
|
||||
f.write(f"{svc_tag}\n")
|
||||
|
||||
if not gpu_map:
|
||||
f.write("No GPU(Video) inventory found or SerialNumber not present.\n")
|
||||
return
|
||||
|
||||
# 정렬: Video.Slot.<num>-<idx> 의 <num>, <idx> 기준
|
||||
def slot_key(k: str):
|
||||
m = re.search(r"Video\.Slot\.(\d+)-(\d+)", k)
|
||||
if m:
|
||||
return (int(m.group(1)), int(m.group(2)))
|
||||
# 예외: 정규 형태가 아니면 뒤로
|
||||
return (1_000_000, 1_000_000, k)
|
||||
|
||||
for fqdd in sorted(gpu_map.keys(), key=slot_key):
|
||||
serial = gpu_map[fqdd]
|
||||
f.write(f"{fqdd}: {serial}\n")
|
||||
|
||||
# 추가 요약: 시리얼만 세미콜론으로 모아서 한 줄로
|
||||
serials_only = [gpu_map[k] for k in sorted(gpu_map.keys(), key=slot_key) if gpu_map[k] != "Not Found"]
|
||||
if serials_only:
|
||||
f.write(f"SERIALS: {';'.join(serials_only)}\n")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error processing IP {idrac_ip}: {e}")
|
||||
|
||||
|
||||
def main(ip_file: str) -> None:
|
||||
ip_path = Path(ip_file)
|
||||
if not ip_path.is_file():
|
||||
logging.error(f"IP file {ip_file} does not exist.")
|
||||
return
|
||||
|
||||
output_dir = resolve_output_dir()
|
||||
|
||||
with ip_path.open("r", encoding="utf-8") as file:
|
||||
ip_addresses = [line.strip() for line in file if line.strip()]
|
||||
|
||||
# 스레드풀 (동시 100개까지)
|
||||
with ThreadPoolExecutor(max_workers=100) as executor:
|
||||
future_to_ip = {executor.submit(fetch_idrac_info, ip, output_dir): ip for ip in ip_addresses}
|
||||
for future in as_completed(future_to_ip):
|
||||
ip = future_to_ip[future]
|
||||
try:
|
||||
future.result()
|
||||
logging.info(f"✅ Completed: {ip}")
|
||||
except Exception as e:
|
||||
logging.error(f"❌ Error processing {ip}: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
if len(sys.argv) != 2:
|
||||
logging.error("Usage: python GPU_Serial_v1.py <ip_file>")
|
||||
sys.exit(1)
|
||||
main(sys.argv[1])
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
레거시 호환성 래퍼 - Intel_Server_info.py
|
||||
실제 로직은 unified/collect_server_info.py의 'intel_server' 프로파일 사용
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
script_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(script_dir))
|
||||
|
||||
from unified.collect_server_info import main as unified_main
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python Intel_Server_info.py <ip_file>")
|
||||
sys.exit(1)
|
||||
|
||||
# intel_server 프로파일 사용
|
||||
sys.argv.append("intel_server")
|
||||
unified_main()
|
||||
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
import logging
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 저장 위치: data/scripts 아래에 있다면 → data/idrac_info 생성
|
||||
def resolve_output_dir() -> Path:
|
||||
here = Path(__file__).resolve().parent
|
||||
base = here.parent if here.name.lower() == "scripts" else here
|
||||
out = base / "temp" / "staging"
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
return out
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# iDRAC 접속 계정
|
||||
IDRAC_USER = "root"
|
||||
IDRAC_PASS = "calvin"
|
||||
|
||||
|
||||
def run(cmd: list[str]) -> str:
|
||||
"""racadm 명령 실행 (stdout 수집)"""
|
||||
try:
|
||||
return subprocess.getoutput(" ".join(cmd))
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
|
||||
def parse_single_value(pattern: str, text: str) -> Optional[str]:
|
||||
"""단일 값 추출용"""
|
||||
m = re.search(pattern, text, flags=re.IGNORECASE)
|
||||
return m.group(1).strip() if m else None
|
||||
|
||||
|
||||
def find_mac_by_fqdd(fqdd: str, text: str) -> Optional[str]:
|
||||
"""
|
||||
swinventory 출력에서 FQDD = {fqdd} 라인을 찾고,
|
||||
그 주변(±10줄) 내에서 MAC 주소를 추출.
|
||||
"""
|
||||
lines = text.splitlines()
|
||||
for i, line in enumerate(lines):
|
||||
if f"FQDD = {fqdd}" in line:
|
||||
for j in range(max(0, i - 10), min(i + 10, len(lines))):
|
||||
m = re.search(r"([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})", lines[j])
|
||||
if m:
|
||||
return m.group(1)
|
||||
return None
|
||||
|
||||
|
||||
def extract_vendors(hwinventory: str) -> tuple[str, str]:
|
||||
"""
|
||||
[InstanceID: DIMM...] 또는 [InstanceID: Disk.Bay...] 블록 내 Manufacturer 추출
|
||||
"""
|
||||
# Memory Vendors
|
||||
mem_vendors = re.findall(
|
||||
r"\[InstanceID:\s*DIMM[^\]]*\][^\[]*?Manufacturer\s*=\s*([^\n\r]+)",
|
||||
hwinventory,
|
||||
flags=re.IGNORECASE
|
||||
)
|
||||
mem_vendors = [v.strip() for v in mem_vendors if v.strip()]
|
||||
memory = ", ".join(sorted(set(mem_vendors))) if mem_vendors else "Not Found"
|
||||
|
||||
# SSD Vendors
|
||||
ssd_vendors = re.findall(
|
||||
r"\[InstanceID:\s*Disk\.Bay[^\]]*\][^\[]*?Manufacturer\s*=\s*([^\n\r]+)",
|
||||
hwinventory,
|
||||
flags=re.IGNORECASE
|
||||
)
|
||||
ssd_vendors = [v.strip() for v in ssd_vendors if v.strip()]
|
||||
ssd = ", ".join(sorted(set(ssd_vendors))) if ssd_vendors else "Not Found"
|
||||
|
||||
return memory, ssd
|
||||
|
||||
|
||||
def fetch_idrac_info_one(ip: str, output_dir: Path) -> None:
|
||||
"""단일 서버 iDRAC 정보 수집"""
|
||||
logging.info(f"[+] Collecting iDRAC info from {ip} ...")
|
||||
|
||||
getsysinfo = run(["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "getsysinfo"])
|
||||
hwinventory = run(["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "hwinventory"])
|
||||
swinventory = run(["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "swinventory"])
|
||||
|
||||
# 서비스 태그
|
||||
svc_tag = parse_single_value(r"SVC\s*Tag\s*=\s*(\S+)", getsysinfo)
|
||||
if not svc_tag:
|
||||
logging.error(f"[!] Failed to retrieve SVC Tag for IP: {ip}")
|
||||
return
|
||||
|
||||
# iDRAC MAC
|
||||
idrac_mac = parse_single_value(r"MAC\s*Address\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
|
||||
|
||||
# NIC.Integrated / Onboard MAC
|
||||
integrated_1 = parse_single_value(r"NIC\.Integrated\.1-1-1\s+Ethernet\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
|
||||
integrated_2 = parse_single_value(r"NIC\.Integrated\.1-2-1\s+Ethernet\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
|
||||
onboard_1 = parse_single_value(r"NIC\.Embedded\.1-1-1\s+Ethernet\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
|
||||
onboard_2 = parse_single_value(r"NIC\.Embedded\.2-1-1\s+Ethernet\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
|
||||
|
||||
# NIC Slot별 MAC
|
||||
NIC_Slot_2_1 = find_mac_by_fqdd("NIC.Slot.2-1-1", swinventory)
|
||||
NIC_Slot_2_2 = find_mac_by_fqdd("NIC.Slot.2-2-1", swinventory)
|
||||
NIC_Slot_3_1 = find_mac_by_fqdd("NIC.Slot.3-1-1", swinventory)
|
||||
NIC_Slot_3_2 = find_mac_by_fqdd("NIC.Slot.3-2-1", swinventory)
|
||||
|
||||
# 메모리 / SSD 제조사
|
||||
memory, ssd = extract_vendors(hwinventory)
|
||||
|
||||
# 결과 파일 저장
|
||||
out_file = output_dir / f"{svc_tag}.txt"
|
||||
with out_file.open("w", encoding="utf-8", newline="\n") as f:
|
||||
f.write(f"{svc_tag}\n")
|
||||
f.write(f"{integrated_1 or ''}\n")
|
||||
f.write(f"{integrated_2 or ''}\n")
|
||||
f.write(f"{onboard_1 or ''}\n")
|
||||
f.write(f"{onboard_2 or ''}\n")
|
||||
f.write(f"{NIC_Slot_2_1 or ''}\n")
|
||||
f.write(f"{NIC_Slot_2_2 or ''}\n")
|
||||
f.write(f"{idrac_mac or ''}\n")
|
||||
f.write(f"{memory}\n")
|
||||
f.write(f"{ssd}\n")
|
||||
|
||||
logging.info(f"[✔] {svc_tag} ({ip}) info saved.")
|
||||
|
||||
|
||||
def main(ip_file: str) -> None:
|
||||
ip_path = Path(ip_file)
|
||||
if not ip_path.is_file():
|
||||
logging.error(f"[!] IP file {ip_file} does not exist.")
|
||||
return
|
||||
|
||||
output_dir = resolve_output_dir()
|
||||
ips = [line.strip() for line in ip_path.read_text(encoding="utf-8").splitlines() if line.strip()]
|
||||
if not ips:
|
||||
logging.error("[!] No IP addresses found in the file.")
|
||||
return
|
||||
|
||||
for ip in ips:
|
||||
try:
|
||||
fetch_idrac_info_one(ip, output_dir)
|
||||
except Exception as e:
|
||||
logging.error(f"[!] Error processing {ip}: {e}")
|
||||
|
||||
try:
|
||||
ip_path.unlink(missing_ok=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
logging.info("\n정보 수집 완료.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys, time
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
logging.error("Usage: python script.py <ip_file>")
|
||||
sys.exit(1)
|
||||
|
||||
start = time.time()
|
||||
main(sys.argv[1])
|
||||
end = time.time()
|
||||
elapsed = int(end - start)
|
||||
h, m, s = elapsed // 3600, (elapsed % 3600) // 60, elapsed % 60
|
||||
logging.info(f"수집 완료 시간: {h}시간 {m}분 {s}초")
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="$(dirname "$0")/../temp/staging"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
#local set1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.MemSettings.CorrEccSmi Disabled)
|
||||
#local set2=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.ProcSettings.ProcVirtualization Disabled)
|
||||
#local set3=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.BiosBootSettings.SetBootOrderEn NIC.PxeDevice.1-1,NIC.PxeDevice.2-1)
|
||||
#local set4=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.NetworkSettings.PxeDev2EnDis Enabled)
|
||||
#local set5=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.PxeDev2Settings.PxeDev2Interface NIC.Integrated.1-2-1)
|
||||
local set6=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.IntegratedDevices.EmbNic1Nic2 Enabled)
|
||||
#local set7=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.SysProfileSettings.SysProfile Custom)
|
||||
#local set8=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.SysProfileSettings.DynamicLinkWidthManagement Unforced)
|
||||
#local set9=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.MiscSettings.ErrPrompt Disabled)
|
||||
local set10=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS jobqueue create BIOS.Setup.1-1 -r forced)
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="$(dirname "$0")/../temp/staging"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
#local set1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.MemSettings.CorrEccSmi Disabled)
|
||||
#local set2=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.ProcSettings.ProcVirtualization Disabled)
|
||||
#local set3=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.BiosBootSettings.SetBootOrderEn NIC.PxeDevice.1-1,NIC.PxeDevice.2-1)
|
||||
#local set4=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.NetworkSettings.PxeDev2EnDis Enabled)
|
||||
#local set5=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.PxeDev2Settings.PxeDev2Interface NIC.Integrated.1-2-1)
|
||||
local set6=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.IntegratedDevices.EmbNic1Nic2 DisabledOs)
|
||||
#local set7=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.SysProfileSettings.SysProfile Custom)
|
||||
#local set8=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.SysProfileSettings.DynamicLinkWidthManagement Unforced)
|
||||
#local set9=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set BIOS.MiscSettings.ErrPrompt Disabled)
|
||||
local set10=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS jobqueue create BIOS.Setup.1-1 -r forced)
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,97 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="$(dirname "$0")/../temp/staging"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# 모든 hwinventory 저장
|
||||
local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo)
|
||||
#local swinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS swinventory)
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory)
|
||||
|
||||
#서비스 태그 가져오기
|
||||
local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#iDRAC MAC 확인
|
||||
local idrac_mac=$(echo "$getsysinfo" | grep -i "MAC Address = " | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#NIC.Integrated MAC 확인
|
||||
local Integrated_1=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Integrated_2=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-2-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#추가 NIC MAC 확인
|
||||
#local NIC_Slot_1=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.1-1-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
#local NIC_Slot_2=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.1-2-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#OnBoard MAC 확인
|
||||
local Onboard_1=$(echo "$getsysinfo" | grep -P "NIC.Embedded.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Onboard_2=$(echo "$getsysinfo" | grep -P "NIC.Embedded.2-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#파트 벤더 확인
|
||||
local memory=$(echo "$hwinventory" | grep -A5 "DIMM" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
local nvme_m2=$(echo "$hwinventory" | grep -A3 "Disk.Direct" | grep "Manufacturer" | awk -F '= ' '{print $2}' | sort | uniq)
|
||||
local ssd=$(echo "$hwinventory" | grep -A3 "Disk.Bay" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
|
||||
# 서비스 태그가 존재하는지 확인
|
||||
if [ -z "$SVC_TAG" ]; then
|
||||
echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP"
|
||||
return
|
||||
fi
|
||||
|
||||
local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt"
|
||||
# SVC Tag 확인
|
||||
echo "$SVC_TAG" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_1" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_2" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_1" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_2" >> "$OUTPUT_FILE"
|
||||
echo "$idrac_mac" >> "$OUTPUT_FILE"
|
||||
echo "$memory" >> "$OUTPUT_FILE"
|
||||
echo "$ssd" >> "$OUTPUT_FILE"
|
||||
#임시파일 제거
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "정보 수집 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
레거시 호환성 래퍼 - MAC_info.py
|
||||
실제 로직은 unified/collect_mac.py의 'default' 프로파일 사용
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# unified 스크립트 경로 추가
|
||||
script_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(script_dir))
|
||||
|
||||
# unified 스크립트 임포트 및 실행
|
||||
from unified.collect_mac import main as unified_main
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 기존 인터페이스 유지: python MAC_info.py <ip_file>
|
||||
# 내부적으로 unified 스크립트 호출 (default 프로파일 사용)
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python MAC_info.py <ip_file>")
|
||||
sys.exit(1)
|
||||
|
||||
# 프로파일 이름 추가
|
||||
sys.argv.append("default")
|
||||
unified_main()
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
레거시 호환성 래퍼 - PortGUID.py
|
||||
실제 로직은 unified/collect_guid.py의 'default' 프로파일 사용
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
script_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(script_dir))
|
||||
|
||||
from unified.collect_guid import main as unified_main
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python PortGUID.py <ip_file>")
|
||||
sys.exit(1)
|
||||
|
||||
# default 프로파일 사용
|
||||
sys.argv.append("default")
|
||||
unified_main()
|
||||
@@ -0,0 +1,168 @@
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
import logging
|
||||
|
||||
from dotenv import load_dotenv, find_dotenv
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# .env 자동 탐색 로드 (현재 파일 기준 상위 디렉터리까지 검색)
|
||||
load_dotenv(find_dotenv())
|
||||
|
||||
IDRAC_USER = os.getenv("IDRAC_USER")
|
||||
IDRAC_PASS = os.getenv("IDRAC_PASS")
|
||||
|
||||
|
||||
def resolve_output_dir() -> Path:
|
||||
"""
|
||||
실행 위치와 무관하게 결과를 data/idrac_info 밑으로 저장.
|
||||
- 스크립트가 data/scripts/ 에 있다면 → data/idrac_info
|
||||
- 그 외 위치라도 → (스크립트 상위 폴더)/idrac_info
|
||||
"""
|
||||
here = Path(__file__).resolve().parent # .../data/scripts 또는 다른 폴더
|
||||
# case 1: .../data/scripts → data/idrac_info
|
||||
if here.name.lower() == "scripts" and here.parent.name.lower() == "data":
|
||||
base = here.parent # data
|
||||
# case 2: .../scripts (상위가 data가 아닐 때도 상위 폴더를 base로 사용)
|
||||
elif here.name.lower() == "scripts":
|
||||
base = here.parent
|
||||
# case 3: 일반적인 경우: 현재 파일의 상위 폴더
|
||||
else:
|
||||
base = here.parent
|
||||
|
||||
out = base / "temp" / "staging"
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
return out
|
||||
|
||||
|
||||
def fetch_idrac_info(idrac_ip: str, output_dir: Path) -> None:
|
||||
try:
|
||||
# 서비스 태그 가져오기 (get 제외)
|
||||
cmd_getsysinfo = [
|
||||
"racadm", "-r", idrac_ip, "-u", IDRAC_USER or "", "-p", IDRAC_PASS or "", "getsysinfo"
|
||||
]
|
||||
getsysinfo = subprocess.getoutput(" ".join(cmd_getsysinfo))
|
||||
svc_tag_match = re.search(r"SVC Tag\s*=\s*(\S+)", getsysinfo)
|
||||
svc_tag = svc_tag_match.group(1) if svc_tag_match else None
|
||||
|
||||
if not svc_tag:
|
||||
logging.error(f"Failed to retrieve SVC Tag for IP: {idrac_ip}")
|
||||
return
|
||||
|
||||
# InfiniBand.VndrConfigPage 목록 가져오기
|
||||
cmd_list = [
|
||||
"racadm", "-r", idrac_ip, "-u", IDRAC_USER or "", "-p", IDRAC_PASS or "", "get", "InfiniBand.VndrConfigPage"
|
||||
]
|
||||
output_list = subprocess.getoutput(" ".join(cmd_list))
|
||||
|
||||
# InfiniBand.VndrConfigPage.<숫자> 및 Key 값 추출
|
||||
matches = re.findall(
|
||||
r"InfiniBand\.VndrConfigPage\.(\d+)\s+\[Key=InfiniBand\.Slot\.(\d+)-\d+#VndrConfigPage]",
|
||||
output_list
|
||||
)
|
||||
|
||||
# 결과 저장 파일
|
||||
output_file = output_dir / f"{svc_tag}.txt"
|
||||
|
||||
with output_file.open("w", encoding="utf-8", newline="\n") as f:
|
||||
# 서비스 태그
|
||||
f.write(f"{svc_tag}\n")
|
||||
|
||||
# --- 슬롯/GUID 수집 후 원하는 순서로 기록 ---
|
||||
slot_to_guid: dict[str, str] = {}
|
||||
slots_in_match_order: list[str] = []
|
||||
|
||||
# 각 페이지 상세 조회
|
||||
for number, slot in matches:
|
||||
cmd_detail = [
|
||||
"racadm", "-r", idrac_ip, "-u", IDRAC_USER or "", "-p", IDRAC_PASS or "",
|
||||
"get", f"InfiniBand.VndrConfigPage.{number}"
|
||||
]
|
||||
output_detail = subprocess.getoutput(" ".join(cmd_detail))
|
||||
|
||||
# PortGUID 추출
|
||||
match_guid = re.search(r"PortGUID=(\S+)", output_detail)
|
||||
port_guid = match_guid.group(1) if match_guid else "Not Found"
|
||||
|
||||
s = str(slot)
|
||||
slot_to_guid[s] = port_guid
|
||||
slots_in_match_order.append(s)
|
||||
|
||||
# 검색된 슬롯 개수에 따라 출력 순서 결정
|
||||
# 환경변수에서 슬롯 우선순위 읽기 (GUIDtxtT0Execl.py와 동일)
|
||||
slot_priority_str = os.getenv("GUID_SLOT_PRIORITY", "")
|
||||
|
||||
if slot_priority_str:
|
||||
# 사용자 지정 슬롯 우선순위 사용
|
||||
desired_order = [s.strip() for s in slot_priority_str.split(",") if s.strip()]
|
||||
logging.info(f"사용자 지정 슬롯 우선순위 사용: {desired_order}")
|
||||
else:
|
||||
# 기본 우선순위 (슬롯 개수에 따라)
|
||||
total_slots = len(slots_in_match_order)
|
||||
if total_slots == 4:
|
||||
desired_order = ['38', '37', '32', '34']
|
||||
elif total_slots == 10:
|
||||
desired_order = ['38', '39', '37', '36', '32', '33', '34', '35', '31', '40']
|
||||
else:
|
||||
desired_order = slots_in_match_order
|
||||
logging.info(f"기본 슬롯 우선순위 사용 (슬롯 {total_slots}개): {desired_order}")
|
||||
|
||||
# 지정된 순서대로 파일에 기록 + GUID 요약 생성
|
||||
hex_guid_list: list[str] = []
|
||||
for s in desired_order:
|
||||
guid = slot_to_guid.get(s, "Not Found")
|
||||
f.write(f"Slot.{s}: {guid}\n")
|
||||
if guid != "Not Found":
|
||||
hex_guid_list.append(f"0x{guid.replace(':', '').upper()}")
|
||||
|
||||
if hex_guid_list:
|
||||
# GUID 순서: 사용자 지정 순서대로 세미콜론으로 연결
|
||||
f.write(f"GUID: {';'.join(hex_guid_list)}\n")
|
||||
logging.info(f"GUID 합치기 완료: {len(hex_guid_list)}개 슬롯")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error processing IP {idrac_ip}: {e}")
|
||||
|
||||
|
||||
def main(ip_file: str) -> None:
|
||||
ip_path = Path(ip_file)
|
||||
if not ip_path.is_file():
|
||||
logging.error(f"IP file {ip_file} does not exist.")
|
||||
return
|
||||
|
||||
output_dir = resolve_output_dir() # ← 여기서 OS 무관 저장 위치 확정 (data/idrac_info)
|
||||
# print(f"[debug] output_dir = {output_dir}") # 필요 시 확인
|
||||
|
||||
with ip_path.open("r", encoding="utf-8") as file:
|
||||
ip_addresses = [line.strip() for line in file if line.strip()]
|
||||
|
||||
# 스레드풀
|
||||
with ThreadPoolExecutor(max_workers=100) as executor:
|
||||
future_to_ip = {executor.submit(fetch_idrac_info, ip, output_dir): ip for ip in ip_addresses}
|
||||
|
||||
for future in as_completed(future_to_ip):
|
||||
ip = future_to_ip[future]
|
||||
try:
|
||||
future.result()
|
||||
logging.info(f"Completed: {ip}")
|
||||
except Exception as e:
|
||||
logging.error(f"Error processing {ip}: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
if len(sys.argv) != 2:
|
||||
logging.error("Usage: python script.py <ip_file>")
|
||||
sys.exit(1)
|
||||
|
||||
main(sys.argv[1])
|
||||
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
import logging
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 저장 위치: data/scripts 아래에 있다면 → data/idrac_info 생성
|
||||
def resolve_output_dir() -> Path:
|
||||
here = Path(__file__).resolve().parent
|
||||
base = here.parent if here.name.lower() == "scripts" else here
|
||||
out = base / "temp" / "staging"
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
return out
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# iDRAC 접속 계정
|
||||
IDRAC_USER = "root"
|
||||
IDRAC_PASS = "calvin"
|
||||
|
||||
|
||||
def run(cmd: list[str]) -> str:
|
||||
"""racadm 명령 실행 (stdout 수집)"""
|
||||
try:
|
||||
return subprocess.getoutput(" ".join(cmd))
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
|
||||
def parse_single_value(pattern: str, text: str) -> Optional[str]:
|
||||
"""단일 값 추출용"""
|
||||
m = re.search(pattern, text, flags=re.IGNORECASE)
|
||||
return m.group(1).strip() if m else None
|
||||
|
||||
|
||||
def find_mac_by_fqdd(fqdd: str, text: str) -> Optional[str]:
|
||||
"""
|
||||
swinventory 출력에서 FQDD = {fqdd} 라인을 찾고,
|
||||
그 주변(±10줄) 내에서 MAC 주소를 추출.
|
||||
"""
|
||||
lines = text.splitlines()
|
||||
for i, line in enumerate(lines):
|
||||
if f"FQDD = {fqdd}" in line:
|
||||
for j in range(max(0, i - 10), min(i + 10, len(lines))):
|
||||
m = re.search(r"([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})", lines[j])
|
||||
if m:
|
||||
return m.group(1)
|
||||
return None
|
||||
|
||||
|
||||
def extract_vendors(hwinventory: str) -> tuple[str, str]:
|
||||
"""
|
||||
[InstanceID: DIMM...] 또는 [InstanceID: Disk.Bay...] 블록 내 Manufacturer 추출
|
||||
"""
|
||||
# Memory Vendors
|
||||
mem_vendors = re.findall(
|
||||
r"\[InstanceID:\s*DIMM[^\]]*\][^\[]*?Manufacturer\s*=\s*([^\n\r]+)",
|
||||
hwinventory,
|
||||
flags=re.IGNORECASE
|
||||
)
|
||||
mem_vendors = [v.strip() for v in mem_vendors if v.strip()]
|
||||
memory = ", ".join(sorted(set(mem_vendors))) if mem_vendors else "Not Found"
|
||||
|
||||
# SSD Vendors
|
||||
ssd_vendors = re.findall(
|
||||
r"\[InstanceID:\s*Disk\.Bay[^\]]*\][^\[]*?Manufacturer\s*=\s*([^\n\r]+)",
|
||||
hwinventory,
|
||||
flags=re.IGNORECASE
|
||||
)
|
||||
ssd_vendors = [v.strip() for v in ssd_vendors if v.strip()]
|
||||
ssd = ", ".join(sorted(set(ssd_vendors))) if ssd_vendors else "Not Found"
|
||||
|
||||
return memory, ssd
|
||||
|
||||
|
||||
def fetch_idrac_info_one(ip: str, output_dir: Path) -> None:
|
||||
"""단일 서버 iDRAC 정보 수집"""
|
||||
logging.info(f"[+] Collecting iDRAC info from {ip} ...")
|
||||
|
||||
getsysinfo = run(["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "getsysinfo"])
|
||||
hwinventory = run(["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "hwinventory"])
|
||||
swinventory = run(["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "swinventory"])
|
||||
|
||||
# 서비스 태그
|
||||
svc_tag = parse_single_value(r"SVC\s*Tag\s*=\s*(\S+)", getsysinfo)
|
||||
if not svc_tag:
|
||||
logging.error(f"[!] Failed to retrieve SVC Tag for IP: {ip}")
|
||||
return
|
||||
|
||||
# iDRAC MAC
|
||||
idrac_mac = parse_single_value(r"MAC\s*Address\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
|
||||
|
||||
# NIC.Integrated / Onboard MAC
|
||||
integrated_1 = parse_single_value(r"NIC\.Integrated\.1-1-1\s+Ethernet\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
|
||||
integrated_2 = parse_single_value(r"NIC\.Integrated\.1-2-1\s+Ethernet\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
|
||||
onboard_1 = parse_single_value(r"NIC\.Embedded\.1-1-1\s+Ethernet\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
|
||||
onboard_2 = parse_single_value(r"NIC\.Embedded\.2-1-1\s+Ethernet\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo)
|
||||
|
||||
# 메모리 / SSD 제조사
|
||||
memory, ssd = extract_vendors(hwinventory)
|
||||
|
||||
# 결과 파일 저장
|
||||
out_file = output_dir / f"{svc_tag}.txt"
|
||||
with out_file.open("w", encoding="utf-8", newline="\n") as f:
|
||||
f.write(f"{svc_tag}\n")
|
||||
f.write(f"{integrated_1 or ''}\n")
|
||||
f.write(f"{integrated_2 or ''}\n")
|
||||
f.write(f"{onboard_1 or ''}\n")
|
||||
f.write(f"{onboard_2 or ''}\n")
|
||||
f.write(f"{idrac_mac or ''}\n")
|
||||
f.write(f"{memory}\n")
|
||||
f.write(f"{ssd}\n")
|
||||
|
||||
logging.info(f"[✔] {svc_tag} ({ip}) info saved.")
|
||||
|
||||
|
||||
def main(ip_file: str) -> None:
|
||||
ip_path = Path(ip_file)
|
||||
if not ip_path.is_file():
|
||||
logging.error(f"[!] IP file {ip_file} does not exist.")
|
||||
return
|
||||
|
||||
output_dir = resolve_output_dir()
|
||||
ips = [line.strip() for line in ip_path.read_text(encoding="utf-8").splitlines() if line.strip()]
|
||||
if not ips:
|
||||
logging.error("[!] No IP addresses found in the file.")
|
||||
return
|
||||
|
||||
for ip in ips:
|
||||
try:
|
||||
fetch_idrac_info_one(ip, output_dir)
|
||||
except Exception as e:
|
||||
logging.error(f"[!] Error processing {ip}: {e}")
|
||||
|
||||
try:
|
||||
ip_path.unlink(missing_ok=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
logging.info("\n정보 수집 완료.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys, time
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
logging.error("Usage: python script.py <ip_file>")
|
||||
sys.exit(1)
|
||||
|
||||
start = time.time()
|
||||
main(sys.argv[1])
|
||||
end = time.time()
|
||||
elapsed = int(end - start)
|
||||
h, m, s = elapsed // 3600, (elapsed % 3600) // 60, elapsed % 60
|
||||
logging.info(f"수집 완료 시간: {h}시간 {m}분 {s}초")
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="$(dirname "$0")/../temp/staging"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
local set=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS systemerase cryptographicerasepd)
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
import logging
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 저장 위치 결정
|
||||
def resolve_output_dir() -> Path:
|
||||
here = Path(__file__).resolve().parent
|
||||
if here.name.lower() == "scripts" and here.parent.name.lower() == "data":
|
||||
base = here.parent
|
||||
elif here.name.lower() == "scripts":
|
||||
base = here.parent
|
||||
else:
|
||||
base = here.parent
|
||||
|
||||
out = base / "temp" / "staging"
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
return out
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# iDRAC 계정
|
||||
IDRAC_USER = "root"
|
||||
IDRAC_PASS = "calvin"
|
||||
|
||||
|
||||
def run(cmd: list[str]) -> str:
|
||||
"""racadm 명령 실행 (stdout만 반환)"""
|
||||
try:
|
||||
return subprocess.getoutput(" ".join(cmd))
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
|
||||
def parse_single_value(pattern: str, text: str) -> Optional[str]:
|
||||
m = re.search(pattern, text, flags=re.IGNORECASE)
|
||||
return m.group(1).strip() if m else None
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# hwinventory 블록 기반 Manufacturer 추출 (핵심 수정 부분)
|
||||
def extract_manufacturers(hwinventory: str, instance_prefix: str) -> list[str]:
|
||||
"""
|
||||
instance_prefix:
|
||||
- 'DIMM.' → 메모리
|
||||
- 'Disk.Bay.' → 디스크
|
||||
"""
|
||||
vendors = []
|
||||
|
||||
blocks = re.split(r"\n\s*\n", hwinventory)
|
||||
for block in blocks:
|
||||
if f"[InstanceID: {instance_prefix}" in block:
|
||||
m = re.search(r"Manufacturer\s*=\s*(.+)", block, re.IGNORECASE)
|
||||
if m:
|
||||
vendors.append(m.group(1).strip())
|
||||
|
||||
return vendors
|
||||
|
||||
|
||||
def fetch_idrac_info_one(ip: str, output_dir: Path) -> None:
|
||||
getsysinfo = run([
|
||||
"racadm", "-r", ip,
|
||||
"-u", IDRAC_USER,
|
||||
"-p", IDRAC_PASS,
|
||||
"getsysinfo"
|
||||
])
|
||||
|
||||
hwinventory = run([
|
||||
"racadm", "-r", ip,
|
||||
"-u", IDRAC_USER,
|
||||
"-p", IDRAC_PASS,
|
||||
"hwinventory"
|
||||
])
|
||||
|
||||
# ── Service Tag
|
||||
svc_tag = parse_single_value(r"SVC\s*Tag\s*=\s*(\S+)", getsysinfo)
|
||||
if not svc_tag:
|
||||
logging.error(f"[ERROR] SVC Tag 수집 실패: {ip}")
|
||||
return
|
||||
|
||||
# ── iDRAC MAC
|
||||
idrac_mac = parse_single_value(
|
||||
r"MAC Address\s*=\s*([0-9A-Fa-f:]{17})", getsysinfo
|
||||
)
|
||||
|
||||
# ── Integrated NIC
|
||||
integrated_1 = parse_single_value(
|
||||
r"NIC\.Integrated\.1-1-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})",
|
||||
getsysinfo
|
||||
)
|
||||
integrated_2 = parse_single_value(
|
||||
r"NIC\.Integrated\.1-2-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})",
|
||||
getsysinfo
|
||||
)
|
||||
|
||||
# ── Embedded NIC
|
||||
onboard_1 = parse_single_value(
|
||||
r"NIC\.Embedded\.1-1-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})",
|
||||
getsysinfo
|
||||
)
|
||||
onboard_2 = parse_single_value(
|
||||
r"NIC\.Embedded\.2-1-1.*?([0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2}){5})",
|
||||
getsysinfo
|
||||
)
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Memory / Disk Vendor (수정 완료)
|
||||
mem_vendors = sorted(set(extract_manufacturers(hwinventory, "DIMM.")))
|
||||
ssd_vendors = sorted(set(extract_manufacturers(hwinventory, "Disk.Bay.")))
|
||||
|
||||
memory = "\n".join(mem_vendors)
|
||||
ssd = "\n".join(ssd_vendors)
|
||||
|
||||
# ── 결과 파일 저장
|
||||
out_file = output_dir / f"{svc_tag}.txt"
|
||||
with out_file.open("w", encoding="utf-8", newline="\n") as f:
|
||||
f.write(f"{svc_tag}\n")
|
||||
f.write(f"{integrated_1 or ''}\n")
|
||||
f.write(f"{integrated_2 or ''}\n")
|
||||
f.write(f"{onboard_1 or ''}\n")
|
||||
f.write(f"{onboard_2 or ''}\n")
|
||||
f.write(f"{idrac_mac or ''}\n")
|
||||
f.write(f"{memory}\n")
|
||||
f.write(f"{ssd}\n")
|
||||
|
||||
logging.info(f"[OK] {svc_tag} 수집 완료")
|
||||
|
||||
|
||||
def main(ip_file: str) -> None:
|
||||
ip_path = Path(ip_file)
|
||||
if not ip_path.is_file():
|
||||
logging.error(f"[ERROR] IP 파일 없음: {ip_file}")
|
||||
return
|
||||
|
||||
output_dir = resolve_output_dir()
|
||||
|
||||
ips = [
|
||||
line.strip()
|
||||
for line in ip_path.read_text(encoding="utf-8").splitlines()
|
||||
if line.strip()
|
||||
]
|
||||
|
||||
if not ips:
|
||||
logging.error("[ERROR] IP 목록이 비어 있습니다.")
|
||||
return
|
||||
|
||||
for ip in ips:
|
||||
try:
|
||||
fetch_idrac_info_one(ip, output_dir)
|
||||
except Exception as e:
|
||||
logging.error(f"[ERROR] {ip} 처리 실패: {e}")
|
||||
|
||||
# 원본 Bash 스크립트 동작 유지
|
||||
try:
|
||||
ip_path.unlink(missing_ok=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
logging.info("정보 수집 완료.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
import time
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
logging.error("Usage: python script.py <ip_file>")
|
||||
sys.exit(1)
|
||||
|
||||
start = time.time()
|
||||
main(sys.argv[1])
|
||||
elapsed = int(time.time() - start)
|
||||
|
||||
h, m, s = elapsed // 3600, (elapsed % 3600) // 60, elapsed % 60
|
||||
logging.info(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.")
|
||||
@@ -0,0 +1,271 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
import logging
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 저장 위치: 이 파일이 data/scripts/ 아래 있으면 → data/idrac_info
|
||||
# 그 외여도 이 파일의 상위 폴더에 data/idrac_info 생성
|
||||
def resolve_output_dir() -> Path:
|
||||
here = Path(__file__).resolve().parent
|
||||
# 통상 data/scripts/에 둘 경우 data/idrac_info 로 저장
|
||||
if here.name.lower() == "scripts" and here.parent.name.lower() == "data":
|
||||
base = here.parent # data
|
||||
elif (here / "data").is_dir():
|
||||
base = here / "data"
|
||||
else:
|
||||
base = here # 그래도 현재 기준으로 생성
|
||||
out = base / "temp" / "staging"
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
return out
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# 사용자 이름 및 비밀번호 (Bash 스크립트와 동일)
|
||||
IDRAC_USER = "root"
|
||||
IDRAC_PASS = "calvin"
|
||||
|
||||
|
||||
def sh(cmd: list[str] | str) -> str:
|
||||
"""racadm 호출을 간단히 실행 (stdout만 수집)"""
|
||||
if isinstance(cmd, list):
|
||||
cmd = " ".join(cmd)
|
||||
try:
|
||||
return subprocess.getoutput(cmd)
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
|
||||
def grep_value_line(text: str, key: str, after_eq_strip=True) -> str | None:
|
||||
"""
|
||||
Bash에서 `grep -i "<key>" | awk -F '=' '{print $2}' | tr -d '[:space:]'`
|
||||
에 상응하는 간단 추출기.
|
||||
"""
|
||||
# 대소문자 구분 없이 key를 포함하는 라인을 찾음
|
||||
pat = re.compile(re.escape(key), re.IGNORECASE)
|
||||
for line in text.splitlines():
|
||||
if pat.search(line):
|
||||
if after_eq_strip and "=" in line:
|
||||
return line.split("=", 1)[1].strip().replace(" ", "")
|
||||
return line.strip()
|
||||
return None
|
||||
|
||||
|
||||
def parse_after_eq(text: str, key_regex: str, strip_spaces=True) -> str | None:
|
||||
"""
|
||||
정규표현식으로 키를 찾아 '=' 뒤 값을 추출.
|
||||
ex) key_regex=r"System BIOS Version"
|
||||
"""
|
||||
for line in text.splitlines():
|
||||
# [Key=...] 형식의 줄은 건너뛰기
|
||||
if line.strip().startswith('[') and line.strip().endswith(']'):
|
||||
continue
|
||||
|
||||
if re.search(key_regex, line, flags=re.IGNORECASE):
|
||||
if "=" in line:
|
||||
val = line.split("=", 1)[1]
|
||||
return val.strip().replace(" ", "") if strip_spaces else val.strip()
|
||||
return None
|
||||
|
||||
|
||||
def fetch_idrac_info(ip: str, output_dir: Path) -> None:
|
||||
# 원 스크립트 호출 순서 및 동일 항목 수집
|
||||
hwinventory = sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "hwinventory"])
|
||||
getsysinfo = sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "getsysinfo"])
|
||||
sys_profile = sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "bios.SysProfileSettings"])
|
||||
proc_settings = sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "bios.ProcSettings"])
|
||||
mem_settings = sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "bios.MemSettings"])
|
||||
storage_ctrl = sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "STORAGE.Controller.1"])
|
||||
|
||||
svc_tag = parse_after_eq(getsysinfo, r"SVC\s*Tag")
|
||||
bios_fw = parse_after_eq(getsysinfo, r"System\s*BIOS\s*Version")
|
||||
idrac_fw = parse_after_eq(getsysinfo, r"Firmware\s*Version")
|
||||
intel_nic_fw = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "NIC.FrmwImgMenu.1"]),
|
||||
r"#FamilyVersion")
|
||||
onboard_nic_fw = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "NIC.FrmwImgMenu.5"]),
|
||||
r"#FamilyVersion")
|
||||
raid_fw = parse_after_eq(hwinventory, r"ControllerFirmwareVersion")
|
||||
bios_boot_mode = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "bios.BiosBootSettings"]),
|
||||
r"BootMode")
|
||||
|
||||
# SysProfileSettings 세부
|
||||
sysprof_1 = parse_after_eq(sys_profile, r"SysProfile")
|
||||
sysprof_2 = parse_after_eq(sys_profile, r"EnergyPerformanceBias")
|
||||
sysprof_3 = parse_after_eq(sys_profile, r"MemFrequency")
|
||||
sysprof_4 = parse_after_eq(sys_profile, r"ProcTurboMode")
|
||||
sysprof_5 = parse_after_eq(sys_profile, r"ProcC1E")
|
||||
sysprof_6 = parse_after_eq(sys_profile, r"ProcCStates")
|
||||
sysprof_7 = parse_after_eq(sys_profile, r"MonitorMwait")
|
||||
|
||||
# ProcessorSettings
|
||||
proc_1 = parse_after_eq(proc_settings, r"LogicalProc")
|
||||
proc_2 = parse_after_eq(proc_settings, r"ProcVirtualization")
|
||||
proc_3 = parse_after_eq(proc_settings, r"LlcPrefetch")
|
||||
proc_4 = parse_after_eq(proc_settings, r"ProcX2Apic")
|
||||
|
||||
# MemorySettings
|
||||
mem_1 = parse_after_eq(mem_settings, r"NodeInterleave")
|
||||
mem_2 = parse_after_eq(mem_settings, r"PPROnUCE")
|
||||
mem_3 = parse_after_eq(mem_settings, r"CECriticalSEL")
|
||||
|
||||
# System.ThermalSettings
|
||||
system_thermal = sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "System.ThermalSettings"])
|
||||
system_1 = parse_after_eq(system_thermal, r"ThermalProfile", strip_spaces=False)
|
||||
|
||||
# Bios.IntegratedDevices
|
||||
integ_devs = sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "Bios.IntegratedDevices"])
|
||||
integ_1 = parse_after_eq(integ_devs, r"SriovGlobalEnable")
|
||||
|
||||
# bios.MiscSettings
|
||||
misc = sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "bios.MiscSettings"])
|
||||
misc_1 = parse_after_eq(misc, r"ErrPrompt")
|
||||
|
||||
# iDRAC.* 다양한 설정
|
||||
tz = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.Time.Timezone"]),
|
||||
r"Timezone")
|
||||
active_nic = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.CurrentNIC"]),
|
||||
r"ActiveNIC")
|
||||
ipv4_dhcp = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.CurrentIPv4"]),
|
||||
r"DHCPEnable")
|
||||
ipv6_enable = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.CurrentIPv6"]),
|
||||
r"Enable")
|
||||
redfish_enable = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.Redfish.Enable"]),
|
||||
r"Enable")
|
||||
ssh_enable = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.SSH"]),
|
||||
r"Enable")
|
||||
|
||||
ad_user_domain = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.USERDomain.1.Name"]),
|
||||
r"Name")
|
||||
ad_dc1 = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.ActiveDirectory.DomainController1"]),
|
||||
r"DomainController1")
|
||||
ad_grp1_name = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.ADGroup.1.Name"]),
|
||||
r"Name")
|
||||
ad_grp1_domain = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.ADGroup.1.Domain"]),
|
||||
r"Domain")
|
||||
ad_grp1_priv = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.ADGroup.1.Privilege"]),
|
||||
r"Privilege")
|
||||
ad_grp2_name = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.ADGroup.2.Name"]),
|
||||
r"Name")
|
||||
ad_grp2_domain = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.ADGroup.2.Domain"]),
|
||||
r"Domain")
|
||||
ad_grp2_priv = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.ADGroup.2.Privilege"]),
|
||||
r"Privilege")
|
||||
|
||||
syslog_enable = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.SysLog.SysLogEnable"]),
|
||||
r"SysLogEnable")
|
||||
syslog_s1 = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.SysLog.Server1"]),
|
||||
r"Server1")
|
||||
syslog_s2 = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.SysLog.Server2"]),
|
||||
r"Server2")
|
||||
syslog_port = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.SysLog.Port"]),
|
||||
r"Port")
|
||||
kvm_port = parse_after_eq(sh(["racadm", f"-r{ip}", f"-u{IDRAC_USER}", f"-p{IDRAC_PASS}", "get", "iDRAC.VirtualConsole.Port"]),
|
||||
r"Port")
|
||||
|
||||
if not svc_tag:
|
||||
logging.error(f"Failed to retrieve SVC Tag for IP: {ip}")
|
||||
return
|
||||
|
||||
out_file = output_dir / f"{svc_tag}.txt"
|
||||
with out_file.open("w", encoding="utf-8", newline="\n") 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 : {bios_fw or ''}\n")
|
||||
f.write(f"3. iDRAC Firmware Version : {idrac_fw or ''}\n")
|
||||
f.write(f"4. NIC Integrated Firmware Version : {intel_nic_fw or ''}\n")
|
||||
f.write(f"5. OnBoard NIC Firmware Version : {onboard_nic_fw or ''}\n")
|
||||
f.write(f"6. Raid Controller Firmware Version : {raid_fw or ''}\n\n")
|
||||
|
||||
f.write("---------------------------------------------Bios 설정 정보----------------------------------------------\n")
|
||||
f.write(f"01. Bios Boot Mode : {bios_boot_mode or ''}\n")
|
||||
f.write(f"02. System Profile Settings - System Profile : {sysprof_1 or ''}\n")
|
||||
f.write(f"03. System Profile Settings - CPU Power Management : {sysprof_2 or ''}\n")
|
||||
f.write(f"04. System Profile Settings - Memory Frequency : {sysprof_3 or ''}\n")
|
||||
f.write(f"05. System Profile Settings - Turbo Boost : {sysprof_4 or ''}\n")
|
||||
f.write(f"06. System Profile Settings - C1E : {sysprof_5 or ''}\n")
|
||||
f.write(f"07. System Profile Settings - C-States : {sysprof_6 or ''}\n")
|
||||
f.write(f"08. System Profile Settings - Monitor/Mwait : {sysprof_7 or ''}\n")
|
||||
f.write(f"09. Processor Settings - Logical Processor : {proc_1 or ''}\n")
|
||||
f.write(f"10. Processor Settings - Virtualization Technology : {proc_2 or ''}\n")
|
||||
f.write(f"11. Processor Settings - LLC Prefetch : {proc_3 or ''}\n")
|
||||
f.write(f"12. Processor Settings - x2APIC Mode : {proc_4 or ''}\n")
|
||||
f.write(f"13. Memory Settings - Node Interleaving : {mem_1 or ''}\n")
|
||||
f.write(f"14. Memory Settings - DIMM Self Healing (Post Package Repair) on Uncorrectable Memory Error : {mem_2 or ''}\n")
|
||||
f.write(f"15. Memory Settings - Correctable Error Logging : {mem_3 or ''}\n")
|
||||
f.write(f"16. System Settings - Thermal Profile Optimization : {system_1 or ''}\n")
|
||||
f.write(f"17. Integrated Devices Settings - SR-IOV Global Enable : {integ_1 or ''}\n")
|
||||
f.write(f"18. Miscellaneous Settings - F1/F2 Prompt on Error : {misc_1 or ''}\n\n")
|
||||
|
||||
f.write("---------------------------------------------iDRAC 설정 정보----------------------------------------------\n")
|
||||
f.write(f"01. iDRAC Settings - Timezone : {tz or ''}\n")
|
||||
f.write(f"02. iDRAC Settings - IPMI LAN Selection : {active_nic or ''}\n")
|
||||
f.write(f"03. iDRAC Settings - IPMI IP(IPv4) : {ipv4_dhcp or ''}\n")
|
||||
f.write(f"04. iDRAC Settings - IPMI IP(IPv6) : {ipv6_enable or ''}\n")
|
||||
f.write(f"05. iDRAC Settings - Redfish Support : {redfish_enable or ''}\n")
|
||||
f.write(f"06. iDRAC Settings - SSH Support : {ssh_enable or ''}\n")
|
||||
f.write(f"07. iDRAC Settings - AD User Domain Name : {ad_user_domain or ''}\n")
|
||||
f.write(f"08. iDRAC Settings - SC Server Address : {ad_dc1 or ''}\n")
|
||||
f.write(f"09. iDRAC Settings - SE AD RoleGroup Name : {ad_grp1_name or ''}\n")
|
||||
f.write(f"10. iDRAC Settings - SE AD RoleGroup Dome인 : {ad_grp1_domain or ''}\n")
|
||||
f.write(f"11. iDRAC Settings - SE AD RoleGroup Privilege : {ad_grp1_priv or ''}\n")
|
||||
f.write(f"12. iDRAC Settings - IDC AD RoleGroup Name : {ad_grp2_name or ''}\n")
|
||||
f.write(f"13. iDRAC Settings - IDC AD RoleGroup Domain : {ad_grp2_domain or ''}\n")
|
||||
f.write(f"14. iDRAC Settings - IDC AD RoleGroup Privilege : {ad_grp2_priv or ''}\n")
|
||||
f.write(f"15. iDRAC Settings - Remote Log (syslog) : {syslog_enable or ''}\n")
|
||||
f.write(f"16. iDRAC Settings - syslog server address 1 : {syslog_s1 or ''}\n")
|
||||
f.write(f"17. iDRAC Settings - syslog server address 2 : {syslog_s2 or ''}\n")
|
||||
f.write(f"18. iDRAC Settings - syslog server port : {syslog_port or ''}\n")
|
||||
f.write(f"19. iDRAC Settings - Remote KVM Nonsecure port : {kvm_port or ''}\n")
|
||||
|
||||
|
||||
def main(ip_file: str) -> None:
|
||||
ip_path = Path(ip_file)
|
||||
if not ip_path.is_file():
|
||||
logging.error(f"Usage: python script.py <ip_file>\nIP file {ip_file} does not exist.")
|
||||
return
|
||||
|
||||
output_dir = resolve_output_dir()
|
||||
|
||||
# 원 Bash는 cat $IP_FILE → 파일 전체를 하나의 IP처럼 사용(=실질적으로 "한 줄 IP")
|
||||
# 여기서는 첫 번째 비어있지 않은 줄만 사용해 동일하게 동작시킵니다.
|
||||
lines = [ln.strip() for ln in ip_path.read_text(encoding="utf-8", errors="ignore").splitlines()]
|
||||
ip = next((ln for ln in lines if ln), None)
|
||||
if not ip:
|
||||
logging.error("No IP address found in the file.")
|
||||
return
|
||||
|
||||
start = time.time()
|
||||
fetch_idrac_info(ip, output_dir)
|
||||
end = time.time()
|
||||
|
||||
# 입력 파일 삭제 (원 Bash의 rm -f $IP_FILE와 동일)
|
||||
try:
|
||||
ip_path.unlink(missing_ok=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
elapsed = int(end - start)
|
||||
h, m, s = elapsed // 3600, (elapsed % 3600) // 60, elapsed % 60
|
||||
logging.info("정보 수집 완료.")
|
||||
logging.info(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
if len(sys.argv) != 2:
|
||||
logging.error("Usage: python script.py <ip_file>")
|
||||
sys.exit(1)
|
||||
main(sys.argv[1])
|
||||
@@ -0,0 +1,98 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="$(dirname "$0")/../temp/staging"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# 모든 hwinventory 저장
|
||||
local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo)
|
||||
#local swinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS swinventory)
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory)
|
||||
|
||||
#서비스 태그 가져오기
|
||||
local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#iDRAC MAC 확인
|
||||
local idrac_mac=$(echo "$getsysinfo" | grep -i "MAC Address = " | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#NIC.Integrated MAC 확인
|
||||
local Integrated_1=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Integrated_2=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-2-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#추가 NIC MAC 확인
|
||||
#local NIC_Slot_1=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.1-1-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
#local NIC_Slot_2=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.1-2-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#OnBoard MAC 확인
|
||||
local Onboard_1=$(echo "$getsysinfo" | grep -P "NIC.Embedded.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Onboard_2=$(echo "$getsysinfo" | grep -P "NIC.Embedded.2-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#파트 벤더 확인
|
||||
local memory=$(echo "$hwinventory" | grep -A5 "DIMM" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
local nvme_m2=$(echo "$hwinventory" | grep -A3 "Disk.Direct" | grep "Manufacturer" | awk -F '= ' '{print $2}' | sort | uniq)
|
||||
local ssd=$(echo "$hwinventory" | grep -A3 "Disk.Bay" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
|
||||
# 서비스 태그가 존재하는지 확인
|
||||
if [ -z "$SVC_TAG" ]; then
|
||||
echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP"
|
||||
return
|
||||
fi
|
||||
|
||||
local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt"
|
||||
# SVC Tag 확인
|
||||
echo "$SVC_TAG" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_1" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_2" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_1" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_2" >> "$OUTPUT_FILE"
|
||||
echo "$idrac_mac" >> "$OUTPUT_FILE"
|
||||
echo "$memory" >> "$OUTPUT_FILE"
|
||||
echo "$nvme_m2" >> "$OUTPUT_FILE"
|
||||
echo "$ssd" >> "$OUTPUT_FILE"
|
||||
#임시파일 제거
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "정보 수집 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,314 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="$(dirname "$0")/../temp/staging"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# 모든 hwinventory 저장
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory)
|
||||
# 모든 샷시 정보 저장
|
||||
local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo)
|
||||
# 모든 SysProfileSettings 저장
|
||||
local SysProfileSettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.SysProfileSettings)
|
||||
# ProcessorSettings 저장
|
||||
local ProcessorSettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.ProcSettings)
|
||||
# Memory Settings 저장
|
||||
local MemorySettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.MemSettings)
|
||||
# Raid Settings 저장
|
||||
local STORAGEController=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get STORAGE.Controller.1)
|
||||
|
||||
# 서비스 태그 가져오기
|
||||
local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Bios Firmware Version 확인
|
||||
local Bios_firmware=$(echo "$getsysinfo" | grep -i "System BIOS Version" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Firmware Version 확인
|
||||
local iDRAC_firmware=$(echo "$getsysinfo" | grep -i "Firmware Version" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Intel NIC Firmware Version 확인
|
||||
local Intel_NIC_firmware=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get NIC.FrmwImgMenu.1 | grep -i "#FamilyVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# OnBoard NIC Firmware Version 확인
|
||||
local Onboard_NIC_firmware=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get NIC.FrmwImgMenu.5 | grep -i "#FamilyVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# R/C Firmware Version 확인
|
||||
local Raid_firmware=$(echo "$hwinventory" | grep -i "ControllerFirmwareVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Bios 설정 Boot Mode 확인
|
||||
local Bios_BootMode=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.BiosBootSettings | grep -i "BootMode" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Bios SysProfileSettings 설정 정보 확인
|
||||
local SysProFileSettings_info1=$(echo "$SysProfileSettings" | grep -i "SysProfile=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info2=$(echo "$SysProfileSettings" | grep -i "EnergyPerformanceBias" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info3=$(echo "$SysProfileSettings" | grep -i "MemFrequency" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info4=$(echo "$SysProfileSettings" | grep -i "ProcTurboMode" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info5=$(echo "$SysProfileSettings" | grep -i "ProcC1E" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info6=$(echo "$SysProfileSettings" | grep -i "ProcCStates" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info7=$(echo "$SysProfileSettings" | grep -i "MonitorMwait" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Processor Settings - Logical Processor
|
||||
local ProcessorSettings_info1=$(echo "$ProcessorSettings" | grep -i "LogicalProc" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local ProcessorSettings_info2=$(echo "$ProcessorSettings" | grep -i "ProcVirtualization" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local ProcessorSettings_info3=$(echo "$ProcessorSettings" | grep -i "LlcPrefetch" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local ProcessorSettings_info4=$(echo "$ProcessorSettings" | grep -i "ProcX2Apic" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Memory Settings - Node Interleaving
|
||||
local MemorySettings_info1=$(echo "$MemorySettings" | grep -i "NodeInterleave" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local MemorySettings_info2=$(echo "$MemorySettings" | grep -i "PPROnUCE" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local MemorySettings_info3=$(echo "$MemorySettings" | grep -i "CECriticalSEL" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# System Settings - Thermal Profile Optimization
|
||||
local SystemSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get System.ThermalSettings | grep -i "ThermalProfile" | awk -F '=' '{print $2}')
|
||||
# Integrated Devices Settings - SR-IOV Global Enable
|
||||
local IntegratedDevicesSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get Bios.IntegratedDevices | grep -i "SriovGlobalEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Miscellaneous Settings - F1/F2 Prompt on Error
|
||||
local IMiscellaneousSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.MiscSettings | grep -i "ErrPrompt" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# iDRAC Settings - Timezone
|
||||
local iDRAC_Settings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.Time.Timezone | grep -i "Timezone" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IPMI LAN Selection
|
||||
local iDRAC_Settings_info2=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentNIC | grep -i "ActiveNIC" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IPMI IP(IPv4)
|
||||
local iDRAC_Settings_info3=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentIPv4 | grep -i "DHCPEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IPMI IP(IPv6)
|
||||
local iDRAC_Settings_info4=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentIPv6 | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - Redfish Support
|
||||
local iDRAC_Settings_info5=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.Redfish.Enable | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SSH Support
|
||||
local iDRAC_Settings_info6=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SSH | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - AD User Domain Name
|
||||
local iDRAC_Settings_info7=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.USERDomain.1.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SC Server Address
|
||||
local iDRAC_Settings_info8=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ActiveDirectory.DomainController1 | grep -i "DomainController1" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SE AD RoleGroup Name
|
||||
local iDRAC_Settings_info9=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SE AD RoleGroup Dome인
|
||||
local iDRAC_Settings_info10=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Domain | grep -i "Domain" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SE AD RoleGroup Privilege
|
||||
local iDRAC_Settings_info11=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Privilege | grep -i "Privilege" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IDC AD RoleGroup name
|
||||
local iDRAC_Settings_info12=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IDC AD RoleGroup Dome인
|
||||
local iDRAC_Settings_info13=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Domain | grep -i "Domain" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IDC AD RoleGroup Privilege
|
||||
local iDRAC_Settings_info14=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Privilege | grep -i "Privilege" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
local iDRAC_Settings_info15=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.SysLogEnable | grep -i "SysLogEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - syslog server address 1
|
||||
local iDRAC_Settings_info16=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Server1 | grep -i "Server1" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - syslog server address 2
|
||||
local iDRAC_Settings_info17=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Server2 | grep -i "Server2" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - syslog server port
|
||||
local iDRAC_Settings_info18=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Port | grep -i "Port" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - VirtualConsole Port
|
||||
local iDRAC_Settings_info19=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.VirtualConsole.Port | grep -i "Port" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# RAID Settings - ProductName
|
||||
local RAID_info0=$(echo "$hwinventory" | grep -i "ProductName = PERC" | awk -F '=' '{print $2}')
|
||||
# RAID Settings - ProductName
|
||||
local RAID_info7=$(echo "$hwinventory" | grep -i "ProductName = BOSS" | awk -F '=' '{print $2}')
|
||||
# RAID Settings - RAIDType
|
||||
local RAID_info1=$(echo "$hwinventory" | grep -i "RAIDTypes" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - StripeSize
|
||||
local RAID_info2=$(echo "$hwinventory" | grep -i "StripeSize" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - ReadCachePolicy
|
||||
local RAID_info3=$(echo "$hwinventory" | grep -i "ReadCachePolicy" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - WriteCachePolicy
|
||||
local RAID_info4=$(echo "$hwinventory" | grep -i "WriteCachePolicy" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - CheckConsistencyMode
|
||||
local RAID_info5=$(echo "$STORAGEController" | grep -i "CheckConsistencyMode" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - PatrolReadRate
|
||||
local RAID_info6=$(echo "$STORAGEController" | grep -i "PatrolReadRate" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# 서비스 태그가 존재하는지 확인
|
||||
if [ -z "$SVC_TAG" ]; then
|
||||
echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP"
|
||||
return
|
||||
fi
|
||||
|
||||
local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt"
|
||||
echo "Dell EMC Server Bios,iDRAC,R/C Setting (SVC Tag: $SVC_TAG)" | tee -a "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
echo "------------------------------------------Firware Version 정보------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# SVC Tag 확인
|
||||
echo "1. SVC Tag : $SVC_TAG" >> "$OUTPUT_FILE"
|
||||
|
||||
# Bios Firmware Version 확인
|
||||
echo "2. Bios Firmware : $Bios_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# iDRAC Firmware Version 확인
|
||||
echo "3. iDRAC Firmware Version : $iDRAC_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# Intel NIC Firmware Version 확인
|
||||
echo "4. NIC Integrated Firmware Version : $Intel_NIC_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# OnBoard NIC Firmware Version 확인
|
||||
echo "5. OnBoard NIC Firmware Version : $Onboard_NIC_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# Raid Controller Firmware Version 확인
|
||||
echo "6. Raid Controller Firmware Version : $Raid_firmware" >> "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
|
||||
echo "---------------------------------------------Bios 설정 정보----------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# bios Boot Mode 확인
|
||||
echo "01. Bios Boot Mode : $Bios_BootMode" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - System Profile
|
||||
echo "02. System Profile Settings - System Profile : $SysProFileSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - CPU Power Management
|
||||
echo "03. System Profile Settings - CPU Power Management : $SysProFileSettings_info2" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - Memory Frequency
|
||||
echo "04. System Profile Settings - Memory Frequency : $SysProFileSettings_info3" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - Turbo Boost
|
||||
echo "05. System Profile Settings - Turbo Boost : $SysProFileSettings_info4" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - C1E
|
||||
echo "06. System Profile Settings - C1E : $SysProFileSettings_info5" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - C-States
|
||||
echo "07. System Profile Settings - C-States : $SysProFileSettings_info6" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - C-States
|
||||
echo "08. System Profile Settings - Monitor/Mwait : $SysProFileSettings_info7" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - Logical Processor
|
||||
echo "09. Processor Settings - Logical Processor : $ProcessorSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - Virtualization Technology
|
||||
echo "10. Processor Settings - Virtualization Technology : $ProcessorSettings_info2" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - LLC Prefetch
|
||||
echo "11. Processor Settings - LLC Prefetch : $ProcessorSettings_info3" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - x2APIC Mode
|
||||
echo "12. Processor Settings - x2APIC Mode : $ProcessorSettings_info4" >> "$OUTPUT_FILE"
|
||||
|
||||
# Memory Settings - Node Interleaving
|
||||
echo "13. Memory Settings - Node Interleaving : $MemorySettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Memory Settings - DIMM Self Healing (Post Package Repair) on Uncorrectable Memory Error
|
||||
echo "14. Memory Settings - DIMM Self Healing (Post Package Repair) on Uncorrectable Memory Error : $MemorySettings_info2" >> "$OUTPUT_FILE"
|
||||
|
||||
# Memory Settings - Correctable Error Logging
|
||||
echo "15. Memory Settings - Correctable Error Logging : $MemorySettings_info3" >> "$OUTPUT_FILE"
|
||||
|
||||
# System Settings - Thermal Profile Optimization
|
||||
echo "16. System Settings - Thermal Profile Optimization : $SystemSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Integrated Devices Settings - SR-IOV Global Enable
|
||||
echo "17. Integrated Devices Settings - SR-IOV Global Enable : $IntegratedDevicesSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Miscellaneous Settings - F1/F2 Prompt on Error
|
||||
echo "18. Miscellaneous Settings - F1/F2 Prompt on Error : $IMiscellaneousSettings_info1" >> "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
|
||||
echo "---------------------------------------------iDRAC 설정 정보----------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Timezone
|
||||
echo "01. iDRAC Settings - Timezone : $iDRAC_Settings_info1" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - IPMI LAN Selection
|
||||
echo "02. iDRAC Settings - IPMI LAN Selection : $iDRAC_Settings_info2" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - IPMI IP(IPv4)
|
||||
echo "03. iDRAC Settings - IPMI IP(IPv4) : $iDRAC_Settings_info3" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - IPMI IP(IPv6)
|
||||
echo "04. iDRAC Settings - IPMI IP(IPv6) : $iDRAC_Settings_info4" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Redfish Support
|
||||
echo "05. iDRAC Settings - Redfish Support : $iDRAC_Settings_info5" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SSH Support
|
||||
echo "06. iDRAC Settings - SSH Support : $iDRAC_Settings_info6" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - AD User Domain Name
|
||||
echo "07. iDRAC Settings - AD User Domain Name : $iDRAC_Settings_info7" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SC Server Address
|
||||
echo "08. iDRAC Settings - SC Server Address : $iDRAC_Settings_info8" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE AD RoleGroup Name
|
||||
echo "09. iDRAC Settings - SE AD RoleGroup Name : $iDRAC_Settings_info9" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE AD RoleGroup Dome인
|
||||
echo "10. iDRAC Settings - SE AD RoleGroup Dome인 : $iDRAC_Settings_info10" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE AD RoleGroup Privilege
|
||||
echo "11. iDRAC Settings - SE AD RoleGroup Privilege : $iDRAC_Settings_info11" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE IDC RoleGroup Name
|
||||
echo "12. iDRAC Settings - IDC AD RoleGroup Name : $iDRAC_Settings_info12" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE IDC RoleGroup Dome인
|
||||
echo "13. iDRAC Settings - IDC AD RoleGroup Domain : $iDRAC_Settings_info13" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE IDC RoleGroup Dome인
|
||||
echo "14. iDRAC Settings - IDC AD RoleGroup Privilege : $iDRAC_Settings_info14" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
echo "15. iDRAC Settings - Remote Log (syslog) : $iDRAC_Settings_info15" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
echo "16. iDRAC Settings - syslog server address 1 : $iDRAC_Settings_info16" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
echo "17. iDRAC Settings - syslog server address 2 : $iDRAC_Settings_info17" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - syslog server port
|
||||
echo "18. iDRAC Settings - syslog server port : $iDRAC_Settings_info18" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote KVM Nonsecure port
|
||||
echo "19. iDRAC Settings - Remote KVM Nonsecure port : $iDRAC_Settings_info19" >> "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
|
||||
echo "---------------------------------------------Raid 설정 정보----------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - Raid Types
|
||||
echo "01. RAID Settings - Raid ProductName : $RAID_info7, $RAID_info0" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - Raid Types
|
||||
echo "02. RAID Settings - Raid Typest(NVMe) : $RAID_info1" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - StripeSize
|
||||
echo "03. RAID Settings - StripeSize(NVMe) : $RAID_info2" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - ReadCachePolicy
|
||||
echo "04. RAID Settings - ReadCachePolicy(NVMe) : $RAID_info3" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - ReadCachePolicy
|
||||
echo "05. RAID Settings - WriteCachePolicy(NVMe) : $RAID_info4" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - CheckConsistencyMode
|
||||
echo "06. RAID Settings - CheckConsistencyMode : $RAID_info5" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - PatrolReadMode
|
||||
echo "07. RAID Settings - PatrolReadRate : $RAID_info6" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - period
|
||||
echo "08. RAID Settings - period : 168h" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - Power Save
|
||||
echo "09. RAID Settings - Power Save : No" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - JBODMODE
|
||||
echo "10. RAID Settings - JBODMODE : Controller does not support JBOD" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - maxconcurrentpd
|
||||
echo "11. RAID Settings - maxconcurrentpd : 240" >> "$OUTPUT_FILE"
|
||||
|
||||
# 임시 파일 삭제
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "정보 수집 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,98 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="$(dirname "$0")/../temp/staging"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# 모든 hwinventory 저장
|
||||
local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo)
|
||||
#local swinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS swinventory)
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory)
|
||||
|
||||
#서비스 태그 가져오기
|
||||
local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#iDRAC MAC 확인
|
||||
local idrac_mac=$(echo "$getsysinfo" | grep -i "MAC Address = " | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#NIC.Integrated MAC 확인
|
||||
local Integrated_1=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Integrated_2=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-2-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#추가 NIC MAC 확인
|
||||
#local NIC_Slot_1=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.1-1-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
#local NIC_Slot_2=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.1-2-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#OnBoard MAC 확인
|
||||
local Onboard_1=$(echo "$getsysinfo" | grep -P "NIC.Embedded.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Onboard_2=$(echo "$getsysinfo" | grep -P "NIC.Embedded.2-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#파트 벤더 확인
|
||||
local memory=$(echo "$hwinventory" | grep -A5 "DIMM" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
local nvme_m2=$(echo "$hwinventory" | grep -A3 "Disk.Direct" | grep "Manufacturer" | awk -F '= ' '{print $2}' | sort | uniq)
|
||||
local ssd=$(echo "$hwinventory" | grep -A3 "Disk.Bay" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
|
||||
# 서비스 태그가 존재하는지 확인
|
||||
if [ -z "$SVC_TAG" ]; then
|
||||
echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP"
|
||||
return
|
||||
fi
|
||||
|
||||
local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt"
|
||||
# SVC Tag 확인
|
||||
echo "$SVC_TAG" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_1" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_2" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_1" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_2" >> "$OUTPUT_FILE"
|
||||
echo "$idrac_mac" >> "$OUTPUT_FILE"
|
||||
echo "$memory" >> "$OUTPUT_FILE"
|
||||
echo "$nvme_m2" >> "$OUTPUT_FILE"
|
||||
echo "$ssd" >> "$OUTPUT_FILE"
|
||||
#임시파일 제거
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "정보 수집 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,120 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="$(dirname "$0")/../temp/staging"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# 모든 hwinventory 저장
|
||||
local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo)
|
||||
local swinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS swinventory)
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory)
|
||||
|
||||
#서비스 태그 가져오기
|
||||
local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#iDRAC MAC 확인
|
||||
local idrac_mac=$(echo "$getsysinfo" | grep -i "MAC Address = " | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#NIC.Integrated MAC 확인
|
||||
local Integrated_1=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Integrated_2=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-2-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Integrated_3=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-3-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Integrated_4=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-4-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#NIC.Slot.31 MAC 확인
|
||||
local NICslot31_1=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.31-1-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local NICslot31_2=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.31-2-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#NIC.Slot.40 MAC 확인
|
||||
local NICslot40_1=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.40-1-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local NICslot40_2=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.40-2-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
|
||||
#추가 NIC MAC 확인
|
||||
local InfiniBand_Slot_32=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.32-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local InfiniBand_Slot_34=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.34-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local InfiniBand_Slot_37=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.37-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local InfiniBand_Slot_38=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.38-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
|
||||
#OnBoard MAC 확인
|
||||
local Onboard_1=$(echo "$getsysinfo" | grep -P "NIC.Embedded.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Onboard_2=$(echo "$getsysinfo" | grep -P "NIC.Embedded.2-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#파트 벤더 확인
|
||||
local memory=$(echo "$hwinventory" | grep -A5 "DIMM" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
local ssd=$(echo "$hwinventory" | grep -A3 "Disk.Bay" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq)
|
||||
|
||||
# 서비스 태그가 존재하는지 확인
|
||||
if [ -z "$SVC_TAG" ]; then
|
||||
echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP"
|
||||
return
|
||||
fi
|
||||
|
||||
local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt"
|
||||
# 정보저장
|
||||
echo "$SVC_TAG" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_1" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_2" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_3" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_4" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_1" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_2" >> "$OUTPUT_FILE"
|
||||
echo "$NICslot31_1" >> "$OUTPUT_FILE"
|
||||
echo "$NICslot31_2" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_38" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_37" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_32" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_34" >> "$OUTPUT_FILE"
|
||||
echo "$NICslot40_1" >> "$OUTPUT_FILE"
|
||||
echo "$NICslot40_2" >> "$OUTPUT_FILE"
|
||||
echo "$idrac_mac" >> "$OUTPUT_FILE"
|
||||
echo "$memory" >> "$OUTPUT_FILE"
|
||||
echo "$ssd" >> "$OUTPUT_FILE"
|
||||
#임시파일 제거
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "정보 수집 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
레거시 호환성 래퍼 - XE9680_H200_IB_10EA_MAC_info.py
|
||||
실제 로직은 unified/collect_mac.py의 'xe9680_h200_10ea' 프로파일 사용
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
script_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(script_dir))
|
||||
|
||||
from unified.collect_mac import main as unified_main
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python XE9680_H200_IB_10EA_MAC_info.py <ip_file>")
|
||||
sys.exit(1)
|
||||
|
||||
# xe9680_h200_10ea 프로파일 사용
|
||||
sys.argv.append("xe9680_h200_10ea")
|
||||
unified_main()
|
||||
@@ -0,0 +1,123 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="$(dirname "$0")/../temp/staging"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# 모든 hwinventory 저장
|
||||
local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo)
|
||||
local swinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS swinventory)
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory)
|
||||
|
||||
#서비스 태그 가져오기
|
||||
local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#iDRAC MAC 확인
|
||||
local idrac_mac=$(echo "$getsysinfo" | grep -i "MAC Address = " | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#NIC.Integrated MAC 확인
|
||||
local Integrated_1=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Integrated_2=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-2-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Integrated_3=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-3-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Integrated_4=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-4-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#NIC.Slot.31 MAC 확인
|
||||
#local NICslot31_1=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.31-1-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
#local NICslot31_2=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.31-2-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#추가 NIC MAC 확인
|
||||
local InfiniBand_Slot_31=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.31-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local InfiniBand_Slot_32=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.32-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local InfiniBand_Slot_33=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.33-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local InfiniBand_Slot_34=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.34-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local InfiniBand_Slot_35=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.35-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local InfiniBand_Slot_36=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.36-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local InfiniBand_Slot_37=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.37-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local InfiniBand_Slot_38=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.38-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local InfiniBand_Slot_39=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.39-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local InfiniBand_Slot_40=$(echo "$swinventory" | awk '/FQDD = InfiniBand.Slot.40-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
|
||||
#OnBoard MAC 확인
|
||||
local Onboard_1=$(echo "$getsysinfo" | grep -P "NIC.Embedded.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Onboard_2=$(echo "$getsysinfo" | grep -P "NIC.Embedded.2-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#파트 벤더 확인
|
||||
local memory=$(echo "$hwinventory" | grep -A5 "DIMM" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
local ssd=$(echo "$hwinventory" | grep -A3 "Disk.Bay" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq)
|
||||
|
||||
# 서비스 태그가 존재하는지 확인
|
||||
if [ -z "$SVC_TAG" ]; then
|
||||
echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP"
|
||||
return
|
||||
fi
|
||||
|
||||
local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt"
|
||||
# 정보저장
|
||||
echo "$SVC_TAG" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_1" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_2" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_3" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_4" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_1" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_2" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_38" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_39" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_37" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_36" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_32" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_33" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_34" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_35" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_31" >> "$OUTPUT_FILE"
|
||||
echo "$InfiniBand_Slot_40" >> "$OUTPUT_FILE"
|
||||
echo "$idrac_mac" >> "$OUTPUT_FILE"
|
||||
echo "$memory" >> "$OUTPUT_FILE"
|
||||
echo "$ssd" >> "$OUTPUT_FILE"
|
||||
#임시파일 제거
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "정보 수집 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,210 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import yaml
|
||||
import argparse
|
||||
import subprocess
|
||||
import logging
|
||||
import fnmatch
|
||||
from pathlib import Path
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from dotenv import load_dotenv, find_dotenv
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
# .env 로드
|
||||
load_dotenv(find_dotenv())
|
||||
|
||||
IDRAC_USER = os.getenv("IDRAC_USER")
|
||||
IDRAC_PASS = os.getenv("IDRAC_PASS")
|
||||
|
||||
# 경로 설정
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
PROFILES_FILE = BASE_DIR / "profiles" / "gpu_profiles.yaml"
|
||||
OUTPUT_DIR = BASE_DIR.parent / "temp" / "staging"
|
||||
|
||||
def load_profile(profile_name="default"):
|
||||
"""Load specific profile from gpu_profiles.yaml"""
|
||||
if not PROFILES_FILE.exists():
|
||||
logging.warning(f"Profile file not found at {PROFILES_FILE}. Using defaults.")
|
||||
return {}
|
||||
|
||||
try:
|
||||
with open(PROFILES_FILE, 'r', encoding='utf-8') as f:
|
||||
data = yaml.safe_load(f)
|
||||
profiles = data.get('profiles', {})
|
||||
return profiles.get(profile_name, {})
|
||||
except Exception as e:
|
||||
logging.error(f"Error loading profile: {e}")
|
||||
return {}
|
||||
|
||||
def resolve_output_dir() -> Path:
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
return OUTPUT_DIR
|
||||
|
||||
def parse_gpu_serials_from_hwinventory(hwinv_text: str, target_slots=None) -> dict:
|
||||
"""
|
||||
Parse GPU serials and filter based on target_slots patterns.
|
||||
target_slots: list of glob patterns (e.g. ["Video.Slot.*"])
|
||||
"""
|
||||
results = {}
|
||||
blocks = re.split(r"\n\s*\n", hwinv_text, flags=re.MULTILINE)
|
||||
|
||||
for block in blocks:
|
||||
# Check if it looks like a Video/GPU block
|
||||
if not re.search(r"\[?InstanceID:\s*Video\.Slot\.", block):
|
||||
continue
|
||||
|
||||
# Extract FQDD
|
||||
fqdd = None
|
||||
m_fqdd = re.search(r"^FQDD\s*=\s*([^\r\n]+)", block, flags=re.MULTILINE)
|
||||
if m_fqdd:
|
||||
fqdd = m_fqdd.group(1).strip()
|
||||
else:
|
||||
m_hdr = re.search(r"\[InstanceID:\s*(Video\.Slot\.[^\]\r\n]+)\]", block)
|
||||
if m_hdr:
|
||||
fqdd = m_hdr.group(1).strip()
|
||||
|
||||
if not fqdd:
|
||||
continue
|
||||
|
||||
# Filtering logic
|
||||
if target_slots:
|
||||
matched = False
|
||||
for pattern in target_slots:
|
||||
# fnmatch supports simple unix shell style wildcards (*, ?, [], etc)
|
||||
if fnmatch.fnmatch(fqdd, pattern):
|
||||
matched = True
|
||||
break
|
||||
if not matched:
|
||||
continue
|
||||
|
||||
# Extract SerialNumber
|
||||
m_sn = re.search(r"^SerialNumber\s*=\s*([^\r\n]+)", block, flags=re.MULTILINE)
|
||||
serial = m_sn.group(1).strip() if m_sn else "Not Found"
|
||||
|
||||
results[fqdd] = serial
|
||||
|
||||
return results
|
||||
|
||||
def get_slot_index(fqdd: str):
|
||||
"""
|
||||
Extract logic for sorting.
|
||||
Format usually: Video.Slot.X-Y -> returns (X, Y) tuple
|
||||
"""
|
||||
m = re.search(r"Video\.Slot\.(\d+)-(\d+)", fqdd)
|
||||
if m:
|
||||
return (int(m.group(1)), int(m.group(2)))
|
||||
m_simple = re.search(r"Video\.Slot\.(\d+)", fqdd)
|
||||
if m_simple:
|
||||
return (int(m_simple.group(1)), 0)
|
||||
return (float('inf'), float('inf'))
|
||||
|
||||
def fetch_idrac_info(idrac_ip: str, output_dir: Path, gpu_settings: dict) -> None:
|
||||
try:
|
||||
# 1. Get SVC Tag
|
||||
cmd_getsysinfo = [
|
||||
"racadm", "-r", idrac_ip, "-u", IDRAC_USER or "", "-p", IDRAC_PASS or "", "getsysinfo"
|
||||
]
|
||||
# execute without shell=True for security (if possible), but subprocess.getoutput uses shell
|
||||
# Here we use subprocess.run for better control if needed, but sticking to logic similar to original for now
|
||||
# Ideally: result = subprocess.run(cmd_getsysinfo, capture_output=True, text=True)
|
||||
# But let's stick to getoutput wrapper logic or use run compatible way
|
||||
|
||||
# Using subprocess.run is safer and modern
|
||||
res_sys = subprocess.run(cmd_getsysinfo, capture_output=True, text=True, encoding='utf-8', errors='ignore')
|
||||
getsysinfo = res_sys.stdout
|
||||
|
||||
svc_tag_match = re.search(r"SVC Tag\s*=\s*(\S+)", getsysinfo)
|
||||
svc_tag = svc_tag_match.group(1) if svc_tag_match else None
|
||||
|
||||
if not svc_tag:
|
||||
logging.error(f"Failed to retrieve SVC Tag for IP: {idrac_ip}")
|
||||
return
|
||||
|
||||
# 2. Get Hardware Inventory
|
||||
cmd_hwinv = [
|
||||
"racadm", "-r", idrac_ip, "-u", IDRAC_USER or "", "-p", IDRAC_PASS or "", "hwinventory"
|
||||
]
|
||||
res_inv = subprocess.run(cmd_hwinv, capture_output=True, text=True, encoding='utf-8', errors='ignore')
|
||||
hwinv_text = res_inv.stdout
|
||||
|
||||
# 3. Parse and Filter
|
||||
target_slots = gpu_settings.get('target_slots', ["Video.Slot.*"])
|
||||
gpu_map = parse_gpu_serials_from_hwinventory(hwinv_text, target_slots)
|
||||
|
||||
# 4. Sort
|
||||
sort_order = gpu_settings.get('sort_order', 'slot_index')
|
||||
|
||||
if sort_order == 'slot_index':
|
||||
sorted_keys = sorted(gpu_map.keys(), key=lambda k: (get_slot_index(k), k))
|
||||
elif sort_order == 'serial':
|
||||
sorted_keys = sorted(gpu_map.keys(), key=lambda k: gpu_map[k])
|
||||
else:
|
||||
sorted_keys = sorted(gpu_map.keys())
|
||||
|
||||
# 5. Write Output (Text format)
|
||||
output_file = output_dir / f"{svc_tag}.txt"
|
||||
with output_file.open("w", encoding="utf-8", newline="\n") as f:
|
||||
f.write(f"{svc_tag}\n")
|
||||
|
||||
if not gpu_map:
|
||||
f.write("No matching GPU inventory found.\n")
|
||||
return
|
||||
|
||||
for fqdd in sorted_keys:
|
||||
serial = gpu_map[fqdd]
|
||||
f.write(f"{fqdd}: {serial}\n")
|
||||
|
||||
# Serials only line
|
||||
serials_only = [gpu_map[k] for k in sorted_keys if gpu_map[k] != "Not Found"]
|
||||
if serials_only:
|
||||
f.write(f"SERIALS: {';'.join(serials_only)}\n")
|
||||
|
||||
logging.info(f"Saved {output_file}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error processing IP {idrac_ip}: {e}")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Collect GPU Serial Info")
|
||||
parser.add_argument("ip_file", help="File containing list of IP addresses")
|
||||
parser.add_argument("--profile", default="default", help="Profile name from gpu_profiles.yaml")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
ip_path = Path(args.ip_file)
|
||||
if not ip_path.is_file():
|
||||
logging.error(f"IP file {args.ip_file} does not exist.")
|
||||
return
|
||||
|
||||
# Load Profile
|
||||
profile = load_profile(args.profile)
|
||||
logging.info(f"Loaded profile: {args.profile}")
|
||||
|
||||
gpu_settings = profile.get('gpu_settings', {})
|
||||
|
||||
output_dir = resolve_output_dir()
|
||||
|
||||
with ip_path.open("r", encoding="utf-8") as file:
|
||||
ip_addresses = [line.strip() for line in file if line.strip()]
|
||||
|
||||
with ThreadPoolExecutor(max_workers=50) as executor:
|
||||
future_to_ip = {
|
||||
executor.submit(fetch_idrac_info, ip, output_dir, gpu_settings): ip
|
||||
for ip in ip_addresses
|
||||
}
|
||||
for future in as_completed(future_to_ip):
|
||||
ip = future_to_ip[future]
|
||||
try:
|
||||
future.result()
|
||||
except Exception as e:
|
||||
logging.error(f"Error on {ip}: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,250 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import argparse
|
||||
import concurrent.futures as futures
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional, Tuple, List
|
||||
import logging
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
# ===== 설정: 기본 계정/비밀번호 (환경변수로 덮어쓰기 가능) =====
|
||||
IDRAC_USER = os.getenv("IDRAC_USER", "root")
|
||||
IDRAC_PASS = os.getenv("IDRAC_PASS", "calvin")
|
||||
|
||||
# Resolve output dir relative to script location or CWD
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
if BASE_DIR.name == "scripts":
|
||||
DATA_DIR = BASE_DIR.parent
|
||||
else:
|
||||
DATA_DIR = Path("data").resolve()
|
||||
|
||||
OUTPUT_DIR = DATA_DIR / "temp" / "staging"
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
MAC_RE = re.compile(r"([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
# --- 유틸: 명령 실행 ---
|
||||
def run(cmd: List[str]) -> Tuple[int, str]:
|
||||
try:
|
||||
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, check=False)
|
||||
return p.returncode, p.stdout or ""
|
||||
except Exception as e:
|
||||
return 1, f"__EXEC_ERROR__ {e}"
|
||||
|
||||
# --- 파서: getsysinfo/swinventory/hwinventory 에서 필요한 값 추출 ---
|
||||
def extract_first_mac(text: str) -> Optional[str]:
|
||||
m = MAC_RE.search(text)
|
||||
return m.group(0) if m else None
|
||||
|
||||
def parse_svc_tag(getsysinfo: str) -> Optional[str]:
|
||||
# 예: "SVC Tag = ABCDEF2"
|
||||
m = re.search(r"SVC\s*Tag\s*=\s*([^\s]+)", getsysinfo)
|
||||
return m.group(1).strip() if m else None
|
||||
|
||||
def parse_specific_mac_in_getsysinfo(getsysinfo: str, key: str) -> Optional[str]:
|
||||
"""
|
||||
key 예시:
|
||||
- "NIC.Integrated.1-1-1"
|
||||
- "NIC.Embedded.1-1-1"
|
||||
해당 라인에서 MAC 패턴 추출
|
||||
"""
|
||||
for line in getsysinfo.splitlines():
|
||||
if key in line:
|
||||
mac = extract_first_mac(line)
|
||||
if mac:
|
||||
return mac
|
||||
return None
|
||||
|
||||
def parse_idrac_mac(getsysinfo: str) -> Optional[str]:
|
||||
"""
|
||||
원본 스크립트는 "MAC Address = " 를 grep 했습니다.
|
||||
해당 라인(들) 중 첫 MAC을 사용합니다.
|
||||
"""
|
||||
lines = [ln for ln in getsysinfo.splitlines() if "MAC Address" in ln]
|
||||
for ln in lines:
|
||||
mac = extract_first_mac(ln)
|
||||
if mac:
|
||||
return mac
|
||||
return None
|
||||
|
||||
def parse_infiniband_slot_macs_from_swinventory(swinventory: str, slots: List[int]) -> Dict[int, Optional[str]]:
|
||||
"""
|
||||
bash의 awk 트릭(해당 FQDD의 이전 줄에서 MAC 추출)을 그대로 재현:
|
||||
- swinventory 라인을 순회하면서 직전 라인을 prev로 저장
|
||||
- line이 'FQDD = InfiniBand.Slot.<N>-1' 에 매치되면 prev에서 MAC 추출
|
||||
"""
|
||||
want = {s: None for s in slots}
|
||||
prev = ""
|
||||
for line in swinventory.splitlines():
|
||||
m = re.search(r"FQDD\s*=\s*InfiniBand\.Slot\.(\d+)-1", line)
|
||||
if m:
|
||||
slot = int(m.group(1))
|
||||
if slot in want and want[slot] is None:
|
||||
want[slot] = extract_first_mac(prev) # 이전 줄에서 MAC
|
||||
prev = line
|
||||
return want
|
||||
|
||||
def parse_memory_vendor_initials(hwinventory: str) -> str:
|
||||
"""
|
||||
원본: grep -A5 "DIMM" | grep "Manufacturer" | ... | sort | uniq | cut -c1
|
||||
- 간단화: DIMM 근처 5줄 윈도우에서 Manufacturer 라인 모으기
|
||||
- 제조사 첫 글자만 모아 중복 제거, 정렬 후 이어붙임
|
||||
"""
|
||||
lines = hwinventory.splitlines()
|
||||
idxs = [i for i, ln in enumerate(lines) if "DIMM" in ln]
|
||||
vendors: List[str] = []
|
||||
for i in idxs:
|
||||
window = lines[i : i + 6] # 본문 포함 6줄(= -A5)
|
||||
for ln in window:
|
||||
if "Manufacturer" in ln and "=" in ln:
|
||||
v = ln.split("=", 1)[1].strip()
|
||||
if v:
|
||||
vendors.append(v)
|
||||
initials = sorted({v[0] for v in vendors if v})
|
||||
return "".join(initials)
|
||||
|
||||
def parse_ssd_manufacturers(hwinventory: str) -> str:
|
||||
"""
|
||||
원본: grep -A3 "Disk.Bay" | grep "Manufacturer" | uniq
|
||||
- "Disk.Bay" 라인부터 3줄 윈도우 내 Manufacturer 라인 추출, 고유값 join
|
||||
"""
|
||||
lines = hwinventory.splitlines()
|
||||
vendors: List[str] = []
|
||||
for i, ln in enumerate(lines):
|
||||
if "Disk.Bay" in ln:
|
||||
window = lines[i : i + 4]
|
||||
for w in window:
|
||||
if "Manufacturer" in w and "=" in w:
|
||||
v = w.split("=", 1)[1].strip()
|
||||
if v:
|
||||
vendors.append(v)
|
||||
uniq = sorted({v for v in vendors})
|
||||
return ", ".join(uniq)
|
||||
|
||||
# --- 단일 IP 처리 ---
|
||||
def fetch_idrac_info_for_ip(ip: str) -> Tuple[str, bool, str]:
|
||||
"""
|
||||
returns: (ip, success, message)
|
||||
success=True면 파일 저장 완료
|
||||
"""
|
||||
ip = ip.strip()
|
||||
if not ip:
|
||||
return ip, False, "빈 라인"
|
||||
|
||||
# racadm 호출
|
||||
base = ["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS]
|
||||
|
||||
rc1, getsysinfo = run(base + ["getsysinfo"])
|
||||
rc2, swinventory = run(base + ["swinventory"])
|
||||
rc3, hwinventory = run(base + ["hwinventory"])
|
||||
|
||||
if rc1 != 0 and rc2 != 0 and rc3 != 0:
|
||||
return ip, False, f"모든 racadm 호출 실패:\n{getsysinfo or ''}\n{swinventory or ''}\n{hwinventory or ''}"
|
||||
|
||||
svc_tag = parse_svc_tag(getsysinfo) if getsysinfo else None
|
||||
if not svc_tag:
|
||||
return ip, False, "서비스 태그(SVC Tag) 추출 실패"
|
||||
|
||||
# 개별 필드 파싱
|
||||
integrated_1 = parse_specific_mac_in_getsysinfo(getsysinfo, "NIC.Integrated.1-1-1") if getsysinfo else None
|
||||
integrated_2 = parse_specific_mac_in_getsysinfo(getsysinfo, "NIC.Integrated.1-2-1") if getsysinfo else None
|
||||
integrated_3 = parse_specific_mac_in_getsysinfo(getsysinfo, "NIC.Integrated.1-3-1") if getsysinfo else None
|
||||
integrated_4 = parse_specific_mac_in_getsysinfo(getsysinfo, "NIC.Integrated.1-4-1") if getsysinfo else None
|
||||
|
||||
onboard_1 = parse_specific_mac_in_getsysinfo(getsysinfo, "NIC.Embedded.1-1-1") if getsysinfo else None
|
||||
onboard_2 = parse_specific_mac_in_getsysinfo(getsysinfo, "NIC.Embedded.2-1-1") if getsysinfo else None
|
||||
|
||||
idrac_mac = parse_idrac_mac(getsysinfo) if getsysinfo else None
|
||||
|
||||
# InfiniBand.Slot.<N>-1 MAC (이전 라인에서 MAC 추출) — 출력 순서 유지
|
||||
desired_slots = [38, 39, 37, 36, 32, 33, 34, 35, 31, 40]
|
||||
slot_macs = parse_infiniband_slot_macs_from_swinventory(swinventory, desired_slots) if swinventory else {s: None for s in desired_slots}
|
||||
|
||||
memory_initials = parse_memory_vendor_initials(hwinventory) if hwinventory else ""
|
||||
ssd_vendors = parse_ssd_manufacturers(hwinventory) if hwinventory else ""
|
||||
|
||||
# 저장
|
||||
out_path = OUTPUT_DIR / f"{svc_tag}.txt"
|
||||
with out_path.open("w", encoding="utf-8") as f:
|
||||
# 원본 스크립트와 동일한 출력 순서
|
||||
f.write(f"{svc_tag}\n")
|
||||
f.write(f"{integrated_1 or ''}\n")
|
||||
f.write(f"{integrated_2 or ''}\n")
|
||||
f.write(f"{integrated_3 or ''}\n")
|
||||
f.write(f"{integrated_4 or ''}\n")
|
||||
f.write(f"{onboard_1 or ''}\n")
|
||||
f.write(f"{onboard_2 or ''}\n")
|
||||
# 슬롯 고정 순서
|
||||
for sl in desired_slots:
|
||||
f.write(f"{slot_macs.get(sl) or ''}\n")
|
||||
f.write(f"{idrac_mac or ''}\n")
|
||||
f.write(f"{memory_initials}\n")
|
||||
f.write(f"{ssd_vendors}\n")
|
||||
|
||||
return ip, True, f"저장: {out_path}"
|
||||
|
||||
# --- 메인 ---
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="iDRAC 정보 수집 (Python 포팅)")
|
||||
parser.add_argument("ip_file", help="IP 주소 목록 파일 (줄 단위)")
|
||||
parser.add_argument("--workers", type=int, default=20, help="병렬 스레드 수 (기본 20)")
|
||||
args = parser.parse_args()
|
||||
|
||||
ip_file = Path(args.ip_file)
|
||||
if not ip_file.exists():
|
||||
logging.error(f"IP 파일이 존재하지 않습니다: {ip_file}")
|
||||
sys.exit(1)
|
||||
|
||||
with ip_file.open("r", encoding="utf-8") as f:
|
||||
ips = [ln.strip() for ln in f if ln.strip()]
|
||||
|
||||
if not ips:
|
||||
logging.error("IP 목록이 비어 있습니다.")
|
||||
sys.exit(1)
|
||||
|
||||
logging.info(f"[시작] 총 {len(ips)}대, workers={args.workers}, IDRAC_USER={IDRAC_USER}")
|
||||
|
||||
t0 = time.time()
|
||||
ok = 0
|
||||
fail = 0
|
||||
|
||||
# 병렬 수집
|
||||
with futures.ThreadPoolExecutor(max_workers=args.workers) as ex:
|
||||
futs = {ex.submit(fetch_idrac_info_for_ip, ip): ip for ip in ips}
|
||||
for fut in futures.as_completed(futs):
|
||||
ip = futs[fut]
|
||||
try:
|
||||
_ip, success, msg = fut.result()
|
||||
prefix = "[OK] " if success else "[FAIL] "
|
||||
if success:
|
||||
logging.info(prefix + ip + " - " + msg)
|
||||
else:
|
||||
logging.error(prefix + ip + " - " + msg)
|
||||
ok += int(success)
|
||||
fail += int(not success)
|
||||
except Exception as e:
|
||||
logging.error(f"[EXC] {ip} - {e}")
|
||||
fail += 1
|
||||
|
||||
dt = int(time.time() - t0)
|
||||
h, r = divmod(dt, 3600)
|
||||
m, s = divmod(r, 60)
|
||||
|
||||
logging.info("\n정보 수집 완료.")
|
||||
logging.info(f"성공 {ok}대 / 실패 {fail}대")
|
||||
logging.info(f"수집 완료 시간: {h} 시간, {m} 분, {s} 초.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,4 @@
|
||||
"""
|
||||
공통 라이브러리 패키지
|
||||
"""
|
||||
__version__ = "1.0.0"
|
||||
@@ -0,0 +1,129 @@
|
||||
"""
|
||||
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()
|
||||
@@ -0,0 +1,297 @@
|
||||
"""
|
||||
racadm 출력 파싱 유틸리티
|
||||
"""
|
||||
import re
|
||||
from typing import List, Optional, Dict, Tuple
|
||||
|
||||
|
||||
class InfoParser:
|
||||
"""racadm 명령 출력 파싱 유틸리티"""
|
||||
|
||||
# Word boundary to ensure we don't match partial GUIDs (which are longer)
|
||||
MAC_PATTERN = re.compile(r"\b([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}\b")
|
||||
|
||||
@staticmethod
|
||||
def extract_service_tag(sysinfo: str) -> Optional[str]:
|
||||
"""
|
||||
서비스 태그 추출
|
||||
|
||||
Args:
|
||||
sysinfo: getsysinfo 명령 출력
|
||||
|
||||
Returns:
|
||||
서비스 태그 또는 None
|
||||
"""
|
||||
m = re.search(r"SVC\s*Tag\s*=\s*(\S+)", sysinfo, re.IGNORECASE)
|
||||
return m.group(1).strip() if m else None
|
||||
|
||||
@staticmethod
|
||||
def extract_nic_macs(sysinfo: str, nic_patterns: List[str]) -> Dict[str, Optional[str]]:
|
||||
"""
|
||||
NIC MAC 주소 추출
|
||||
|
||||
Args:
|
||||
sysinfo: getsysinfo 명령 출력
|
||||
nic_patterns: NIC 패턴 리스트 (예: ["NIC.Integrated.1-1-1", "NIC.Embedded.1-1-1"])
|
||||
|
||||
Returns:
|
||||
{pattern: mac_address} 딕셔너리
|
||||
"""
|
||||
results = {}
|
||||
for pattern in nic_patterns:
|
||||
for line in sysinfo.splitlines():
|
||||
if pattern in line:
|
||||
mac = InfoParser.MAC_PATTERN.search(line)
|
||||
results[pattern] = mac.group(0) if mac else None
|
||||
break
|
||||
else:
|
||||
results[pattern] = None
|
||||
return results
|
||||
|
||||
@staticmethod
|
||||
def extract_nic_macs_from_hwinventory(hwinventory: str, nic_patterns: List[str]) -> Dict[str, Optional[str]]:
|
||||
"""
|
||||
hwinventory에서 NIC MAC 주소 추출
|
||||
|
||||
Args:
|
||||
hwinventory: hwinventory 명령 출력
|
||||
nic_patterns: NIC 패턴 리스트 (예: ["NIC.Integrated.1-1-1", "NIC.Slot.1-1-1"])
|
||||
|
||||
Returns:
|
||||
{pattern: mac_address} 딕셔너리
|
||||
"""
|
||||
results = {pattern: None for pattern in nic_patterns}
|
||||
|
||||
# hwinventory를 블록 단위로 분리 (빈 줄로 구분)
|
||||
blocks = re.split(r"\n\s*\n", hwinventory)
|
||||
|
||||
for block in blocks:
|
||||
# 블록 내에서 FQDD 또는 InstanceID 확인
|
||||
fqdd = None
|
||||
|
||||
# FQDD = NIC.Integrated.1-1-1 또는 [InstanceID: NIC.Integrated.1-1-1] 형식 찾기
|
||||
m_fqdd = re.search(r"FQDD\s*=\s*(\S+)", block, re.IGNORECASE)
|
||||
if m_fqdd:
|
||||
fqdd = m_fqdd.group(1).strip()
|
||||
# FQDD 키워드가 없을 경우를 대비해 InstanceID 헤더도 확인
|
||||
elif "[InstanceID:" in block:
|
||||
m_inst = re.search(r"InstanceID:\s*([^\]]+)", block)
|
||||
if m_inst:
|
||||
fqdd = m_inst.group(1).strip()
|
||||
|
||||
if not fqdd:
|
||||
continue
|
||||
|
||||
# 요청된 패턴 중 하나라도 포함하는지 확인 (정확한 매칭을 위해 수정 가능하나, 보통 포함 관계면 충분)
|
||||
# 여기서는 패턴이 FQDD와 정확히 일치하거나 FQDD가 패턴을 포함하는 경우를 찾음
|
||||
matched_pattern = None
|
||||
for pattern in nic_patterns:
|
||||
# 대소문자 무시 비교
|
||||
if pattern.lower() == fqdd.lower():
|
||||
matched_pattern = pattern
|
||||
break
|
||||
|
||||
# 정확히 일치하는 패턴을 못 찾았다면 다음 블록으로
|
||||
if not matched_pattern:
|
||||
continue
|
||||
|
||||
# MAC 주소 찾기
|
||||
# Ethernet Address = AA:BB:CC:DD:EE:FF
|
||||
# CurrentMACAddress = AA:BB:CC:DD:EE:FF
|
||||
# MAC Address = AA:BB:CC:DD:EE:FF
|
||||
mac_match = InfoParser.MAC_PATTERN.search(block)
|
||||
|
||||
if mac_match:
|
||||
results[matched_pattern] = mac_match.group(0)
|
||||
|
||||
return results
|
||||
|
||||
@staticmethod
|
||||
def extract_idrac_mac(sysinfo: str) -> Optional[str]:
|
||||
"""
|
||||
iDRAC MAC 주소 추출
|
||||
|
||||
Args:
|
||||
sysinfo: getsysinfo 명령 출력
|
||||
|
||||
Returns:
|
||||
iDRAC MAC 주소 또는 None
|
||||
"""
|
||||
for line in sysinfo.splitlines():
|
||||
if "MAC Address" in line:
|
||||
mac = InfoParser.MAC_PATTERN.search(line)
|
||||
if mac:
|
||||
return mac.group(0)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def extract_vendors(hwinventory: str, component_prefix: str, instance_must_contain: str = None) -> List[str]:
|
||||
"""
|
||||
컴포넌트 벤더 추출
|
||||
|
||||
Args:
|
||||
hwinventory: hwinventory 명령 출력
|
||||
component_prefix: 컴포넌트 접두사 ("DIMM", "Disk.Bay", "BOSS" 등)
|
||||
instance_must_contain: InstanceID/FQDD에 반드시 포함돼야 할 문자열 (예: "BOSS")
|
||||
|
||||
Returns:
|
||||
벤더 리스트 (중복 제거, 정렬됨)
|
||||
"""
|
||||
vendors = set()
|
||||
blocks = re.split(r"\n\s*\n", hwinventory)
|
||||
|
||||
for block in blocks:
|
||||
# Check if this block is for the target component using InstanceID or FQDD
|
||||
is_target_component = False
|
||||
matched_id = None
|
||||
|
||||
# Check InstanceID header: [InstanceID: DIMM.Socket.A1]
|
||||
if f"[InstanceID: {component_prefix}" in block:
|
||||
is_target_component = True
|
||||
m_inst = re.search(r"\[InstanceID:\s*([^\]]+)\]", block)
|
||||
if m_inst:
|
||||
matched_id = m_inst.group(1).strip()
|
||||
|
||||
# Also check FQDD line if InstanceID header check fails (fallback)
|
||||
elif not is_target_component:
|
||||
m_fqdd = re.search(r"^FQDD\s*=\s*(\S+)", block, re.MULTILINE)
|
||||
if m_fqdd and component_prefix in m_fqdd.group(1):
|
||||
is_target_component = True
|
||||
matched_id = m_fqdd.group(1).strip()
|
||||
|
||||
if not is_target_component:
|
||||
continue
|
||||
|
||||
# instance_must_contain 필터 적용
|
||||
if instance_must_contain and matched_id and instance_must_contain not in matched_id:
|
||||
continue
|
||||
|
||||
m = re.search(r"Manufacturer\s*=\s*(.+)", block, re.IGNORECASE)
|
||||
if m:
|
||||
vendors.add(m.group(1).strip())
|
||||
|
||||
return sorted(vendors)
|
||||
|
||||
@staticmethod
|
||||
def extract_infiniband_page_map(pages_output: str) -> List[Tuple[str, str]]:
|
||||
"""
|
||||
InfiniBand 페이지 번호와 슬롯 번호 매핑 추출
|
||||
|
||||
Args:
|
||||
pages_output: get InfiniBand.VndrConfigPage 출력
|
||||
|
||||
Returns:
|
||||
[(page_number, slot_number), ...] 리스트
|
||||
"""
|
||||
# InfiniBand.VndrConfigPage.1 [Key=InfiniBand.Slot.38-1#VndrConfigPage]
|
||||
matches = re.findall(
|
||||
r"InfiniBand\.VndrConfigPage\.(\d+)\s+\[Key=InfiniBand\.Slot\.(\d+)-\d+#VndrConfigPage]",
|
||||
pages_output
|
||||
)
|
||||
return matches
|
||||
|
||||
@staticmethod
|
||||
def extract_port_guid(page_detail: str) -> Optional[str]:
|
||||
"""
|
||||
InfiniBand 페이지 상세에서 PortGUID 추출
|
||||
|
||||
Args:
|
||||
page_detail: get InfiniBand.VndrConfigPage.{N} 출력
|
||||
|
||||
Returns:
|
||||
PortGUID 값 또는 None
|
||||
"""
|
||||
m = re.search(r"PortGUID=(\S+)", page_detail)
|
||||
return m.group(1) if m else None
|
||||
|
||||
@staticmethod
|
||||
def extract_value_by_pattern(text: str, pattern: str) -> Optional[str]:
|
||||
"""
|
||||
패턴으로 값 추출 (= 뒤의 값)
|
||||
|
||||
Args:
|
||||
text: 검색할 텍스트
|
||||
pattern: 검색 패턴
|
||||
|
||||
Returns:
|
||||
추출된 값 또는 None
|
||||
"""
|
||||
for line in text.splitlines():
|
||||
if pattern.lower() in line.lower():
|
||||
if '=' in line:
|
||||
return line.split('=', 1)[1].strip()
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def extract_infiniband_macs_from_swinventory(swinventory: str, target_slots: List[int]) -> Dict[int, str]:
|
||||
"""
|
||||
swinventory에서 InfiniBand 슬롯의 MAC 주소 추출
|
||||
(FQDD 라인 바로 윗줄에 MAC 주소가 있다는 가정 - 레거시 스크립트 로직)
|
||||
|
||||
Args:
|
||||
swinventory: swinventory 명령 출력
|
||||
target_slots: 추출할 슬롯 번호 리스트
|
||||
|
||||
Returns:
|
||||
{slot: mac_address} 딕셔너리
|
||||
"""
|
||||
results = {}
|
||||
prev_line = ""
|
||||
|
||||
# 슬롯별 패턴 미리 생성 (예: "FQDD = InfiniBand.Slot.31-1")
|
||||
slot_patterns = {slot: f"FQDD = InfiniBand.Slot.{slot}-1" for slot in target_slots}
|
||||
|
||||
for line in swinventory.splitlines():
|
||||
for slot, pattern in slot_patterns.items():
|
||||
if pattern in line:
|
||||
# 이전 라인에서 MAC 찾기
|
||||
mac = InfoParser.MAC_PATTERN.search(prev_line)
|
||||
if mac:
|
||||
results[slot] = mac.group(0)
|
||||
prev_line = line
|
||||
|
||||
return results
|
||||
|
||||
@staticmethod
|
||||
def extract_gpu_serials(hwinventory: str) -> Dict[str, str]:
|
||||
"""
|
||||
iDRAC hwinventory 전체 텍스트에서 GPU(Video.Slot.*) 블록을 찾아
|
||||
{FQDD(or InstanceID): SerialNumber} 딕셔너리로 반환.
|
||||
|
||||
Args:
|
||||
hwinventory: hwinventory 명령 출력
|
||||
|
||||
Returns:
|
||||
{fqdd: serial} 딕셔너리
|
||||
"""
|
||||
results = {}
|
||||
|
||||
# 빈 줄 기준 블록 분할(여러 개의 개행을 하나의 경계로)
|
||||
blocks = re.split(r"\n\s*\n", hwinventory, flags=re.MULTILINE)
|
||||
|
||||
for block in blocks:
|
||||
# GPU(Video) 블록만 처리
|
||||
# Video.Slot.X 또는 유사 패턴
|
||||
if not re.search(r"\[?InstanceID:\s*Video\.Slot\.", block):
|
||||
continue
|
||||
|
||||
# FQDD 우선, 없으면 [InstanceID: ...]에서 추출
|
||||
fqdd = None
|
||||
m_fqdd = re.search(r"^FQDD\s*=\s*([^\r\n]+)", block, flags=re.MULTILINE)
|
||||
if m_fqdd:
|
||||
fqdd = m_fqdd.group(1).strip()
|
||||
else:
|
||||
m_hdr = re.search(r"\[InstanceID:\s*(Video\.Slot\.[^\]\r\n]+)\]", block)
|
||||
if m_hdr:
|
||||
fqdd = m_hdr.group(1).strip()
|
||||
|
||||
if not fqdd:
|
||||
continue
|
||||
|
||||
# SerialNumber 추출
|
||||
m_sn = re.search(r"^SerialNumber\s*=\s*([^\r\n]+)", block, flags=re.MULTILINE)
|
||||
serial = m_sn.group(1).strip() if m_sn else "Not Found"
|
||||
|
||||
results[fqdd] = serial
|
||||
|
||||
return results
|
||||
@@ -0,0 +1,22 @@
|
||||
# GPU 서버 정보 수집 프로파일 (GUID + GPU Serial)
|
||||
profiles:
|
||||
default:
|
||||
description: "기본 GPU 시리얼 수집 설정"
|
||||
# GUID 관련 설정 (제거됨)
|
||||
# slot_priority: [38, 39, 37, 36, 32, 33, 34, 35, 31, 40]
|
||||
|
||||
# GPU Serial 관련 설정
|
||||
gpu_settings:
|
||||
target_slots: ["Video.Slot.*"]
|
||||
sort_order: "slot_index" # slot_index, serial, etc.
|
||||
|
||||
output_format: "combined"
|
||||
|
||||
h100_cluster:
|
||||
description: "H100 클러스터용 설정"
|
||||
slot_priority: [1, 2, 3, 4]
|
||||
gpu_settings:
|
||||
target_slots: ["Video.Slot.0-1", "Video.Slot.1-1"]
|
||||
sort_order: "slot_index"
|
||||
|
||||
output_format: "combined"
|
||||
@@ -0,0 +1,11 @@
|
||||
# GUID 수집 프로파일 정의
|
||||
profiles:
|
||||
default:
|
||||
description: "기본 GUID 수집"
|
||||
slot_priority: [38, 39, 37, 36, 32, 33, 34, 35, 31, 40]
|
||||
output_format: "combined" # combined 또는 individual
|
||||
|
||||
custom_priority:
|
||||
description: "사용자 정의 슬롯 우선순위"
|
||||
slot_priority: [] # 런타임에 환경변수 GUID_SLOT_PRIORITY에서 읽음
|
||||
output_format: "combined"
|
||||
@@ -0,0 +1,107 @@
|
||||
profiles:
|
||||
16G_R760XD2:
|
||||
description: 기본 MAC 수집 (Integrated + Embedded)
|
||||
exclude_boss: true
|
||||
include_disk_vendor: true
|
||||
include_idrac_mac: true
|
||||
include_memory_vendor: true
|
||||
nic_patterns:
|
||||
- NIC.Integrated.1-1-1
|
||||
- NIC.Integrated.1-2-1
|
||||
- NIC.Slot.3-1-1
|
||||
- NIC.Slot.3-2-1
|
||||
- NIC.Embedded.1-1-1
|
||||
- NIC.Embedded.2-1-1
|
||||
16G_T8/T8A:
|
||||
description: 새 프로파일
|
||||
extends: default
|
||||
16G_TYPE4,6:
|
||||
description: 기본 MAC 수집 (Integrated + Embedded)
|
||||
exclude_boss: true
|
||||
include_disk_vendor: true
|
||||
include_idrac_mac: true
|
||||
include_memory_vendor: true
|
||||
nic_patterns:
|
||||
- NIC.Integrated.1-1-1
|
||||
- NIC.Integrated.1-2-1
|
||||
- NIC.Embedded.1-1-1
|
||||
- NIC.Embedded.2-1-1
|
||||
16G_TYPE8,8A:
|
||||
description: 기본 MAC 수집 (Integrated + Embedded)
|
||||
exclude_boss: true
|
||||
include_disk_vendor: true
|
||||
include_idrac_mac: true
|
||||
include_memory_vendor: true
|
||||
nic_patterns:
|
||||
- NIC.Integrated.1-1-1
|
||||
- NIC.Integrated.1-2-1
|
||||
- NIC.Embedded.1-1-1
|
||||
- NIC.Embedded.2-1-1
|
||||
TY11_60ea:
|
||||
description: 기본 MAC 수집 (Integrated + Embedded)
|
||||
exclude_boss: true
|
||||
include_disk_vendor: true
|
||||
include_idrac_mac: true
|
||||
include_memory_vendor: true
|
||||
nic_patterns:
|
||||
- NIC.Integrated.1-1-1
|
||||
- NIC.Integrated.1-2-1
|
||||
- NIC.Slot.1-1-1
|
||||
- NIC.Slot.1-2-1
|
||||
- NIC.Slot.2-1-1
|
||||
- NIC.Slot.2-2-1
|
||||
- NIC.Embedded.1-1-1
|
||||
- NIC.Embedded.2-1-1
|
||||
default:
|
||||
description: 기본 MAC 수집 (Integrated + Embedded)
|
||||
exclude_boss: true
|
||||
include_disk_vendor: true
|
||||
include_idrac_mac: true
|
||||
include_memory_vendor: true
|
||||
nic_patterns:
|
||||
- NIC.Integrated.1-1-1
|
||||
- NIC.Integrated.1-2-1
|
||||
- NIC.Embedded.1-1-1
|
||||
- NIC.Embedded.2-1-1
|
||||
jp_54ea:
|
||||
description: JP 54EA 서버
|
||||
extends: default
|
||||
jp_type11a:
|
||||
description: JP_TYPE11A
|
||||
extends: default
|
||||
nic_patterns:
|
||||
- NIC.Integrated.1-1-1
|
||||
- NIC.Integrated.1-2-1
|
||||
- NIC.Embedded.1-1-1
|
||||
- NIC.Embedded.2-1-1
|
||||
- NIC.Slot.1-1-1
|
||||
- NIC.Slot.1-2-1
|
||||
- NIC.Slot.2-1-1
|
||||
- NIC.Slot.2-2-1
|
||||
sp_18ea:
|
||||
description: SP 18EA 서버
|
||||
extends: default
|
||||
type11:
|
||||
description: TYPE11 서버
|
||||
extends: default
|
||||
xe9680_h200_10ea:
|
||||
description: XE9680 H200 10EA InfiniBand
|
||||
extends: default
|
||||
infiniband_slots:
|
||||
- 38
|
||||
- 39
|
||||
- 37
|
||||
- 36
|
||||
- 32
|
||||
- 33
|
||||
- 34
|
||||
- 35
|
||||
- 31
|
||||
- 40
|
||||
nic_patterns:
|
||||
- NIC.Integrated.1-1-1
|
||||
- NIC.Integrated.1-2-1
|
||||
- NIC.Integrated.1-3-1
|
||||
- NIC.Integrated.1-4-1
|
||||
- NIC.Embedded.1-1-1
|
||||
- NIC.Embedded.2-1-1
|
||||
@@ -0,0 +1,676 @@
|
||||
profiles:
|
||||
JYH_AMD:
|
||||
bios_settings:
|
||||
- command: get bios.BiosBootSettings
|
||||
name: BIOS Boot Mode
|
||||
pattern: BootMode
|
||||
- command: get bios.SysProfileSettings
|
||||
name: System Profile
|
||||
pattern: SysProfile=
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Memory Frequency
|
||||
pattern: MemFrequency
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Turbo Boost
|
||||
pattern: ProcTurboMode
|
||||
- command: get bios.SysProfileSettings
|
||||
name: C-States
|
||||
pattern: ProcCStates
|
||||
- command: get bios.ProcSettings
|
||||
name: Logical Processor
|
||||
pattern: LogicalProc
|
||||
- command: get bios.ProcSettings
|
||||
name: Virtualization Technology
|
||||
pattern: ProcVirtualization
|
||||
- command: get bios.MemSettings
|
||||
name: DramRefreshDelay
|
||||
pattern: DramRefreshDelay
|
||||
- command: get bios.ProcSettings
|
||||
name: x2APIC Mode
|
||||
pattern: ProcX2Apic
|
||||
- command: get bios.MemSettings
|
||||
name: DIMM Self Healing
|
||||
pattern: PPROnUCE
|
||||
- command: get bios.MemSettings
|
||||
name: Correctable Error Logging
|
||||
pattern: CECriticalSEL
|
||||
- command: get System.ThermalSettings
|
||||
name: Thermal Profile Optimization
|
||||
pattern: ThermalProfile
|
||||
- command: get Bios.IntegratedDevices
|
||||
name: SR-IOV Global Enable
|
||||
pattern: SriovGlobalEnable
|
||||
- command: get bios.MiscSettings
|
||||
name: F1/F2 Prompt on Error
|
||||
pattern: ErrPrompt
|
||||
- command: get iDRAC.ASRConfig
|
||||
name: ASR Config
|
||||
pattern: Enable=
|
||||
- command: get Bios.IntegratedDevices.OsWatchdogTimer
|
||||
name: Os watchdof timer
|
||||
pattern: OswatchdogTimer=
|
||||
description: 기본 서버 정보 수집 (BIOS, iDRAC, RAID)
|
||||
extends: minimal
|
||||
firmware:
|
||||
- command: get NIC.FrmwImgMenu.1
|
||||
name: NIC(XE810) Integrated Firmware
|
||||
pattern: '#FamilyVersion'
|
||||
- command: get NIC.FrmwImgMenu.3
|
||||
name: NIC(BCM5720) Integrated Firmware
|
||||
pattern: '#FamilyVersion'
|
||||
- command: hwinventory
|
||||
name: RAID Controller Firmware
|
||||
pattern: ControllerFirmwareVersion
|
||||
idrac_settings:
|
||||
- command: get iDRAC.Time.Timezone
|
||||
name: Timezone
|
||||
pattern: Timezone
|
||||
- command: get iDRAC.CurrentNIC
|
||||
name: IPMI LAN Selection
|
||||
pattern: ActiveNIC
|
||||
- command: get iDRAC.CurrentIPv4
|
||||
name: IPMI IPv4 DHCP
|
||||
pattern: DHCPEnable
|
||||
- command: get iDRAC.CurrentIPv6
|
||||
name: IPMI IPv6 Enable
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.Redfish.Enable
|
||||
name: Redfish Support
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.SSH
|
||||
name: SSH Support
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.USERDomain.1.Name
|
||||
name: AD User Domain Name
|
||||
pattern: Name
|
||||
- command: get iDRAC.ActiveDirectory.DomainController1
|
||||
name: SC Server Address
|
||||
pattern: DomainController1
|
||||
- command: get iDRAC.SysLog.SysLogEnable
|
||||
name: Remote Log (syslog)
|
||||
pattern: SysLogEnable
|
||||
- command: get iDRAC.SysLog.Server1
|
||||
name: Syslog Server 1
|
||||
pattern: Server1
|
||||
- command: get iDRAC.SysLog.Server2
|
||||
name: Syslog Server 2
|
||||
pattern: Server2
|
||||
- command: get iDRAC.SysLog.Port
|
||||
name: Syslog Port
|
||||
pattern: Port
|
||||
- command: get iDRAC.VirtualConsole.Port
|
||||
name: VirtualConsole Port
|
||||
pattern: Port
|
||||
raid_settings:
|
||||
- command: hwinventory
|
||||
name: BOSS ProductName
|
||||
pattern: ProductName = BOSS
|
||||
- command: hwinventory
|
||||
name: RAID Types
|
||||
pattern: RAIDTypes
|
||||
- command: hwinventory
|
||||
name: StripeSize
|
||||
pattern: StripeSize
|
||||
- command: hwinventory
|
||||
name: ReadCachePolicy
|
||||
pattern: ReadCachePolicy
|
||||
- command: hwinventory
|
||||
name: WriteCachePolicy
|
||||
pattern: WriteCachePolicy
|
||||
- command: get STORAGE.Controller.1
|
||||
name: CheckConsistencyMode
|
||||
pattern: CheckConsistencyMode
|
||||
R760XD2_Server_info:
|
||||
bios_settings:
|
||||
- command: get bios.BiosBootSettings
|
||||
name: BIOS Boot Mode
|
||||
pattern: BootMode
|
||||
- command: get bios.SysProfileSettings
|
||||
name: System Profile
|
||||
pattern: SysProfile=
|
||||
- command: get bios.SysProfileSettings
|
||||
name: CPU Power Management
|
||||
pattern: EnergyPerformanceBias
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Memory Frequency
|
||||
pattern: MemFrequency
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Turbo Boost
|
||||
pattern: ProcTurboMode
|
||||
- command: get bios.SysProfileSettings
|
||||
name: C1E
|
||||
pattern: ProcC1E
|
||||
- command: get bios.SysProfileSettings
|
||||
name: C-States
|
||||
pattern: ProcCStates
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Monitor/Mwait
|
||||
pattern: MonitorMwait
|
||||
- command: get bios.ProcSettings
|
||||
name: Logical Processor
|
||||
pattern: LogicalProc
|
||||
- command: get bios.ProcSettings
|
||||
name: Virtualization Technology
|
||||
pattern: ProcVirtualization
|
||||
- command: get bios.ProcSettings
|
||||
name: LLC Prefetch
|
||||
pattern: LlcPrefetch
|
||||
- command: get bios.ProcSettings
|
||||
name: x2APIC Mode
|
||||
pattern: ProcX2Apic
|
||||
- command: get bios.MemSettings
|
||||
name: Node Interleaving
|
||||
pattern: NodeInterleave
|
||||
- command: get bios.MemSettings
|
||||
name: DIMM Self Healing
|
||||
pattern: PPROnUCE
|
||||
- command: get bios.MemSettings
|
||||
name: Correctable Error Logging
|
||||
pattern: CECriticalSEL
|
||||
- command: get System.ThermalSettings
|
||||
name: Thermal Profile Optimization
|
||||
pattern: ThermalProfile
|
||||
- command: get Bios.IntegratedDevices
|
||||
name: SR-IOV Global Enable
|
||||
pattern: SriovGlobalEnable
|
||||
- command: get bios.MiscSettings
|
||||
name: F1/F2 Prompt on Error
|
||||
pattern: ErrPrompt
|
||||
- command: get iDRAC.ASRConfig
|
||||
name: ASR Config
|
||||
pattern: Enable=
|
||||
- command: get Bios.IntegratedDevices.OsWatchdogTimer
|
||||
name: Os watchdof timer
|
||||
pattern: OswatchdogTimer=
|
||||
description: 기본 서버 정보 수집 (BIOS, iDRAC, RAID)
|
||||
extends: minimal
|
||||
firmware:
|
||||
- command: get NIC.FrmwImgMenu.1
|
||||
name: NIC Integrated Firmware
|
||||
pattern: '#FamilyVersion'
|
||||
- command: hwinventory
|
||||
name: RAID Controller Firmware
|
||||
pattern: ControllerFirmwareVersion
|
||||
- command: hwinventory
|
||||
name: BOSS Controller Firmware
|
||||
pattern: ControllerFirmwareVersion = 2
|
||||
idrac_settings:
|
||||
- command: get iDRAC.Time.Timezone
|
||||
name: Timezone
|
||||
pattern: Timezone
|
||||
- command: get iDRAC.CurrentNIC
|
||||
name: IPMI LAN Selection
|
||||
pattern: ActiveNIC
|
||||
- command: get iDRAC.CurrentIPv4
|
||||
name: IPMI IPv4 DHCP
|
||||
pattern: DHCPEnable
|
||||
- command: get iDRAC.CurrentIPv6
|
||||
name: IPMI IPv6 Enable
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.Redfish.Enable
|
||||
name: Redfish Support
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.SSH
|
||||
name: SSH Support
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.USERDomain.1.Name
|
||||
name: AD User Domain Name
|
||||
pattern: Name
|
||||
- command: get iDRAC.ActiveDirectory.DomainController1
|
||||
name: SC Server Address
|
||||
pattern: DomainController1
|
||||
- command: get iDRAC.SysLog.SysLogEnable
|
||||
name: Remote Log (syslog)
|
||||
pattern: SysLogEnable
|
||||
- command: get iDRAC.SysLog.Server1
|
||||
name: Syslog Server 1
|
||||
pattern: Server1
|
||||
- command: get iDRAC.SysLog.Server2
|
||||
name: Syslog Server 2
|
||||
pattern: Server2
|
||||
- command: get iDRAC.SysLog.Port
|
||||
name: Syslog Port
|
||||
pattern: Port
|
||||
- command: get iDRAC.VirtualConsole.Port
|
||||
name: VirtualConsole Port
|
||||
pattern: Port
|
||||
raid_settings:
|
||||
- command: hwinventory
|
||||
name: RAID ProductName
|
||||
pattern: ProductName = PERC
|
||||
- command: hwinventory
|
||||
name: BOSS ProductName
|
||||
pattern: ProductName = BOSS
|
||||
- command: hwinventory
|
||||
name: RAID Types
|
||||
pattern: RAIDTypes
|
||||
- command: hwinventory
|
||||
name: StripeSize
|
||||
pattern: StripeSize
|
||||
- command: hwinventory
|
||||
name: ReadCachePolicy
|
||||
pattern: ReadCachePolicy
|
||||
- command: hwinventory
|
||||
name: WriteCachePolicy
|
||||
pattern: WriteCachePolicy
|
||||
- command: get STORAGE.Controller.1
|
||||
name: CheckConsistencyMode
|
||||
pattern: CheckConsistencyMode
|
||||
- command: get STORAGE.Controller.1
|
||||
name: PatrolReadRate
|
||||
pattern: PatrolReadRate
|
||||
amd_server:
|
||||
bios_settings:
|
||||
- command: get bios.ProcSettings
|
||||
name: AMD SMT Mode
|
||||
pattern: SmtMode
|
||||
- command: get bios.ProcSettings
|
||||
name: AMD IOMMU
|
||||
pattern: Iommu
|
||||
description: AMD 서버 전용 프로파일
|
||||
extends: default
|
||||
default:
|
||||
bios_settings:
|
||||
- command: get bios.BiosBootSettings
|
||||
name: BIOS Boot Mode
|
||||
pattern: BootMode
|
||||
- command: get bios.SysProfileSettings
|
||||
name: System Profile
|
||||
pattern: SysProfile=
|
||||
- command: get bios.SysProfileSettings
|
||||
name: CPU Power Management
|
||||
pattern: EnergyPerformanceBias
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Memory Frequency
|
||||
pattern: MemFrequency
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Turbo Boost
|
||||
pattern: ProcTurboMode
|
||||
- command: get bios.SysProfileSettings
|
||||
name: C1E
|
||||
pattern: ProcC1E
|
||||
- command: get bios.SysProfileSettings
|
||||
name: C-States
|
||||
pattern: ProcCStates
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Monitor/Mwait
|
||||
pattern: MonitorMwait
|
||||
- command: get bios.ProcSettings
|
||||
name: Logical Processor
|
||||
pattern: LogicalProc
|
||||
- command: get bios.ProcSettings
|
||||
name: Virtualization Technology
|
||||
pattern: ProcVirtualization
|
||||
- command: get bios.ProcSettings
|
||||
name: LLC Prefetch
|
||||
pattern: LlcPrefetch
|
||||
- command: get bios.ProcSettings
|
||||
name: x2APIC Mode
|
||||
pattern: ProcX2Apic
|
||||
- command: get bios.MemSettings
|
||||
name: Node Interleaving
|
||||
pattern: NodeInterleave
|
||||
- command: get bios.MemSettings
|
||||
name: DIMM Self Healing
|
||||
pattern: PPROnUCE
|
||||
- command: get bios.MemSettings
|
||||
name: Correctable Error Logging
|
||||
pattern: CECriticalSEL
|
||||
- command: get System.ThermalSettings
|
||||
name: Thermal Profile Optimization
|
||||
pattern: ThermalProfile
|
||||
- command: get Bios.IntegratedDevices
|
||||
name: SR-IOV Global Enable
|
||||
pattern: SriovGlobalEnable
|
||||
- command: get bios.MiscSettings
|
||||
name: F1/F2 Prompt on Error
|
||||
pattern: ErrPrompt
|
||||
description: 기본 서버 정보 수집 (BIOS, iDRAC, RAID)
|
||||
extends: minimal
|
||||
firmware:
|
||||
- command: get NIC.FrmwImgMenu.1
|
||||
name: NIC Integrated Firmware
|
||||
pattern: '#FamilyVersion'
|
||||
- command: get NIC.FrmwImgMenu.5
|
||||
name: OnBoard NIC Firmware
|
||||
pattern: '#FamilyVersion'
|
||||
- command: hwinventory
|
||||
name: RAID Controller Firmware
|
||||
pattern: ControllerFirmwareVersion
|
||||
idrac_settings:
|
||||
- command: get iDRAC.Time.Timezone
|
||||
name: Timezone
|
||||
pattern: Timezone
|
||||
- command: get iDRAC.CurrentNIC
|
||||
name: IPMI LAN Selection
|
||||
pattern: ActiveNIC
|
||||
- command: get iDRAC.CurrentIPv4
|
||||
name: IPMI IPv4 DHCP
|
||||
pattern: DHCPEnable
|
||||
- command: get iDRAC.CurrentIPv6
|
||||
name: IPMI IPv6 Enable
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.Redfish.Enable
|
||||
name: Redfish Support
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.SSH
|
||||
name: SSH Support
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.USERDomain.1.Name
|
||||
name: AD User Domain Name
|
||||
pattern: Name
|
||||
- command: get iDRAC.ActiveDirectory.DomainController1
|
||||
name: SC Server Address
|
||||
pattern: DomainController1
|
||||
- command: get iDRAC.SysLog.SysLogEnable
|
||||
name: Remote Log (syslog)
|
||||
pattern: SysLogEnable
|
||||
- command: get iDRAC.SysLog.Server1
|
||||
name: Syslog Server 1
|
||||
pattern: Server1
|
||||
- command: get iDRAC.SysLog.Server2
|
||||
name: Syslog Server 2
|
||||
pattern: Server2
|
||||
- command: get iDRAC.SysLog.Port
|
||||
name: Syslog Port
|
||||
pattern: Port
|
||||
- command: get iDRAC.VirtualConsole.Port
|
||||
name: VirtualConsole Port
|
||||
pattern: Port
|
||||
raid_settings:
|
||||
- command: hwinventory
|
||||
name: RAID ProductName
|
||||
pattern: ProductName = PERC
|
||||
- command: hwinventory
|
||||
name: RAID Types
|
||||
pattern: RAIDTypes
|
||||
- command: hwinventory
|
||||
name: StripeSize
|
||||
pattern: StripeSize
|
||||
- command: hwinventory
|
||||
name: ReadCachePolicy
|
||||
pattern: ReadCachePolicy
|
||||
- command: hwinventory
|
||||
name: WriteCachePolicy
|
||||
pattern: WriteCachePolicy
|
||||
- command: get STORAGE.Controller.1
|
||||
name: CheckConsistencyMode
|
||||
pattern: CheckConsistencyMode
|
||||
- command: get STORAGE.Controller.1
|
||||
name: PatrolReadRate
|
||||
pattern: PatrolReadRate
|
||||
intel_server:
|
||||
description: Intel 서버 전용 프로파일
|
||||
extends: default
|
||||
minimal:
|
||||
description: 최소 정보만 수집 (펌웨어 버전만)
|
||||
firmware:
|
||||
- command: getsysinfo
|
||||
name: SVC Tag
|
||||
pattern: SVC Tag
|
||||
- command: getsysinfo
|
||||
name: BIOS Firmware
|
||||
pattern: System BIOS Version
|
||||
- command: getsysinfo
|
||||
name: iDRAC Firmware
|
||||
pattern: Firmware Version
|
||||
문병철매니저님_AMD_T8A:
|
||||
bios_settings:
|
||||
- command: get bios.BiosBootSettings
|
||||
name: BIOS Boot Mode
|
||||
pattern: BootMode
|
||||
- command: get bios.SysProfileSettings
|
||||
name: System Profile
|
||||
pattern: SysProfile=
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Memory Frequency
|
||||
pattern: MemFrequency
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Turbo Boost
|
||||
pattern: ProcTurboMode
|
||||
- command: get bios.SysProfileSettings
|
||||
name: C-States
|
||||
pattern: ProcCStates
|
||||
- command: get bios.ProcSettings
|
||||
name: Logical Processor
|
||||
pattern: LogicalProc
|
||||
- command: get bios.ProcSettings
|
||||
name: Virtualization Technology
|
||||
pattern: ProcVirtualization
|
||||
- command: get bios.MemSettings
|
||||
name: DramRefreshDelay
|
||||
pattern: DramRefreshDelay
|
||||
- command: get bios.ProcSettings
|
||||
name: x2APIC Mode
|
||||
pattern: ProcX2Apic
|
||||
- command: get bios.MemSettings
|
||||
name: DIMM Self Healing
|
||||
pattern: PPROnUCE
|
||||
- command: get bios.MemSettings
|
||||
name: Correctable Error Logging
|
||||
pattern: CECriticalSEL
|
||||
- command: get System.ThermalSettings
|
||||
name: Thermal Profile Optimization
|
||||
pattern: ThermalProfile
|
||||
- command: get Bios.IntegratedDevices
|
||||
name: SR-IOV Global Enable
|
||||
pattern: SriovGlobalEnable
|
||||
- command: get bios.MiscSettings
|
||||
name: F1/F2 Prompt on Error
|
||||
pattern: ErrPrompt
|
||||
- command: get iDRAC.ASRConfig
|
||||
name: ASR Config
|
||||
pattern: Enable=
|
||||
- command: get Bios.IntegratedDevices.OsWatchdogTimer
|
||||
name: Os watchdof timer
|
||||
pattern: OswatchdogTimer=
|
||||
description: 기본 서버 정보 수집 (BIOS, iDRAC, RAID)
|
||||
extends: minimal
|
||||
firmware:
|
||||
- command: get NIC.FrmwImgMenu.1
|
||||
name: NIC(XE810) Integrated Firmware
|
||||
pattern: '#FamilyVersion'
|
||||
- command: get NIC.FrmwImgMenu.3
|
||||
name: NIC(BCM5720) Integrated Firmware
|
||||
pattern: '#FamilyVersion'
|
||||
- command: hwinventory
|
||||
name: RAID Controller Firmware
|
||||
pattern: ControllerFirmwareVersion
|
||||
idrac_settings:
|
||||
- command: get iDRAC.Time.Timezone
|
||||
name: Timezone
|
||||
pattern: Timezone
|
||||
- command: get iDRAC.CurrentNIC
|
||||
name: IPMI LAN Selection
|
||||
pattern: ActiveNIC
|
||||
- command: get iDRAC.CurrentIPv4
|
||||
name: IPMI IPv4 DHCP
|
||||
pattern: DHCPEnable
|
||||
- command: get iDRAC.CurrentIPv6
|
||||
name: IPMI IPv6 Enable
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.Redfish.Enable
|
||||
name: Redfish Support
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.SSH
|
||||
name: SSH Support
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.USERDomain.1.Name
|
||||
name: AD User Domain Name
|
||||
pattern: Name
|
||||
- command: get iDRAC.ActiveDirectory.DomainController1
|
||||
name: SC Server Address
|
||||
pattern: DomainController1
|
||||
- command: get iDRAC.SysLog.SysLogEnable
|
||||
name: Remote Log (syslog)
|
||||
pattern: SysLogEnable
|
||||
- command: get iDRAC.SysLog.Server1
|
||||
name: Syslog Server 1
|
||||
pattern: Server1
|
||||
- command: get iDRAC.SysLog.Server2
|
||||
name: Syslog Server 2
|
||||
pattern: Server2
|
||||
- command: get iDRAC.SysLog.Port
|
||||
name: Syslog Port
|
||||
pattern: Port
|
||||
- command: get iDRAC.VirtualConsole.Port
|
||||
name: VirtualConsole Port
|
||||
pattern: Port
|
||||
raid_settings:
|
||||
- command: hwinventory
|
||||
name: BOSS ProductName
|
||||
pattern: ProductName = BOSS
|
||||
- command: hwinventory
|
||||
name: RAID Types
|
||||
pattern: RAIDTypes
|
||||
- command: hwinventory
|
||||
name: StripeSize
|
||||
pattern: StripeSize
|
||||
- command: hwinventory
|
||||
name: ReadCachePolicy
|
||||
pattern: ReadCachePolicy
|
||||
- command: hwinventory
|
||||
name: WriteCachePolicy
|
||||
pattern: WriteCachePolicy
|
||||
- command: get STORAGE.Controller.1
|
||||
name: CheckConsistencyMode
|
||||
pattern: CheckConsistencyMode
|
||||
문병철매니저님_INTEL_SERVER:
|
||||
bios_settings:
|
||||
- command: get bios.BiosBootSettings
|
||||
name: BIOS Boot Mode
|
||||
pattern: BootMode
|
||||
- command: get bios.SysProfileSettings
|
||||
name: System Profile
|
||||
pattern: SysProfile=
|
||||
- command: get bios.SysProfileSettings
|
||||
name: CPU Power Management
|
||||
pattern: EnergyPerformanceBias
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Memory Frequency
|
||||
pattern: MemFrequency
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Turbo Boost
|
||||
pattern: ProcTurboMode
|
||||
- command: get bios.SysProfileSettings
|
||||
name: C1E
|
||||
pattern: ProcC1E
|
||||
- command: get bios.SysProfileSettings
|
||||
name: C-States
|
||||
pattern: ProcCStates
|
||||
- command: get bios.SysProfileSettings
|
||||
name: Monitor/Mwait
|
||||
pattern: MonitorMwait
|
||||
- command: get bios.ProcSettings
|
||||
name: Logical Processor
|
||||
pattern: LogicalProc
|
||||
- command: get bios.ProcSettings
|
||||
name: Virtualization Technology
|
||||
pattern: ProcVirtualization
|
||||
- command: get bios.ProcSettings
|
||||
name: LLC Prefetch
|
||||
pattern: LlcPrefetch
|
||||
- command: get bios.ProcSettings
|
||||
name: x2APIC Mode
|
||||
pattern: ProcX2Apic
|
||||
- command: get bios.MemSettings
|
||||
name: Node Interleaving
|
||||
pattern: NodeInterleave
|
||||
- command: get bios.MemSettings
|
||||
name: DIMM Self Healing
|
||||
pattern: PPROnUCE
|
||||
- command: get bios.MemSettings
|
||||
name: Correctable Error Logging
|
||||
pattern: CECriticalSEL
|
||||
- command: get System.ThermalSettings
|
||||
name: Thermal Profile Optimization
|
||||
pattern: ThermalProfile
|
||||
- command: get Bios.IntegratedDevices
|
||||
name: SR-IOV Global Enable
|
||||
pattern: SriovGlobalEnable
|
||||
- command: get bios.MiscSettings
|
||||
name: F1/F2 Prompt on Error
|
||||
pattern: ErrPrompt
|
||||
- command: get iDRAC.ASRConfig
|
||||
name: ASR Config
|
||||
pattern: Enable=
|
||||
- command: get Bios.IntegratedDevices.OsWatchdogTimer
|
||||
name: Os watchdof timer
|
||||
pattern: OswatchdogTimer=
|
||||
description: 기본 서버 정보 수집 (BIOS, iDRAC, RAID)
|
||||
extends: minimal
|
||||
firmware:
|
||||
- command: get NIC.FrmwImgMenu.1
|
||||
name: NIC Integrated Firmware
|
||||
pattern: '#FamilyVersion'
|
||||
- command: hwinventory
|
||||
name: RAID Controller Firmware
|
||||
pattern: ControllerFirmwareVersion
|
||||
- command: hwinventory
|
||||
name: BOSS Controller Firmware
|
||||
pattern: ControllerFirmwareVersion = 2
|
||||
idrac_settings:
|
||||
- command: get iDRAC.Time.Timezone
|
||||
name: Timezone
|
||||
pattern: Timezone
|
||||
- command: get iDRAC.CurrentNIC
|
||||
name: IPMI LAN Selection
|
||||
pattern: ActiveNIC
|
||||
- command: get iDRAC.CurrentIPv4
|
||||
name: IPMI IPv4 DHCP
|
||||
pattern: DHCPEnable
|
||||
- command: get iDRAC.CurrentIPv6
|
||||
name: IPMI IPv6 Enable
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.Redfish.Enable
|
||||
name: Redfish Support
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.SSH
|
||||
name: SSH Support
|
||||
pattern: Enable=
|
||||
- command: get iDRAC.USERDomain.1.Name
|
||||
name: AD User Domain Name
|
||||
pattern: Name
|
||||
- command: get iDRAC.ActiveDirectory.DomainController1
|
||||
name: SC Server Address
|
||||
pattern: DomainController1
|
||||
- command: get iDRAC.SysLog.SysLogEnable
|
||||
name: Remote Log (syslog)
|
||||
pattern: SysLogEnable
|
||||
- command: get iDRAC.SysLog.Server1
|
||||
name: Syslog Server 1
|
||||
pattern: Server1
|
||||
- command: get iDRAC.SysLog.Server2
|
||||
name: Syslog Server 2
|
||||
pattern: Server2
|
||||
- command: get iDRAC.SysLog.Port
|
||||
name: Syslog Port
|
||||
pattern: Port
|
||||
- command: get iDRAC.VirtualConsole.Port
|
||||
name: VirtualConsole Port
|
||||
pattern: Port
|
||||
raid_settings:
|
||||
- command: hwinventory
|
||||
name: RAID ProductName
|
||||
pattern: ProductName = PERC
|
||||
- command: hwinventory
|
||||
name: BOSS ProductName
|
||||
pattern: ProductName = BOSS
|
||||
- command: hwinventory
|
||||
name: RAID Types
|
||||
pattern: RAIDTypes
|
||||
- command: hwinventory
|
||||
name: StripeSize
|
||||
pattern: StripeSize
|
||||
- command: hwinventory
|
||||
name: ReadCachePolicy
|
||||
pattern: ReadCachePolicy
|
||||
- command: hwinventory
|
||||
name: WriteCachePolicy
|
||||
pattern: WriteCachePolicy
|
||||
- command: get STORAGE.Controller.1
|
||||
name: CheckConsistencyMode
|
||||
pattern: CheckConsistencyMode
|
||||
- command: get STORAGE.Controller.1
|
||||
name: PatrolReadRate
|
||||
pattern: PatrolReadRate
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="$(dirname "$0")/../temp/staging"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set storage.Controller.1.PatrolReadRate 9 )
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="$(dirname "$0")/../temp/staging"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS jobqueue create RAID.Slot.2-1 -r pwrcycle)
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="$(dirname "$0")/../temp/staging"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set iDRAC.VirtualConsole.Port 25513)
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
통합 GPU 시리얼 수집 스크립트
|
||||
hwinventory에서 Video.Slot 정보 수집
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import logging
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
from core.idrac_client import IDRACClient
|
||||
from core.parsers import InfoParser
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
def collect_gpu_for_ip(ip: str, output_dir: Path) -> tuple:
|
||||
"""단일 IP에 대한 GPU Serial 정보 수집"""
|
||||
try:
|
||||
logging.info(f"[{ip}] GPU 정보 수집 시작")
|
||||
|
||||
client = IDRACClient(ip)
|
||||
|
||||
# 1. Get Service Tag
|
||||
sysinfo = client.get_sysinfo()
|
||||
svc_tag = InfoParser.extract_service_tag(sysinfo)
|
||||
|
||||
if not svc_tag:
|
||||
return ip, False, "서비스 태그 추출 실패"
|
||||
|
||||
# 2. Get Hardware Inventory
|
||||
hwinventory = client.get_hwinventory()
|
||||
|
||||
# 3. Parse GPU Serials
|
||||
gpu_map = InfoParser.extract_gpu_serials(hwinventory)
|
||||
|
||||
# 4. Write File
|
||||
output_file = output_dir / f"{svc_tag}.txt"
|
||||
|
||||
# 정렬 로직 (Legacy GPU_Serial_v1.py 유지)
|
||||
def slot_key(k: str):
|
||||
m = re.search(r"Video\.Slot\.(\d+)-(\d+)", k)
|
||||
if m:
|
||||
return (int(m.group(1)), int(m.group(2)))
|
||||
return (1_000_000, 1_000_000, k)
|
||||
|
||||
with output_file.open('w', encoding='utf-8', newline='\n') as f:
|
||||
f.write(f"{svc_tag}\n")
|
||||
|
||||
if not gpu_map:
|
||||
f.write("No GPU(Video) inventory found or SerialNumber not present.\n")
|
||||
return ip, True, f"저장: {output_file.name} (GPU 없음)"
|
||||
|
||||
# Write individual slots
|
||||
sorted_keys = sorted(gpu_map.keys(), key=slot_key)
|
||||
for fqdd in sorted_keys:
|
||||
serial = gpu_map[fqdd]
|
||||
f.write(f"{fqdd}: {serial}\n")
|
||||
|
||||
# Write summary line
|
||||
serials_only = [gpu_map[k] for k in sorted_keys if gpu_map[k] != "Not Found"]
|
||||
if serials_only:
|
||||
f.write(f"SERIALS: {';'.join(serials_only)}\n")
|
||||
|
||||
return ip, True, f"저장: {output_file.name} ({len(serials_only)}개 발견)"
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"[{ip}] 오류: {e}")
|
||||
return ip, False, f"오류: {e}"
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python collect_gpu.py <ip_file>")
|
||||
sys.exit(1)
|
||||
|
||||
ip_file = Path(sys.argv[1])
|
||||
|
||||
if not ip_file.exists():
|
||||
logging.error(f"IP 파일 없음: {ip_file}")
|
||||
sys.exit(1)
|
||||
|
||||
# 출력 디렉토리
|
||||
# 출력 디렉토리 (스크립트 위치 기준)
|
||||
script_dir = Path(__file__).resolve().parent
|
||||
data_root = script_dir.parent.parent
|
||||
output_dir = data_root / "temp" / "staging"
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# IP 목록 읽기
|
||||
ips = [line.strip() for line in ip_file.read_text(encoding='utf-8').splitlines() if line.strip()]
|
||||
|
||||
if not ips:
|
||||
logging.error("IP 목록이 비어 있습니다.")
|
||||
sys.exit(1)
|
||||
|
||||
logging.info(f"총 {len(ips)}대 GPU 정보 수집 시작")
|
||||
|
||||
# 병렬 처리
|
||||
ok, fail = 0, 0
|
||||
with ThreadPoolExecutor(max_workers=20) as executor:
|
||||
futures = {executor.submit(collect_gpu_for_ip, ip, output_dir): ip for ip in ips}
|
||||
|
||||
for future in futures:
|
||||
ip, success, msg = future.result()
|
||||
if success:
|
||||
logging.info(f"[OK] {ip} - {msg}")
|
||||
ok += 1
|
||||
else:
|
||||
logging.error(f"[FAIL] {ip} - {msg}")
|
||||
fail += 1
|
||||
|
||||
logging.info(f"완료: 성공 {ok}대 / 실패 {fail}대")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
통합 GUID 수집 스크립트
|
||||
프로파일 기반으로 InfiniBand GUID 수집
|
||||
"""
|
||||
import sys
|
||||
import yaml
|
||||
import os
|
||||
from pathlib import Path
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import logging
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
from core.idrac_client import IDRACClient
|
||||
from core.parsers import InfoParser
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
|
||||
def load_profile(profile_name: str) -> dict:
|
||||
"""프로파일 로드"""
|
||||
profile_file = Path(__file__).parent.parent / "profiles" / "guid_profiles.yaml"
|
||||
|
||||
if not profile_file.exists():
|
||||
logging.error(f"프로파일 파일 없음: {profile_file}")
|
||||
sys.exit(1)
|
||||
|
||||
with open(profile_file, 'r', encoding='utf-8') as f:
|
||||
profiles = yaml.safe_load(f)['profiles']
|
||||
|
||||
profile = profiles.get(profile_name, profiles['default'])
|
||||
|
||||
# 환경변수에서 슬롯 우선순위 읽기 (custom_priority 프로파일용)
|
||||
if not profile.get('slot_priority'):
|
||||
env_priority = os.getenv("GUID_SLOT_PRIORITY", "")
|
||||
if env_priority:
|
||||
profile['slot_priority'] = [int(s.strip()) for s in env_priority.split(",") if s.strip()]
|
||||
else:
|
||||
profile['slot_priority'] = profiles['default']['slot_priority']
|
||||
|
||||
return profile
|
||||
|
||||
|
||||
def collect_guid_for_ip(ip: str, profile: dict, output_dir: Path) -> tuple:
|
||||
"""단일 IP에 대한 GUID 정보 수집 (PortGUID_v1.py 로직 기반)"""
|
||||
try:
|
||||
logging.info(f"[{ip}] DEBUG: Running Unified GUID Script v2.2 (PortGUID_v1 Logic)")
|
||||
|
||||
# IDRAC credentials from env or default
|
||||
idrac_user = os.getenv("IDRAC_USER", "root")
|
||||
idrac_pass = os.getenv("IDRAC_PASS", "calvin")
|
||||
|
||||
# 1. Get Service Tag (using raw subprocess like v1)
|
||||
cmd_getsysinfo = [
|
||||
"racadm", "-r", ip, "-u", idrac_user, "-p", idrac_pass, "getsysinfo"
|
||||
]
|
||||
# v1 uses subprocess.getoutput which runs with shell=True/standard shell behavior.
|
||||
# Here we replicate it or use subprocess.run with capture_output.
|
||||
# PortGUID_v1 uses: getsysinfo = subprocess.getoutput(" ".join(cmd_getsysinfo))
|
||||
|
||||
# Using subprocess.run for better control but mimicking the command structure
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
try:
|
||||
# mimic v1: Use the exact same command string style
|
||||
proc_info = subprocess.run(cmd_getsysinfo, capture_output=True, text=True, timeout=60)
|
||||
getsysinfo = proc_info.stdout
|
||||
except Exception as e:
|
||||
return ip, False, f"SVC Tag 수집 실패: {e}"
|
||||
|
||||
svc_tag_match = re.search(r"SVC Tag\s*=\s*(\S+)", getsysinfo)
|
||||
svc_tag = svc_tag_match.group(1) if svc_tag_match else None
|
||||
|
||||
if not svc_tag:
|
||||
return ip, False, "서비스 태그 추출 실패 (Regex miss)"
|
||||
|
||||
# 2. Get InfiniBand Page List
|
||||
cmd_list = [
|
||||
"racadm", "-r", ip, "-u", idrac_user, "-p", idrac_pass, "get", "InfiniBand.VndrConfigPage"
|
||||
]
|
||||
proc_list = subprocess.run(cmd_list, capture_output=True, text=True, timeout=60)
|
||||
output_list = proc_list.stdout
|
||||
|
||||
# 3. Parse Page Map
|
||||
matches = re.findall(
|
||||
r"InfiniBand\.VndrConfigPage\.(\d+)\s+\[Key=InfiniBand\.Slot\.(\d+)-\d+#VndrConfigPage]",
|
||||
output_list
|
||||
)
|
||||
|
||||
slot_to_guid = {}
|
||||
# 4. Fetch Detail for each page
|
||||
for number, slot in matches:
|
||||
cmd_detail = [
|
||||
"racadm", "-r", ip, "-u", idrac_user, "-p", idrac_pass,
|
||||
"get", f"InfiniBand.VndrConfigPage.{number}"
|
||||
]
|
||||
proc_detail = subprocess.run(cmd_detail, capture_output=True, text=True, timeout=60)
|
||||
output_detail = proc_detail.stdout
|
||||
|
||||
match_guid = re.search(r"PortGUID=(\S+)", output_detail)
|
||||
port_guid = match_guid.group(1) if match_guid else None
|
||||
|
||||
if port_guid:
|
||||
slot_to_guid[int(slot)] = port_guid
|
||||
|
||||
# 5. Determine Priority (Preference: Profile > Env > Default(v1 logic))
|
||||
# Logic from PortGUID_v1.py:
|
||||
# if total_slots == 4: order = ...
|
||||
# elif total_slots == 10: order = ...
|
||||
|
||||
# We will use the profile's logic if available, but fallback to v1 logic if profile is 'default' and matches slot counts
|
||||
desired_order = profile.get('slot_priority', [])
|
||||
|
||||
# If profile didn't specify (or empty), use v1 adaptive logic
|
||||
if not desired_order:
|
||||
total_slots = len(matches)
|
||||
if total_slots == 4:
|
||||
desired_order = [38, 37, 32, 34]
|
||||
elif total_slots == 10:
|
||||
desired_order = [38, 39, 37, 36, 32, 33, 34, 35, 31, 40]
|
||||
else:
|
||||
desired_order = [int(slot) for _, slot in matches] # Just collection order
|
||||
logging.info(f"[{ip}] DEBUG: Using Adaptive Priority (Count={total_slots}): {desired_order}")
|
||||
else:
|
||||
logging.info(f"[{ip}] DEBUG: Using Profile Priority: {desired_order}")
|
||||
|
||||
# 6. Write File
|
||||
output_file = output_dir / f"{svc_tag}.txt"
|
||||
with output_file.open('w', encoding='utf-8', newline='\n') as f:
|
||||
f.write(f"{svc_tag}\n")
|
||||
|
||||
hex_guid_list = []
|
||||
|
||||
# Write in desired order
|
||||
for slot in desired_order:
|
||||
guid = slot_to_guid.get(slot)
|
||||
if guid:
|
||||
f.write(f"Slot.{slot}: {guid}\n")
|
||||
|
||||
# Format
|
||||
fmt_guid = guid.replace(':', '').upper()
|
||||
if not fmt_guid.startswith("0X"):
|
||||
fmt_guid = "0x" + fmt_guid
|
||||
hex_guid_list.append(fmt_guid)
|
||||
|
||||
# Remaining slots (if any weren't in priority list)?
|
||||
# v1 doesn't write them if not in priority list. We will stick to v1 behavior.
|
||||
|
||||
if profile.get('output_format', 'combined') == 'combined' and hex_guid_list:
|
||||
f.write(f"GUID: {';'.join(hex_guid_list)}\n")
|
||||
|
||||
return ip, True, f"저장: {output_file.name} ({len(hex_guid_list)}개 GUID/v1_Logic)"
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"[{ip}] 오류: {e}")
|
||||
return ip, False, f"오류: {e}"
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python collect_guid.py <ip_file> [profile_name]")
|
||||
print("Available profiles: default, custom_priority")
|
||||
sys.exit(1)
|
||||
|
||||
ip_file = Path(sys.argv[1])
|
||||
profile_name = sys.argv[2] if len(sys.argv) > 2 else "default"
|
||||
|
||||
if not ip_file.exists():
|
||||
logging.error(f"IP 파일 없음: {ip_file}")
|
||||
sys.exit(1)
|
||||
|
||||
# 프로파일 로드
|
||||
profile = load_profile(profile_name)
|
||||
logging.info(f"프로파일 사용: {profile_name} - {profile.get('description', '')}")
|
||||
logging.info(f"슬롯 우선순위: {profile['slot_priority']}")
|
||||
|
||||
# 출력 디렉토리
|
||||
# 출력 디렉토리 (스크립트 위치 기준)
|
||||
script_dir = Path(__file__).resolve().parent
|
||||
data_root = script_dir.parent.parent
|
||||
output_dir = data_root / "temp" / "staging"
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# IP 목록 읽기
|
||||
ips = [line.strip() for line in ip_file.read_text(encoding='utf-8').splitlines() if line.strip()]
|
||||
|
||||
if not ips:
|
||||
logging.error("IP 목록이 비어 있습니다.")
|
||||
sys.exit(1)
|
||||
|
||||
logging.info(f"총 {len(ips)}대 처리 시작")
|
||||
|
||||
# 병렬 처리
|
||||
ok, fail = 0, 0
|
||||
with ThreadPoolExecutor(max_workers=20) as executor:
|
||||
futures = {executor.submit(collect_guid_for_ip, ip, profile, output_dir): ip for ip in ips}
|
||||
|
||||
for future in futures:
|
||||
ip, success, msg = future.result()
|
||||
if success:
|
||||
logging.info(f"[OK] {ip} - {msg}")
|
||||
ok += 1
|
||||
else:
|
||||
logging.error(f"[FAIL] {ip} - {msg}")
|
||||
fail += 1
|
||||
|
||||
logging.info(f"완료: 성공 {ok}대 / 실패 {fail}대")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,191 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
통합 MAC 수집 스크립트
|
||||
프로파일 기반으로 다양한 서버 타입 지원
|
||||
"""
|
||||
import sys
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import logging
|
||||
|
||||
# core 모듈 임포트
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
from core.idrac_client import IDRACClient
|
||||
from core.parsers import InfoParser
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
|
||||
def load_profile(profile_name: str) -> dict:
|
||||
"""프로파일 로드 및 상속 처리"""
|
||||
profile_file = Path(__file__).parent.parent / "profiles" / "mac_profiles.yaml"
|
||||
|
||||
if not profile_file.exists():
|
||||
logging.error(f"프로파일 파일 없음: {profile_file}")
|
||||
sys.exit(1)
|
||||
|
||||
with open(profile_file, 'r', encoding='utf-8') as f:
|
||||
profiles = yaml.safe_load(f)['profiles']
|
||||
|
||||
profile = profiles.get(profile_name)
|
||||
if not profile:
|
||||
logging.error(f"프로파일 '{profile_name}' 없음. 사용 가능: {list(profiles.keys())}")
|
||||
sys.exit(1)
|
||||
|
||||
# extends 처리
|
||||
if 'extends' in profile:
|
||||
base = profiles[profile['extends']].copy()
|
||||
base.update(profile)
|
||||
profile = base
|
||||
|
||||
return profile
|
||||
|
||||
|
||||
def collect_mac_for_ip(ip: str, profile: dict, output_dir: Path) -> tuple:
|
||||
"""단일 IP에 대한 MAC 정보 수집"""
|
||||
try:
|
||||
client = IDRACClient(ip)
|
||||
parser = InfoParser()
|
||||
|
||||
# 데이터 수집
|
||||
sysinfo = client.get_sysinfo()
|
||||
hwinventory = client.get_hwinventory()
|
||||
|
||||
# 서비스 태그
|
||||
svc_tag = parser.extract_service_tag(sysinfo)
|
||||
if not svc_tag:
|
||||
return ip, False, "서비스 태그 추출 실패"
|
||||
|
||||
# NIC MAC 주소
|
||||
# NIC MAC 주소
|
||||
# sysinfo보다 hwinventory가 더 상세한 정보(Slot NIC 등)를 포함하므로 변경
|
||||
nic_macs = parser.extract_nic_macs_from_hwinventory(hwinventory, profile['nic_patterns'])
|
||||
|
||||
# iDRAC MAC
|
||||
idrac_mac = None
|
||||
if profile.get('include_idrac_mac'):
|
||||
idrac_mac = parser.extract_idrac_mac(sysinfo)
|
||||
|
||||
# InfiniBand (선택적)
|
||||
ib_guids = {}
|
||||
if 'infiniband_slots' in profile:
|
||||
# Legacy logic: Fetch from swinventory (checking previous line of FQDD)
|
||||
swinventory = client.get_swinventory()
|
||||
ib_guids = parser.extract_infiniband_macs_from_swinventory(swinventory, profile['infiniband_slots'])
|
||||
|
||||
# 벤더 정보
|
||||
memory_vendors = []
|
||||
disk_vendors = []
|
||||
boss_disk_vendors = []
|
||||
|
||||
if profile.get('include_memory_vendor'):
|
||||
memory_vendors = parser.extract_vendors(hwinventory, "DIMM")
|
||||
|
||||
if profile.get('include_disk_vendor'):
|
||||
if profile.get('exclude_boss'):
|
||||
# 일반 디스크 벤더 (BOSS 제외)
|
||||
regular_vendors = set()
|
||||
for prefix in ["Disk.Bay.", "Disk.M.2.", "Disk.Slot."]:
|
||||
regular_vendors.update(parser.extract_vendors(hwinventory, prefix))
|
||||
disk_vendors = sorted(regular_vendors)
|
||||
# BOSS 디스크 벤더 별도 수집 (Disk.Direct. 중 BOSS 포함 항목만)
|
||||
boss_disk_vendors = parser.extract_vendors(hwinventory, "Disk.Direct.", instance_must_contain="BOSS")
|
||||
else:
|
||||
disk_vendors = parser.extract_vendors(hwinventory, "Disk.")
|
||||
|
||||
# 파일 저장
|
||||
output_file = output_dir / f"{svc_tag}.txt"
|
||||
with output_file.open('w', encoding='utf-8', newline='\n') as f:
|
||||
f.write(f"{svc_tag}\n")
|
||||
|
||||
# NIC MAC (순서 유지)
|
||||
for pattern in profile['nic_patterns']:
|
||||
f.write(f"{nic_macs.get(pattern) or ''}\n")
|
||||
|
||||
# InfiniBand (있을 경우)
|
||||
if ib_guids:
|
||||
for slot in profile['infiniband_slots']:
|
||||
f.write(f"{ib_guids.get(slot) or ''}\n")
|
||||
|
||||
# iDRAC MAC
|
||||
if idrac_mac:
|
||||
f.write(f"{idrac_mac}\n")
|
||||
|
||||
# 벤더 정보
|
||||
for vendor in memory_vendors:
|
||||
f.write(f"{vendor}\n")
|
||||
for vendor in disk_vendors:
|
||||
f.write(f"{vendor}\n")
|
||||
for vendor in boss_disk_vendors:
|
||||
f.write(f"{vendor}\n")
|
||||
|
||||
return ip, True, f"저장: {output_file.name}"
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"[{ip}] 오류: {e}")
|
||||
return ip, False, f"오류: {e}"
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python collect_mac.py <ip_file> [profile_name]")
|
||||
print("Available profiles: default, xe9680_h200_10ea, type11, jp_54ea, sp_18ea")
|
||||
sys.exit(1)
|
||||
|
||||
ip_file = Path(sys.argv[1])
|
||||
profile_name = sys.argv[2] if len(sys.argv) > 2 else "default"
|
||||
|
||||
if not ip_file.exists():
|
||||
logging.error(f"IP 파일 없음: {ip_file}")
|
||||
sys.exit(1)
|
||||
|
||||
# 프로파일 로드
|
||||
profile = load_profile(profile_name)
|
||||
logging.info(f"프로파일 사용: {profile_name} - {profile.get('description', '')}")
|
||||
|
||||
# 출력 디렉토리 (스크립트 위치 기준)
|
||||
# script: data/scripts/unified/collect_mac.py -> data_root: data/
|
||||
script_dir = Path(__file__).resolve().parent
|
||||
data_root = script_dir.parent.parent
|
||||
output_dir = data_root / "temp" / "staging"
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# IP 목록 읽기
|
||||
ips = [line.strip() for line in ip_file.read_text(encoding='utf-8').splitlines() if line.strip()]
|
||||
|
||||
if not ips:
|
||||
logging.error("IP 목록이 비어 있습니다.")
|
||||
sys.exit(1)
|
||||
|
||||
logging.info(f"총 {len(ips)}대 처리 시작")
|
||||
|
||||
# 병렬 처리
|
||||
ok, fail = 0, 0
|
||||
with ThreadPoolExecutor(max_workers=20) as executor:
|
||||
futures = {executor.submit(collect_mac_for_ip, ip, profile, output_dir): ip for ip in ips}
|
||||
|
||||
for future in futures:
|
||||
ip, success, msg = future.result()
|
||||
if success:
|
||||
logging.info(f"[OK] {ip} - {msg}")
|
||||
ok += 1
|
||||
else:
|
||||
logging.error(f"[FAIL] {ip} - {msg}")
|
||||
fail += 1
|
||||
|
||||
logging.info(f"완료: 성공 {ok}대 / 실패 {fail}대")
|
||||
|
||||
# IP 파일 삭제 (기존 스크립트와 동일)
|
||||
try:
|
||||
ip_file.unlink(missing_ok=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,192 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
통합 서버 정보 수집 스크립트
|
||||
프로파일 기반으로 BIOS/iDRAC/RAID 설정 수집
|
||||
"""
|
||||
import sys
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import logging
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
from core.idrac_client import IDRACClient
|
||||
from core.parsers import InfoParser
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] root: %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
|
||||
def load_profile(profile_name: str) -> dict:
|
||||
"""프로파일 로드 및 상속 처리"""
|
||||
profile_file = Path(__file__).parent.parent / "profiles" / "server_info_profiles.yaml"
|
||||
|
||||
if not profile_file.exists():
|
||||
logging.error(f"프로파일 파일 없음: {profile_file}")
|
||||
sys.exit(1)
|
||||
|
||||
with open(profile_file, 'r', encoding='utf-8') as f:
|
||||
profiles = yaml.safe_load(f)['profiles']
|
||||
|
||||
profile = profiles.get(profile_name)
|
||||
if not profile:
|
||||
logging.error(f"프로파일 '{profile_name}' 없음. 사용 가능: {list(profiles.keys())}")
|
||||
sys.exit(1)
|
||||
|
||||
# extends 처리
|
||||
if 'extends' in profile:
|
||||
base = profiles[profile['extends']].copy()
|
||||
# 리스트 병합
|
||||
for key in ['firmware', 'bios_settings', 'idrac_settings', 'raid_settings', 'custom_items']:
|
||||
if key in profile:
|
||||
base_items = base.get(key, [])
|
||||
profile_items = profile[key]
|
||||
# 중복 제거하면서 병합
|
||||
base[key] = base_items + profile_items
|
||||
base.update({k: v for k, v in profile.items() if k not in ['firmware', 'bios_settings', 'idrac_settings', 'raid_settings', 'custom_items']})
|
||||
profile = base
|
||||
|
||||
return profile
|
||||
|
||||
|
||||
def collect_server_info_for_ip(ip: str, profile: dict, output_dir: Path) -> tuple:
|
||||
"""단일 IP에 대한 서버 정보 수집"""
|
||||
try:
|
||||
client = IDRACClient(ip)
|
||||
parser = InfoParser()
|
||||
|
||||
# 서비스 태그 추출
|
||||
sysinfo = client.get_sysinfo()
|
||||
svc_tag = parser.extract_service_tag(sysinfo)
|
||||
if not svc_tag:
|
||||
return ip, False, "서비스 태그 추출 실패"
|
||||
|
||||
# 결과 파일 생성
|
||||
output_file = output_dir / f"{svc_tag}.txt"
|
||||
|
||||
with output_file.open('w', encoding='utf-8', newline='\n') as f:
|
||||
f.write(f"Dell EMC Server Bios,iDRAC,R/C Setting (SVC Tag: {svc_tag})\n\n")
|
||||
|
||||
# 펌웨어 버전 정보
|
||||
if 'firmware' in profile:
|
||||
f.write("-" * 42 + " Firmware Version 정보 " + "-" * 42 + "\n")
|
||||
for idx, item in enumerate(profile['firmware'], 1):
|
||||
value = _get_value_from_command(client, item['command'], item['pattern'])
|
||||
f.write(f"{idx}. {item['name']} : {value}\n")
|
||||
f.write("\n")
|
||||
|
||||
# BIOS 설정 정보
|
||||
if 'bios_settings' in profile:
|
||||
f.write("-" * 45 + " Bios 설정 정보 " + "-" * 46 + "\n")
|
||||
for idx, item in enumerate(profile['bios_settings'], 1):
|
||||
value = _get_value_from_command(client, item['command'], item['pattern'])
|
||||
f.write(f"{idx:02d}. {item['name']} : {value}\n")
|
||||
f.write("\n")
|
||||
|
||||
# iDRAC 설정 정보
|
||||
if 'idrac_settings' in profile:
|
||||
f.write("-" * 45 + " iDRAC 설정 정보 " + "-" * 45 + "\n")
|
||||
for idx, item in enumerate(profile['idrac_settings'], 1):
|
||||
value = _get_value_from_command(client, item['command'], item['pattern'])
|
||||
f.write(f"{idx:02d}. {item['name']} : {value}\n")
|
||||
f.write("\n")
|
||||
|
||||
# RAID 설정 정보
|
||||
if 'raid_settings' in profile:
|
||||
f.write("-" * 45 + " Raid 설정 정보 " + "-" * 46 + "\n")
|
||||
for idx, item in enumerate(profile['raid_settings'], 1):
|
||||
value = _get_value_from_command(client, item['command'], item['pattern'])
|
||||
f.write(f"{idx:02d}. {item['name']} : {value}\n")
|
||||
f.write("\n")
|
||||
|
||||
# 커스텀 항목 (있을 경우)
|
||||
if 'custom_items' in profile and profile['custom_items']:
|
||||
f.write("-" * 45 + " 커스텀 항목 " + "-" * 46 + "\n")
|
||||
for idx, item in enumerate(profile['custom_items'], 1):
|
||||
value = _get_value_from_command(client, item['command'], item['pattern'])
|
||||
f.write(f"{idx:02d}. {item['name']} : {value}\n")
|
||||
f.write("\n")
|
||||
|
||||
return ip, True, f"저장: {output_file.name}"
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"[{ip}] 오류: {e}")
|
||||
return ip, False, f"오류: {e}"
|
||||
|
||||
|
||||
def _get_value_from_command(client: IDRACClient, command: str, pattern: str) -> str:
|
||||
"""racadm 명령 실행 및 값 추출"""
|
||||
# 캐싱된 데이터 사용
|
||||
if command == "getsysinfo":
|
||||
output = client.get_sysinfo()
|
||||
elif command == "hwinventory":
|
||||
output = client.get_hwinventory()
|
||||
else:
|
||||
_, output = client.run_command(command)
|
||||
|
||||
# 패턴 매칭
|
||||
value = InfoParser.extract_value_by_pattern(output, pattern)
|
||||
return value if value else "N/A"
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python collect_server_info.py <ip_file> [profile_name]")
|
||||
print("Available profiles: default, intel_server, amd_server, minimal")
|
||||
sys.exit(1)
|
||||
|
||||
ip_file = Path(sys.argv[1])
|
||||
profile_name = sys.argv[2] if len(sys.argv) > 2 else "default"
|
||||
|
||||
if not ip_file.exists():
|
||||
logging.error(f"IP 파일 없음: {ip_file}")
|
||||
sys.exit(1)
|
||||
|
||||
# 프로파일 로드
|
||||
profile = load_profile(profile_name)
|
||||
logging.info(f"프로파일 사용: {profile_name} - {profile.get('description', '')}")
|
||||
|
||||
# 출력 디렉토리 (data/temp/staging)
|
||||
script_dir = Path(__file__).resolve().parent
|
||||
# unified 디렉토리에 있으므로, data 디렉토리는 3단계 상위 (unified -> scripts -> data)
|
||||
data_dir = script_dir.parent.parent
|
||||
|
||||
# 만약 구조가 다를 경우를 대비한 안전장치 (scripts가 아닐 경우 등)
|
||||
if data_dir.name != "data":
|
||||
# fallback: 현재 작업 디렉토리 기준 data 찾기 시도
|
||||
data_dir = Path("data").resolve()
|
||||
|
||||
output_dir = data_dir / "temp" / "staging"
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# IP 목록 읽기
|
||||
ips = [line.strip() for line in ip_file.read_text(encoding='utf-8').splitlines() if line.strip()]
|
||||
|
||||
if not ips:
|
||||
logging.error("IP 목록이 비어 있습니다.")
|
||||
sys.exit(1)
|
||||
|
||||
logging.info(f"총 {len(ips)}대 처리 시작")
|
||||
|
||||
# 병렬 처리 (서버 정보 수집은 racadm 호출이 많아 worker 수 줄임)
|
||||
ok, fail = 0, 0
|
||||
with ThreadPoolExecutor(max_workers=10) as executor:
|
||||
futures = {executor.submit(collect_server_info_for_ip, ip, profile, output_dir): ip for ip in ips}
|
||||
|
||||
for future in futures:
|
||||
ip, success, msg = future.result()
|
||||
if success:
|
||||
logging.info(f"[OK] {ip} - {msg}")
|
||||
ok += 1
|
||||
else:
|
||||
logging.error(f"[FAIL] {ip} - {msg}")
|
||||
fail += 1
|
||||
|
||||
logging.info(f"완료: 성공 {ok}대 / 실패 {fail}대")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,239 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
통합 시스템 제어 스크립트 (Unified System Control Script)
|
||||
기존의 개별 제어 스크립트들을 하나로 통합하였습니다.
|
||||
|
||||
지원 기능:
|
||||
- power_on (06-PowerON.py)
|
||||
- power_off (07-PowerOFF.py)
|
||||
- log_clear (05-clrsel.py)
|
||||
- job_delete (08-job_delete_all.py)
|
||||
- tsr_collect (03-tsr_log.py)
|
||||
- tsr_save (04-tsr_save.py)
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import subprocess
|
||||
import time
|
||||
import logging
|
||||
import re
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Load .env relative to script location or current directory
|
||||
load_dotenv()
|
||||
|
||||
IDRAC_USER = os.getenv("IDRAC_USER", "root")
|
||||
IDRAC_PASS = os.getenv("IDRAC_PASS", "calvin")
|
||||
TSR_SHARE_URL = os.getenv("TSR_SHARE_URL", "//10.10.3.15/share/")
|
||||
OME_USER = os.getenv("OME_USER", "")
|
||||
OME_PASS = os.getenv("OME_PASS", "")
|
||||
TSR_JOB_TIMEOUT = int(os.getenv("TSR_JOB_TIMEOUT", "900"))
|
||||
TSR_JOB_POLL_INTERVAL = int(os.getenv("TSR_JOB_POLL_INTERVAL", "10"))
|
||||
TSR_SAVE_WORKERS = int(os.getenv("TSR_SAVE_WORKERS", "30"))
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Command Definitions
|
||||
# -----------------------------------------------------------------------------
|
||||
# Each action maps to a function that returns the racadm command list
|
||||
def cmd_power_on(ip):
|
||||
return ["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "serveraction", "powerup"]
|
||||
|
||||
def cmd_power_off(ip):
|
||||
return ["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "serveraction", "powerdown"]
|
||||
|
||||
def cmd_log_clear(ip):
|
||||
return ["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "clrsel"]
|
||||
|
||||
def cmd_job_delete(ip):
|
||||
return ["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "jobqueue", "delete", "-i", "ALL"]
|
||||
|
||||
def cmd_tsr_collect(ip):
|
||||
return ["racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS, "techsupreport", "collect"]
|
||||
|
||||
def cmd_tsr_save(ip):
|
||||
return [
|
||||
"racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS,
|
||||
"techsupreport", "export", "-l", TSR_SHARE_URL, "-u", OME_USER, "-p", OME_PASS
|
||||
]
|
||||
|
||||
ACTION_MAP = {
|
||||
"power_on": cmd_power_on,
|
||||
"power_off": cmd_power_off,
|
||||
"log_clear": cmd_log_clear,
|
||||
"job_delete": cmd_job_delete,
|
||||
"tsr_collect": cmd_tsr_collect,
|
||||
"tsr_save": cmd_tsr_save,
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Execution Logic
|
||||
# -----------------------------------------------------------------------------
|
||||
def redact_cmd(cmd):
|
||||
redacted = []
|
||||
hide_next = False
|
||||
for part in cmd:
|
||||
if hide_next:
|
||||
redacted.append("***")
|
||||
hide_next = False
|
||||
continue
|
||||
redacted.append(part)
|
||||
if part == "-p":
|
||||
hide_next = True
|
||||
return redacted
|
||||
|
||||
|
||||
def extract_job_id(output: str) -> Optional[str]:
|
||||
match = re.search(r"Job ID\s*=\s*(JID_\d+)", output or "")
|
||||
return match.group(1) if match else None
|
||||
|
||||
|
||||
def wait_for_job(ip: str, job_id: str) -> bool:
|
||||
deadline = time.time() + TSR_JOB_TIMEOUT
|
||||
view_cmd = [
|
||||
"racadm", "-r", ip, "-u", IDRAC_USER, "-p", IDRAC_PASS,
|
||||
"jobqueue", "view", "-i", job_id
|
||||
]
|
||||
|
||||
while time.time() < deadline:
|
||||
result = subprocess.run(
|
||||
view_cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=120
|
||||
)
|
||||
output = "\n".join(part for part in [result.stdout.strip(), result.stderr.strip()] if part)
|
||||
logger.info(f"[{ip}] Job {job_id} status:\n{output}")
|
||||
|
||||
if "Status=Completed" in output:
|
||||
return True
|
||||
if "Status=Failed" in output:
|
||||
return False
|
||||
|
||||
time.sleep(TSR_JOB_POLL_INTERVAL)
|
||||
|
||||
logger.error(f"[{ip}] Job {job_id} status check timed out after {TSR_JOB_TIMEOUT} seconds.")
|
||||
return False
|
||||
|
||||
|
||||
def execute_action(ip: str, action_name: str) -> bool:
|
||||
"""Run the racadm command for a single IP."""
|
||||
try:
|
||||
cmd_func = ACTION_MAP.get(action_name)
|
||||
if not cmd_func:
|
||||
logger.error(f"[{ip}] Unknown action: {action_name}")
|
||||
return False
|
||||
|
||||
cmd = cmd_func(ip)
|
||||
logger.info(f"[{ip}] Executing {action_name}...")
|
||||
if action_name == "tsr_save":
|
||||
logger.info(f"[{ip}] Command: {redact_cmd(cmd)}")
|
||||
|
||||
# Run command
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=600 # Generous timeout for TSR operations
|
||||
)
|
||||
output = "\n".join(part for part in [result.stdout.strip(), result.stderr.strip()] if part)
|
||||
|
||||
if result.returncode == 0:
|
||||
logger.info(f"[{ip}] Success: {output}")
|
||||
if action_name == "tsr_save":
|
||||
job_id = extract_job_id(output)
|
||||
if not job_id:
|
||||
logger.error(f"[{ip}] TSR Save did not return a Job ID.")
|
||||
return False
|
||||
return wait_for_job(ip, job_id)
|
||||
return True
|
||||
else:
|
||||
logger.error(f"[{ip}] Failed: {output}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[{ip}] Exception: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Unified System Control Script")
|
||||
parser.add_argument("action", choices=ACTION_MAP.keys(), help="Action to perform")
|
||||
parser.add_argument("ip_file", type=Path, help="Path to the IP list file")
|
||||
|
||||
# Optional: Allow passing IP directly via args instead of file (future extension)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
ip_file = args.ip_file
|
||||
action = args.action
|
||||
|
||||
if not ip_file.is_file():
|
||||
logger.error(f"IP file not found: {ip_file}")
|
||||
sys.exit(1)
|
||||
|
||||
# Read IPs
|
||||
try:
|
||||
with ip_file.open("r", encoding="utf-8") as f:
|
||||
ips = [line.strip() for line in f if line.strip()]
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to read IP file: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
if not ips:
|
||||
logger.warning("No IPs found in file.")
|
||||
sys.exit(0)
|
||||
|
||||
logger.info(f"Starting '{action}' for {len(ips)} servers...")
|
||||
start_time = time.time()
|
||||
|
||||
success_count = 0
|
||||
failed_count = 0
|
||||
|
||||
if action == "tsr_save":
|
||||
max_workers = max(1, min(TSR_SAVE_WORKERS, len(ips)))
|
||||
logger.info(f"TSR Save parallel workers={max_workers}")
|
||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||
futures = [executor.submit(execute_action, ip, action) for ip in ips]
|
||||
for future in futures:
|
||||
if future.result():
|
||||
success_count += 1
|
||||
else:
|
||||
failed_count += 1
|
||||
else:
|
||||
# Parallel Execution
|
||||
# Adjust max_workers as needed. 20 is a safe defaults for I/O bound network tasks.
|
||||
with ThreadPoolExecutor(max_workers=20) as executor:
|
||||
futures = [executor.submit(execute_action, ip, action) for ip in ips]
|
||||
for future in futures:
|
||||
if future.result():
|
||||
success_count += 1
|
||||
else:
|
||||
failed_count += 1
|
||||
|
||||
elapsed = time.time() - start_time
|
||||
logger.info(
|
||||
f"Completed '{action}' in {elapsed:.2f} seconds. "
|
||||
f"success={success_count}, failed={failed_count}"
|
||||
)
|
||||
|
||||
if failed_count:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,312 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# 모든 hwinventory 저장
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory)
|
||||
# 모든 샷시 정보 저장
|
||||
local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo)
|
||||
# 모든 SysProfileSettings 저장
|
||||
local SysProfileSettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.SysProfileSettings)
|
||||
# ProcessorSettings 저장
|
||||
local ProcessorSettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.ProcSettings)
|
||||
# Memory Settings 저장
|
||||
local MemorySettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.MemSettings)
|
||||
# Raid Settings 저장
|
||||
local STORAGEController=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get STORAGE.Controller.1)
|
||||
|
||||
# 서비스 태그 가져오기
|
||||
local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Bios Firmware Version 확인
|
||||
local Bios_firmware=$(echo "$getsysinfo" | grep -i "System BIOS Version" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Firmware Version 확인
|
||||
local iDRAC_firmware=$(echo "$getsysinfo" | grep -i "Firmware Version" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Intel NIC Firmware Version 확인
|
||||
local Intel_NIC_firmware=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get NIC.FrmwImgMenu.1 | grep -i "#FamilyVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# OnBoard NIC Firmware Version 확인
|
||||
local Onboard_NIC_firmware=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get NIC.FrmwImgMenu.5 | grep -i "#FamilyVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# R/C Firmware Version 확인
|
||||
local Raid_firmware=$(echo "$hwinventory" | grep -i "ControllerFirmwareVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Bios 설정 Boot Mode 확인
|
||||
local Bios_BootMode=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.BiosBootSettings | grep -i "BootMode" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Bios SysProfileSettings 설정 정보 확인
|
||||
local SysProFileSettings_info1=$(echo "$SysProfileSettings" | grep -i "SysProfile=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info2=$(echo "$SysProfileSettings" | grep -i "EnergyPerformanceBias" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info3=$(echo "$SysProfileSettings" | grep -i "MemFrequency" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info4=$(echo "$SysProfileSettings" | grep -i "ProcTurboMode" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info5=$(echo "$SysProfileSettings" | grep -i "ProcC1E" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info6=$(echo "$SysProfileSettings" | grep -i "ProcCStates" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info7=$(echo "$SysProfileSettings" | grep -i "MonitorMwait" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Processor Settings - Logical Processor
|
||||
local ProcessorSettings_info1=$(echo "$ProcessorSettings" | grep -i "LogicalProc" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local ProcessorSettings_info2=$(echo "$ProcessorSettings" | grep -i "ProcVirtualization" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local ProcessorSettings_info3=$(echo "$ProcessorSettings" | grep -i "LlcPrefetch" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local ProcessorSettings_info4=$(echo "$ProcessorSettings" | grep -i "ProcX2Apic" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Memory Settings - Node Interleaving
|
||||
local MemorySettings_info1=$(echo "$MemorySettings" | grep -i "NodeInterleave" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local MemorySettings_info2=$(echo "$MemorySettings" | grep -i "PPROnUCE" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local MemorySettings_info3=$(echo "$MemorySettings" | grep -i "CECriticalSEL" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# System Settings - Thermal Profile Optimization
|
||||
local SystemSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get System.ThermalSettings | grep -i "ThermalProfile" | awk -F '=' '{print $2}')
|
||||
# Integrated Devices Settings - SR-IOV Global Enable
|
||||
local IntegratedDevicesSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get Bios.IntegratedDevices | grep -i "SriovGlobalEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Miscellaneous Settings - F1/F2 Prompt on Error
|
||||
local IMiscellaneousSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.MiscSettings | grep -i "ErrPrompt" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# iDRAC Settings - Timezone
|
||||
local iDRAC_Settings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.Time.Timezone | grep -i "Timezone" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IPMI LAN Selection
|
||||
local iDRAC_Settings_info2=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentNIC | grep -i "ActiveNIC" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IPMI IP(IPv4)
|
||||
local iDRAC_Settings_info3=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentIPv4 | grep -i "DHCPEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IPMI IP(IPv6)
|
||||
local iDRAC_Settings_info4=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentIPv6 | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - Redfish Support
|
||||
local iDRAC_Settings_info5=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.Redfish.Enable | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SSH Support
|
||||
local iDRAC_Settings_info6=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SSH | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - AD User Domain Name
|
||||
local iDRAC_Settings_info7=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.USERDomain.1.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SC Server Address
|
||||
local iDRAC_Settings_info8=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ActiveDirectory.DomainController1 | grep -i "DomainController1" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SE AD RoleGroup Name
|
||||
local iDRAC_Settings_info9=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SE AD RoleGroup Dome인
|
||||
local iDRAC_Settings_info10=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Domain | grep -i "Domain" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SE AD RoleGroup Privilege
|
||||
local iDRAC_Settings_info11=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Privilege | grep -i "Privilege" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IDC AD RoleGroup name
|
||||
local iDRAC_Settings_info12=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IDC AD RoleGroup Dome인
|
||||
local iDRAC_Settings_info13=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Domain | grep -i "Domain" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IDC AD RoleGroup Privilege
|
||||
local iDRAC_Settings_info14=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Privilege | grep -i "Privilege" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
local iDRAC_Settings_info15=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.SysLogEnable | grep -i "SysLogEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - syslog server address 1
|
||||
local iDRAC_Settings_info16=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Server1 | grep -i "Server1" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - syslog server address 2
|
||||
local iDRAC_Settings_info17=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Server2 | grep -i "Server2" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - syslog server port
|
||||
local iDRAC_Settings_info18=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Port | grep -i "Port" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - VirtualConsole Port
|
||||
local iDRAC_Settings_info19=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.VirtualConsole.Port | grep -i "Port" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# RAID Settings - ProductName
|
||||
local RAID_info0=$(echo "$hwinventory" | grep -i "ProductName = PERC" | awk -F '=' '{print $2}')
|
||||
# RAID Settings - RAIDType
|
||||
local RAID_info1=$(echo "$hwinventory" | grep -i "RAIDTypes" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - StripeSize
|
||||
local RAID_info2=$(echo "$hwinventory" | grep -i "StripeSize" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - ReadCachePolicy
|
||||
local RAID_info3=$(echo "$hwinventory" | grep -i "ReadCachePolicy" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - WriteCachePolicy
|
||||
local RAID_info4=$(echo "$hwinventory" | grep -i "WriteCachePolicy" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - PatrolReadRate
|
||||
local RAID_info5=$(echo "$STORAGEController" | grep -i "CheckConsistencyRate" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - PatrolReadRate
|
||||
local RAID_info6=$(echo "$STORAGEController" | grep -i "PatrolReadMode" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# 서비스 태그가 존재하는지 확인
|
||||
if [ -z "$SVC_TAG" ]; then
|
||||
echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP"
|
||||
return
|
||||
fi
|
||||
|
||||
local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt"
|
||||
echo "Dell EMC Server Bios,iDRAC,R/C Setting (SVC Tag: $SVC_TAG)" | tee -a "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
echo "------------------------------------------Firware Version 정보------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# SVC Tag 확인
|
||||
echo "1. SVC Tag : $SVC_TAG" >> "$OUTPUT_FILE"
|
||||
|
||||
# Bios Firmware Version 확인
|
||||
echo "2. Bios Firmware : $Bios_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# iDRAC Firmware Version 확인
|
||||
echo "3. iDRAC Firmware Version : $iDRAC_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# Intel NIC Firmware Version 확인
|
||||
echo "4. NIC Integrated Firmware Version : $Intel_NIC_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# OnBoard NIC Firmware Version 확인
|
||||
echo "5. OnBoard NIC Firmware Version : $Onboard_NIC_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# Raid Controller Firmware Version 확인
|
||||
echo "6. Raid Controller Firmware Version : $Raid_firmware" >> "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
|
||||
echo "---------------------------------------------Bios 설정 정보----------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# bios Boot Mode 확인
|
||||
echo "01. Bios Boot Mode : $Bios_BootMode" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - System Profile
|
||||
echo "02. System Profile Settings - System Profile : $SysProFileSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - CPU Power Management
|
||||
echo "03. System Profile Settings - CPU Power Management : $SysProFileSettings_info2" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - Memory Frequency
|
||||
echo "04. System Profile Settings - Memory Frequency : $SysProFileSettings_info3" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - Turbo Boost
|
||||
echo "05. System Profile Settings - Turbo Boost : $SysProFileSettings_info4" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - C1E
|
||||
echo "06. System Profile Settings - C1E : $SysProFileSettings_info5" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - C-States
|
||||
echo "07. System Profile Settings - C-States : $SysProFileSettings_info6" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - C-States
|
||||
echo "08. System Profile Settings - Monitor/Mwait : $SysProFileSettings_info7" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - Logical Processor
|
||||
echo "09. Processor Settings - Logical Processor : $ProcessorSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - Virtualization Technology
|
||||
echo "10. Processor Settings - Virtualization Technology : $ProcessorSettings_info2" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - LLC Prefetch
|
||||
echo "11. Processor Settings - LLC Prefetch : $ProcessorSettings_info3" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - x2APIC Mode
|
||||
echo "12. Processor Settings - x2APIC Mode : $ProcessorSettings_info4" >> "$OUTPUT_FILE"
|
||||
|
||||
# Memory Settings - Node Interleaving
|
||||
echo "13. Memory Settings - Node Interleaving : $MemorySettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Memory Settings - DIMM Self Healing (Post Package Repair) on Uncorrectable Memory Error
|
||||
echo "14. Memory Settings - DIMM Self Healing (Post Package Repair) on Uncorrectable Memory Error : $MemorySettings_info2" >> "$OUTPUT_FILE"
|
||||
|
||||
# Memory Settings - Correctable Error Logging
|
||||
echo "15. Memory Settings - Correctable Error Logging : $MemorySettings_info3" >> "$OUTPUT_FILE"
|
||||
|
||||
# System Settings - Thermal Profile Optimization
|
||||
echo "16. System Settings - Thermal Profile Optimization : $SystemSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Integrated Devices Settings - SR-IOV Global Enable
|
||||
echo "17. Integrated Devices Settings - SR-IOV Global Enable : $IntegratedDevicesSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Miscellaneous Settings - F1/F2 Prompt on Error
|
||||
echo "18. Miscellaneous Settings - F1/F2 Prompt on Error : $IMiscellaneousSettings_info1" >> "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
|
||||
echo "---------------------------------------------iDRAC 설정 정보----------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Timezone
|
||||
echo "01. iDRAC Settings - Timezone : $iDRAC_Settings_info1" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - IPMI LAN Selection
|
||||
echo "02. iDRAC Settings - IPMI LAN Selection : $iDRAC_Settings_info2" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - IPMI IP(IPv4)
|
||||
echo "03. iDRAC Settings - IPMI IP(IPv4) : $iDRAC_Settings_info3" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - IPMI IP(IPv6)
|
||||
echo "04. iDRAC Settings - IPMI IP(IPv6) : $iDRAC_Settings_info4" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Redfish Support
|
||||
echo "05. iDRAC Settings - Redfish Support : $iDRAC_Settings_info5" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SSH Support
|
||||
echo "06. iDRAC Settings - SSH Support : $iDRAC_Settings_info6" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - AD User Domain Name
|
||||
echo "07. iDRAC Settings - AD User Domain Name : $iDRAC_Settings_info7" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SC Server Address
|
||||
echo "08. iDRAC Settings - SC Server Address : $iDRAC_Settings_info8" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE AD RoleGroup Name
|
||||
echo "09. iDRAC Settings - SE AD RoleGroup Name : $iDRAC_Settings_info9" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE AD RoleGroup Dome인
|
||||
echo "10. iDRAC Settings - SE AD RoleGroup Dome인 : $iDRAC_Settings_info10" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE AD RoleGroup Privilege
|
||||
echo "11. iDRAC Settings - SE AD RoleGroup Privilege : $iDRAC_Settings_info11" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE IDC RoleGroup Name
|
||||
echo "12. iDRAC Settings - IDC AD RoleGroup Name : $iDRAC_Settings_info12" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE IDC RoleGroup Dome인
|
||||
echo "13. iDRAC Settings - IDC AD RoleGroup Domain : $iDRAC_Settings_info13" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE IDC RoleGroup Dome인
|
||||
echo "14. iDRAC Settings - IDC AD RoleGroup Privilege : $iDRAC_Settings_info14" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
echo "15. iDRAC Settings - Remote Log (syslog) : $iDRAC_Settings_info15" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
echo "16. iDRAC Settings - syslog server address 1 : $iDRAC_Settings_info16" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
echo "17. iDRAC Settings - syslog server address 2 : $iDRAC_Settings_info17" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - syslog server port
|
||||
echo "18. iDRAC Settings - syslog server port : $iDRAC_Settings_info18" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote KVM Nonsecure port
|
||||
echo "19. iDRAC Settings - Remote KVM Nonsecure port : $iDRAC_Settings_info19" >> "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
|
||||
echo "---------------------------------------------Raid 설정 정보----------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - Raid Types
|
||||
echo "01. RAID Settings - Raid ProductName : $RAID_info0" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - Raid Types
|
||||
echo "02. RAID Settings - Raid Typest : $RAID_info1" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - StripeSize
|
||||
echo "03. RAID Settings - StripeSize : $RAID_info2" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - ReadCachePolicy
|
||||
echo "04. RAID Settings - ReadCachePolicy : $RAID_info3" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - ReadCachePolicy
|
||||
echo "05. RAID Settings - WriteCachePolicy : $RAID_info4" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - CheckConsistencyRate
|
||||
echo "06. RAID Settings - CheckConsistencyRate : $RAID_info5" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - PatrolReadMode
|
||||
echo "07. RAID Settings - PatrolReadMode : $RAID_info6" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - period
|
||||
echo "08. RAID Settings - period : 168h" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - Power Save
|
||||
echo "09. RAID Settings - Power Save : No" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - JBODMODE
|
||||
echo "10. RAID Settings - JBODMODE : Controller does not support JBOD" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - maxconcurrentpd
|
||||
echo "11. RAID Settings - maxconcurrentpd : 240" >> "$OUTPUT_FILE"
|
||||
|
||||
# 임시 파일 삭제
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "정보 수집 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,151 @@
|
||||
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} 초.")
|
||||
@@ -0,0 +1,312 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# 모든 hwinventory 저장
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory)
|
||||
# 모든 샷시 정보 저장
|
||||
local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo)
|
||||
# 모든 SysProfileSettings 저장
|
||||
local SysProfileSettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.SysProfileSettings)
|
||||
# ProcessorSettings 저장
|
||||
local ProcessorSettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.ProcSettings)
|
||||
# Memory Settings 저장
|
||||
local MemorySettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.MemSettings)
|
||||
# Raid Settings 저장
|
||||
local STORAGEController=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get STORAGE.Controller.1)
|
||||
|
||||
# 서비스 태그 가져오기
|
||||
local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Bios Firmware Version 확인
|
||||
local Bios_firmware=$(echo "$getsysinfo" | grep -i "System BIOS Version" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Firmware Version 확인
|
||||
local iDRAC_firmware=$(echo "$getsysinfo" | grep -i "Firmware Version" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Intel NIC Firmware Version 확인
|
||||
local Intel_NIC_firmware=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get NIC.FrmwImgMenu.1 | grep -i "#FamilyVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# OnBoard NIC Firmware Version 확인
|
||||
local Onboard_NIC_firmware=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get NIC.FrmwImgMenu.5 | grep -i "#FamilyVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# R/C Firmware Version 확인
|
||||
local Raid_firmware=$(echo "$hwinventory" | grep -i "ControllerFirmwareVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Bios 설정 Boot Mode 확인
|
||||
local Bios_BootMode=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.BiosBootSettings | grep -i "BootMode" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Bios SysProfileSettings 설정 정보 확인
|
||||
local SysProFileSettings_info1=$(echo "$SysProfileSettings" | grep -i "SysProfile=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info2=$(echo "$SysProfileSettings" | grep -i "EnergyPerformanceBias" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info3=$(echo "$SysProfileSettings" | grep -i "MemFrequency" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info4=$(echo "$SysProfileSettings" | grep -i "ProcTurboMode" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info5=$(echo "$SysProfileSettings" | grep -i "ProcC1E" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info6=$(echo "$SysProfileSettings" | grep -i "ProcCStates" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info7=$(echo "$SysProfileSettings" | grep -i "MonitorMwait" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Processor Settings - Logical Processor
|
||||
local ProcessorSettings_info1=$(echo "$ProcessorSettings" | grep -i "LogicalProc" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local ProcessorSettings_info2=$(echo "$ProcessorSettings" | grep -i "ProcVirtualization" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local ProcessorSettings_info3=$(echo "$ProcessorSettings" | grep -i "LlcPrefetch" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local ProcessorSettings_info4=$(echo "$ProcessorSettings" | grep -i "ProcX2Apic" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Memory Settings - Node Interleaving
|
||||
local MemorySettings_info1=$(echo "$MemorySettings" | grep -i "NodeInterleave" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local MemorySettings_info2=$(echo "$MemorySettings" | grep -i "PPROnUCE" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local MemorySettings_info3=$(echo "$MemorySettings" | grep -i "CECriticalSEL" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# System Settings - Thermal Profile Optimization
|
||||
local SystemSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get System.ThermalSettings | grep -i "ThermalProfile" | awk -F '=' '{print $2}')
|
||||
# Integrated Devices Settings - SR-IOV Global Enable
|
||||
local IntegratedDevicesSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get Bios.IntegratedDevices | grep -i "SriovGlobalEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Miscellaneous Settings - F1/F2 Prompt on Error
|
||||
local IMiscellaneousSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.MiscSettings | grep -i "ErrPrompt" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# iDRAC Settings - Timezone
|
||||
local iDRAC_Settings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.Time.Timezone | grep -i "Timezone" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IPMI LAN Selection
|
||||
local iDRAC_Settings_info2=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentNIC | grep -i "ActiveNIC" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IPMI IP(IPv4)
|
||||
local iDRAC_Settings_info3=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentIPv4 | grep -i "DHCPEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IPMI IP(IPv6)
|
||||
local iDRAC_Settings_info4=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentIPv6 | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - Redfish Support
|
||||
local iDRAC_Settings_info5=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.Redfish.Enable | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SSH Support
|
||||
local iDRAC_Settings_info6=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SSH | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - AD User Domain Name
|
||||
local iDRAC_Settings_info7=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.USERDomain.1.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SC Server Address
|
||||
local iDRAC_Settings_info8=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ActiveDirectory.DomainController1 | grep -i "DomainController1" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SE AD RoleGroup Name
|
||||
local iDRAC_Settings_info9=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SE AD RoleGroup Dome인
|
||||
local iDRAC_Settings_info10=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Domain | grep -i "Domain" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SE AD RoleGroup Privilege
|
||||
local iDRAC_Settings_info11=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Privilege | grep -i "Privilege" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IDC AD RoleGroup name
|
||||
local iDRAC_Settings_info12=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IDC AD RoleGroup Dome인
|
||||
local iDRAC_Settings_info13=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Domain | grep -i "Domain" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IDC AD RoleGroup Privilege
|
||||
local iDRAC_Settings_info14=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Privilege | grep -i "Privilege" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
local iDRAC_Settings_info15=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.SysLogEnable | grep -i "SysLogEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - syslog server address 1
|
||||
local iDRAC_Settings_info16=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Server1 | grep -i "Server1" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - syslog server address 2
|
||||
local iDRAC_Settings_info17=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Server2 | grep -i "Server2" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - syslog server port
|
||||
local iDRAC_Settings_info18=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Port | grep -i "Port" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - VirtualConsole Port
|
||||
local iDRAC_Settings_info19=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.VirtualConsole.Port | grep -i "Port" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# RAID Settings - ProductName
|
||||
local RAID_info0=$(echo "$hwinventory" | grep -i "ProductName = PERC" | awk -F '=' '{print $2}')
|
||||
# RAID Settings - RAIDType
|
||||
local RAID_info1=$(echo "$hwinventory" | grep -i "RAIDTypes" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - StripeSize
|
||||
local RAID_info2=$(echo "$hwinventory" | grep -i "StripeSize" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - ReadCachePolicy
|
||||
local RAID_info3=$(echo "$hwinventory" | grep -i "ReadCachePolicy" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - WriteCachePolicy
|
||||
local RAID_info4=$(echo "$hwinventory" | grep -i "WriteCachePolicy" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - PatrolReadRate
|
||||
local RAID_info5=$(echo "$STORAGEController" | grep -i "CheckConsistencyRate" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - PatrolReadRate
|
||||
local RAID_info6=$(echo "$STORAGEController" | grep -i "PatrolReadMode" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# 서비스 태그가 존재하는지 확인
|
||||
if [ -z "$SVC_TAG" ]; then
|
||||
echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP"
|
||||
return
|
||||
fi
|
||||
|
||||
local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt"
|
||||
echo "Dell EMC Server Bios,iDRAC,R/C Setting (SVC Tag: $SVC_TAG)" | tee -a "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
echo "------------------------------------------Firware Version 정보------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# SVC Tag 확인
|
||||
echo "1. SVC Tag : $SVC_TAG" >> "$OUTPUT_FILE"
|
||||
|
||||
# Bios Firmware Version 확인
|
||||
echo "2. Bios Firmware : $Bios_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# iDRAC Firmware Version 확인
|
||||
echo "3. iDRAC Firmware Version : $iDRAC_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# Intel NIC Firmware Version 확인
|
||||
echo "4. NIC Integrated Firmware Version : $Intel_NIC_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# OnBoard NIC Firmware Version 확인
|
||||
echo "5. OnBoard NIC Firmware Version : $Onboard_NIC_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# Raid Controller Firmware Version 확인
|
||||
echo "6. Raid Controller Firmware Version : $Raid_firmware" >> "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
|
||||
echo "---------------------------------------------Bios 설정 정보----------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# bios Boot Mode 확인
|
||||
echo "01. Bios Boot Mode : $Bios_BootMode" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - System Profile
|
||||
echo "02. System Profile Settings - System Profile : $SysProFileSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - CPU Power Management
|
||||
echo "03. System Profile Settings - CPU Power Management : $SysProFileSettings_info2" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - Memory Frequency
|
||||
echo "04. System Profile Settings - Memory Frequency : $SysProFileSettings_info3" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - Turbo Boost
|
||||
echo "05. System Profile Settings - Turbo Boost : $SysProFileSettings_info4" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - C1E
|
||||
echo "06. System Profile Settings - C1E : $SysProFileSettings_info5" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - C-States
|
||||
echo "07. System Profile Settings - C-States : $SysProFileSettings_info6" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - C-States
|
||||
echo "08. System Profile Settings - Monitor/Mwait : $SysProFileSettings_info7" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - Logical Processor
|
||||
echo "09. Processor Settings - Logical Processor : $ProcessorSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - Virtualization Technology
|
||||
echo "10. Processor Settings - Virtualization Technology : $ProcessorSettings_info2" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - LLC Prefetch
|
||||
echo "11. Processor Settings - LLC Prefetch : $ProcessorSettings_info3" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - x2APIC Mode
|
||||
echo "12. Processor Settings - x2APIC Mode : $ProcessorSettings_info4" >> "$OUTPUT_FILE"
|
||||
|
||||
# Memory Settings - Node Interleaving
|
||||
echo "13. Memory Settings - Node Interleaving : $MemorySettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Memory Settings - DIMM Self Healing (Post Package Repair) on Uncorrectable Memory Error
|
||||
echo "14. Memory Settings - DIMM Self Healing (Post Package Repair) on Uncorrectable Memory Error : $MemorySettings_info2" >> "$OUTPUT_FILE"
|
||||
|
||||
# Memory Settings - Correctable Error Logging
|
||||
echo "15. Memory Settings - Correctable Error Logging : $MemorySettings_info3" >> "$OUTPUT_FILE"
|
||||
|
||||
# System Settings - Thermal Profile Optimization
|
||||
echo "16. System Settings - Thermal Profile Optimization : $SystemSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Integrated Devices Settings - SR-IOV Global Enable
|
||||
echo "17. Integrated Devices Settings - SR-IOV Global Enable : $IntegratedDevicesSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Miscellaneous Settings - F1/F2 Prompt on Error
|
||||
echo "18. Miscellaneous Settings - F1/F2 Prompt on Error : $IMiscellaneousSettings_info1" >> "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
|
||||
echo "---------------------------------------------iDRAC 설정 정보----------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Timezone
|
||||
echo "01. iDRAC Settings - Timezone : $iDRAC_Settings_info1" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - IPMI LAN Selection
|
||||
echo "02. iDRAC Settings - IPMI LAN Selection : $iDRAC_Settings_info2" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - IPMI IP(IPv4)
|
||||
echo "03. iDRAC Settings - IPMI IP(IPv4) : $iDRAC_Settings_info3" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - IPMI IP(IPv6)
|
||||
echo "04. iDRAC Settings - IPMI IP(IPv6) : $iDRAC_Settings_info4" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Redfish Support
|
||||
echo "05. iDRAC Settings - Redfish Support : $iDRAC_Settings_info5" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SSH Support
|
||||
echo "06. iDRAC Settings - SSH Support : $iDRAC_Settings_info6" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - AD User Domain Name
|
||||
echo "07. iDRAC Settings - AD User Domain Name : $iDRAC_Settings_info7" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SC Server Address
|
||||
echo "08. iDRAC Settings - SC Server Address : $iDRAC_Settings_info8" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE AD RoleGroup Name
|
||||
echo "09. iDRAC Settings - SE AD RoleGroup Name : $iDRAC_Settings_info9" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE AD RoleGroup Dome인
|
||||
echo "10. iDRAC Settings - SE AD RoleGroup Dome인 : $iDRAC_Settings_info10" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE AD RoleGroup Privilege
|
||||
echo "11. iDRAC Settings - SE AD RoleGroup Privilege : $iDRAC_Settings_info11" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE IDC RoleGroup Name
|
||||
echo "12. iDRAC Settings - IDC AD RoleGroup Name : $iDRAC_Settings_info12" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE IDC RoleGroup Dome인
|
||||
echo "13. iDRAC Settings - IDC AD RoleGroup Domain : $iDRAC_Settings_info13" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE IDC RoleGroup Dome인
|
||||
echo "14. iDRAC Settings - IDC AD RoleGroup Privilege : $iDRAC_Settings_info14" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
echo "15. iDRAC Settings - Remote Log (syslog) : $iDRAC_Settings_info15" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
echo "16. iDRAC Settings - syslog server address 1 : $iDRAC_Settings_info16" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
echo "17. iDRAC Settings - syslog server address 2 : $iDRAC_Settings_info17" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - syslog server port
|
||||
echo "18. iDRAC Settings - syslog server port : $iDRAC_Settings_info18" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote KVM Nonsecure port
|
||||
echo "19. iDRAC Settings - Remote KVM Nonsecure port : $iDRAC_Settings_info19" >> "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
|
||||
echo "---------------------------------------------Raid 설정 정보----------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - Raid Types
|
||||
echo "01. RAID Settings - Raid ProductName : $RAID_info0" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - Raid Types
|
||||
echo "02. RAID Settings - Raid Typest : $RAID_info1" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - StripeSize
|
||||
echo "03. RAID Settings - StripeSize : $RAID_info2" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - ReadCachePolicy
|
||||
echo "04. RAID Settings - ReadCachePolicy : $RAID_info3" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - ReadCachePolicy
|
||||
echo "05. RAID Settings - WriteCachePolicy : $RAID_info4" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - CheckConsistencyRate
|
||||
echo "06. RAID Settings - CheckConsistencyRate : $RAID_info5" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - PatrolReadMode
|
||||
echo "07. RAID Settings - PatrolReadMode : $RAID_info6" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - period
|
||||
echo "08. RAID Settings - period : 168h" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - Power Save
|
||||
echo "09. RAID Settings - Power Save : No" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - JBODMODE
|
||||
echo "10. RAID Settings - JBODMODE : Controller does not support JBOD" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - maxconcurrentpd
|
||||
echo "11. RAID Settings - maxconcurrentpd : 240" >> "$OUTPUT_FILE"
|
||||
|
||||
# 임시 파일 삭제
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "정보 수집 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set -t xml -f /app/idrac_info/xml/T6_R760_XML_P.xml -b "graceful" -w 800 -s "Off")
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "all Config 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set -t xml -f /app/idrac_info/xml/T6_R760_RAID_A.xml -b "graceful" -w 800 -s "Off")
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "Raid Config 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file> <xml_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
XML_FILE=$2 # 추가된 부분
|
||||
|
||||
echo "스크립트 실행 중: IP 파일 경로 - $IP_FILE, XML 파일 경로 - $XML_FILE" # 로그 추가
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$XML_FILE" ]; then
|
||||
echo "XML file $XML_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
echo "Applying configuration to $IDRAC_IP using XML file $XML_FILE" # 로그 추가
|
||||
|
||||
# DellEMC Server 설정 명령어
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS set -t xml -f $XML_FILE)
|
||||
|
||||
echo "명령어 실행 완료: $hwinventory" # 명령어 실행 결과 로그 추가
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "all Config 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS techsupreport collect)
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
#local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS techsupreport export -l //10.29.7.2/share/ -u OME -p epF!@34)
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS techsupreport export -l //10.10.3.251/share/ -u OME -p epF!@34)
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS clrsel)
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "Log clear 완료."
|
||||
echo "log clear 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS serveraction powerup)
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "Server Power On 완료."
|
||||
echo "Scripts 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS serveraction powerdown)
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "Server Power Off 완료."
|
||||
echo "Server Power Off 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS update -f /app/idrac_info/fw/idrac.EXE)
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# DellEMC Server
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS jobqueue delete -i ALL)
|
||||
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "설정 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,98 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# 모든 hwinventory 저장
|
||||
local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo)
|
||||
local swinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS swinventory)
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory)
|
||||
|
||||
#서비스 태그 가져오기
|
||||
local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#iDRAC MAC 확인
|
||||
local idrac_mac=$(echo "$getsysinfo" | grep -i "MAC Address = " | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#NIC.Integrated MAC 확인
|
||||
local Integrated_1=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Integrated_2=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-2-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#추가 NIC MAC 확인
|
||||
local NIC_Slot_1=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.1-1-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local NIC_Slot_2=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.1-2-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#OnBoard MAC 확인
|
||||
local Onboard_1=$(echo "$getsysinfo" | grep -P "NIC.Embedded.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Onboard_2=$(echo "$getsysinfo" | grep -P "NIC.Embedded.2-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#파트 벤더 확인
|
||||
local memory=$(echo "$hwinventory" | grep -A5 "DIMM" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
local ssd=$(echo "$hwinventory" | grep -A3 "Disk.Bay" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
|
||||
# 서비스 태그가 존재하는지 확인
|
||||
if [ -z "$SVC_TAG" ]; then
|
||||
echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP"
|
||||
return
|
||||
fi
|
||||
|
||||
local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt"
|
||||
# SVC Tag 확인
|
||||
echo "$SVC_TAG" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_1" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_2" >> "$OUTPUT_FILE"
|
||||
echo "$NIC_Slot_1" >> "$OUTPUT_FILE"
|
||||
echo "$NIC_Slot_2" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_1" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_2" >> "$OUTPUT_FILE"
|
||||
echo "$idrac_mac" >> "$OUTPUT_FILE"
|
||||
echo "$memory" >> "$OUTPUT_FILE"
|
||||
echo "$ssd" >> "$OUTPUT_FILE"
|
||||
#임시파일 제거
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "정보 수집 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,97 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# 모든 hwinventory 저장
|
||||
local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo)
|
||||
#local swinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS swinventory)
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory)
|
||||
|
||||
#서비스 태그 가져오기
|
||||
local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#iDRAC MAC 확인
|
||||
local idrac_mac=$(echo "$getsysinfo" | grep -i "MAC Address = " | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#NIC.Integrated MAC 확인
|
||||
local Integrated_1=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Integrated_2=$(echo "$getsysinfo" | grep -i "NIC.Integrated.1-2-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#추가 NIC MAC 확인
|
||||
#local NIC_Slot_1=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.1-1-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
#local NIC_Slot_2=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.1-2-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#OnBoard MAC 확인
|
||||
local Onboard_1=$(echo "$getsysinfo" | grep -P "NIC.Embedded.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local Onboard_2=$(echo "$getsysinfo" | grep -P "NIC.Embedded.2-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#파트 벤더 확인
|
||||
local memory=$(echo "$hwinventory" | grep -A5 "DIMM" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
local nvme_m2=$(echo "$hwinventory" | grep -A3 "Disk.Direct" | grep "Manufacturer" | awk -F '= ' '{print $2}' | sort | uniq)
|
||||
local ssd=$(echo "$hwinventory" | grep -A3 "Disk.Bay" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
|
||||
# 서비스 태그가 존재하는지 확인
|
||||
if [ -z "$SVC_TAG" ]; then
|
||||
echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP"
|
||||
return
|
||||
fi
|
||||
|
||||
local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt"
|
||||
# SVC Tag 확인
|
||||
echo "$SVC_TAG" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_1" >> "$OUTPUT_FILE"
|
||||
echo "$Integrated_2" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_1" >> "$OUTPUT_FILE"
|
||||
echo "$Onboard_2" >> "$OUTPUT_FILE"
|
||||
echo "$idrac_mac" >> "$OUTPUT_FILE"
|
||||
echo "$memory" >> "$OUTPUT_FILE"
|
||||
echo "$ssd" >> "$OUTPUT_FILE"
|
||||
#임시파일 제거
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "정보 수집 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,100 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# 모든 hwinventory 저장
|
||||
local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo)
|
||||
local swinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS swinventory)
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory)
|
||||
|
||||
#서비스 태그 가져오기
|
||||
local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#iDRAC MAC 확인
|
||||
local idrac_mac=$(echo "$getsysinfo" | grep -i "MAC Address = " | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
#NIC.Integrated MAC 확인
|
||||
local NIC_Mezzanine_1=$(echo "$getsysinfo" | grep -i "NIC.Mezzanine.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local NIC_Mezzanine_2=$(echo "$getsysinfo" | grep -i "NIC.Mezzanine.1-2-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local NIC_Embedded_1=$(echo "$getsysinfo" | grep -i "NIC.Embedded.1-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local NIC_Embedded_2=$(echo "$getsysinfo" | grep -i "NIC.Embedded.2-1-1" | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#InfiniBand MAC 확인
|
||||
local NIC_Slot_2_1=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.2-1-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}" )
|
||||
local NIC_Slot_2_2=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.2-2-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local NIC_Slot_3_1=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.3-1-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
local NIC_Slot_3_2=$(echo "$swinventory" | awk '/FQDD = NIC.Slot.3-2-1/ {print x; next} {x=$0}' | tail -1 | grep -o -E "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}")
|
||||
|
||||
#파트 벤더 확인
|
||||
local memory=$(echo "$hwinventory" | grep -A5 "DIMM" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
local ssd=$(echo "$hwinventory" | grep -A3 "Disk.Bay" | grep "Manufacturer" | awk -F '=' '{print $2}' | awk '{$1=$1};1' | sort | uniq | cut -c1)
|
||||
|
||||
# 서비스 태그가 존재하는지 확인
|
||||
if [ -z "$SVC_TAG" ]; then
|
||||
echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP"
|
||||
return
|
||||
fi
|
||||
|
||||
local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt"
|
||||
# SVC Tag 확인
|
||||
echo "$SVC_TAG" >> "$OUTPUT_FILE"
|
||||
echo "$NIC_Mezzanine_1" >> "$OUTPUT_FILE"
|
||||
echo "$NIC_Mezzanine_2" >> "$OUTPUT_FILE"
|
||||
echo "$NIC_Slot_2_1" >> "$OUTPUT_FILE"
|
||||
echo "$NIC_Slot_2_2" >> "$OUTPUT_FILE"
|
||||
echo "$NIC_Slot_3_1" >> "$OUTPUT_FILE"
|
||||
echo "$NIC_Slot_3_2" >> "$OUTPUT_FILE"
|
||||
echo "$NIC_Embedded_1" >> "$OUTPUT_FILE"
|
||||
echo "$NIC_Embedded_2" >> "$OUTPUT_FILE"
|
||||
echo "$idrac_mac" >> "$OUTPUT_FILE"
|
||||
echo "$memory" >> "$OUTPUT_FILE"
|
||||
echo "$ssd" >> "$OUTPUT_FILE"
|
||||
#임시파일 제거
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "정보 수집 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,316 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 사용자 이름 및 비밀번호 설정
|
||||
IDRAC_USER="root"
|
||||
IDRAC_PASS="calvin"
|
||||
|
||||
# IP 주소 파일 경로 인자 받기
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <ip_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IP_FILE=$1
|
||||
|
||||
if [ ! -f "$IP_FILE" ]; then
|
||||
echo "IP file $IP_FILE does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 정보 저장 디렉터리 설정
|
||||
OUTPUT_DIR="idrac_info"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
|
||||
# iDRAC 정보를 가져오는 함수 정의
|
||||
fetch_idrac_info() {
|
||||
local IDRAC_IP=$(cat $IP_FILE)
|
||||
|
||||
# 모든 hwinventory 저장
|
||||
local hwinventory=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS hwinventory)
|
||||
# 모든 샷시 정보 저장
|
||||
local getsysinfo=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS getsysinfo)
|
||||
# 모든 SysProfileSettings 저장
|
||||
local SysProfileSettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.SysProfileSettings)
|
||||
# ProcessorSettings 저장
|
||||
local ProcessorSettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.ProcSettings)
|
||||
# Memory Settings 저장
|
||||
local MemorySettings=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.MemSettings)
|
||||
# Raid Settings 저장
|
||||
local STORAGEController=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get STORAGE.Controller.1)
|
||||
|
||||
# 서비스 태그 가져오기
|
||||
local SVC_TAG=$(echo "$getsysinfo" | grep -i "SVC Tag" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Bios Firmware Version 확인
|
||||
local Bios_firmware=$(echo "$getsysinfo" | grep -i "System BIOS Version" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Firmware Version 확인
|
||||
local iDRAC_firmware=$(echo "$getsysinfo" | grep -i "Firmware Version" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Intel NIC Firmware Version 확인
|
||||
local Intel_NIC_firmware=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get NIC.FrmwImgMenu.1 | grep -i "#FamilyVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# OnBoard NIC Firmware Version 확인
|
||||
local Onboard_NIC_firmware=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get NIC.FrmwImgMenu.5 | grep -i "#FamilyVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# R/C Firmware Version 확인
|
||||
local Raid_firmware=$(echo "$hwinventory" | grep -i "ControllerFirmwareVersion" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Bios 설정 Boot Mode 확인
|
||||
local Bios_BootMode=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.BiosBootSettings | grep -i "BootMode" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Bios SysProfileSettings 설정 정보 확인
|
||||
local SysProFileSettings_info1=$(echo "$SysProfileSettings" | grep -i "SysProfile=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info2=$(echo "$SysProfileSettings" | grep -i "ProcPwrPerf" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info3=$(echo "$SysProfileSettings" | grep -i "MemFrequency" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info4=$(echo "$SysProfileSettings" | grep -i "ProcTurboMode" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info5=$(echo "$SysProfileSettings" | grep -i "PcieAspmL1" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info6=$(echo "$SysProfileSettings" | grep -i "ProcCStates" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info7=$(echo "$SysProfileSettings" | grep -i "DeterminismSlider" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local SysProFileSettings_info8=$(echo "$SysProfileSettings" | grep -i "DynamicLinkWidthManagement" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Processor Settings - Logical Processor
|
||||
local ProcessorSettings_info1=$(echo "$ProcessorSettings" | grep -i "LogicalProc" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local ProcessorSettings_info2=$(echo "$ProcessorSettings" | grep -i "ProcVirtualization" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local ProcessorSettings_info3=$(echo "$ProcessorSettings" | grep -i "NumaNodesPerSocket" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local ProcessorSettings_info4=$(echo "$ProcessorSettings" | grep -i "ProcX2Apic" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# Memory Settings - Node Interleaving
|
||||
local MemorySettings_info1=$(echo "$MemorySettings" | grep -i "DramRefreshDelay" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local MemorySettings_info2=$(echo "$MemorySettings" | grep -i "PPROnUCE" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
local MemorySettings_info3=$(echo "$MemorySettings" | grep -i "CECriticalSEL" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# System Settings - Thermal Profile Optimization
|
||||
local SystemSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get System.ThermalSettings | grep -i "ThermalProfile" | awk -F '=' '{print $2}')
|
||||
# Integrated Devices Settings - SR-IOV Global Enable
|
||||
local IntegratedDevicesSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get Bios.IntegratedDevices | grep -i "SriovGlobalEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# Miscellaneous Settings - F1/F2 Prompt on Error
|
||||
local IMiscellaneousSettings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get bios.MiscSettings | grep -i "ErrPrompt" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# iDRAC Settings - Timezone
|
||||
local iDRAC_Settings_info1=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.Time.Timezone | grep -i "Timezone" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IPMI LAN Selection
|
||||
local iDRAC_Settings_info2=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentNIC | grep -i "ActiveNIC" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IPMI IP(IPv4)
|
||||
local iDRAC_Settings_info3=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentIPv4 | grep -i "DHCPEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IPMI IP(IPv6)
|
||||
local iDRAC_Settings_info4=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.CurrentIPv6 | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - Redfish Support
|
||||
local iDRAC_Settings_info5=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.Redfish.Enable | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SSH Support
|
||||
local iDRAC_Settings_info6=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SSH | grep -i "Enable=" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - AD User Domain Name
|
||||
local iDRAC_Settings_info7=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.USERDomain.1.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SC Server Address
|
||||
local iDRAC_Settings_info8=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ActiveDirectory.DomainController1 | grep -i "DomainController1" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SE AD RoleGroup Name
|
||||
local iDRAC_Settings_info9=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SE AD RoleGroup Dome인
|
||||
local iDRAC_Settings_info10=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Domain | grep -i "Domain" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - SE AD RoleGroup Privilege
|
||||
local iDRAC_Settings_info11=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.1.Privilege | grep -i "Privilege" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IDC AD RoleGroup name
|
||||
local iDRAC_Settings_info12=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Name | grep -i "Name" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IDC AD RoleGroup Dome인
|
||||
local iDRAC_Settings_info13=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Domain | grep -i "Domain" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - IDC AD RoleGroup Privilege
|
||||
local iDRAC_Settings_info14=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.ADGroup.2.Privilege | grep -i "Privilege" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
local iDRAC_Settings_info15=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.SysLogEnable | grep -i "SysLogEnable" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - syslog server address 1
|
||||
local iDRAC_Settings_info16=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Server1 | grep -i "Server1" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - syslog server address 2
|
||||
local iDRAC_Settings_info17=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Server2 | grep -i "Server2" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - syslog server port
|
||||
local iDRAC_Settings_info18=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.SysLog.Port | grep -i "Port" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# iDRAC Settings - VirtualConsole Port
|
||||
local iDRAC_Settings_info19=$(racadm -r $IDRAC_IP -u $IDRAC_USER -p $IDRAC_PASS get iDRAC.VirtualConsole.Port | grep -i "Port" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# RAID Settings - ProductName
|
||||
local RAID_info0=$(echo "$hwinventory" | grep -i "ProductName = PERC" | awk -F '=' '{print $2}')
|
||||
# RAID Settings - RAIDType
|
||||
local RAID_info1=$(echo "$hwinventory" | grep -i "RAIDTypes" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - StripeSize
|
||||
local RAID_info2=$(echo "$hwinventory" | grep -i "StripeSize" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - ReadCachePolicy
|
||||
local RAID_info3=$(echo "$hwinventory" | grep -i "ReadCachePolicy" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - WriteCachePolicy
|
||||
local RAID_info4=$(echo "$hwinventory" | grep -i "WriteCachePolicy" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - PatrolReadRate
|
||||
local RAID_info5=$(echo "$STORAGEController" | grep -i "CheckConsistencyRate" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
# RAID Settings - PatrolReadRate
|
||||
local RAID_info6=$(echo "$STORAGEController" | grep -i "PatrolReadMode" | awk -F '=' '{print $2}' | tr -d '[:space:]')
|
||||
|
||||
# 서비스 태그가 존재하는지 확인
|
||||
if [ -z "$SVC_TAG" ]; then
|
||||
echo "Failed to retrieve SVC Tag for IP: $IDRAC_IP"
|
||||
return
|
||||
fi
|
||||
|
||||
local OUTPUT_FILE="$OUTPUT_DIR/$SVC_TAG.txt"
|
||||
echo "Dell EMC Server Bios,iDRAC,R/C Setting (SVC Tag: $SVC_TAG)" | tee -a "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
echo "------------------------------------------Firware Version 정보------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# SVC Tag 확인
|
||||
echo "1. SVC Tag : $SVC_TAG" >> "$OUTPUT_FILE"
|
||||
|
||||
# Bios Firmware Version 확인
|
||||
echo "2. Bios Firmware : $Bios_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# iDRAC Firmware Version 확인
|
||||
echo "3. iDRAC Firmware Version : $iDRAC_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# Intel NIC Firmware Version 확인
|
||||
echo "4. NIC Integrated Firmware Version : $Intel_NIC_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# OnBoard NIC Firmware Version 확인
|
||||
echo "5. OnBoard NIC Firmware Version : $Onboard_NIC_firmware" >> "$OUTPUT_FILE"
|
||||
|
||||
# Raid Controller Firmware Version 확인
|
||||
echo "6. Raid Controller Firmware Version : $Raid_firmware" >> "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
|
||||
echo "---------------------------------------------Bios 설정 정보----------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# bios Boot Mode 확인
|
||||
echo "01. Bios Boot Mode : $Bios_BootMode" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - System Profile
|
||||
echo "02. System Profile Settings - System Profile : $SysProFileSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - CPU Power Management
|
||||
echo "03. System Profile Settings - CPU Power Management : $SysProFileSettings_info2" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - Memory Frequency
|
||||
echo "04. System Profile Settings - Memory Frequency : $SysProFileSettings_info3" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - Turbo Boost
|
||||
echo "05. System Profile Settings - Turbo Boost : $SysProFileSettings_info4" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - C1E
|
||||
echo "06. System Profile Settings - PCI ASPM L1 Link Power Management : $SysProFileSettings_info5" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - C-States
|
||||
echo "07. System Profile Settings - C-States : $SysProFileSettings_info6" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - Determinism Slider
|
||||
echo "08. System Profile Settings - Determinism Slider : $SysProFileSettings_info7" >> "$OUTPUT_FILE"
|
||||
|
||||
# SysProfileSettings - Dynamic Link Width Management (DLWM)
|
||||
echo "08. System Profile Settings - Dynamic Link Width Management (DLWM) : $SysProFileSettings_info8" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - Logical Processor
|
||||
echo "09. Processor Settings - Logical Processor : $ProcessorSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - Virtualization Technology
|
||||
echo "10. Processor Settings - Virtualization Technology : $ProcessorSettings_info2" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - NUMA Nodes Per Socket
|
||||
echo "11. Processor Settings - NUMA Nodes Per Socket : $ProcessorSettings_info3" >> "$OUTPUT_FILE"
|
||||
|
||||
# Processor Settings - x2APIC Mode
|
||||
echo "12. Processor Settings - x2APIC Mode : $ProcessorSettings_info4" >> "$OUTPUT_FILE"
|
||||
|
||||
# Memory Settings - Dram Refresh Delayg
|
||||
echo "13. Memory Settings - Dram Refresh Delay : $MemorySettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Memory Settings - DIMM Self Healing (Post Package Repair) on Uncorrectable Memory Error
|
||||
echo "14. Memory Settings - DIMM Self Healing (Post Package Repair) on Uncorrectable Memory Error : $MemorySettings_info2" >> "$OUTPUT_FILE"
|
||||
|
||||
# Memory Settings - Correctable Error Logging
|
||||
echo "15. Memory Settings - Correctable Error Logging : $MemorySettings_info3" >> "$OUTPUT_FILE"
|
||||
|
||||
# System Settings - Thermal Profile Optimization
|
||||
echo "16. System Settings - Thermal Profile Optimization : $SystemSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Integrated Devices Settings - SR-IOV Global Enable
|
||||
echo "17. Integrated Devices Settings - SR-IOV Global Enable : $IntegratedDevicesSettings_info1" >> "$OUTPUT_FILE"
|
||||
|
||||
# Miscellaneous Settings - F1/F2 Prompt on Error
|
||||
echo "18. Miscellaneous Settings - F1/F2 Prompt on Error : $IMiscellaneousSettings_info1" >> "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
|
||||
echo "---------------------------------------------iDRAC 설정 정보----------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Timezone
|
||||
echo "01. iDRAC Settings - Timezone : $iDRAC_Settings_info1" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - IPMI LAN Selection
|
||||
echo "02. iDRAC Settings - IPMI LAN Selection : $iDRAC_Settings_info2" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - IPMI IP(IPv4)
|
||||
echo "03. iDRAC Settings - IPMI IP(IPv4) : $iDRAC_Settings_info3" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - IPMI IP(IPv6)
|
||||
echo "04. iDRAC Settings - IPMI IP(IPv6) : $iDRAC_Settings_info4" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Redfish Support
|
||||
echo "05. iDRAC Settings - Redfish Support : $iDRAC_Settings_info5" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SSH Support
|
||||
echo "06. iDRAC Settings - SSH Support : $iDRAC_Settings_info6" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - AD User Domain Name
|
||||
echo "07. iDRAC Settings - AD User Domain Name : $iDRAC_Settings_info7" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SC Server Address
|
||||
echo "08. iDRAC Settings - SC Server Address : $iDRAC_Settings_info8" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE AD RoleGroup Name
|
||||
echo "09. iDRAC Settings - SE AD RoleGroup Name : $iDRAC_Settings_info9" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE AD RoleGroup Dome인
|
||||
echo "10. iDRAC Settings - SE AD RoleGroup Dome인 : $iDRAC_Settings_info10" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE AD RoleGroup Privilege
|
||||
echo "11. iDRAC Settings - SE AD RoleGroup Privilege : $iDRAC_Settings_info11" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE IDC RoleGroup Name
|
||||
echo "12. iDRAC Settings - IDC AD RoleGroup Name : $iDRAC_Settings_info12" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE IDC RoleGroup Dome인
|
||||
echo "13. iDRAC Settings - IDC AD RoleGroup Domain : $iDRAC_Settings_info13" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - SE IDC RoleGroup Dome인
|
||||
echo "14. iDRAC Settings - IDC AD RoleGroup Privilege : $iDRAC_Settings_info14" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
echo "15. iDRAC Settings - Remote Log (syslog) : $iDRAC_Settings_info15" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
echo "16. iDRAC Settings - syslog server address 1 : $iDRAC_Settings_info16" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote Log (syslog)
|
||||
echo "17. iDRAC Settings - syslog server address 2 : $iDRAC_Settings_info17" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - syslog server port
|
||||
echo "18. iDRAC Settings - syslog server port : $iDRAC_Settings_info18" >> "$OUTPUT_FILE"
|
||||
# iDRAC Settings - Remote KVM Nonsecure port
|
||||
echo "19. iDRAC Settings - Remote KVM Nonsecure port : $iDRAC_Settings_info19" >> "$OUTPUT_FILE"
|
||||
echo -e "\n" >> "$OUTPUT_FILE"
|
||||
|
||||
# echo "---------------------------------------------Raid 설정 정보----------------------------------------------" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - Raid Types
|
||||
#echo "01. RAID Settings - Raid ProductName : $RAID_info0" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - Raid Types
|
||||
#echo "02. RAID Settings - Raid Typest : $RAID_info1" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - StripeSize
|
||||
#echo "03. RAID Settings - StripeSize : $RAID_info2" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - ReadCachePolicy
|
||||
#echo "04. RAID Settings - ReadCachePolicy : $RAID_info3" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - ReadCachePolicy
|
||||
#echo "05. RAID Settings - WriteCachePolicy : $RAID_info4" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - CheckConsistencyRate
|
||||
#echo "06. RAID Settings - CheckConsistencyRate : $RAID_info5" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - PatrolReadMode
|
||||
#echo "07. RAID Settings - PatrolReadMode : $RAID_info6" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - period
|
||||
#echo "08. RAID Settings - period : 168h" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - Power Save
|
||||
#echo "09. RAID Settings - Power Save : No" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - JBODMODE
|
||||
#echo "10. RAID Settings - JBODMODE : Controller does not support JBOD" >> "$OUTPUT_FILE"
|
||||
# RAID Settings - maxconcurrentpd
|
||||
#echo "11. RAID Settings - maxconcurrentpd : 240" >> "$OUTPUT_FILE"
|
||||
|
||||
# 임시 파일 삭제
|
||||
rm -f $IP_FILE
|
||||
}
|
||||
|
||||
export -f fetch_idrac_info
|
||||
export IDRAC_USER
|
||||
export IDRAC_PASS
|
||||
export OUTPUT_DIR
|
||||
|
||||
# 시작 시간 기록
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# IP 목록 파일을 읽어 병렬로 작업 수행
|
||||
fetch_idrac_info
|
||||
|
||||
# 종료 시간 기록
|
||||
END_TIME=$(date +%s)
|
||||
|
||||
# 소요 시간 계산
|
||||
ELAPSED_TIME=$(($END_TIME - $START_TIME))
|
||||
ELAPSED_HOURS=$(($ELAPSED_TIME / 3600))
|
||||
ELAPSED_MINUTES=$((($ELAPSED_TIME % 3600) / 60))
|
||||
ELAPSED_SECONDS=$(($ELAPSED_TIME % 60))
|
||||
|
||||
echo "정보 수집 완료."
|
||||
echo "수집 완료 시간: $ELAPSED_HOURS 시간, $ELAPSED_MINUTES 분, $ELAPSED_SECONDS 초."
|
||||
@@ -0,0 +1,172 @@
|
||||
from __future__ import annotations
|
||||
import os
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from collections import OrderedDict
|
||||
import pandas as pd
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Cross-platform root resolver (Windows / Linux / macOS)
|
||||
# ------------------------------------------------------------
|
||||
def resolve_data_root() -> Path:
|
||||
"""
|
||||
Priority:
|
||||
1) Env var IDRAC_DATA_DIR (absolute/relative OK)
|
||||
2) nearest parent of this file that contains a 'data' folder
|
||||
3) ./data under current working directory
|
||||
"""
|
||||
env = os.getenv("IDRAC_DATA_DIR")
|
||||
if env:
|
||||
return Path(env).expanduser().resolve()
|
||||
|
||||
here = Path(__file__).resolve()
|
||||
for p in [here] + list(here.parents):
|
||||
if (p / "data").is_dir():
|
||||
return (p / "data").resolve()
|
||||
|
||||
return (Path.cwd() / "data").resolve()
|
||||
|
||||
|
||||
DATA_ROOT = resolve_data_root()
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Utilities
|
||||
# ------------------------------------------------------------
|
||||
def read_lines_any_encoding(path: Path) -> list[str]:
|
||||
"""Read text file trying common encodings (utf-8/utf-8-sig/cp949/euc-kr/latin-1)."""
|
||||
encodings = ["utf-8-sig", "utf-8", "cp949", "euc-kr", "latin-1"]
|
||||
for enc in encodings:
|
||||
try:
|
||||
with path.open("r", encoding=enc, errors="strict") as f:
|
||||
return f.read().splitlines()
|
||||
except Exception:
|
||||
continue
|
||||
# last resort with replacement
|
||||
with path.open("r", encoding="utf-8", errors="replace") as f:
|
||||
return f.read().splitlines()
|
||||
|
||||
|
||||
def parse_txt_with_st(file_path: Path) -> dict:
|
||||
"""
|
||||
Parse a .txt file:
|
||||
- First line becomes 'S/T'
|
||||
- Remaining lines in 'Key: Value' form
|
||||
Keeps insertion order.
|
||||
"""
|
||||
lines = read_lines_any_encoding(file_path)
|
||||
if not lines:
|
||||
return {}
|
||||
|
||||
data = OrderedDict()
|
||||
data["S/T"] = lines[0].strip()
|
||||
|
||||
for raw in lines[1:]:
|
||||
line = raw.strip()
|
||||
if not line or ":" not in line:
|
||||
continue
|
||||
key, value = line.split(":", 1)
|
||||
data[key.strip()] = value.strip()
|
||||
|
||||
return dict(data)
|
||||
|
||||
|
||||
def collect_file_list(input_dir: Path, list_file: Path | None) -> list[Path]:
|
||||
"""
|
||||
1) list_file가 주어지고 존재하면: 그 목록 순서대로 <name>.txt를 input_dir에서 찾음
|
||||
2) 없으면: input_dir 안의 *.txt 전체를 파일명 오름차순으로 사용
|
||||
"""
|
||||
files: list[Path] = []
|
||||
|
||||
if list_file and list_file.is_file():
|
||||
names = [x.strip() for x in read_lines_any_encoding(list_file) if x.strip()]
|
||||
for name in names:
|
||||
p = input_dir / f"{name}.txt"
|
||||
if p.is_file():
|
||||
files.append(p)
|
||||
else:
|
||||
print(f"[WARN] 파일을 찾을 수 없습니다: {p.name}")
|
||||
return files
|
||||
|
||||
# fallback: 디렉토리 스캔
|
||||
files = sorted(input_dir.glob("*.txt"))
|
||||
if not files:
|
||||
print(f"[WARN] 입력 폴더에 .txt 파일이 없습니다: {input_dir}")
|
||||
return files
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="GUID/GPU 시리얼 텍스트들을 하나의 Excel로 병합"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--preset",
|
||||
choices=["guid", "gpu"],
|
||||
default="guid",
|
||||
help="경로 프리셋 선택 (guid: 기존 GUID 경로, gpu: gpu_serial 폴더)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--input-dir",
|
||||
type=Path,
|
||||
default=None,
|
||||
help="입력 텍스트 폴더(기본: preset에 따름)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--list-file",
|
||||
type=Path,
|
||||
default=None,
|
||||
help="처리할 파일명 목록(txt). 없으면 폴더 내 *.txt 전체 처리"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-xlsx",
|
||||
type=Path,
|
||||
default=None,
|
||||
help="출력 엑셀 경로(기본: preset에 따름)"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# ---- Preset 기본값 설정 ----
|
||||
if args.preset == "guid":
|
||||
default_input_dir = Path(os.getenv("GUID_TXT_DIR", DATA_ROOT / "repository" / "guid_file"))
|
||||
default_list_file = Path(os.getenv("GUID_LIST_FILE", DATA_ROOT / "server_list" / "guid_list.txt"))
|
||||
default_output = Path(os.getenv("GUID_OUTPUT_XLSX", DATA_ROOT / "temp" / "staging" / "XE9680_GUID.xlsx"))
|
||||
else: # gpu
|
||||
default_input_dir = Path(os.getenv("GPU_TXT_DIR", DATA_ROOT / "repository" / "gpu_serial"))
|
||||
default_list_file = Path(os.getenv("GPU_LIST_FILE", DATA_ROOT / "server_list" / "gpu_serial_list.txt"))
|
||||
default_output = Path(os.getenv("GPU_OUTPUT_XLSX", DATA_ROOT / "temp" / "staging" / "GPU_SERIALS.xlsx"))
|
||||
|
||||
input_dir: Path = args.input_dir or default_input_dir
|
||||
list_file: Path | None = args.list_file or (default_list_file if default_list_file.is_file() else None)
|
||||
output_xlsx: Path = args.output_xlsx or default_output
|
||||
|
||||
# 출력 폴더 보장
|
||||
output_xlsx.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if not input_dir.is_dir():
|
||||
raise FileNotFoundError(f"입력 폴더가 없습니다: {input_dir}")
|
||||
|
||||
# 파일 목록 수집
|
||||
txt_files = collect_file_list(input_dir, list_file)
|
||||
|
||||
# 데이터 누적
|
||||
rows: list[dict] = []
|
||||
for txt_path in txt_files:
|
||||
rows.append(parse_txt_with_st(txt_path))
|
||||
|
||||
if not rows:
|
||||
print("[INFO] 병합할 데이터가 없습니다.")
|
||||
return
|
||||
|
||||
# DataFrame (모든 키의 합집합 컬럼 생성)
|
||||
df = pd.DataFrame(rows)
|
||||
|
||||
# No 열 선두 삽입
|
||||
df.insert(0, "No", range(1, len(df) + 1))
|
||||
|
||||
# 저장
|
||||
df.to_excel(output_xlsx, index=False)
|
||||
print(f"엑셀 파일이 생성되었습니다: {output_xlsx}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
from __future__ import annotations
|
||||
import os
|
||||
from pathlib import Path
|
||||
from collections import OrderedDict
|
||||
import pandas as pd
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Cross-platform root resolver (Windows / Linux / macOS)
|
||||
# ------------------------------------------------------------
|
||||
def resolve_data_root() -> Path:
|
||||
"""
|
||||
Priority:
|
||||
1) Env var IDRAC_DATA_DIR (absolute/relative OK)
|
||||
2) nearest parent of this file that contains a 'data' folder
|
||||
3) ./data under current working directory
|
||||
"""
|
||||
env = os.getenv("IDRAC_DATA_DIR")
|
||||
if env:
|
||||
return Path(env).expanduser().resolve()
|
||||
|
||||
here = Path(__file__).resolve()
|
||||
for p in [here] + list(here.parents):
|
||||
if (p / "data").is_dir():
|
||||
return (p / "data").resolve()
|
||||
|
||||
return (Path.cwd() / "data").resolve()
|
||||
|
||||
|
||||
DATA_ROOT = resolve_data_root()
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Paths (can be overridden with env vars if needed)
|
||||
# ------------------------------------------------------------
|
||||
SERVER_LIST_DIR = Path(os.getenv("GUID_SERVER_LIST_DIR", DATA_ROOT / "server_list"))
|
||||
SERVER_LIST_FILE = Path(os.getenv("GUID_LIST_FILE", SERVER_LIST_DIR / "guid_list.txt"))
|
||||
|
||||
GUID_TXT_DIR = Path(os.getenv("GUID_TXT_DIR", DATA_ROOT / "repository" / "guid_file"))
|
||||
|
||||
OUTPUT_XLSX = Path(
|
||||
os.getenv("GUID_OUTPUT_XLSX", DATA_ROOT / "temp" / "staging" / "XE9680_GUID.xlsx")
|
||||
)
|
||||
|
||||
# Make sure output directory exists
|
||||
OUTPUT_XLSX.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Utilities
|
||||
# ------------------------------------------------------------
|
||||
def read_lines_any_encoding(path: Path) -> list[str]:
|
||||
"""Read text file trying common encodings (utf-8/utf-8-sig/cp949/euc-kr/latin-1)."""
|
||||
encodings = ["utf-8-sig", "utf-8", "cp949", "euc-kr", "latin-1"]
|
||||
for enc in encodings:
|
||||
try:
|
||||
with path.open("r", encoding=enc, errors="strict") as f:
|
||||
return f.read().splitlines()
|
||||
except Exception:
|
||||
continue
|
||||
# last resort with replacement
|
||||
with path.open("r", encoding="utf-8", errors="replace") as f:
|
||||
return f.read().splitlines()
|
||||
|
||||
|
||||
def parse_txt_with_st(file_path: Path) -> dict:
|
||||
"""
|
||||
Parse a GUID .txt file:
|
||||
- First line becomes 'S/T'
|
||||
- Remaining lines in 'Key: Value' form
|
||||
Keeps insertion order.
|
||||
"""
|
||||
lines = read_lines_any_encoding(file_path)
|
||||
if not lines:
|
||||
return {}
|
||||
|
||||
data = OrderedDict()
|
||||
data["S/T"] = lines[0].strip()
|
||||
|
||||
for raw in lines[1:]:
|
||||
line = raw.strip()
|
||||
if not line or ":" not in line:
|
||||
continue
|
||||
key, value = line.split(":", 1)
|
||||
data[key.strip()] = value.strip()
|
||||
|
||||
return dict(data)
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# 슬롯 우선순위 설정
|
||||
# ------------------------------------------------------------
|
||||
# 환경변수에서 슬롯 우선순위 읽기 (예: "38,39,37,36,32,33,34,35,31,40")
|
||||
slot_priority_str = os.getenv("GUID_SLOT_PRIORITY", "")
|
||||
if slot_priority_str:
|
||||
SLOT_PRIORITY = [s.strip() for s in slot_priority_str.split(",") if s.strip()]
|
||||
print(f"[INFO] 사용자 지정 슬롯 우선순위: {SLOT_PRIORITY}")
|
||||
else:
|
||||
# 기본 우선순위 (10개)
|
||||
SLOT_PRIORITY = ['38', '39', '37', '36', '32', '33', '34', '35', '31', '40']
|
||||
print(f"[INFO] 기본 슬롯 우선순위 사용: {SLOT_PRIORITY}")
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Load list of file basenames from guid_list.txt
|
||||
# ------------------------------------------------------------
|
||||
if not SERVER_LIST_FILE.is_file():
|
||||
raise FileNotFoundError(f"guid_list.txt not found: {SERVER_LIST_FILE}")
|
||||
|
||||
file_names = [x.strip() for x in read_lines_any_encoding(SERVER_LIST_FILE) if x.strip()]
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Collect rows
|
||||
# ------------------------------------------------------------
|
||||
rows: list[dict] = []
|
||||
for name in file_names:
|
||||
txt_path = GUID_TXT_DIR / f"{name}.txt"
|
||||
if not txt_path.is_file():
|
||||
print(f"[WARN] 파일을 찾을 수 없습니다: {txt_path.name}")
|
||||
# still append at least S/T if you want a row placeholder
|
||||
# rows.append({"S/T": name})
|
||||
continue
|
||||
|
||||
parsed_data = parse_txt_with_st(txt_path)
|
||||
|
||||
# 슬롯 우선순위에 따라 데이터 재정렬
|
||||
reordered_data = OrderedDict()
|
||||
reordered_data["S/T"] = parsed_data.get("S/T", "")
|
||||
|
||||
# 슬롯 데이터를 우선순위 순서대로 추가
|
||||
# 슬롯 데이터를 우선순위 순서대로 추가하며 GUID 문자열 재구성
|
||||
new_guid_list = []
|
||||
|
||||
for slot_num in SLOT_PRIORITY:
|
||||
slot_key = f"Slot.{slot_num}"
|
||||
val = parsed_data.get(slot_key)
|
||||
|
||||
# 데이터가 있으면 컬럼 추가
|
||||
if val:
|
||||
reordered_data[slot_key] = val
|
||||
|
||||
# GUID 재구성을 위한 수집 (Not Found 제외, 포맷 확인)
|
||||
if val != "Not Found" and ":" in val:
|
||||
# 예: 3825:F303:0085:07A6 -> 0x3825F303008507A6
|
||||
clean_hex = val.replace(":", "").upper()
|
||||
new_guid_list.append(f"0x{clean_hex}")
|
||||
|
||||
# 1순위: 재구성된 GUID (사용자가 지정한 슬롯 순서대로)
|
||||
# 2순위: 파일에 있던 원본 GUID
|
||||
if new_guid_list:
|
||||
reordered_data["GUID"] = ";".join(new_guid_list)
|
||||
elif "GUID" in parsed_data:
|
||||
reordered_data["GUID"] = parsed_data["GUID"]
|
||||
|
||||
# 나머지 필드들 추가 (슬롯이 아닌 것들)
|
||||
for key, value in parsed_data.items():
|
||||
if key not in reordered_data:
|
||||
reordered_data[key] = value
|
||||
|
||||
rows.append(dict(reordered_data))
|
||||
|
||||
# Build DataFrame (union of keys across all rows)
|
||||
df = pd.DataFrame(rows)
|
||||
|
||||
# Prepend No column (1..N)
|
||||
df.insert(0, "No", range(1, len(df) + 1))
|
||||
|
||||
# Save to Excel
|
||||
df.to_excel(OUTPUT_XLSX, index=False)
|
||||
|
||||
print(f"엑셀 파일이 생성되었습니다: {OUTPUT_XLSX}")
|
||||
@@ -0,0 +1,109 @@
|
||||
from __future__ import annotations
|
||||
import os
|
||||
from pathlib import Path
|
||||
import pandas as pd
|
||||
|
||||
# ---------------------------------------------
|
||||
# Cross-platform paths (Windows & Linux/Mac)
|
||||
# ---------------------------------------------
|
||||
def resolve_data_root() -> Path:
|
||||
"""
|
||||
Priority:
|
||||
1) Env var IDRAC_DATA_DIR (absolute/relative OK)
|
||||
2) nearest parent of this file that contains a 'data' folder
|
||||
3) ./data under current working directory
|
||||
"""
|
||||
env = os.getenv("IDRAC_DATA_DIR")
|
||||
if env:
|
||||
return Path(env).expanduser().resolve()
|
||||
|
||||
here = Path(__file__).resolve()
|
||||
for p in [here] + list(here.parents):
|
||||
if (p / "data").is_dir():
|
||||
return (p / "data").resolve()
|
||||
|
||||
return (Path.cwd() / "data").resolve()
|
||||
|
||||
|
||||
DATA_ROOT = resolve_data_root()
|
||||
|
||||
SERVER_LIST_DIR = DATA_ROOT / "server_list"
|
||||
SERVER_LIST_FILE = SERVER_LIST_DIR / "server_list.txt"
|
||||
|
||||
MAC_TXT_DIR = DATA_ROOT / "repository" / "mac"
|
||||
OUTPUT_XLSX = DATA_ROOT / "temp" / "staging" / "mac_info.xlsx"
|
||||
|
||||
# Ensure output directory exists
|
||||
OUTPUT_XLSX.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# ---------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------
|
||||
def read_lines_any_encoding(path: Path) -> list[str]:
|
||||
"""Read a text file trying common encodings (handles Windows & UTF-8)."""
|
||||
encodings = ["utf-8-sig", "utf-8", "cp949", "euc-kr", "latin-1"]
|
||||
for enc in encodings:
|
||||
try:
|
||||
with path.open("r", encoding=enc, errors="strict") as f:
|
||||
return f.read().splitlines()
|
||||
except Exception:
|
||||
continue
|
||||
# last resort with replacement
|
||||
with path.open("r", encoding="utf-8", errors="replace") as f:
|
||||
return f.read().splitlines()
|
||||
|
||||
# ---------------------------------------------
|
||||
# Load server list (file names without .txt)
|
||||
# ---------------------------------------------
|
||||
if not SERVER_LIST_FILE.is_file():
|
||||
raise FileNotFoundError(f"server_list.txt not found: {SERVER_LIST_FILE}")
|
||||
|
||||
file_names = read_lines_any_encoding(SERVER_LIST_FILE)
|
||||
|
||||
data_list: list[str] = []
|
||||
index_list: list[int | str] = []
|
||||
|
||||
sequence_number = 1
|
||||
|
||||
for name in file_names:
|
||||
# normalize and skip blanks
|
||||
base = (name or "").strip()
|
||||
if not base:
|
||||
continue
|
||||
|
||||
txt_path = MAC_TXT_DIR / f"{base}.txt"
|
||||
if not txt_path.is_file():
|
||||
# if a file is missing, keep row aligned with an empty line
|
||||
data_list.append("")
|
||||
index_list.append("")
|
||||
continue
|
||||
|
||||
lines = read_lines_any_encoding(txt_path)
|
||||
for i, line in enumerate(lines):
|
||||
cleaned = (line or "").strip().upper()
|
||||
if cleaned:
|
||||
data_list.append(cleaned)
|
||||
if i == 0: # first line is always the service tag
|
||||
index_list.append(sequence_number)
|
||||
sequence_number += 1
|
||||
else:
|
||||
index_list.append("") # keep column blank if not service tag
|
||||
else:
|
||||
data_list.append("")
|
||||
index_list.append("")
|
||||
|
||||
print(f"Length of index_list: {len(index_list)}")
|
||||
print(f"Length of data_list: {len(data_list)}")
|
||||
|
||||
# ---------------------------------------------
|
||||
# Save to Excel
|
||||
# ---------------------------------------------
|
||||
df = pd.DataFrame({
|
||||
"Index": index_list, # will be column A
|
||||
"Content": data_list, # will be column B
|
||||
})
|
||||
|
||||
# header=False to start at column A without headers, index=False to omit row numbers
|
||||
df.to_excel(OUTPUT_XLSX, index=False, header=False)
|
||||
|
||||
print(f"Saved: {OUTPUT_XLSX}")
|
||||
@@ -0,0 +1,80 @@
|
||||
7Y3J2H4
|
||||
G8KS3H4
|
||||
F9KS3H4
|
||||
2BKS3H4
|
||||
JW3J2H4
|
||||
49KS3H4
|
||||
BX3J2H4
|
||||
5X3J2H4
|
||||
HX3J2H4
|
||||
1NRS3H4
|
||||
7PRS3H4
|
||||
4X3J2H4
|
||||
29KS3H4
|
||||
CY3J2H4
|
||||
3RPJ5H4
|
||||
GQPJ5H4
|
||||
C4DY4H4
|
||||
G3DY4H4
|
||||
79KS3H4
|
||||
8X3J2H4
|
||||
9QPJ5H4
|
||||
B4DY4H4
|
||||
45DY4H4
|
||||
HPPJ5H4
|
||||
88KS3H4
|
||||
JX3J2H4
|
||||
7Z3J2H4
|
||||
DVRS3H4
|
||||
18KS3H4
|
||||
5Y3J2H4
|
||||
H3DY4H4
|
||||
94DY4H4
|
||||
F3DY4H4
|
||||
24DY4H4
|
||||
69PG4H4
|
||||
19PG4H4
|
||||
J1DY4H4
|
||||
4QPJ5H4
|
||||
D4DY4H4
|
||||
8TPJ5H4
|
||||
43DY4H4
|
||||
53DY4H4
|
||||
2QPJ5H4
|
||||
CPPJ5H4
|
||||
44DY4H4
|
||||
FQPJ5H4
|
||||
G2DY4H4
|
||||
H7KS3H4
|
||||
D9KS3H4
|
||||
49PG4H4
|
||||
5RPJ5H4
|
||||
9RPJ5H4
|
||||
2JKS3H4
|
||||
23DY4H4
|
||||
BNRS3H4
|
||||
79PG4H4
|
||||
JKPG4H4
|
||||
GNRS3H4
|
||||
FY3J2H4
|
||||
9NRS3H4
|
||||
B8PG4H4
|
||||
39PG4H4
|
||||
99PG4H4
|
||||
48PG4H4
|
||||
D8PG4H4
|
||||
3PRS3H4
|
||||
D8KS3H4
|
||||
1X3J2H4
|
||||
9X3J2H4
|
||||
2X3J2H4
|
||||
J2DY4H4
|
||||
BQPJ5H4
|
||||
2Z3J2H4
|
||||
GX3J2H4
|
||||
C9KS3H4
|
||||
3WRG4H4
|
||||
1JKS3H4
|
||||
29PG4H4
|
||||
DQPJ5H4
|
||||
68DY4H4
|
||||
@@ -0,0 +1,80 @@
|
||||
7Y3J2H4
|
||||
G8KS3H4
|
||||
F9KS3H4
|
||||
2BKS3H4
|
||||
JW3J2H4
|
||||
49KS3H4
|
||||
BX3J2H4
|
||||
5X3J2H4
|
||||
HX3J2H4
|
||||
1NRS3H4
|
||||
7PRS3H4
|
||||
4X3J2H4
|
||||
29KS3H4
|
||||
CY3J2H4
|
||||
3RPJ5H4
|
||||
GQPJ5H4
|
||||
C4DY4H4
|
||||
G3DY4H4
|
||||
79KS3H4
|
||||
8X3J2H4
|
||||
9QPJ5H4
|
||||
B4DY4H4
|
||||
45DY4H4
|
||||
HPPJ5H4
|
||||
88KS3H4
|
||||
JX3J2H4
|
||||
7Z3J2H4
|
||||
DVRS3H4
|
||||
18KS3H4
|
||||
5Y3J2H4
|
||||
H3DY4H4
|
||||
94DY4H4
|
||||
F3DY4H4
|
||||
24DY4H4
|
||||
69PG4H4
|
||||
19PG4H4
|
||||
J1DY4H4
|
||||
4QPJ5H4
|
||||
D4DY4H4
|
||||
8TPJ5H4
|
||||
43DY4H4
|
||||
53DY4H4
|
||||
2QPJ5H4
|
||||
CPPJ5H4
|
||||
44DY4H4
|
||||
FQPJ5H4
|
||||
G2DY4H4
|
||||
H7KS3H4
|
||||
D9KS3H4
|
||||
49PG4H4
|
||||
5RPJ5H4
|
||||
9RPJ5H4
|
||||
2JKS3H4
|
||||
23DY4H4
|
||||
BNRS3H4
|
||||
79PG4H4
|
||||
JKPG4H4
|
||||
GNRS3H4
|
||||
FY3J2H4
|
||||
9NRS3H4
|
||||
B8PG4H4
|
||||
39PG4H4
|
||||
99PG4H4
|
||||
48PG4H4
|
||||
D8PG4H4
|
||||
3PRS3H4
|
||||
D8KS3H4
|
||||
1X3J2H4
|
||||
9X3J2H4
|
||||
2X3J2H4
|
||||
J2DY4H4
|
||||
BQPJ5H4
|
||||
2Z3J2H4
|
||||
GX3J2H4
|
||||
C9KS3H4
|
||||
3WRG4H4
|
||||
1JKS3H4
|
||||
29PG4H4
|
||||
DQPJ5H4
|
||||
68DY4H4
|
||||
@@ -0,0 +1,60 @@
|
||||
DKK3674
|
||||
GFF3674
|
||||
HGK3674
|
||||
JFF3674
|
||||
2HF3674
|
||||
4MK3674
|
||||
BJF3674
|
||||
6KK3674
|
||||
2HK3674
|
||||
FKK3674
|
||||
CGF3674
|
||||
6KF3674
|
||||
4GF3674
|
||||
FJK3674
|
||||
1LK3674
|
||||
8GF3674
|
||||
FJF3674
|
||||
7HF3674
|
||||
5GF3674
|
||||
6JF3674
|
||||
8LK3674
|
||||
FDF3674
|
||||
8HK3674
|
||||
FHK3674
|
||||
5LK3674
|
||||
HHK3674
|
||||
7FF3674
|
||||
CKK3674
|
||||
3JF3674
|
||||
2GF3674
|
||||
3HF3674
|
||||
GGK3674
|
||||
6HK3674
|
||||
CJK3674
|
||||
3JK3674
|
||||
8JK3674
|
||||
FGF3674
|
||||
5HF3674
|
||||
4JF3674
|
||||
5CF3674
|
||||
282S574
|
||||
HHF3674
|
||||
DCF3674
|
||||
4FF3674
|
||||
2KF3674
|
||||
HCF3674
|
||||
8KK3674
|
||||
DHK3674
|
||||
HDF3674
|
||||
GCF3674
|
||||
5MK3674
|
||||
5FF3674
|
||||
DMK3674
|
||||
4KF3674
|
||||
BKK3674
|
||||
CLK3674
|
||||
6LK3674
|
||||
2MK3674
|
||||
4HK3674
|
||||
BLK3674
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,72 @@
|
||||
import os
|
||||
import zipfile
|
||||
|
||||
# list.txt에서 파일명을 읽어오는 함수
|
||||
def read_file_list():
|
||||
list_file = os.path.join(os.getcwd(), 'list.txt')
|
||||
if not os.path.isfile(list_file):
|
||||
raise ValueError(f"'{list_file}'은(는) 파일이 아니거나 존재하지 않습니다.")
|
||||
|
||||
try:
|
||||
with open(list_file, 'r', encoding='utf-8') as f:
|
||||
return [line.strip() for line in f.readlines() if line.strip()]
|
||||
except FileNotFoundError:
|
||||
print(f"'{list_file}' 파일이 존재하지 않습니다.")
|
||||
return []
|
||||
|
||||
# 특정 폴더에서 파일을 검색하고 압축하는 함수
|
||||
def zip_selected_files(folder_path, file_list, output_zip):
|
||||
with zipfile.ZipFile(output_zip, 'w') as zipf:
|
||||
for file_name in file_list:
|
||||
# 확장자를 .txt로 고정
|
||||
file_name_with_ext = f"{file_name}.txt"
|
||||
|
||||
file_path = os.path.join(folder_path, file_name_with_ext)
|
||||
if os.path.exists(file_path):
|
||||
print(f"압축 중: {file_name_with_ext}")
|
||||
zipf.write(file_path, arcname=file_name_with_ext)
|
||||
else:
|
||||
print(f"파일을 찾을 수 없거나 지원되지 않는 파일 형식입니다: {file_name_with_ext}")
|
||||
print(f"완료: '{output_zip}' 파일이 생성되었습니다.")
|
||||
|
||||
# /app/idrac_info/backup/ 폴더 내 폴더를 나열하고 사용자 선택 받는 함수
|
||||
def select_folder():
|
||||
# Assume script is in data/server_list, backup is in data/system/backup
|
||||
base_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "system", "backup")
|
||||
if not os.path.isdir(base_path):
|
||||
raise ValueError(f"기본 경로 '{base_path}'이(가) 존재하지 않습니다.")
|
||||
|
||||
folders = [f for f in os.listdir(base_path) if os.path.isdir(os.path.join(base_path, f))]
|
||||
if not folders:
|
||||
raise ValueError(f"'{base_path}'에 폴더가 존재하지 않습니다.")
|
||||
|
||||
print("사용 가능한 폴더:")
|
||||
for idx, folder in enumerate(folders, start=1):
|
||||
print(f"{idx}. {folder}")
|
||||
|
||||
choice = int(input("원하는 폴더의 번호를 선택하세요: ").strip())
|
||||
if choice < 1 or choice > len(folders):
|
||||
raise ValueError("올바른 번호를 선택하세요.")
|
||||
|
||||
return os.path.join(base_path, folders[choice - 1])
|
||||
|
||||
# 주요 실행 코드
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
# /app/idrac_info/backup/ 폴더 내에서 폴더 선택
|
||||
folder_path = select_folder()
|
||||
|
||||
output_zip_name = input("생성할 zip 파일명을 입력하세요 (확장자 제외, 예: output): ").strip()
|
||||
|
||||
# zip 파일 경로를 현재 디렉토리로 설정
|
||||
output_zip = os.path.join(os.getcwd(), f"{output_zip_name}.zip")
|
||||
|
||||
# 파일명 리스트 가져오기
|
||||
file_list = read_file_list()
|
||||
|
||||
if not file_list:
|
||||
print("list.txt에 파일명이 없습니다.")
|
||||
else:
|
||||
zip_selected_files(folder_path, file_list, output_zip)
|
||||
except ValueError as e:
|
||||
print(e)
|
||||
@@ -0,0 +1,20 @@
|
||||
BDNXRH4
|
||||
J9MXRH4
|
||||
6DNXRH4
|
||||
59MXRH4
|
||||
G9MXRH4
|
||||
79MXRH4
|
||||
B9MXRH4
|
||||
99MXRH4
|
||||
9GMXRH4
|
||||
49MXRH4
|
||||
89MXRH4
|
||||
G8MXRH4
|
||||
H8MXRH4
|
||||
1BMXRH4
|
||||
4BMXRH4
|
||||
GV5MQH4
|
||||
6W5MQH4
|
||||
JT5MQH4
|
||||
DT5MQH4
|
||||
3V5MQH4
|
||||
@@ -0,0 +1,307 @@
|
||||
from __future__ import annotations
|
||||
import os
|
||||
import argparse
|
||||
import sys
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from collections import OrderedDict
|
||||
import pandas as pd
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Logging Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [INFO] %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Path Resolution
|
||||
# -----------------------------------------------------------------------------
|
||||
def resolve_data_root() -> Path:
|
||||
"""
|
||||
Priority:
|
||||
1) Env var IDRAC_DATA_DIR (absolute/relative OK)
|
||||
2) nearest parent of this file that contains a 'data' folder
|
||||
3) ./data under current working directory
|
||||
"""
|
||||
env = os.getenv("IDRAC_DATA_DIR")
|
||||
if env:
|
||||
return Path(env).expanduser().resolve()
|
||||
|
||||
here = Path(__file__).resolve()
|
||||
for p in [here] + list(here.parents):
|
||||
if (p / "data").is_dir():
|
||||
return (p / "data").resolve()
|
||||
|
||||
# Fallback to current working directory assumption
|
||||
cwd_data = Path.cwd() / "data"
|
||||
if cwd_data.is_dir():
|
||||
return cwd_data.resolve()
|
||||
|
||||
# Final fallback: Assume we are in data/server_list/ -> go up two levels
|
||||
return here.parent.parent
|
||||
|
||||
DATA_ROOT = resolve_data_root()
|
||||
|
||||
# Default Paths (can be overridden by args)
|
||||
DEFAULT_GUID_INPUT = DATA_ROOT / "repository" / "guid_file"
|
||||
DEFAULT_GPU_INPUT = DATA_ROOT / "repository" / "gpu_serial"
|
||||
DEFAULT_MAC_INPUT = DATA_ROOT / "repository" / "mac"
|
||||
|
||||
DEFAULT_GUID_LIST = DATA_ROOT / "server_list" / "guid_list.txt"
|
||||
DEFAULT_GPU_LIST = DATA_ROOT / "server_list" / "gpu_serial_list.txt"
|
||||
DEFAULT_MAC_LIST = DATA_ROOT / "server_list" / "server_list.txt"
|
||||
|
||||
DEFAULT_GUID_OUTPUT = DATA_ROOT / "temp" / "staging" / "XE9680_GUID.xlsx"
|
||||
DEFAULT_GPU_OUTPUT = DATA_ROOT / "temp" / "staging" / "GPU_SERIALS.xlsx"
|
||||
DEFAULT_MAC_OUTPUT = DATA_ROOT / "temp" / "staging" / "mac_info.xlsx"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Utility Functions
|
||||
# -----------------------------------------------------------------------------
|
||||
def read_lines_any_encoding(path: Path) -> list[str]:
|
||||
"""Read text file trying common encodings."""
|
||||
if not path.is_file():
|
||||
return []
|
||||
|
||||
encodings = ["utf-8-sig", "utf-8", "cp949", "euc-kr", "latin-1"]
|
||||
for enc in encodings:
|
||||
try:
|
||||
with path.open("r", encoding=enc, errors="strict") as f:
|
||||
return f.read().splitlines()
|
||||
except Exception:
|
||||
continue
|
||||
# last resort
|
||||
with path.open("r", encoding="utf-8", errors="replace") as f:
|
||||
return f.read().splitlines()
|
||||
|
||||
def parse_txt_key_value(file_path: Path) -> dict:
|
||||
"""
|
||||
Parse standarized Key: Value files (GPU, GUID).
|
||||
First line is assumed to be S/T (Service Tag).
|
||||
"""
|
||||
lines = read_lines_any_encoding(file_path)
|
||||
if not lines:
|
||||
return {}
|
||||
|
||||
data = OrderedDict()
|
||||
data["S/T"] = lines[0].strip()
|
||||
|
||||
for raw in lines[1:]:
|
||||
line = raw.strip()
|
||||
if not line or ":" not in line:
|
||||
continue
|
||||
key, value = line.split(":", 1)
|
||||
data[key.strip()] = value.strip()
|
||||
|
||||
return dict(data)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Mode: MAC
|
||||
# -----------------------------------------------------------------------------
|
||||
def process_mac(input_dir: Path, list_file: Path, output_xlsx: Path):
|
||||
"""
|
||||
Logic from excel.py
|
||||
"""
|
||||
if not list_file.is_file():
|
||||
raise FileNotFoundError(f"Server list file not found: {list_file}")
|
||||
|
||||
file_names = read_lines_any_encoding(list_file)
|
||||
|
||||
data_list: list[str] = []
|
||||
index_list: list[int | str] = []
|
||||
sequence_number = 1
|
||||
|
||||
for name in file_names:
|
||||
base = (name or "").strip()
|
||||
if not base:
|
||||
continue
|
||||
|
||||
txt_path = input_dir / f"{base}.txt"
|
||||
|
||||
if not txt_path.is_file():
|
||||
# Missing file handling
|
||||
data_list.append("")
|
||||
index_list.append("")
|
||||
continue
|
||||
|
||||
lines = read_lines_any_encoding(txt_path)
|
||||
for i, line in enumerate(lines):
|
||||
cleaned = (line or "").strip().upper()
|
||||
if cleaned:
|
||||
data_list.append(cleaned)
|
||||
# First line is always the service tag
|
||||
if i == 0:
|
||||
index_list.append(sequence_number)
|
||||
sequence_number += 1
|
||||
else:
|
||||
index_list.append("")
|
||||
else:
|
||||
data_list.append("")
|
||||
index_list.append("")
|
||||
|
||||
# Create DataFrame
|
||||
df = pd.DataFrame({
|
||||
"Index": index_list,
|
||||
"Content": data_list,
|
||||
})
|
||||
|
||||
# Save without header, without index
|
||||
output_xlsx.parent.mkdir(parents=True, exist_ok=True)
|
||||
df.to_excel(output_xlsx, index=False, header=False)
|
||||
logger.info(f"[MAC] Saved to {output_xlsx}")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Mode: GPU
|
||||
# -----------------------------------------------------------------------------
|
||||
def process_gpu(input_dir: Path, list_file: Path, output_xlsx: Path):
|
||||
"""
|
||||
Logic from GPUTOExecl.py
|
||||
"""
|
||||
if not input_dir.is_dir():
|
||||
raise FileNotFoundError(f"Input directory not found: {input_dir}")
|
||||
|
||||
# File collection
|
||||
files: list[Path] = []
|
||||
if list_file and list_file.is_file():
|
||||
names = [x.strip() for x in read_lines_any_encoding(list_file) if x.strip()]
|
||||
for name in names:
|
||||
p = input_dir / f"{name}.txt"
|
||||
if p.is_file():
|
||||
files.append(p)
|
||||
else:
|
||||
logger.warning(f"[GPU] File not found: {p.name}")
|
||||
else:
|
||||
# Fallback to glob
|
||||
files = sorted(input_dir.glob("*.txt"))
|
||||
|
||||
if not files:
|
||||
logger.warning("[GPU] No files to process.")
|
||||
return
|
||||
|
||||
# Parse
|
||||
rows = []
|
||||
for p in files:
|
||||
rows.append(parse_txt_key_value(p))
|
||||
|
||||
df = pd.DataFrame(rows)
|
||||
# Insert 'No' column
|
||||
df.insert(0, "No", range(1, len(df) + 1))
|
||||
|
||||
output_xlsx.parent.mkdir(parents=True, exist_ok=True)
|
||||
df.to_excel(output_xlsx, index=False)
|
||||
logger.info(f"[GPU] Saved to {output_xlsx}")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Mode: GUID
|
||||
# -----------------------------------------------------------------------------
|
||||
def process_guid(input_dir: Path, list_file: Path, output_xlsx: Path):
|
||||
"""
|
||||
Logic from GUIDtxtT0Execl.py
|
||||
"""
|
||||
if not input_dir.is_dir():
|
||||
raise FileNotFoundError(f"Input directory not found: {input_dir}")
|
||||
|
||||
# Determine Slot Priority
|
||||
slot_priority_str = os.getenv("GUID_SLOT_PRIORITY", "")
|
||||
if slot_priority_str:
|
||||
slot_priority = [s.strip() for s in slot_priority_str.split(",") if s.strip()]
|
||||
logger.info(f"[GUID] Custom slot priority: {slot_priority}")
|
||||
else:
|
||||
slot_priority = ['38', '39', '37', '36', '32', '33', '34', '35', '31', '40']
|
||||
logger.info(f"[GUID] Default slot priority: {slot_priority}")
|
||||
|
||||
# File collection
|
||||
files: list[Path] = []
|
||||
names = []
|
||||
if list_file and list_file.is_file():
|
||||
names = [x.strip() for x in read_lines_any_encoding(list_file) if x.strip()]
|
||||
|
||||
# Process
|
||||
rows = []
|
||||
for name in names:
|
||||
txt_path = input_dir / f"{name}.txt"
|
||||
if not txt_path.is_file():
|
||||
logger.warning(f"[GUID] File not found: {txt_path.name}")
|
||||
continue
|
||||
|
||||
raw_data = parse_txt_key_value(txt_path)
|
||||
|
||||
# Reorder and reconstruct GUID
|
||||
ordered_data = OrderedDict()
|
||||
ordered_data["S/T"] = raw_data.get("S/T", "")
|
||||
|
||||
new_guid_list = []
|
||||
for slot_num in slot_priority:
|
||||
slot_key = f"Slot.{slot_num}"
|
||||
val = raw_data.get(slot_key)
|
||||
if val:
|
||||
ordered_data[slot_key] = val
|
||||
if val != "Not Found" and ":" in val:
|
||||
clean_hex = val.replace(":", "").upper()
|
||||
new_guid_list.append(f"0x{clean_hex}")
|
||||
|
||||
# GUID Selection logic
|
||||
if new_guid_list:
|
||||
ordered_data["GUID"] = ";".join(new_guid_list)
|
||||
elif "GUID" in raw_data:
|
||||
ordered_data["GUID"] = raw_data["GUID"]
|
||||
|
||||
# Add remaining fields
|
||||
for k, v in raw_data.items():
|
||||
if k not in ordered_data:
|
||||
ordered_data[k] = v
|
||||
|
||||
rows.append(dict(ordered_data))
|
||||
|
||||
if not rows:
|
||||
logger.warning("[GUID] No data processed.")
|
||||
# Create empty excel if needed or just return
|
||||
return
|
||||
|
||||
df = pd.DataFrame(rows)
|
||||
df.insert(0, "No", range(1, len(df) + 1))
|
||||
|
||||
output_xlsx.parent.mkdir(parents=True, exist_ok=True)
|
||||
df.to_excel(output_xlsx, index=False)
|
||||
logger.info(f"[GUID] Saved to {output_xlsx}")
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Main Entry Point
|
||||
# -----------------------------------------------------------------------------
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Unified Excel Generator")
|
||||
parser.add_argument("--mode", required=True, choices=["mac", "gpu", "guid"], help="Generation mode")
|
||||
parser.add_argument("--input-dir", type=Path, help="Input directory (optional override)")
|
||||
parser.add_argument("--list-file", type=Path, help="List file (optional override)")
|
||||
parser.add_argument("--output-xlsx", type=Path, help="Output XLSX path (optional override)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
mode = args.mode
|
||||
|
||||
# Determine effective paths based on mode and overrides
|
||||
if mode == "mac":
|
||||
input_dir = args.input_dir or DEFAULT_MAC_INPUT
|
||||
list_file = args.list_file or DEFAULT_MAC_LIST
|
||||
output_xlsx = args.output_xlsx or DEFAULT_MAC_OUTPUT
|
||||
process_mac(input_dir, list_file, output_xlsx)
|
||||
|
||||
elif mode == "gpu":
|
||||
input_dir = args.input_dir or DEFAULT_GPU_INPUT
|
||||
list_file = args.list_file or DEFAULT_GPU_LIST
|
||||
output_xlsx = args.output_xlsx or DEFAULT_GPU_OUTPUT
|
||||
process_gpu(input_dir, list_file, output_xlsx)
|
||||
|
||||
elif mode == "guid":
|
||||
input_dir = args.input_dir or DEFAULT_GUID_INPUT
|
||||
list_file = args.list_file or DEFAULT_GUID_LIST
|
||||
output_xlsx = args.output_xlsx or DEFAULT_GUID_OUTPUT
|
||||
process_guid(input_dir, list_file, output_xlsx)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user