26S06f2

QK·약 8시간 전
#!/usr/bin/env bash
#
# node_check.sh
# ------------------------------------------------------------------------
# 목적: 인프라팀이 OS 설치까지 완료해 인도한 물리 노드에 대해, DevOps 인수
#       테스트 관점에서 기본 HW(NIC 포함) / OS / 커널 상태를 점검하고
#       결과를 파일로 남긴다. 이후 aggregate_report.py 로 여러 노드 결과를
#       한번에 통계/이상치 분석한다.
#
# 설계 원칙:
#   1) 카테고리별로 함수 하나 = 점검 하나. 필요없으면 상단 RUN_* 값을 0으로
#      바꾸거나, 함수 자체를 지우고 main()의 호출부만 지우면 됨 (추가/삭제 용이).
#   2) 모든 점검 결과는 raw 로그(원본 명령 출력) + summary.csv(기계 판독용
#      1줄 요약) 두 군데에 남긴다. 통계 스크립트는 summary.csv만 본다.
#   3) 실제 서버를 훼손/재부팅 하는 위험한 명령은 넣지 않는다. 부하성 테스트
#      (stress-ng, fio, iperf3)는 시간/강도를 상단 변수로 제한하고 기본값은
#      "짧고 안전하게" 잡는다. 필요하면 값만 늘리면 됨.
#   4) status 값은 PASS / WARN / FAIL / INFO 4종.
#      - PASS/FAIL: 스크립트가 자체 판단 가능한 절대 기준(에러 카운터=0 등)
#      - WARN     : 기준선 근처거나 확인이 필요한 값
#      - INFO     : 절대 기준이 없고, 여러 노드를 모아봐야 이상치를 알 수
#                    있는 값(예: iperf3 처리량, fio IOPS). aggregate 스크립트가
#                    노드간 편차로 이상치를 잡아준다.
#   판단 기준의 근거는 README.md 참고.
#
# 사용법:
#   sudo ./node_check.sh
#   결과: /var/log/node-accept/<hostname>_<timestamp>/ 아래
#
set -u
# 주의: set -e 는 의도적으로 사용하지 않음. 점검 스크립트 특성상 개별 명령
# 실패(예: 특정 툴 미설치)가 스크립트 전체를 중단시키면 안 되기 때문.

# =========================================================================
# 0. 전역 설정 (여기서 on/off 스위치와 기준값을 관리한다)
# =========================================================================

NODE_NAME="$(hostname)"
TS="$(date +%Y%m%d_%H%M%S)"
RESULT_ROOT="${RESULT_ROOT:-/var/log/node-accept}"
OUTDIR="${RESULT_ROOT}/${NODE_NAME}_${TS}"
RAWDIR="${OUTDIR}/raw"
SUMMARY_CSV="${OUTDIR}/summary.csv"

# --- 카테고리 on/off 스위치 (1=실행, 0=skip) -----------------------------
# 필요 없는 점검은 여기서 0으로 끄면 된다. 새 점검을 추가할 때도
# 스위치부터 하나 만들고 시작할 것.
RUN_INVENTORY=1        # 시스템/BIOS/재고 정보
RUN_CPU_INFO=1         # CPU 스펙/거버너 확인
RUN_CPU_STRESS=1       # CPU 부하 테스트 (stress-ng)
RUN_MEM_INFO=1         # 메모리 슬롯/NUMA/ECC 확인
RUN_MEM_STRESS=1       # 메모리 부하 테스트 (stress-ng --vm)
RUN_STORAGE_INFO=1     # 디스크 SMART/헬스
RUN_STORAGE_FIO=0      # fio 성능 테스트 (기본 OFF: 대상 경로를 반드시 지정해야 함, 아래 FIO_TESTDIR 확인)
RUN_NIC_INFO=1         # NIC 링크/드라이버/오프로드/에러카운터
RUN_NIC_IPERF=0        # iperf3 처리량 (기본 OFF: 상대 서버(IPERF_TARGET) 지정 필요)
RUN_OS_KERNEL=1        # 커널/모듈/sysctl/swap 등 OS 기본 상태
RUN_TIME_SYNC=1        # NTP/chrony 동기화 상태

