Zabbix оповещения на jabber

Сейчас будем разбираться с оповещениями zabbix на jabber. В ранних статьях мы уже устанавливали jabber сервер Openfire и будем использовать его на примере.

Для начала, в opebfire необходимо создать пользователя для zabbix сервера с которого будем отправлять сообщения и добавляем его в группу.

С коробки zabbix я не смог отправлять оповещения, поэтому будем использовать скрипт.

создаем файл jabber в /etc/zabbix/alert.d:

nano /etc/zabbix/alert.d/jabber
#!/usr/bin/perl

use common::sense;
use Net::XMPP;

use constant {
SERVER => 'jabber.domain.ru',
PORT => 5222,
USER => 'server',
PASSWORD => 'password',
RESOURCE => 'company',
TLS => 0,
DEBUG => 0,
};

$0 =~ s{.*/}{};
my ($to, $subj, $body, $type) = @ARGV;
$type ||= 'headline';

die << "EOF" unless @ARGV == 3 or @ARGV == 4;
Usage: $0 <jid> <subject> <body> [type]
EOF

utf8::decode($subj);
utf8::decode($body);

my $bot = new Net::XMPP::Client( debuglevel => DEBUG );

$bot->SetCallBacks(
    onconnect => sub{},
        onauth => sub{
        $bot->PresenceSend;
        $bot->MessageSend( to => $to, subject => $subj, body => $body, type => $type );
        $bot->Disconnect();
        },
            ondisconnect => sub{}
            );

            $bot->Execute(
            hostname => SERVER,
            port => PORT,
            tls => TLS,
            username => USER,
            password => PASSWORD,
            resource => RESOURCE,
            register => 0,
            connectiontype => 'tcpip'
            );

Делаем его запускающимся:

chmod +x /etc/zabbix/alert.d/jabber
cd /etc/zabbix/alert.d

Пробуем запустить:

./jabber

Получаем вот такую ошибку, а все из-за того что скрипт использует модули perl common::sense; Net::XMPP;

Can’t locate common/sense.pm in @INC (@INC contains: /etc/perl /usr/local/lib/perl/5.10.1 /usr/local/share/perl/5.10.1 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.10 /usr/share/perl/5.10 /usr/local/lib/site_perl .) at ./jabber line 3.
BEGIN failed—compilation aborted at ./jabber line 3.

perl -MCPAN -e 'install +common::sense'
perl -MCPAN -e 'install +Net::XMPP'

Пробуем отправить сообщение с помощью скрипта:

./jabber admin@domain.ru test test

сообщения также не доходят (тишина).

Добавлено из комментарий (спасибо Андрею):

Необходимо найти и закомментировать строку в

/usr/local/share/perl/5.14.2/Net/XMPP/Protocol.pm

return $self->AuthSASL(%args);

Кстати, в скрипте можно включить debug для просмотра где у нас ошибка:

DEBUG => 1,

Так же смотрим логи openfire в /var/log/openfire/warn.log

Важный момент:

Если у вас Openfire заведен на поддомене, например jabber.domain.ru, то и отправлять сообщения пользователю нужно с указанием с доменом третьего уровня:

./jabber admin@jabber.domain.ru test test

Теперь остается в Вебморде zabbix добавить скрипт:

Администрирование -> Типы средств передачи -> Jabber — где Тип: выбрать Сценарий, Название скрипта — jabber

 

