Почему systemctl не возвращает значение при проверке NRPE?
У меня проблема с проверкой NRPE, которую я написал.
Это простой сценарий оболочки, который запускает "systemctl is-active [service_name]" и возвращает значение нашему 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. Когда я заменяю systemctl другой командой, например "echo", она работает.
Итак, я думаю, что есть что-то с 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 "$1"; do
case "$1" in
--service)
SERV=$2
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
2 ответа
Я наконец нашел проблему: версия NRPE!!!
На моем сервере NRPE находится в nrpe-3.2.1-6
.
Я запускаю свой сценарий через NRPE на другом сервере, и он работает.
Этот другой сервер работает nrpe-3.2.1-8
.
Итак, решение: обновление!
Спасибо за ваше время и идеи, особенно >> /tmp/paxdebug.dynflowd 2>&1
идея, которая помогла мне разобраться в проблеме.
Хорошо, похоже на cron
задания, может быть, что NRPE (сервер) работает в среде, отличной от среды вашей оболочки, и эта отдельная среда каким-то образом не работает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
скрипт, который будет принадлежать (и, следовательно, запускаться от имени) пользователю, которому разрешено запускать 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
[[ "$1" = "${service}" ]] && result=""
done
# If it IS allowed, get actual status.
[[ -z "${result}" ]] && result="$(/usr/bin/systemctl is-active "$1")"
echo "${result}"
Могут быть и другие методы (и они могут быть лучше), но, надеюсь, это будет хорошим началом, если проблема действительно в этом.
Просто знай, что я думаю setuid
игнорируется для сценариев оболочки, в которых есть строка shebang (например, #!/usr/bin/env bash
), поэтому вам, возможно, придется обойти это, возможно, создав настоящий исполняемый файл для выполнения этой работы.
Если вам действительно нужно создать для него настоящий исполняемый файл, вы можете начать со следующего кода C, который представляет собой адаптацию сценария оболочки, приведенного выше:
#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;
}