You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MegaRAID Nagios监控插件CLI运行正常但LibreNMS返回异常排查

MegaRAID Nagios插件LibreNMS调用异常排查

故障现象

插件原始代码如下:

#!/usr/bin/env python3
import paramiko
import os.path
import sys
OK = 0
WARNING = 1
CRITICAL = 2
DEPENDENT = 3
UNKNOWN = 4
active = str("Active")
online = str("Online")
optimal = str("Optimal")
k = str("OK")
degrade = str("Degraded")
fail = str("Failed")
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(
        hostname='<hostname>',
        username='<service account>', 
        key_filename=os.path.join(os.path.expanduser('~'), ".ssh", "id_rsa.pub")
        )
stdin,stdout,stderr = client.exec_command("sudo /opt/MegaRAID/MegaCli/MegaCli64 -ShowSummary -a0")
check = str(stdout.read().decode('ascii'))
client.close()
OK_STR = str("RAID is OK!")
WARN_STR = str("Warning! Something is wrong with the RAID!")
CRIT_STR = str("CRITICAL! THE RAID IS BROKEN")
UNK_STR = str("Uh oh! Something ain't right?")
print(check)
if (degrade) in (check):
    print(WARN_STR) and sys.exit(WARNING)
elif (fail) in (check):
    print(CRIT_STR) and sys.exit(CRITICAL)
elif str('Exit Code: 0x00') in (check):
    print(OK_STR) and sys.exit(OK) 
else:
    sys.exit(UNKNOWN) and print(UNK_STR)

已知运行表现:

  • 普通用户在CLI终端手动执行时,输出内容、退出码均符合设计预期,通过echo $?验证退出码逻辑正确
  • LibreNMS前端调用该插件时,无法捕获任何stdout输出,插件固定返回退出码1,与终端运行表现完全不一致

根因定位

故障由4个叠加问题导致,终端运行正常是因为个人用户环境的配置兜底了代码错误:

  1. SSH密钥路径配置错误
    代码中key_filename指定的是id_rsa.pub公钥文件,SSH公钥认证本地必须读取私钥完成认证,公钥仅需要部署在远端服务器。终端运行时,本地SSH Agent会自动缓存已加载的私钥,自动完成认证,代码里配置的错误公钥路径实际未生效;而LibreNMS运行插件的用户为独立服务用户(通常为librenms),无SSH Agent缓存,读取公钥做认证直接失败。
  2. 无异常捕获逻辑
    代码未对SSH连接、命令执行阶段的任何异常做捕获,一旦出现认证失败、权限不足、网络波动、目录不可写等问题,Python进程会直接抛出traceback到stderr,以退出码1终止,正好匹配LibreNMS侧看到的固定返回1、无stdout输出的现象。
  3. 运行环境权限不匹配
    LibreNMS的服务用户默认家目录权限、.ssh目录配置与个人登录用户不同:一是没有配置远端主机的host key记录,AutoAddPolicy写入known_hosts时可能因目录不存在、权限不足报错;二是SSH连到远端后执行sudo命令,默认需要tty终端,paramiko的exec_command默认不分配tty,会直接触发sudo权限错误,且代码未读取stderr内容,完全无法感知该错误。
  4. 分支逻辑存在短路bug
    代码中所有状态分支都使用print(xxx) and sys.exit(xxx)写法,Python中print()函数返回值为None(布尔假),and运算遇到假值会直接短路,后续sys.exit逻辑存在失效风险;最后else分支将sys.exit放在and前面,执行退出后后续print完全不会触发,直接导致状态字符串丢失。

修复方案

按以下步骤逐一修正即可:

  • 修正SSH密钥配置:将key_filename路径改为私钥路径,即把路径末尾的id_rsa.pub改为id_rsa;给librenms用户配置独立的.ssh目录,目录权限设为700,私钥文件权限设为600,属主全部为librenms用户,确保进程可正常读取私钥、写入known_hosts。
  • 补全全链路异常捕获:将SSH连接、命令执行逻辑全部包裹在try-except块中,所有错误信息统一打印到stdout后返回UNKNOWN退出码,同时读取命令执行的stderr内容,与stdout合并做状态判断。
  • 修正分支逻辑:拆分所有print + sys.exit的and写法,先打印状态字符串,再执行退出操作,避免短路运算导致逻辑失效、输出丢失。
  • 配置远端免密与sudo权限:将librenms用户的公钥部署到被监控节点对应服务账号的~/.ssh/authorized_keys中,文件权限设为600;在被监控节点的sudoers配置中,给对应服务账号添加MegaCli命令的NOPASSWD权限,同时添加配置Defaults:<对应服务账号名> !requiretty,关闭sudo的tty校验。

修复后参考代码

#!/usr/bin/env python3
import paramiko
import os.path
import sys
OK = 0
WARNING = 1
CRITICAL = 2
DEPENDENT = 3
UNKNOWN = 4
degrade = "Degraded"
fail = "Failed"
OK_STR = "RAID is OK!"
WARN_STR = "Warning! Something is wrong with the RAID!"
CRIT_STR = "CRITICAL! THE RAID IS BROKEN"
UNK_STR = "Uh oh! Something ain't right?"

def exit_with_code(code, msg):
    print(msg)
    sys.exit(code)

try:
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    key_path = os.path.join(os.path.expanduser('~'), ".ssh", "id_rsa")
    client.connect(
            hostname='<hostname>',
            username='<service account>', 
            key_filename=key_path,
            timeout=10
            )
    stdin,stdout,stderr = client.exec_command("sudo /opt/MegaRAID/MegaCli/MegaCli64 -ShowSummary -a0", get_pty=True)
    check_out = stdout.read().decode('ascii', errors='ignore')
    check_err = stderr.read().decode('ascii', errors='ignore')
    client.close()
    check = check_out + check_err
except Exception as e:
    exit_with_code(UNKNOWN, f"{UNK_STR} SSH connect failed: {str(e)}")

print(check)
if degrade in check:
    exit_with_code(WARNING, WARN_STR)
elif fail in check:
    exit_with_code(CRITICAL, CRIT_STR)
elif 'Exit Code: 0x00' in check:
    exit_with_code(OK, OK_STR)
else:
    exit_with_code(UNKNOWN, UNK_STR)

内容的提问来源于stack exchange,提问作者Alex Noel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 11:30:43