# --- 부하 테스트 파라미터 (기본은 짧고 가볍게) ----------------------------
CPU_STRESS_DURATION=60         # 초
MEM_STRESS_DURATION=60         # 초
MEM_STRESS_PERCENT=70          # 전체 메모리 대비 사용 비율(%)
FIO_RUNTIME=30                 # 초
FIO_SIZE="2G"
FIO_TESTDIR="${FIO_TESTDIR:-/data/fio-test}"   # 실제 대상 디스크 마운트 경로로 변경할 것
IPERF_TARGET="${IPERF_TARGET:-}"               # 예: IPERF_TARGET=10.0.0.5 ./node_check.sh
IPERF_DURATION=15

# --- 판단 기준값 (환경에 맞게 조정) --------------------------------------
THRESH_NIC_MIN_SPEED_MBPS=10000     # 기대 최소 링크 속도(Mb/s). 10G 이하 노드면 낮출 것
THRESH_MEM_MIN_GB=0                 # 0이면 스펙 비교 생략(로그로만 기록)
THRESH_SWAP_MUST_BE_ZERO=1          # K8s 노드는 swap 0이어야 함

# =========================================================================
# 1. 공통 유틸
# =========================================================================

mkdir -p "$RAWDIR"
echo "category|check|value|unit|status|note" > "$SUMMARY_CSV"

log() { echo "[$(date +%H:%M:%S)] $*"; }

have() { command -v "$1" >/dev/null 2>&1; }

# record <category> <check> <value> <unit> <status> <note>
# summary.csv 에 한 줄 남긴다. 값에 파이프(|)가 들어가지 않도록 주의.
record() {
    local category="$1" check="$2" value="$3" unit="$4" status="$5" note="${6:-}"
    echo "${category}|${check}|${value}|${unit}|${status}|${note}" >> "$SUMMARY_CSV"
}

# 결과를 raw 로그 파일로 저장하며 화면에도 출력
run_and_log() {
    local logfile="$1"; shift
    { echo "### CMD: $*"; echo "### TIME: $(date)"; echo; "$@"; } >> "${RAWDIR}/${logfile}" 2>&1
}

# =========================================================================
# 2. 사전 요구 도구 체크 (없으면 WARN만 남기고 계속 진행)
# =========================================================================
check_prereqs() {
    log "필수 도구 확인 중..."
    local tools=(dmidecode lscpu lspci lsblk ethtool smartctl nvme sensors \
                 stress-ng fio iperf3 chronyc numactl lldpctl ipmitool)
    for t in "${tools[@]}"; do
        if have "$t"; then
            record "prereq" "$t" "installed" "" "PASS" ""
        else
            record "prereq" "$t" "missing" "" "WARN" "관련 점검이 스킵되거나 정보가 누락될 수 있음. 설치 필요시: apt/yum install"
        fi
    done
}

# =========================================================================
# 3. 인벤토리/BIOS
# =========================================================================
check_inventory() {
    log "인벤토리/BIOS 정보 수집 중..."
    run_and_log "inventory_dmidecode.log" dmidecode
    run_and_log "inventory_lspci.log" lspci -vvv

    local sys_vendor sys_model bios_ver
    sys_vendor=$(dmidecode -s system-manufacturer 2>/dev/null | head -1)
    sys_model=$(dmidecode -s system-product-name 2>/dev/null | head -1)
    bios_ver=$(dmidecode -s bios-version 2>/dev/null | head -1)

    record "inventory" "system_vendor" "${sys_vendor:-unknown}" "" "INFO" "발주 스펙과 육안 대조"
    record "inventory" "system_model" "${sys_model:-unknown}" "" "INFO" "발주 스펙과 육안 대조"
    record "inventory" "bios_version" "${bios_ver:-unknown}" "" "INFO" "동일 랙/클러스터 노드간 버전 일치 여부 확인"

    # BMC(iDRAC/iLO 등) 연결 확인 (있는 경우만)
    if have ipmitool; then
        if ipmitool mc info >/dev/null 2>>"${RAWDIR}/inventory_bmc.log"; then
            record "inventory" "bmc_reachable" "yes" "" "PASS" ""
        else
            record "inventory" "bmc_reachable" "no" "" "WARN" "BMC 접근 불가 - 로컬에서 IPMI 미지원 환경일 수 있음, 별도 확인 필요"
        fi
    fi
}

