使用 Nagios 检查您的 Zypper

作者:Mitch Frazier

如果您使用 Nagios 监控您的系统,并在远程服务器上运行 openSUSE,那么这里提供的 bash 脚本将检查在线更新,并且设计为由 Nagios 运行,以便结果将显示在 Nagios 服务详情页面上。

这个脚本非常简单,因为它只是解析了 zypper 命令的输出。更复杂的解决方案可能会直接与 libzypp 交互,libzypp 是提供zypper功能的库。当然,这是不可能用 bash 实现的。快速浏览 libzypp 文档 后,似乎目前唯一可行的选择是 C++。

一个 Nagios 插件脚本通过两种方式输出信息

  • 它将一个简短的状态消息(一行文本)写入标准输出,Nagios 会在服务详情页面上显示该消息。
  • 它设置其退出状态,以向 Nagios 指示服务的状态
    • 0 如果服务状态为“OK”
    • 1 如果服务状态为“WARNING”
    • 2 如果服务状态为“CRITICAL”

如果您运行zypper从命令行,您将看到类似于以下内容的输出

  $ sudo zypper list-updates
  * Reading repository 'openSUSE-10.3-Updates' cache
  * Reading repository 'Main Repository (OSS)' cache
  * Reading repository 'Main Repository (NON-OSS)' cache
  * Reading repository 'Packman Repository' cache
  * Reading installed packages [100%]

  Repository:           | Name             | Version | Category | Status
  ----------------------+------------------+---------+----------+-------
  openSUSE-10.3-Updates | dhcpcd           | 5390-0  | optional | Needed
  openSUSE-10.3-Updates | openmotif22-libs | 4540-0  | optional | Needed
  openSUSE-10.3-Updates | ruby             | 5483-0  | security | Needed

该脚本查找“----”行,然后使用“|”作为分隔符,将后续行拆分为字段。然后,使用这些数据构建输出文本并设置状态。如果没有可用的更新,状态设置为 0;如果有可用的更新,状态设置为 1;如果任何更新与安全相关,则状态设置为 2。

运行zypper可能需要一段时间,因此您可以在测试模式下运行脚本以获得一些即时满足感。在测试模式下,它包含一些测试zypper它解析的输出

  $ env TEST=1 sh check_zypper
  3 Updates needed:  package-1(required/Needed), package-3(required/Needed), package-4(required/Needed) (1 Optional update)
  $ echo $?
  1
输出文本是 Nagios 将在服务详情页面上显示的内容。由于脚本退出时的状态为 1(表示有可用的更新),Nagios 会将服务状态设置为“WARNING”。

脚本如下

#!/bin/bash

max_packages=3
TEST=${TEST:-0}
VERBOSE=${VERBOSE:-0}
nl='
'

# Read list of packages that need updating according to zypper.
OIFS=$IFS
IFS=$nl
if [[ $TEST -eq 0 ]]; then
    zypper_lines=($(/usr/bin/sudo /usr/bin/zypper list-updates 2>&1))
    stat=$?
    if [[ $stat -ne 0 ]]; then
        echo "Zypper exited with code: $stat"
        exit 1
    fi
else
    zypper_lines=(
        "test line 1"
        "test line 2"
        "------------"
        "Main Repository | package-1 | 50-0  | required | Needed"
        "Main Repository | package-2 | 48-0  | optional | Needed"
        "Test Repository | package-3 | 40-0  | required | Needed"
        "Test Repository | package-4 | 40-0  | required | Needed"
        )
fi
IFS=$OIFS

# Count the number of optional and non-optional packages.
npackages=0
noptional_packages=0
nsecurity_packages=0
in_packages=0

for ix in ${!zypper_lines[*]}
do
    line=${zypper_lines[$ix]}
    if [[ $VERBOSE -ne 0 ]]; then echo $line; fi

    if [[ $in_packages -eq 0 ]]; then
        if [[ $line =~ ^---- ]]; then in_packages=1; fi
    else
        IFS='|'
        set -- $line
        IFS=$OIFS
        if [[ $# -eq 5 ]]; then
            trepo=$(echo $1)
            tpackage=$(echo $2)
            tversion=$(echo $3)
            tcategory=$(echo $4)
            tstatus=$(echo $5)
            
            if [[ "$tcategory" == 'optional' ]]; then
                let noptional_packages++
            else
                repo[$npackages]=$trepo
                package[$npackages]=$tpackage
                version[$npackages]=$tversion
                category[$npackages]=$tcategory
                status[$npackages]=$tstatus
                let npackages++
                if [[ "$tcategory" == 'security' ]]; then let nsecurity_packages++; fi
            fi
        fi
    fi
done
        
# Output summary.
if [[ $npackages -ne 1 ]]; then s1='s'; else s1='' ; fi
if [[ $noptional_packages -ne 1 ]]; then s2='s'; else s2='' ; fi

n=0
for ix in ${!package[*]}
do
    t[$n]="${package[$ix]}(${category[$ix]}/${status[$ix]})"
    let n++
    if [[ ix -eq $max_packages ]]; then break; fi
done

if [[ ${#package[*]} -gt $max_packages ]]; then t[$n]="..."; fi

if [[ ${#t[*]} -gt 0 ]]; then
    if [[ $npackages -gt 0 ]]; then
        echo -n "$npackages Update$s1 needed: "
        first=1
        for ix in ${!t[*]}
        do
            if [[ $first -eq 1 ]]; then
                echo -n ' '
                first=0
            else
                echo -n ', '
            fi
            echo -n "${t[$ix]}"
        done
        if [[ $noptional_packages -gt 0 ]]; then
            echo -n " ($noptional_packages Optional update$s2)"
        fi
    else
        echo -n "$noptional_packages Optional update$s2"
    fi
    echo
    stat=1
    if [[ $nsecurity_packages -gt 0 ]]; then stat=2; fi
else
    echo "OK, no package updates available"
    stat=0
fi

exit $stat

您需要做一些事情才能将脚本与 Nagios 集成。首先设置sudo以允许 Nagios 用户运行zypper。使用visudo将此添加到sudoers文件

   nagios    ALL=(ALL) NOPASSWD:/usr/bin/zypper
其次,因为运行zypper需要一段时间,您需要在 Nagios 配置文件中增加 service-run-time/etc/nagios/nagios.cfg:
  service_check_timeout=600
最后,当然,您需要设置 Nagios 来运行该脚本
define command{
        command_name    check-zypper
        command_line    /path/to/check_zypper
        }

...

define service{
        use                             generic-service
        host_name                       localhost
        service_description             Updates
        is_volatile                     0
        check_period                    24x7
        max_check_attempts              1
        normal_check_interval           600
        retry_check_interval            60
        contact_groups                  admins
        notifications_enabled           0
        notification_options            c
        notification_interval           960
        notification_period             24x7
        check_command                   check-zypper
        }
除此之外,这会告诉 Nagios 每 10 小时运行一次 check_zypper,如果失败,则在一小时后重试。

附:是的,标题有点“廉价幽默”,但话说回来,我不是决定将我的包管理器称为zypper.

Mitch Frazier 是 Emerson Electric Co. 的一名嵌入式系统程序员。自 2000 年代初以来,Mitch 一直是Linux Journal 的贡献者和朋友。

加载 Disqus 评论