#!/bin/bash
# 综合服务器硬件信息查询脚本
# 功能：显示服务器型号、SN、CPU、内存插槽、磁盘、网卡（含IP和LLDP邻居）信息

# set -euo pipefail

# 颜色定义（可选，用于美化输出）
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color

# 检查是否以 root 运行（部分命令需要）
if [[ $EUID -ne 0 ]]; then
    echo -e "${YELLOW}提示：部分信息（如内存插槽）需要 root 权限，将以 sudo 执行相关命令。${NC}"
    SUDO="sudo"
else
    SUDO=""
fi

# 打印分隔线
print_separator() {
    echo "======================================================================"
}

# 1. 服务器型号和SN
print_cpu() {
    echo -e "${GREEN}服务器信息 $(date +%Y%m%d_%H:%M:%S) ${NC}"
    hostname=$(hostname)
    product_name=$(cat /sys/class/dmi/id/product_name 2>/dev/null || echo "unknown")
    product_serial=$(cat /sys/class/dmi/id/product_serial 2>/dev/null || echo "unknown")
    echo "主机名: $hostname"
    echo "型号SN: $product_name SN:$product_serial"

    # 2. CPU信息
    print_separator
    echo -e "${GREEN}CPU 信息 $(date +%Y%m%d_%H:%M:%S) ${NC}"
    if command -v lscpu >/dev/null 2>&1; then
        cpu_model=$(lscpu | grep "Model name" | cut -d: -f2 | sed 's/^[[:space:]]*//')
        sockets=$(lscpu | grep "Socket(s)" | cut -d: -f2 | sed 's/^[[:space:]]*//')
        cores_per_socket=$(lscpu | grep "Core(s) per socket" | cut -d: -f2 | sed 's/^[[:space:]]*//')
        threads_per_core=$(lscpu | grep "Thread(s) per core" | cut -d: -f2 | sed 's/^[[:space:]]*//')
        echo "处理器: $sockets x $cpu_model"
        echo "核心数: $cores_per_socket"
        echo "线程数: $threads_per_core"
        echo "总线程: $((sockets * cores_per_socket * threads_per_core))"
    else
        echo -e "${RED}未找到 lscpu 命令，无法获取 CPU 信息。${NC}"
    fi
}

# 3. 内存插槽布局
print_ram() {
    echo -e "${GREEN}内存信息 $(date +%Y%m%d_%H:%M:%S) ${NC}"
    if command -v dmidecode >/dev/null 2>&1; then
        $SUDO dmidecode -t 17 2>/dev/null | awk '
        BEGIN {
            printf "┌────────────┬──────────┬────────────┬──────────┐\n"
            printf "│ 插槽位置   │   容量   │   类型     │   频率   │\n"
            printf "├────────────┼──────────┼────────────┼──────────┤\n"
        }
        /Locator:/ && !/Bank/ { locator = $NF }
        /Size:/ && $2 ~ /^[0-9]+$/ && $2 != "" { size = $2 " GB" }
        /Type:/ && $2 != "Unknown" { type = $2 }
        /Speed:/ {
            if (match($0, /[0-9]+/)) {
                speed = substr($0, RSTART, RLENGTH) " MHz"
            }
        }
        NF == 0 && locator && size {
            printf "│ %-10s │ %-8s │ %-10s │ %-8s │\n", locator, size, type, speed
            locator = ""; size = ""; type = ""; speed = ""
        }
        END {
            if (locator && size) {
                printf "│ %-10s │ %-8s │ %-10s │ %-8s │\n", locator, size, type, speed
            }
            print "└────────────┴──────────┴────────────┴──────────┘"
        }'
    else
        echo -e "${RED}未找到 dmidecode 命令，无法获取内存信息。${NC}"
    fi
}
# 4. 磁盘信息
print_disk(){
    echo -e "${GREEN}磁盘信息 $(date +%Y%m%d_%H:%M:%S) ${NC}"
    if command -v lsblk >/dev/null 2>&1; then
        echo "以下为物理磁盘及分区概况："
        lsblk -o NAME,SIZE,TRAN,TYPE,MODEL,SERIAL,MOUNTPOINT,FSTYPE,PHY-SEC,LOG-SEC 2>/dev/null | grep -E "TYPE|disk|part|lvm"
    else
        echo -e "${RED}未找到 lsblk 命令，无法获取磁盘信息。${NC}"
    fi
}