# =========================================================================
# 4. CPU
# =========================================================================
check_cpu_info() {
    log "CPU 정보 수집 중..."
    run_and_log "cpu_lscpu.log" lscpu
    run_and_log "cpu_numa.log" numactl -H

    local model cores threads governor
    model=$(lscpu | awk -F: '/Model name/{gsub(/^ +/,"",$2); print $2; exit}')
    cores=$(lscpu | awk -F: '/^CPU\(s\):/{gsub(/^ +/,"",$2); print $2; exit}')
    governor=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 2>/dev/null || echo "unknown")

    record "cpu" "model" "${model:-unknown}" "" "INFO" ""
    record "cpu" "logical_cores" "${cores:-unknown}" "count" "INFO" "발주 스펙과 대조"

    if [[ "$governor" == "performance" ]]; then
        record "cpu" "scaling_governor" "$governor" "" "PASS" ""
    elif [[ "$governor" == "unknown" ]]; then
        record "cpu" "scaling_governor" "$governor" "" "WARN" "cpufreq 인터페이스 없음(가상화/일부 플랫폼) - 확인 필요"
    else
        record "cpu" "scaling_governor" "$governor" "" "WARN" "K8s 노드는 performance governor 권장. 현재 $governor"
    fi
}

check_cpu_stress() {
    log "CPU 부하 테스트 (${CPU_STRESS_DURATION}s) 중..."
    if ! have stress-ng; then
        record "cpu" "stress_test" "skipped" "" "WARN" "stress-ng 미설치"
        return
    fi
    local ncpu; ncpu=$(nproc)
    run_and_log "cpu_stress.log" stress-ng --cpu "$ncpu" --timeout "${CPU_STRESS_DURATION}s" --metrics-brief

    if grep -q "successful run completed" "${RAWDIR}/cpu_stress.log" 2>/dev/null; then
        record "cpu" "stress_test" "completed" "" "PASS" "${CPU_STRESS_DURATION}s 전체 코어 부하 정상 완료"
    else
        record "cpu" "stress_test" "failed_or_incomplete" "" "FAIL" "raw 로그(cpu_stress.log) 확인 필요, 크래시/OOM/throttle 의심"
    fi

    # 온도/쓰로틀링 (있는 경우)
    if have sensors; then
        run_and_log "cpu_sensors_after_stress.log" sensors
        record "cpu" "sensors_snapshot" "collected" "" "INFO" "raw 로그에서 부하 직후 온도 확인, throttle 여부는 turbostat 권장"
    fi
}

