为什么 systemctl 在 NRPE 检查中没有 return 值?

Why systemctl doesn't return a value in an NRPE check?

我写的 NRPE 检查有问题。

这是一个简单的 shell 脚本,运行 "systemctl is-active [service_name]" 和 return 对我们的 Thruk 的价值。

当我 运行 直接使用用户 nrpe 的脚本时,它有效:

-bash-4.2$ /usr/lib64/nagios/plugins/check_service_active.sh --service dynflowd
dynflowd
Service dynflowd démarré

但是当我在本地使用 NRPE 运行 它时,它告诉我服务已停止:

-bash-4.2$ ./check_nrpe -H 127.0.0.1 -c check_service_active -a 'dynflowd'
dynflowd
Service dynflowd arrêté

经过多次测试,我发现它与systemctl命令有关。 当我用 "echo" 等另一个命令替换 systemctl 时,它起作用了。

所以我认为 NRPE 和 systemctl 有一些东西,但我找不到什么? 我在 Google.

上找不到任何相关信息

所以我来了!

预先感谢您的回复,如果我的理解不够,请见谅。

这是我的脚本:

#!/bin/sh
#
# Script d'interrogation d'un service via systemctl

# Nagios return codes
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3
STATE_DEPENDENT=4

#Recuperation des parametres
while test -n ""; do
        case "" in
                --service)
                        SERV=
                        shift
                        ;;

                -u)
                        print_usage
                        exit $STATE_OK
                        ;;
        esac
        shift
done

STAT=$(systemctl is-active $SERV)

if [[ $STAT  == "active" ]]
then
        echo "Service $SERV démarré"
        exit $STATE_OK
else
        echo "Service $SERV arrêté"
        exit $STATE_CRITICAL
fi

好的,类似于 cron 工作,可能 是 NRPE(服务器)运行 与您的 [=78] 具有不同的环境=],并且那个独特的环境在某种程度上不正确 运行ning systemctl

查看此内容的一种简单方法是修改:

STAT=$(systemctl is-active $SERV)

暂时在线,以便您了解发生了什么。更改脚本,使该行现在变为:

(
    echo ==== $(date) ==== ${SERV}
    systemctl is-active $SERV
) >> /tmp/paxdebug.dynflowd 2>&1
STAT=$(systemctl is-active $SERV)

这将与 运行 获取状态的脚本一样,将一些有用的信息写入 /tmp/paxdebug.dynflowd 文件,然后您可以检查该文件以确切了解 NRPE 中发生了什么-启动脚本实例。

希望它会说一些像 Cannot find systemctl 这样简单的东西(表示路径问题)但是,无论它给你什么,它应该有助于找出问题的确切原因。


更新 1:根据您的评论,尝试 运行 systemctl 结果:

systemctl: command not found

几乎可以肯定是因为路径错误。您可以通过将以下行添加到我发布的调试代码中来检查路径:

echo "PATH is [$PATH]"

要修复它,请修改脚本中的路径以包含 /usr/bin(假设这是 systemctl 所在的位置)或仅 运行 绝对路径(在调试和原始区域):

/usr/bin/systemctl is-active ${SERV}
STAT=$(/usr/bin/systemctl is-active ${SERV})

更新 2:根据您的意见,在使用绝对路径的情况下,您现在得到:

/usr/lib64/nagios/plugins/check_service_active.sh: line 32:
    /usr/bin/systemctl: Permission denied

可能 是 NRPE 运行 低权限级别,或者作为不同的用户提供安全性免受攻击。考虑到 systemd 对系统的 运行 的重要性,允许不受限制地访问它是不明智的。

所以,和之前的更新类似,在调试区添加如下内容:

/bin/ls -al /usr/bin/systemctl # Check "ls" is in this directory first.
/usr/bin/id                    # Ditto for "id".

第一行将为您提供权限,第二行将为您提供用户详细信息。到那时,它就变成了弄清楚如何在不违反安全性的情况下 运行 systemctl 的练习。

如果事实证明这是权限或用户问题,一种可能性是提供一个安全性良好的setuid脚本,该脚本将由(和因此 运行 as) 允许 运行 systemctl 的用户。不过我真的意思是有保障,既然不想开坑:

# SysCtlIsActive.sh: only allows certain services to be queried.

# Limit to these ones (white-space separated).

allowed="dynflowd"

# If not allowed, reject with special status.

result="GoAway"
for service in ${allowed} ; do
    [[ "" = "${service}" ]] && result=""
done

# If it IS allowed, get actual status.

[[ -z "${result}" ]] && result="$(/usr/bin/systemctl is-active "")"

echo "${result}"

可能有 其他 方法(它们可能更好)但如果这确实是问题所在,那应该是一个好的开始。


请注意,我认为 setuid 对于具有 shebang 行(如 #!/usr/bin/env bash)的 shell 脚本会被忽略,因此您可能需要解决这个问题,可能是通过构建一个真正的可执行文件来完成这项工作。

如果您必须为其构建一个真正的可执行文件,您可以从以下 C 代码开始,它是上述 shell 脚本的改编版:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    // Check service name provided.

    if (argc < 2) {
        puts("NoServiceProvided");
        return 1;
    }

    // Check service name allowed.

    static char *allowed[] = { "dynflowd", NULL };
    int isAllowed = 0;
    for (char **service = &(allowed[0]); *service != NULL; service++) {
        if (strcmp(*service, argv[1]) == 0) {
            isAllowed = 1;
            break;
        }
    }
    if (! isAllowed) {
        puts("InvalidServiceName");
        return 1;
    }

    // Try to allocate memory for command.

    char *prefix = "/usr/bin/systemctl is-active ";
    char *cmdBuff = malloc(strlen(prefix) + strlen(argv[1]) + 1);
    if (cmdBuff == NULL) {
        puts("OutOfMemory");
        return 1;
    }

    // Execute command, free memory, and return.

    sprintf(cmdBuff, "%s%s", prefix, argv[1]);
    system(cmdBuff);
    free(cmdBuff);

    return 0;
}

我终于找到问题了:NRPE版本!!!

在我的服务器上,NRPE 在 nrpe-3.2.1-6.

我 运行 我的脚本通过另一台服务器上的 NRPE 运行并且有效。

这台服务器 运行s nrpe-3.2.1-8.

所以解决方案是:更新 !

感谢您的宝贵时间和想法,尤其是 >> /tmp/paxdebug.dynflowd 2>&1 帮助我解决问题的想法。