
์๋ฒ ๊ด๋ฆฌ์์ ๋ก๊ทธ ๋ชจ๋ํฐ๋ง์ ์์คํ ์์ ์ฑ๊ณผ ๋ฌธ์ ํด๊ฒฐ์ ํต์ฌ์ ๋๋ค.
ํจ์จ์ ์ธ ๋ก๊ทธ ๋ชจ๋ํฐ๋ง ํด์ ์ฌ์ฉํ๋ฉด ๋๋์ ์๋ฒ ๋ก๊ทธ๋ฅผ ํ๋์ ํ์ ํ ์ ์๊ณ ,
์๋ฆผ ๊ธฐ๋ฅ์ผ๋ก ๋ฌธ์ ๋ฅผ ์ ์ํ ํด๊ฒฐํ ์ ์์ต๋๋ค.
ํ์ง๋ง, ๋น์ฉ์ด๋ ํ๊ฒฝ์ ์ธ ์ ์ฝ์ผ๋ก ์ธํด ์ด๋ฌํ ํด์ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ,
์ง์ ๋ก๊ทธ๋ฅผ ์์งํ๊ณ ๋ถ์ํด์ผ ํ๋ ์ํฉ๋ ์ข ์ข ๋ฐ์ํฉ๋๋ค.
Dell ํ๋์จ์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ iDRAC์ ์ ์ํด Lifecycle Log๋ฅผ ํ์ธํ๋ ๊ฒ์ด ๋ํ์ ์ธ ๋ฐฉ๋ฒ์ ๋๋ค.
- ์น ์ธํฐํ์ด์ค๋ฅผ ํตํ ๋ก๊ทธ ์์ง
- iDRAC ์น ์ธํฐํ์ด์ค์ ๋ก๊ทธ์ธํฉ๋๋ค.
- โMaintenanceโ ํญ์์ โLifecycle Logโ๋ฅผ ์ ํํฉ๋๋ค.
- Log Filter๋ฅผ ์ค์ ํ๊ณ ๋ก๊ทธ๋ฅผ ์์งํฉ๋๋ค.

iDRAC์์๋ ์ง๊ด์ ์ธ ์น ์ธํฐํ์ด์ค๋ฅผ ํตํด ๋ก๊ทธ๋ฅผ ์ฝ๊ฒ ์์งํ ์ ์์ต๋๋ค.
ํ์ง๋ง ์๋ฒ ์๊ฐ ๋ง์ ๊ฒฝ์ฐ, ๊ฐ๊ฐ์ iDRAC์ ์ ์ํ๋ ๋ฐ ์๊ฐ์ด ๋ง์ด ์์๋๊ณ
๋ก๊ทธ๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ์์งํ๊ณ ๋ถ์ํ๋ ๊ณผ์ ๋ํ ๋นํจ์จ์ ์ธ ์์ ์ด ๋ ์ ์์ต๋๋ค.
์ฌ๋ฌ ์๋ฒ์ ๋ก๊ทธ๋ฅผ ์์งํด์ผ ํ ๊ฒฝ์ฐ RACADM ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ๋ฉด
CLI ํ๊ฒฝ์์ ์ผ๊ด ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ฏ๋ก, ์๊ฐ๊ณผ ๋ ธ๋ ฅ์ ํฌ๊ฒ ์ ์ฝํ ์ ์์ต๋๋ค.
[BMC/iDRAC] RACADM๋ ๋ฌด์์ธ๊ฐ?
์ ๋ฌด์ ์ผ๋ก ํ๋์จ์ด๋ฅผ ์ ๊ฒํ๊ธฐ ์ํด BMC๋ฅผ ํ์ฉํ๋ ์ผ์ด ๋ง์ต๋๋ค. BMC(Baseboard Management Controller)๋ ์๋ฒ์ ๋ฌผ๋ฆฌ์ ์ํ๋ฅผ ์๊ฒฉ์ผ๋ก ๋ชจ๋ํฐ๋งํ๊ณ ๊ด๋ฆฌํ ์ ์๋๋ก ์ง์ํ๋ ํ๋์จ์ด ๊ด๋ฆฌ ์นฉ
endyd1567.tistory.com
- RACADM์ ํตํ ๋ก๊ทธ ์์ง
- ์ ๊ฒํ ์๋ฒ์ iDRAC IP์ ๋ก๊ทธ์ธ ๊ณ์ ์ ๋ณด๋ฅผ ํ์ธํฉ๋๋ค.
- RACADM ๋ช ๋ น์ด๋ฅผ ์คํํฉ๋๋ค.
# lclog
Lifecycle Log๋ฅผ ๊ด๋ฆฌํ๋ ๋ช ๋ น์ด
๋ก๊ทธ ์กฐํ, ์๊ฒฉ ๋ด๋ณด๋ด๊ธฐ, ์ฃผ์ ์ถ๊ฐ ๊ธฐ๋ฅ
# racadm lclog view -i <number of records> -a <agent id> -c <category>
# -s <severity> -b <sub-category> -q <sequence no> -n <number of records>
# -r <start timestamp> -e <end timestamp>
racadm -r 192.168.0.58 -u root -p calvin lclog view -s Warning -r "2024-11-01 00:00:00" -e "2024-12-01 23:59:59"
"lclog view" ๋ช ๋ น์ด์ ์ต์ ์ผ๋ก ๋ก๊ทธ์ ์ฌ๊ฐ๋๋ฅผ ๊ธฐ์ค์ผ๋ก ํํฐ๋งํ๊ฑฐ๋
์์ ๋ฐ ์ข ๋ฃ ํ์์คํฌํ๋ฅผ ์ง์ ํ์ฌ ํน์ ์๊ฐ ๋ฒ์์ ๋ก๊ทธ ์กฐํ๋ ๊ฐ๋ฅํฉ๋๋ค.