# =========================================================================
# 5. 메모리
# =========================================================================
check_mem_info() {
    log "메모리 정보 수집 중..."
    run_and_log "mem_dmidecode.log" dmidecode -t memory
    run_and_log "mem_free.log" free -h

    local total_gb populated empty
    total_gb=$(free -g | awk '/Mem:/{print $2}')
    populated=$(dmidecode -t memory 2>/dev/null | grep -c "Size: [0-9]")
    empty=$(dmidecode -t memory 2>/dev/null | grep -c "Size: No Module Installed")

    record "memory" "total_memory" "${total_gb:-unknown}" "GB" "INFO" "발주 스펙과 대조"
    record "memory" "populated_dimm_slots" "${populated:-unknown}" "count" "INFO" "채널 밸런스 확인 - 슬롯 배치가 균등해야 성능 저하 없음"
    record "memory" "empty_dimm_slots" "${empty:-unknown}" "count" "INFO" ""

    # ECC 에러 체크
    if have ras-mc-ctl; then
        run_and_log "mem_ecc.log" ras-mc-ctl --summary
        if grep -qE "Corrected|Uncorrected" "${RAWDIR}/mem_ecc.log" 2>/dev/null && \
           ! grep -q "0 Corrected" "${RAWDIR}/mem_ecc.log" 2>/dev/null; then
            record "memory" "ecc_errors" "detected" "" "WARN" "raw 로그(mem_ecc.log) 확인, 반복 발생시 FAIL로 격상 권장"
        else
            record "memory" "ecc_errors" "none_detected" "" "PASS" ""
        fi
    else
        record "memory" "ecc_errors" "not_checked" "" "WARN" "ras-mc-ctl(edac-utils) 미설치, dmesg 내 EDAC/MCE 로그 수동 확인 권장"
    fi

    run_and_log "mem_dmesg_mce.log" bash -c "dmesg | grep -iE 'mce|edac' || echo 'no mce/edac lines found'"
}

check_mem_stress() {
    log "메모리 부하 테스트 (${MEM_STRESS_DURATION}s, ${MEM_STRESS_PERCENT}%) 중..."
    if ! have stress-ng; then
        record "memory" "stress_test" "skipped" "" "WARN" "stress-ng 미설치"
        return
    fi
    run_and_log "mem_stress.log" stress-ng --vm 2 --vm-bytes "${MEM_STRESS_PERCENT}%" \
        --timeout "${MEM_STRESS_DURATION}s" --metrics-brief --verify

    if grep -q "successful run completed" "${RAWDIR}/mem_stress.log" 2>/dev/null; then
        record "memory" "stress_test" "completed" "" "PASS" "--verify 옵션으로 메모리 비교검증 포함"
    else
        record "memory" "stress_test" "failed_or_incomplete" "" "FAIL" "raw 로그(mem_stress.log) 확인 필요, 비트 오류/OOM 의심"
    fi
}

# =========================================================================
# 6. 스토리지
# =========================================================================
check_storage_info() {
    log "스토리지 정보 수집 중..."
    run_and_log "storage_lsblk.log" lsblk -o NAME,SIZE,MODEL,ROTA,TYPE,MOUNTPOINT

    for dev in /dev/sd? /dev/nvme?n1; do
        [[ -e "$dev" ]] || continue
        local base; base=$(basename "$dev")
        if have smartctl; then
            run_and_log "storage_smart_${base}.log" smartctl -a "$dev"
            local health
            health=$(smartctl -H "$dev" 2>/dev/null | grep -iE "overall-health|SMART overall-health")
            if echo "$health" | grep -qi "PASSED"; then
                record "storage" "smart_health_${base}" "PASSED" "" "PASS" ""
            elif [[ -n "$health" ]]; then
                record "storage" "smart_health_${base}" "$health" "" "FAIL" "SMART 헬스 이상, 즉시 확인 필요"
            else
                record "storage" "smart_health_${base}" "unknown" "" "WARN" "smartctl 결과 파싱 실패, raw 로그 확인"
            fi
        fi
    done

    if have nvme; then
        for dev in /dev/nvme?; do
            [[ -e "$dev" ]] || continue
            run_and_log "storage_nvme_smartlog_$(basename "$dev").log" nvme smart-log "$dev"
        done
    fi
}