# 5. 物理网卡详细信息（含LLDP邻居）
print_nic() {
    echo -e "${GREEN}物理网信息卡 $(date +%Y%m%d_%H:%M:%S) ${NC}"

    # 确保 lldpd 服务运行并等待邻居信息收集
    if ! systemctl is-active --quiet lldpd 2>/dev/null; then
        echo "lldpd未启动，启动 lldpd 服务..."
        systemctl start lldpd 2>/dev/null || true
        sleep 5   # 等待服务启动并收集邻居信息
    fi

    # 获取 LLDP 邻居信息并构建映射表（接口名 -> 邻居描述）
    declare -A lldp_map
    if command -v lldpcli >/dev/null 2>&1 && command -v jq >/dev/null 2>&1; then
        # 尝试获取 JSON 输出，忽略错误
        lldp_json=$(lldpcli show neighbors summary -f json 2>/dev/null)
        if [ -n "$lldp_json" ] && echo "$lldp_json" | jq -e . >/dev/null 2>&1; then
            # 解析 JSON，格式：接口名 --> 邻居@端口
            while IFS='' read -r line; do
                # 示例 line: "eth0-->switch1@GigabitEthernet1/0/1"
                [[ -n "$line" ]] && {
                    iface="${line%%-->*}"
                    neighbor="${line#*-->}"
                    lldp_map["$iface"]="$neighbor"
                }
            done < <(echo "$lldp_json" | jq -r '[.lldp.interface] | flatten[] | to_entries[] | "\(.key)-->\(.value.chassis | keys[0])@\(.value.port.id.value)"')
        fi
    else
        echo "警告: 未安装 lldpcli 或 jq，无法获取 LLDP 邻居信息" >&2
    fi

    # 输出网卡信息表格，包含 LLDP 邻居列
    {
        # 表头（新增一列 LLDP 邻居）
        printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" \
            "网卡名称" "物理MAC" "当前MAC" "状态" "速率" "PCI地址" "设备描述" "LLDP邻居"
        printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" \
            "---------" "--------" "--------" "----" "----" "-------" "--------" "---------"

        lspci -D | grep Ethernet | while read pci_id line; do
            iface=$(ls /sys/bus/pci/devices/"$pci_id"/net/ 2>/dev/null | head -n1)
            [ -n "$iface" ] && {
                # 获取 MAC 地址
                perm_mac=$(ethtool -P "$iface" 2>/dev/null | awk '/Permanent address:/{print $3}')
                if [ -z "$perm_mac" ] || [ "$perm_mac" = "00:00:00:00:00:00" ]; then
                    current_mac=$(cat "/sys/class/net/$iface/address" 2>/dev/null)
                    perm_mac="$current_mac"
                else
                    current_mac=$(cat "/sys/class/net/$iface/address" 2>/dev/null)
                fi

                # 状态和速率
                state=$(cat "/sys/class/net/$iface/operstate" 2>/dev/null || echo "unknown")
                speed=$(cat "/sys/class/net/$iface/speed" 2>/dev/null)
                [ -z "$speed" ] || [ "$speed" = "-1" ] && speed="N/A" || speed="${speed}M"

                # 获取 LLDP 邻居（如果存在）
                lldp_neighbor="${lldp_map[$iface]:-未获取}"

                # 输出一行，新增 LLDP 列
                printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" \
                    "$iface" \
                    "${perm_mac:-未获取}" \
                    "${current_mac:-未获取}" \
                    "$state" \
                    "$speed" \
                    "$pci_id" \
                    "${line##*: }" \
                    "$lldp_neighbor"
            }
        done
    } | column -t -s $'\t'
}

print_info() {
    echo "脚本开始执行 $(date +%Y%m%d_%H:%M:%S)"
    print_separator
    print_cpu
    print_separator
    print_ram
    print_separator
    print_disk
    print_separator
    print_nic
    print_separator
    echo "脚本执行完成 $(date +%Y%m%d_%H:%M:%S)"
}

print_info | tee -a /tmp/server_info_$(cat /sys/class/dmi/id/product_serial 2>/dev/null || echo "unknown").txt