์ ๋ช
๋ น์ด๋ 192.168.0.58 IP๋ฅผ ๊ฐ์ง iDRAC์์ Warning ์์ค์ ๋ก๊ทธ๋ฅผ
2024๋
11์ 1์ผ๋ถํฐ 12์ 1์ผ๊น์ง ์์งํ๋ ์์
๋๋ค.
RACADM์ ๋ค์ค IP ์ฒ๋ฆฌ๋ฅผ ์ง์ํ์ง ์์ผ๋ฏ๋ก ์ฌ๋ฌ ์๋ฒ์ ๋ํด ๋ฐ๋ณต ์์
์ด ํ์ํฉ๋๋ค.
์ด๋ฅผ ์๋ํํ๊ธฐ ์ํด ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ๋ฉด ๋ณด๋ค ํจ์จ์ ์ผ๋ก ๋ก๊ทธ๋ฅผ ์์งํ ์ ์์ต๋๋ค.
# racadm_get_lclog.sh
์ง์ ๋ ์๊ฐ ๋ฒ์์ ๋ก๊ทธ๋ฅผ ์์งํ๊ณ ํ์์ ํ์ผ๋ก ์ ์ฅํฉ๋๋ค.
#!/bin/bash
RACUSER="root"
RACPSWD="calvin"
log_output="false" # ๋ก๊ทธ ์ ์ฅ ์ฌ๋ถ
log_base_dir="./LifeCycleLog" # ๊ธฐ๋ณธ ๋ก๊ทธ ์ ์ฅ ๋๋ ํ ๋ฆฌ
start_time=""
end_time=""
client_name=""
# Usage ์ถ๋ ฅ ํจ์
usage() {
echo "Usage: $0 [-h <iDRAC_IP> | -f <file_with_iDRAC_IPs>] [-r <start_time>] [-e <end_time>] [-c <client_name>]"
echo "Options:"
echo " -h <iDRAC_IP> Specify a single iDRAC IP address"
echo " -f <file> Specify a file containing iDRAC IP addresses (one per line)"
echo " -r <start_time> Start time for logs in format 'yyyy-mm-dd HH:MM:SS'"
echo " -e <end_time> End time for logs in format 'yyyy-mm-dd HH:MM:SS'"
echo " -c <client_name> Specify a client name for log directory"
exit 1
}
# ๋ก๊ทธ ์ ์ฅ ์ฌ๋ถ ๋ฌป๊ธฐ
ask_log_saving() {
read -p "Do you want to save logs? (y/n): " answer
case $answer in
[Yy]*) log_output="true" ;;
[Nn]*) log_output="false" ;;
*) echo "Invalid input. Defaulting to no log saving."; log_output="false" ;;
esac
}
# ์ต์
์ฒ๋ฆฌ
while getopts "h:f:r:e:c:" opt; do
case $opt in
h) # ๋จ์ผ iDRAC IP
remote_idrac=$OPTARG
;;
f) # ํ์ผ ์
๋ ฅ
ip_file=$OPTARG
;;
r) # ์์ ์๊ฐ
start_time=$OPTARG
;;
e) # ์ข
๋ฃ ์๊ฐ
end_time=$OPTARG
;;
c) # ํด๋ผ์ด์ธํธ ์ด๋ฆ
client_name=$OPTARG
;;
*) # ์๋ชป๋ ์ต์
usage
;;
esac
done
# ์ต์
์ ํจ์ฑ ๊ฒ์ฆ
if [[ -z $remote_idrac && -z $ip_file ]]; then
echo "Error: You must provide either -h or -f option."
usage
fi
if [[ -n $remote_idrac && -n $ip_file ]]; then
echo "Error: Options -h and -f cannot be used together."
usage
fi
# ๋ก๊ทธ ์ ์ฅ ์ฌ๋ถ ํ์ธ
ask_log_saving
# ๋ก๊ทธ ๋๋ ํ ๋ฆฌ ์ค์
if [[ $log_output == "true" ]]; then
if [[ -n $client_name ]]; then
log_base_dir="${log_base_dir}/${client_name}"
fi
log_date_dir="${log_base_dir}/$(date +"%Y%m%d")"
mkdir -p "$log_date_dir"
echo "Logs will be saved in directory: $log_date_dir"
fi
# iDRAC ๋ก๊ทธ ์ฒ๋ฆฌ ํจ์
process_idrac_logs() {
local ip=$1
echo "Processing iDRAC: $ip"
# ๋ช
๋ น์ด ๊ตฌ์ฑ
if [[ -z $start_time && -z $end_time ]]; then
cmd="racadm -r \"$ip\" -u \"$RACUSER\" -p \"$RACPSWD\" lclog view -s Critical,Warning"
else
cmd="racadm -r \"$ip\" -u \"$RACUSER\" -p \"$RACPSWD\" lclog view -s Critical,Warning -r \"$start_time\" -e \"$end_time\""
fi
# ๋ก๊ทธ ์ ์ฅ ๊ฒฝ๋ก ์์ฑ
if [[ $log_output == "true" ]]; then
timestamp=$(date +"%H%M%S")
log_file="${log_date_dir}/${ip}_${timestamp}.log"
eval "$cmd" 2>&1 | tee "$log_file"
else
eval "$cmd"
fi
# ์ข
๋ฃ ์ฝ๋ ํ์ธ
if [[ $? -ne 0 ]]; then
echo "Warning: Unable to connect to $ip. Skipping..."
return 1
fi
}
# ๋จ์ผ IP ์ฒ๋ฆฌ
if [[ -n $remote_idrac ]]; then
# IP ํ์ ํ์ธ
if [[ ! $remote_idrac =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Error: Invalid IP address format."
exit 1
fi
process_idrac_logs "$remote_idrac"
fi
# ํ์ผ ๋ด IP ์ฒ๋ฆฌ
if [[ -n $ip_file ]]; then
if [[ ! -f $ip_file ]]; then
echo "Error: File '$ip_file' not found."
exit 1
fi
while IFS= read -r ip || [[ -n $ip ]]; do
# IP ํ์ ํ์ธ
if [[ ! $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Warning: Skipping invalid IP address '$ip'"
continue
fi
process_idrac_logs "$ip"
done < "$ip_file"
fi


์ฌ๋ฌ ์๋ฒ๋ค์ Lifecycle Log๋ฅผ RACADM์ ์ด์ฉํ์ฌ ์ฝ๊ฒ ํ์ผ๋ก ์ ์ฅํ์์ต๋๋ค.
์ด์ ๋ ์์งํ ๋ก๊ทธ๋ฅผ ๋ถ์ํ ์ฐจ๋ก์ ๋๋ค.
์์งํ ๋ก๊ทธ ์ค ์๋ก์ด ์ด๋ฒคํธ๋ฅผ ํ์ ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
ํ ๋ฌ ์ ์ ์์งํ ๋ก๊ทธ์ ์ต๊ทผ ๋ก๊ทธ๋ฅผ ๋น๊ตํด ๋ณด๊ฒ ์ต๋๋ค.

์ง์ ๋ ํ์ผ์ ๋น๊ตํ๋ฉฐ ์๋ก์ด ๋ก๊ทธ๋ฅผ ์ฐพ์๋ด ์๋ค.
Message๋ฅผ ํ์ธํ์ฌ ์ค๋ณต๋ ๋ก๊ทธ์ธ์ง ์๋กญ๊ฒ ๋์จ ๋ก๊ทธ์ธ์ง ํ์ ํ๋ ค๋ฉด ์๊ฐ์ด ์๋นํ ๊ฑธ๋ฆด ์ ์์ต๋๋ค.
๋ํ, ์์ ํ๋ ๊ณผ์ ์์ ์ค์๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ๋ ์์ต๋๋ค.
์ด๋ฌํ ๋ก๊ทธ๋ค์ ์ง์ ๋น๊ตํ๋ ๊ฒ์ ๋นํจ์จ์ ์ด๊ธฐ์ ์ด ๋ํ ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ์ฌ ์์ ์ ์ํํ๋๋ก ํด๋ณด๊ฒ ์ต๋๋ค.
# new_log_filter.py
๋ก๊ทธ ํ์ผ์ด ์ ์ฅ๋ ๋ ๋๋ ํฐ๋ฆฌ๋ฅผ ๋น๊ตํ์ฌ ์๋ก์ด ๋ฉ์์ง์ ์ค๋ณต ๋ฉ์์ง๋ฅผ ๊ตฌ๋ถํฉ๋๋ค.
์๋ ์ฝ๋ ์คํ์ ํ์ด์ฌ ์ค์น๊ฐ ํ์ํฉ๋๋ค.
import os
import sys
# Parse the provided logs to extract the "Message" values and compare them.
def extract_messages_with_metadata(file_path):
"""Extracts 'Message' along with 'Severity' and 'Timestamp' values from a log file."""
messages = set()
metadata = {}
with open(file_path, 'r', encoding='utf-8') as file:
current_message = None
current_severity = None
current_timestamp = None
for line in file:
if line.strip().startswith("Message "):
key, value = line.split("=", 1)
current_message = value.strip()
elif line.strip().startswith("Severity"):
key, value = line.split("=", 1)
current_severity = value.strip()
elif line.strip().startswith("Timestamp"):
key, value = line.split("=", 1)
current_timestamp = value.strip()
if current_message:
messages.add(current_message)
metadata[current_message] = {
"Severity": current_severity,
"Timestamp": current_timestamp
}
current_message = None
current_severity = None
current_timestamp = None
return messages, metadata
def find_logs_by_ip(directory1, directory2):
"""Finds and pairs logs by IP addresses between two directories."""
logs_by_ip = {}
for directory, index in zip([directory1, directory2], [0, 1]):
for root, _, files in os.walk(directory):
for file in files:
if file.endswith(".log"):
ip = file.split("_")[0] # Assuming IP is the first part of the filename
logs_by_ip.setdefault(ip, [None, None])[index] = os.path.join(root, file)
return logs_by_ip
def process_logs(directory1_path, directory2_path):
logs_by_ip = find_logs_by_ip(directory1_path, directory2_path)
output_lines = []
for ip, log_files in logs_by_ip.items():
if not all(log_files):
continue
last_log_path, recent_log_path = log_files
last_log_messages, last_log_metadata = extract_messages_with_metadata(last_log_path)
recent_log_messages, recent_log_metadata = extract_messages_with_metadata(recent_log_path)
new_messages = recent_log_messages - last_log_messages
overlapping_messages = recent_log_messages & last_log_messages
def format_messages(messages, metadata):
sorted_messages = sorted(messages, key=lambda m: metadata[m]['Timestamp'], reverse=True)
return "\n".join([
f"{metadata[message]['Timestamp']} {metadata[message]['Severity']}: {message}"
for message in sorted_messages
])
output_lines.extend([
f"\n\n-----------------------------------New Log Messages for {ip}-----------------------------------------",
"\n[New Warnings]", format_messages(
[m for m in new_messages if recent_log_metadata[m]['Severity'] == 'Warning'], recent_log_metadata
),
"\n[New Criticals]", format_messages(
[m for m in new_messages if recent_log_metadata[m]['Severity'] == 'Critical'], recent_log_metadata
),
f"\n\n-----------------------------------Last Log Messages for {ip}----------------------------------------",
"\n[Last Warnings]", format_messages(
[m for m in overlapping_messages if recent_log_metadata[m]['Severity'] == 'Warning'], recent_log_metadata
),
"\n[Last Criticals]", format_messages(
[m for m in overlapping_messages if recent_log_metadata[m]['Severity'] == 'Critical'], recent_log_metadata
)
])
return "\n".join(output_lines)
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python new_log_filter.py <Last_directory_path> <New_directory_path>")
print("Example: python new_log_filter.py 20241101 20241201")
sys.exit(1)
directory1_path, directory2_path = sys.argv[1], sys.argv[2]
save_output = input("Do you want to save the output messages to a file? (y/n): ").strip().lower() in ["y", "yes"]
result = process_logs(directory1_path, directory2_path)
print(result)
if save_output:
output_file_path = os.path.join(directory2_path, "new_messages_output.txt")
with open(output_file_path, 'w', encoding='utf-8') as output_file:
output_file.write(result)
print(f"Output saved to {output_file_path}")

๊ฐ IP ์ฃผ์์ ๋ํด ์๋ก์ด ๋ก๊ทธ์ ์ค๋ณต๋ ๋ก๊ทธ๋ฅผ ๊ตฌ๋ถํ์ฌ ์ถ๋ ฅํฉ๋๋ค.
์ฌ๊ฐ๋(Warning, Critical) ๋ณ๋ก ๋๋์ด ๋ฉ์์ง๊ฐ ์ ๋ฆฌ๋ฉ๋๋ค.
cf)
๋ก๊ทธ ๊ธฐ๊ฐ์ ์ค์ ํ์ง ์๊ณ ๋ชจ๋ ๋ก๊ทธ๋ฅผ ์์งํ์ฌ ๋น๊ตํ๋ฉด
๋ถํ์ํ ๊ณผ๊ฑฐ ๋ก๊ทธ๊ฐ ๋น๊ต ๋์์ ํฌํจ๋์ด ํ๋ฒ ๋์จ ๋ก๊ทธ๋ค์ ๋ชจ๋ Last Log๋ก ํฌํจ์ด ๋ฉ๋๋ค.
๋น๊ตํ ๋ ๋ก๊ทธ ํ์ผ์ ๊ธฐ๊ฐ์ด ๊ฒน์น์ง ์๊ฒ ์ค์ ํด์ผ ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค.
RACADM ๋ช ๋ น์ด์ ์คํฌ๋ฆฝํธ๋ฅผ ํ์ฉํ๋ฉด ๋ก๊ทธ ๋ชจ๋ํฐ๋ง ํด ์์ด๋
๋ค์์ ์๋ฒ์์ ๋ฐ์ํ ๋ก๊ทธ๋ฅผ ํจ์จ์ ์ผ๋ก ์์งํ ์ ์์ต๋๋ค.
์๋ํ๋ฅผ ํตํด ๋ฐ๋ณต ์์
์ ์ค์ด๊ณ ๋ก๊ทธ ๋ฐ์ดํฐ๋ฅผ ์ฒด๊ณ์ ์ผ๋ก ๊ด๋ฆฌํ๋ฉด,
ํด ์ฌ์ฉ ๋๋น ํฐ ๋น์ฉ ์ ๊ฐ๊ณผ ๋๋ถ์ด ์ง์ ๊ด๋ฆฌ์ ์ฅ์ ๋ ์ป์ ์ ์์ต๋๋ค.
์ฐธ๊ณ ์๋ฃ
'Hardware > BMC' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[BMC/iDRAC] RACADM๋ ๋ฌด์์ธ๊ฐ? (0) | 2024.12.24 |
---|