check_storage_fio() {
    log "fio 성능 테스트 중... (대상: ${FIO_TESTDIR})"
    if ! have fio; then
        record "storage" "fio_test" "skipped" "" "WARN" "fio 미설치"
        return
    fi
    mkdir -p "$FIO_TESTDIR"
    run_and_log "storage_fio.log" fio --name=accept_randrw --directory="$FIO_TESTDIR" \
        --rw=randrw --bs=4k --iodepth=32 --numjobs=4 --size="$FIO_SIZE" \
        --runtime="$FIO_RUNTIME" --time_based --group_reporting

    local read_iops write_iops
    read_iops=$(grep -A1 "read:" "${RAWDIR}/storage_fio.log" | grep "IOPS=" | head -1 | sed -E 's/.*IOPS=([0-9.k]+).*/\1/')
    write_iops=$(grep -A1 "write:" "${RAWDIR}/storage_fio.log" | grep "IOPS=" | head -1 | sed -E 's/.*IOPS=([0-9.k]+).*/\1/')

    # 절대 임계값이 없으므로 INFO로 기록 -> aggregate 스크립트가 노드간 편차로 이상치 판단
    record "storage" "fio_randread_iops" "${read_iops:-unknown}" "IOPS" "INFO" "노드간 편차는 aggregate 리포트 참고"
    record "storage" "fio_randwrite_iops" "${write_iops:-unknown}" "IOPS" "INFO" "노드간 편차는 aggregate 리포트 참고"

    # 테스트 파일 정리
    rm -f "${FIO_TESTDIR}"/accept_randrw.* 2>/dev/null || true
}

# =========================================================================
# 7. NIC
# =========================================================================
check_nic_info() {
    log "NIC 정보 수집 중..."
    local ifaces
    ifaces=$(ls /sys/class/net | grep -vE '^(lo|docker|veth|cni|cilium|virbr)' )

    for ifc in $ifaces; do
        run_and_log "nic_${ifc}_ethtool.log" ethtool "$ifc"
        run_and_log "nic_${ifc}_ethtool_i.log" ethtool -i "$ifc"
        run_and_log "nic_${ifc}_ethtool_stats.log" ethtool -S "$ifc"
        run_and_log "nic_${ifc}_ethtool_offload.log" ethtool -k "$ifc"
        run_and_log "nic_${ifc}_ethtool_channels.log" ethtool -l "$ifc"

        local speed link driver
        speed=$(ethtool "$ifc" 2>/dev/null | awk -F: '/Speed/{gsub(/[^0-9]/,"",$2); print $2}')
        link=$(ethtool "$ifc" 2>/dev/null | awk -F: '/Link detected/{gsub(/^ +/,"",$2); print $2}')
        driver=$(ethtool -i "$ifc" 2>/dev/null | awk -F: '/^driver/{gsub(/^ +/,"",$2); print $2}')

        record "nic" "${ifc}_link_detected" "${link:-unknown}" "" \
            "$([[ "$link" == "yes" ]] && echo PASS || echo WARN)" \
            "$([[ "$link" == "yes" ]] || echo '링크 다운 상태 - 케이블/스위치 포트 확인')"

        if [[ -n "${speed:-}" ]]; then
            if (( speed >= THRESH_NIC_MIN_SPEED_MBPS )); then
                record "nic" "${ifc}_speed" "$speed" "Mb/s" "PASS" ""
            else
                record "nic" "${ifc}_speed" "$speed" "Mb/s" "WARN" "기대 최소 속도(${THRESH_NIC_MIN_SPEED_MBPS}Mb/s) 미만 - 스위치 포트 협상 설정 확인"
            fi
        else
            record "nic" "${ifc}_speed" "unknown" "Mb/s" "WARN" "속도 조회 실패(링크다운 등)"
        fi

        record "nic" "${ifc}_driver" "${driver:-unknown}" "" "INFO" ""

        # 에러/드랍 카운터 합산 체크
        local errsum
        errsum=$(ethtool -S "$ifc" 2>/dev/null | awk -F: '/err|drop|discard/I{gsub(/[^0-9]/,"",$2); if($2+0>0) sum+=$2} END{print sum+0}')
        if [[ "$errsum" == "0" ]]; then
            record "nic" "${ifc}_error_counters" "0" "count" "PASS" ""
        else
            record "nic" "${ifc}_error_counters" "$errsum" "count" "FAIL" "raw 로그(nic_${ifc}_ethtool_stats.log)에서 어떤 카운터인지 확인 필요"
        fi
    done

    # LLDP로 실제 연결된 스위치/포트 확인 (있는 경우)
    if have lldpctl; then
        run_and_log "nic_lldp.log" lldpctl
        record "nic" "lldp_neighbors" "collected" "" "INFO" "raw 로그와 배선도(스위치/포트) 대조 필요"
    else
        record "nic" "lldp_neighbors" "not_checked" "" "WARN" "lldpd/lldpad 미설치 - 배선 오결선 확인 불가"
    fi
}