Tags:
  1. после запуска скрипта не приходит сообщение в дэбаге постоянно пишет
    XMPP::Conn: SendAndReceiveWithID: sent with id(netjabber-0)
    XMPP::Conn: WaitForID: id(netjabber-0)
    XMPP::Conn: ReceivedID: id(netjabber-0)
    XMPP::Conn: ReceivedID: nope…
    XMPP::Conn: WaitForID: haven’t gotten it yet… let’s wait for more packets
    XMPP::Conn: Process: timeout(1)

  2. Еще добавлю. На голой системе нет модулей perl common::sense; Net::XMP.
    Порядок установки:
    sudo apt-get install perl build-essential libssl-dev
    sudo perl -MCPAN -e ‘install O::Socket::SSL’
    sudo perl -MCPAN -e ‘install Net::SSLeay’
    sudo perl -MCPAN -e ‘install common::sense’
    sudo perl -MCPAN -e ‘install Net::XMPP’

  3. Использую готовое решние Zabbix 3.0, возникла проблема при подключении модулей, т.е. они просто ни в какую не ставятся, хотя на обычной машине все норм

    1. Zabbix 3.0.0alpha5
      Скрипт устанавливается нормально
      Тестовый запуск /usr/local/share/zabbix/alertscripts/jabber user@openfire test test срабатывает нормально, сообщение приходит
      Zabbix пишет что отправил сообщение
      Но я сообщений не вижу в jabber-клиенте (spark)

        1. Нашлось. При добавлении «способа оповещений» в zabbix указываем 3 параметра запуска отдельно

          1. Разобрался. Начиная с 3.0 версии в параметрах нужно использовать макросы {ALERT.SENDTO}, {ALERT.SUBJECT} {ALERT.MESSAGE}, вместо старых $1 $2 $3.
            Заработало!

  4. А как из скрипта отправить сообщение в конференцию?
    Если просто указать в качестве получателя адрес конференции — не канает.

  5. Если использовать готовый дистр zabbix на базе SuSE, то в нем отсутствует make и perl -MCPAN -e ‘install +common::sense’ не завершится.
    Выполняем yast -i make и продолжаем…

  6. Если у кого была такая же проблема, то все решается просто: сообщению по-умолчанию делается тип «chat» и еще нужна задержка между выполнением команд. Вот мой код:

    #!/usr/bin/perl

    use common::sense;
    use Net::XMPP;

    use constant {
    SERVER => ‘server’,
    PORT => 5222,
    USER => ‘zabbix’,
    PASSWORD => ‘pass’,
    RESOURCE => ‘script’,
    TLS => 0,
    DEBUG => 1,
    };

    my $lock_file = ‘./.lock’;

    # Ждем отсутствия файла lock

    while (-f $lock_file)
    {
    sleep(10);
    }

    #Создаем lock файл
    open(FILE, «> $lock_file»);
    close(FILE);

    $0 =~ s{.*/}{};
    my ($to, $subj, $body, $type) = @ARGV;
    $type ||= ‘chat’;

    #Если косяк в аргументах lock все равно удаляем
    unless (@ARGV == 3 or @ARGV == 4)
    {
    unlink $lock_file;
    }

    die << "EOF" unless @ARGV == 3 or @ARGV == 4;
    Usage: $0 [type]
    EOF

    utf8::decode($subj);
    utf8::decode($body);

    my $bot = new Net::XMPP::Client( debuglevel => DEBUG, debugfile =>»/usr/local/share/zabbix/alertscripts/jabber_log.log»);

    $bot->SetCallBacks(
    onconnect => sub{},
    onauth => sub{
    $bot->PresenceSend;
    $bot->MessageSend( to => $to, subject => $subj, body => $body, type => $type );
    $bot->Disconnect();
    },
    ondisconnect => sub{}
    );
    $bot->Execute(
    hostname => SERVER,
    port => PORT,
    tls => TLS,
    username => USER,
    password => PASSWORD,
    resource => RESOURCE,
    register => 0,
    connectiontype => ‘tcpip’
    );
    sleep(10);
    #Удаляем lock файл
    unlink $lock_file;

  7. Спасибо! Очень полезная статья. Но у меня возникла проблема со скриптом. При отправке сообщений из zabbix’a на 4 разичных аккаунта сообщения доходили не всем. В процессе тестирования обнаружилось, что если отправлять из командной строки друг за другом сообщения, часть из них не доходит. Также не доходят сообщения если клиент оффлайн… Может, кто-нибудь сталкивался с такой проблемой?

    {{Hider|Лог отправки, если клиент оффлайн
    XML::Stream: new: hostname = (openfire)
    XML::Stream: SetCallBacks: tag(node) func(CODE(0x204ef18))
    XMPP::Conn: xmppCallbackInit: start
    XMPP::Conn: SetCallBacks: tag(message) func(CODE(0x2369850))
    XMPP::Conn: SetCallBacks: tag(presence) func(CODE(0x2364fb8))
    XMPP::Conn: SetCallBacks: tag(iq) func(CODE(0x2364e08))
    XMPP::Conn: SetPresenceCallBacks: type(subscribe) func(CODE(0x2364fe8))
    XMPP::Conn: SetPresenceCallBacks: type(subscribed) func(CODE(0x2369d90))
    XMPP::Conn: SetPresenceCallBacks: type(unsubscribe) func(CODE(0x2369c10))
    XMPP::Conn: SetPresenceCallBacks: type(unsubscribed) func(CODE(0x2369f10))
    XMPP::Conn: SetDirectXPathCallBacks: xpath(/[@xmlns=»urn:ietf:params:xml:ns:xmpp-tls»]) func(CODE(0x2369dc0))
    XMPP::Conn: SetDirectXPathCallBacks: xpath(/[@xmlns=»urn:ietf:params:xml:ns:xmpp-sasl»]) func(CODE(0x236a180))
    XMPP::Conn: xmppCallbackInit: stop
    XMPP::Conn: SetCallBacks: tag(ondisconnect) func(CODE(0x23a5f68))
    XMPP::Conn: SetCallBacks: tag(onauth) func(CODE(0x236a780))
    XMPP::Conn: SetCallBacks: tag(onconnect) func(CODE(0x2318740))
    XMPP::Conn: Execute: begin
    XMPP::Conn: Execute: Attempt to connect (-1)
    XMPP::Conn: Connect: host(server:5222) namespace(jabber:client)
    XMPP::Conn: Connect: timeout(10)
    XML::Stream: Connect: type(tcpip)
    XML::Stream: Connect: Got a connection
    XML::Stream: Send: ()
    XML::Stream: Read: buff(PLAINANONYMOUSzlib)
    XMPP::Conn: Connect: connection made
    XML::Stream: SetCallBacks: tag(node) func(CODE(0x2370258))
    XMPP::Conn: Execute: Connected…
    XMPP::Conn: AuthSASL: shiney new auth
    XML::Stream: Send: (emFiYml4QGJhbmstcGVyZXN2ZXQucnUAemFiYml4ADEyMw==)
    XMPP::Conn: AuthSASL: haven’t authed yet… let’s wait.
    XMPP::Conn: Process: timeout(1)
    XML::Stream: Read: buff()
    XMPP::Conn: AuthSASL: We authed!
    XML::Stream: Send: ()
    XML::Stream: Read: buff(zlib)
    XMPP::Conn: AuthSASL: We got a new session. sid(b74d0583)
    XMPP::Conn: AuthSASL: Binding to resource
    XMPP::Conn: SendAndReceiveWithID: object(Net::XMPP::IQ=HASH(0x23522d8))
    XMPP::Conn: SendWithID: id(netjabber-0)
    XMPP::Conn: SendWithID: in(script)
    XMPP::Conn: RegisterID: tag(iq) id(netjabber-0)
    XMPP::Conn: SendWithID: out(script)
    XMPP::Conn: SendXML: sent(script)
    XML::Stream: Send: (script)
    XMPP::Conn: SendAndReceiveWithID: sent with id(netjabber-0)
    XMPP::Conn: WaitForID: id(netjabber-0)
    XMPP::Conn: ReceivedID: id(netjabber-0)
    XMPP::Conn: ReceivedID: nope…
    XMPP::Conn: WaitForID: haven’t gotten it yet… let’s wait for more packets
    XMPP::Conn: Process: timeout(1)
    XML::Stream: Read: buff(zabbix@server/script)
    XMPP::Conn: CallBack: sid(b74d0583) received(zabbix@server/script)
    XMPP::Conn: CallBack: tag(iq)
    XMPP::Conn: CallBack: id(netjabber-0)
    XMPP::Conn: CallBack: we either want it or were waiting for it.
    XMPP::Conn: CallBack: check directxpath
    XMPP::Conn: CallBack: check directxpath(/[@xmlns=»urn:ietf:params:xml:ns:xmpp-sasl»])
    XMPP::Conn: CallBack: check directxpath(/[@xmlns=»urn:ietf:params:xml:ns:xmpp-tls»])
    XMPP::Conn: BuildObject: tag(iq) package(Net::XMPP::IQ)
    XMPP::Conn: CheckID: tag(iq) id(netjabber-0)
    XMPP::Conn: CheckID: we have that here somewhere…
    XMPP::Conn: CallBack: found registry entry: tag(iq) id(netjabber-0)
    XMPP::Conn: DeregisterID: tag(iq) id(netjabber-0)
    XMPP::Conn: CallBack: they still want it… we still got it…
    XMPP::Conn: GotID: id(netjabber-0) xml(zabbix@server.ru/script)
    XMPP::Conn: ReceivedID: id(netjabber-0)
    XMPP::Conn: ReceivedID: id(netjabber-0)
    XMPP::Conn: WaitForID: we got it!
    XMPP::Conn: GetID: id(netjabber-0)
    XMPP::Conn: ReceivedID: id(netjabber-0)
    XMPP::Conn: CleanID: id(netjabber-0)
    XMPP::Conn: AuthSASL: Starting session
    XMPP::Conn: SendAndReceiveWithID: object(Net::XMPP::IQ=HASH(0x1db2b20))
    XMPP::Conn: SendWithID: id(netjabber-1)
    XMPP::Conn: SendWithID: in()
    XMPP::Conn: RegisterID: tag(iq) id(netjabber-1)
    XMPP::Conn: SendWithID: out()
    XMPP::Conn: SendXML: sent()
    XML::Stream: Send: ()
    XMPP::Conn: SendAndReceiveWithID: sent with id(netjabber-1)
    XMPP::Conn: WaitForID: id(netjabber-1)
    XMPP::Conn: ReceivedID: id(netjabber-1)
    XMPP::Conn: ReceivedID: nope…
    XMPP::Conn: WaitForID: haven’t gotten it yet… let’s wait for more packets
    XMPP::Conn: Process: timeout(1)
    XML::Stream: Read: buff()
    XMPP::Conn: CallBack: sid(b74d0583) received()
    XMPP::Conn: CallBack: tag(iq)
    XMPP::Conn: CallBack: id(netjabber-1)
    XMPP::Conn: CallBack: we either want it or were waiting for it.
    XMPP::Conn: CallBack: check directxpath
    XMPP::Conn: CallBack: check directxpath(/[@xmlns=»urn:ietf:params:xml:ns:xmpp-sasl»])
    XMPP::Conn: CallBack: check directxpath(/[@xmlns=»urn:ietf:params:xml:ns:xmpp-tls»])
    XMPP::Conn: BuildObject: tag(iq) package(Net::XMPP::IQ)
    XMPP::Conn: CheckID: tag(iq) id(netjabber-1)
    XMPP::Conn: CheckID: we have that here somewhere…
    XMPP::Conn: CallBack: found registry entry: tag(iq) id(netjabber-1)
    XMPP::Conn: DeregisterID: tag(iq) id(netjabber-1)
    XMPP::Conn: CallBack: they still want it… we still got it…
    XMPP::Conn: GotID: id(netjabber-1) xml()
    XMPP::Conn: ReceivedID: id(netjabber-1)
    XMPP::Conn: ReceivedID: id(netjabber-1)
    XMPP::Conn: WaitForID: we got it!
    XMPP::Conn: GetID: id(netjabber-1)
    XMPP::Conn: ReceivedID: id(netjabber-1)
    XMPP::Conn: CleanID: id(netjabber-1)
    XMPP::Conn: SendXML: sent()
    XML::Stream: Send: ()
    XMPP::Conn: SendXML: sent(88123)
    XML::Stream: Send: (88123)
    XML::Stream: Send: ()
    XML::Stream: SetCallBacks: tag(node) func(CODE(0x237b838))
    XMPP::Conn: Disconnect: bye bye
    XMPP::Conn: Connected: (0)
    XMPP::Conn: Execute: end

    }}
    В сущности, он такой же, как и если клиент онлайн, но привожу на всякий случай…

  8. извеняюсь что так долго не отвечал.. у меня заработало без скрипта.. на стороннем сервере где openfire установлен небыл включен sasl.. но теперь другая проблема.. письма приходят, но содержание непонятное.. инфо что коммутатор выключен или включен нет в содержании. как то можно ее исправить

  9. @magomed
    Советую смотреть логи openfire и смотреть что показывает при подключении:

    # tail -f /var/log/openfire/warn.log

    Возможно, что это та же ошибка, что комментарием выше….

  10. Добрый день! как в openfire включить sasl аутетнтификацию? а то из за этого у меня некоторые клиенты не подключаются и с заббикса письма не уходят

  11. Спасибо за статью.
    В процессе настройки столкнулся с ошибкой XMPP::Conn: AuthSASL: Authentication failed.

    Нашел решение вот здесь http://community.igniterealtime.org/thread/20551
    This is a known problem.
    At the moment the best you can do is comment out line 1772 in Net/XMPP/Protocol.pm.
    The line:
    return $self->AuthSASL(%args);
    becomes
    return $self->AuthSASL(%args);
    Not pretty but it works.

    Номер строки отличается от описанной в форуме так, что нужно искать строку return $self->AuthSASL(%args); и просто ремить после чего все заработало
    Может кому пригодится в процессе настройки.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *