То, как демон snmptrapd работает с ловушками, не позволяет получать какие-либо ловушки SNMPv3 без указания EngineID отправляющего устройства, т. е. если вы просто делаете следующее в /etc/snmp/snmptrapd.conf:
createUser snmpv3USER SHA auth_pass AES priv_pass
authUser log,execute snmpv3USER
perl do "/usr/bin/zabbix_trap_receiver.pl";
Вы никогда не получите ловушки SNMPv3 в файле /tmp/zabbix _traps.tmp, потому что usmUser, созданный внутри /var/lib/net -snmp/snmptrapd.conf, не соответствует фактическим требованиям, т.е. это..
Когда дело доходит до сообщений SNMPv3, большинство коммутаторов не могут их отправлять, поэтому мы застряли только с ловушками SNMPv3, а способ программирования snmptrapd работает только с идентификаторами EngineID для ловушек SNMPv3. Даже если я использую disableAuthorization yes в snmptrapd.conf, ловушки SNMPv3 не будут работать без EngineID для каждого отправляющего устройства, то есть устройства-коммутатора.
Теперь, чтобы получать ловушки SNMPv3, вам нужно получить все EngineID для всех коммутаторов, для этого я написал скрипт на Python, чтобы построить snmptrapd.conf с использованием SNMPv3, что является большим облегчением. Фактический файл имеет комментарий перед каждой строкой createUser, который показывает имя коммутатора и IP-адрес. Эта часть информации о ловушках SNMPv3 на самом деле упоминается в документации net -snmp, но когда я прочитал ее в первый раз, я не мог ее понять, потому что там написано The difference is that SNMPv3 TRAPs use the engineID of the local application sending the trap rather than the engineID of the remote application
, поэтому, когда вы прочитаете ее в первый раз, вы будете сбиты с толку, но с немного концентрации становится очень ясно:
SNMPv3 TRAPs are a bit more complicated in some ways, but it makes sense the protocol works this way if you spend a long time thinking about it. The difference is that SNMPv3 TRAPs use the engineID of the local application sending the trap rather than the engineID of the remote application. This means that you have to create users in your remote user database with a bit more care and need to create one for every engineID you wish to send traps from. This means that if you want to have 100 snmp agents send snmpv3 traps to your trap receiver, you need 100 createUser directives in your /var/net-snmp/snmptrapd.conf file.
Файл /etc/snmp/snmptrapd.conf выглядит следующим образом:
createUser -e 0x800007c703609c9f1eff01 snmpv3USER SHA auth_pass AES priv_pass
createUser -e 0x800007c703cc4e24e4c6c3 snmpv3USER SHA auth_pass AES priv_pass
createUser -e 0x800007c703d4c19e743e86 snmpv3USER SHA auth_pass AES priv_pass
createUser -e 0x800007c70378a6e10ca715 snmpv3USER SHA auth_pass AES priv_pass
createUser -e 0x800007c70378a6e10c46f0 snmpv3USER SHA auth_pass AES priv_pass
createUser -e 0x800007c70378a6e121bacd snmpv3USER SHA auth_pass AES priv_pass
createUser -e 0x800007c70378a6e121b7d8 snmpv3USER SHA auth_pass AES priv_pass
createUser -e 0x800007c703609c9f5136f4 snmpv3USER SHA auth_pass AES priv_pass
authUser log,execute snmpv3USER
perl do "/usr/bin/zabbix_trap_receiver.pl";
Файл намного длиннее, но теперь я могу получать все ловушки со всех коммутаторов. Я видел на stackoverflow, что у кого-то получилось с DES без использования EngineID, но это настоящая хрень, у меня никогда не работало ни для DES, ни для AES без EngineID.Это просто то, что было сделано на фоне другого программного обеспечения для мониторинга, которое ведет запись EngineID всех устройств для задачи приема ловушек.
Я также заметил, что ловушки от основного коммутатора поступают с виртуального интерфейса влана, на котором находится zabbix, поэтому мне пришлось модифицировать скрипт zabbix _trap _Receiver.pl следующим образом:
use NetSNMP::TrapReceiver; # should be added in order to get the script to work, otherwise it fails -- elekgeek 2nd DEC 2019
# get the host name
$pdu_info{'receivedfrom'} =~ s/192.168.168.254/192.168.168.1/ig; # I added this line to get the core switch IP instead of zabbix's VLAN SVI IP, otherwise trap is not added to the CORE trap.fallback -- elekgeek 2nd DEC 2019
my $hostname = $pdu_info{'receivedfrom'} || 'unknown';
if ($hostname ne 'unknown')
При работе с ловушками мне приходилось видеть их как историю, поэтому я изменил пункт SNMP traps (fallback )с Тип информации=Журнал на Тип информации=Текст в шаблоне Template Module Generic SNMPv3
.
Удачи в заббиксировании!
I would like to find out why systemd thinks it should be stopping the service unit. What can I configure or enable to determine why systemd took the "stop" action?
Чтобы увидеть текущее -состояние службы, вы можете:
systemd-cgls -l <service-cgroup-path>
:там вы увидите все процессы сервисов, как они есть на данный момент. Путь cgroup службы можно получить с помощью команды systemctl show -p ControlGroup <service-name>
. В более поздних версияхsystemd
(не в v219 )вы также можете использовать удобную -u <service-name>
опцию systemd-cgls
вместо пути cgroup службы systemctl show <service-name>
команду :. Это даст массу информации о состоянии службы, как известно systemd
, и на основе этой информации вы сможете сделать более подробный вывод о том, что происходит Чтобы исследовать случай «подозрения на остановку», правильно добавить эти команды как команды ExecStop
. Вы можете просто добавить их в начало вашего собственного stop.service-c
скрипта (, если это действительно скрипт ).
Или же вы можете добавить их как дополнительные ExecStop
команды самостоятельно перед вашей stop.service-c
командой, как в:
[Service]
Type=forking
ExecStart=/local-path/start.service-c
ExecStop=-/bin/sh -c 'systemd-cgls -l -u %n && systemctl show %n'
ExecStop=/local-path/stop.service-c
Restart=on-failure
Обратите внимание, что спецификатор %n
правильно обрабатывается systemd
, даже если он встречается в строках в кавычках.
В качестве альтернативы вы также можете:
[Service]
Type=forking
ExecStart=/local-path/start.service-c
ExecStop=-/usr/bin/systemd-cgls -l -u %n
ExecStop=-/bin/systemctl show %n
ExecStop=/local-path/stop.service-c
Restart=on-failure
Обратите также внимание на префикс -
перед командами, чтобы игнорировать их статус выхода на тот случай, если они потерпят неудачу по непонятным причинам.
Естественно, вы также можете использовать их как ExecStartPost
команды, чтобы обдумать текущее -состояние сразу после того, как systemd
считает службу "успешно запущенной".(снова заставляет игнорировать их статус выхода или systemd
отключит всю службу в случае сбоя ).
Что касается вывода systemd-cgls
, выполняемого как команда ExecStop
, вы должны отметить, что процесс MainPID
все еще отображается в то время :, если он действительно появляется, то это доказывает, что ExecStop
действительно был выполнен автономно systemd
, как вы предполагаете. Иначе (, если MainPID
процесс не присутствует в выводе systemd-cgls
во время «остановки» ), это означает, что ExecStop
был запущен в результате процесса MainPID
, завершающегося по собственному желанию.(Дополнительные аргументы см. ниже). Вы также можете обратить внимание на номера PID процессов службы вместе с номерами PID команды (now dead )ExecStart
, чтобы попытаться сделать вывод о том, чтоfork(2)
-происходило с момента запуска службы и всего вместе, потому что это очень важно для службы type=forking
, чтобы оценить, хорошо ли она -себя ведет.(Дополнительные аргументы см. ниже).
Что касается systemctl show
вывода, выполняемого как команда ExecStop
, я бы сказал, что наиболее важными свойствами, на которые следует обратить внимание в вашем конкретном случае , являются:
MainPID
:читает 0
, если основной процесс службы завершился по собственному желанию, иначе считывает PID основного процесса службы, если он все еще жив и, таким образом, действительно остановленsystemd
ExecMainExitTimestamp
:считывает время выхода в формате date
, если основной процесс службы завершился по собственному желанию, иначе не считывает вообще, если процесс все еще жив и, следовательно, действительно остановленsystemd
ExecMainExitTimestampMonotonic
:как указано выше, но читается в монотонных часах Linux и читается 0
, если процесс еще жив ExecMainCode
:это соответствует строке code=
вsystemctl status
1 ,только он сообщает десятичное значение символов CLD_*
вместо их перевода в английские слова :в соответствии с текущими значениями Linux для CLD_*
символов (, которые представляют собой enum
, начиная с 1
), ExecMainCode
имеет значение 0
, если процесс все еще жив и, таким образом, действительно собирается быть остановленным systemd
, в противном случае отображается 1
, если процесс уже_exit(2)
-ed по собственной инициативе, 2
, если он былоkill(2)
-издано (в этом варианте использования явно не поsystemd
)и так далее Обратите внимание , однако, что указанные выше поля не соответствуют текущему состоянию службы , если systemd
не удалось обнаружить основной процесс службы во время запуска службы..(пояснения см. ниже). Они скорее соответствуют самому последнему прогону, для которогоsystemd
удалось полностью выполнить обнаружение.
В ваших рассуждениях я вижу два ключевых момента, заслуживающих дополнительного разъяснения:
type=forking
услуги
type=forking
особенно сложны для systemd
, особенно при использованииGuessMainPID=yes
(по умолчанию, поэтому то, что вы сейчас используете для своего агента ). Для этих типов служб ожидается, что команда ExecStart
будет fork(2)
сама один раз , а затем завершится, в то время как ее разветвленный процесс, как ожидается, будет жить долго и процветать как MainPID
службы. Остальное:
GuessMainPID
просто теряет след и systemd
просто считает, что служба завершилась регулярно и спонтанно, и, таким образом, выполняет свою обязанность по очистке всего (, т.е. запускает ExecStop
и т. д. ), но без регистрации сообщения Stopping service...
, потому что, насколько что касается systemd
,он реагировал только на преднамеренный выход службы ExecStart
исходный процесс fork(2)
дважды (или более )выполняется )перед выходом, тогда GuessMainPID
сдается и systemd
воздерживается от сноса всего, когда исходныйExecStart
Процесс завершается. Это лучший случай, потому что фактические процессы службы выживают, но он еще не идеален, потому что тогда systemd
также не будет полностью отслеживать события, что приводит, например, к. как минимум несогласованные/неполные журналы журналов. ExecStop
исполнение
Команды ExecStop
запускаются также , когда процесс MainPID
успешно завершается сам по себе, если основной процесс также запущен успешно (, что ваше дело под рукой ). Я понимаю, что это кажется нелогичным, но это просто нормальное поведение, так какsystemd
:он просто считает команду службы ExecStop
предпочтительным способом очистки после этой службы, прежде чем прибегать к (по умолчанию, см.systemd.kill(5)
)отправка Сначала SIGTERM, а потом, возможно, SIGKILL.
Нигде на справочной странице systemd.service(5)
об этом не говорится так явно, но об этом можно сделать вывод из нескольких фрагментов документации, особенно тех, которые касаются переменных среды, доступных для команд Exec*
. См. $SERVICE_RESULT
, $EXIT_CODE
и$EXIT_STATUS
переменные, чтобы узнать, какие значения они могут принимать, какое семантическое значение они имеют, и тот факт, что они доступны именно для команд ExecStop
, а также ExecStopPost
..
Помимо не -явной (или личной интерпретации )документации, давайте посмотрим на источники, которые обеспечивают такое поведение. Взято из версии 219, здесь service_sigchld_event()
вызываетservice_enter_running()
по событию, относящемуся к дочернему элементу, который, как известно, находится в состоянии "работает",а затем последняя функция, вызывающаяservice_enter_stop()
действие «остановки» во всех случаях, кроме случаев, когда RemainAfterExit=yes
или type=dbus
или основной процесс службы не обнаружен(см. type=forking
пояснение выше)или контрольная -группа не здорова.
Что касается , почему люди systemd
решили сделать это, я не знаю, так как я не systemd
разработчик, но я вижу полезность такого поведения, чтобы дать все еще живы -но -"неизвестные" процессы службы, их шанс быть уведомленным об их неизбежном прекращении самым приятным способом, прежде чем получить суровый SIGTERM и SIGKILL в качестве последнего средства systemd
продолжает закрывать всю контрольную -группу. Эта мера особенно полезна именно для служб type=forking
, потому что systemd
труднее всего правильно отследить их, как объяснено в абзаце type=
systemd.service(5)
, и потому что systemd
пытается очистить устаревшие/ ленивые/плохо -реализованные службы, которые не закрываются корректно перед выходом.
ХТХ
1. code=
, за которым следует слово, представляющее «причину выхода» из процесса :, будь то exited
или был killed
или trapped
или даже dumped
; на практике :буквально слово, переводящее различные CLD_*
значения, действительные для поля siginfo_t.si_code
, как описано вsigaction(2)