check_nic_iperf() {
    if [[ -z "$IPERF_TARGET" ]]; then
        record "nic" "iperf3_throughput" "skipped" "" "WARN" "IPERF_TARGET 환경변수 미지정 (상대 서버 IP 필요)"
        return
    fi
    log "iperf3 처리량 테스트 -> ${IPERF_TARGET} (${IPERF_DURATION}s) 중..."
    if ! have iperf3; then
        record "nic" "iperf3_throughput" "skipped" "" "WARN" "iperf3 미설치"
        return
    fi
    run_and_log "nic_iperf3.log" iperf3 -c "$IPERF_TARGET" -t "$IPERF_DURATION" -J

    local gbps
    gbps=$(grep -o '"bits_per_second":[0-9.]*' "${RAWDIR}/nic_iperf3.log" | tail -1 | cut -d: -f2)
    if [[ -n "$gbps" ]]; then
        local mbps; mbps=$(awk -v b="$gbps" 'BEGIN{printf "%.0f", b/1000000}')
        record "nic" "iperf3_throughput" "$mbps" "Mb/s" "INFO" "이론 링크속도 대비/노드간 편차는 aggregate 리포트 참고"
    else
        record "nic" "iperf3_throughput" "unknown" "Mb/s" "WARN" "결과 파싱 실패, raw 로그 확인"
    fi
}

# =========================================================================
# 8. OS / 커널 기본 상태
# =========================================================================
check_os_kernel() {
    log "OS/커널 상태 점검 중..."
    run_and_log "os_uname.log" uname -a
    run_and_log "os_sysctl_all.log" sysctl -a

    local kver; kver=$(uname -r)
    record "os" "kernel_version" "$kver" "" "INFO" "K8s/CNI(Cilium) 호환 매트릭스와 대조"

    # swap
    local swaptotal
    swaptotal=$(free -m | awk '/Swap:/{print $2}')
    if [[ "$THRESH_SWAP_MUST_BE_ZERO" == "1" ]]; then
        if [[ "$swaptotal" == "0" ]]; then
            record "os" "swap_total" "0" "MB" "PASS" ""
        else
            record "os" "swap_total" "$swaptotal" "MB" "FAIL" "K8s 노드는 swap off 필요 (swapoff -a, fstab 수정)"
        fi
    fi

    # 필수 커널 모듈
    local mods=(overlay br_netfilter)
    for m in "${mods[@]}"; do
        if lsmod | grep -q "^${m}"; then
            record "os" "kmod_${m}" "loaded" "" "PASS" ""
        else
            record "os" "kmod_${m}" "not_loaded" "" "FAIL" "modprobe ${m} 필요 (K8s 필수 모듈)"
        fi
    done

    # 필수 sysctl (README의 baseline 값과 비교하고 싶으면 여기 임계값 추가)
    local ip_forward
    ip_forward=$(sysctl -n net.ipv4.ip_forward 2>/dev/null)
    record "os" "net.ipv4.ip_forward" "${ip_forward:-unknown}" "" \
        "$([[ "$ip_forward" == "1" ]] && echo PASS || echo FAIL)" \
        "$([[ "$ip_forward" == "1" ]] || echo 'K8s 필수: sysctl -w net.ipv4.ip_forward=1')"

    local max_map
    max_map=$(sysctl -n vm.max_map_count 2>/dev/null)
    record "os" "vm.max_map_count" "${max_map:-unknown}" "" \
        "$([[ "${max_map:-0}" -ge 262144 ]] 2>/dev/null && echo PASS || echo WARN)" \
        "권장 262144 이상 (README 참고)"

    # SELinux/AppArmor 상태
    if have getenforce; then
        record "os" "selinux_status" "$(getenforce)" "" "INFO" "설계된 정책과 일치하는지 확인"
    fi
    if have aa-status; then
        run_and_log "os_apparmor.log" aa-status
        record "os" "apparmor_status" "collected" "" "INFO" "raw 로그 확인"
    fi

    # ulimit
    record "os" "ulimit_nofile" "$(ulimit -n)" "" "INFO" "권장 baseline과 비교 (README)"
    record "os" "ulimit_nproc" "$(ulimit -u)" "" "INFO" "권장 baseline과 비교 (README)"
}

# =========================================================================
# 9. 시간 동기화
# =========================================================================
check_time_sync() {
    log "시간 동기화 상태 확인 중..."
    if have chronyc; then
        run_and_log "time_chrony.log" chronyc tracking
        local offset
        offset=$(chronyc tracking 2>/dev/null | awk -F: '/System time/{gsub(/[^0-9.]/,"",$2); print $2}')
        if [[ -n "$offset" ]]; then
            # 100ms 이상 벗어나면 WARN
            if awk -v o="$offset" 'BEGIN{exit !(o<0.1)}'; then
                record "time" "chrony_offset_sec" "$offset" "sec" "PASS" ""
            else
                record "time" "chrony_offset_sec" "$offset" "sec" "WARN" "오프셋 100ms 이상, NTP 서버 접근성 확인"
            fi
        else
            record "time" "chrony_offset_sec" "unknown" "sec" "WARN" "raw 로그(time_chrony.log) 확인"
        fi
    else
        record "time" "chrony_status" "not_checked" "" "WARN" "chrony 미설치 - 다른 NTP 클라이언트 확인 필요"
    fi
}

# =========================================================================
# 10. main
# =========================================================================
main() {
    log "노드 인수 점검 시작: ${NODE_NAME} -> ${OUTDIR}"

    check_prereqs

    [[ "$RUN_INVENTORY"    == "1" ]] && check_inventory
    [[ "$RUN_CPU_INFO"     == "1" ]] && check_cpu_info
    [[ "$RUN_CPU_STRESS"   == "1" ]] && check_cpu_stress
    [[ "$RUN_MEM_INFO"     == "1" ]] && check_mem_info
    [[ "$RUN_MEM_STRESS"   == "1" ]] && check_mem_stress
    [[ "$RUN_STORAGE_INFO" == "1" ]] && check_storage_info
    [[ "$RUN_STORAGE_FIO"  == "1" ]] && check_storage_fio
    [[ "$RUN_NIC_INFO"     == "1" ]] && check_nic_info
    [[ "$RUN_NIC_IPERF"    == "1" ]] && check_nic_iperf
    [[ "$RUN_OS_KERNEL"    == "1" ]] && check_os_kernel
    [[ "$RUN_TIME_SYNC"    == "1" ]] && check_time_sync

    local fail warn
    fail=$(awk -F'|' '$5=="FAIL"' "$SUMMARY_CSV" | wc -l)
    warn=$(awk -F'|' '$5=="WARN"' "$SUMMARY_CSV" | wc -l)

    log "점검 완료. FAIL=${fail}, WARN=${warn}"
    log "결과 디렉터리: ${OUTDIR}"
    log "요약 파일: ${SUMMARY_CSV}"
    echo
    echo "=== FAIL 항목 ==="
    awk -F'|' '$5=="FAIL"{print}' "$SUMMARY_CSV"
    echo
    echo "=== WARN 항목 ==="
    awk -F'|' '$5=="WARN"{print}' "$SUMMARY_CSV"
}

main "$@"
profile
engineer

0개의 댓글