Некоторое время назад был рассмотрен вопрос использования модема SENSE GM02 в частности для отправки SMS. Сейчас немного усложним задачу: попробуем "расшарить" модем по сети, чтобы его можно было использовать одновременно с нескольких компьютеров.
Зачем это нужно? Ну например если есть несколько серверов мониторинга, каждый из которых должен иметь возможность отправлять SMS, а модем у нас только один и подключен к одному из серверов.
Немного конкретизируем задачу: есть Zabbix-сервер, работающий под управлением FreeBSD и сервер под управлением Ubuntu 11.04 с подключенным к нему модемом и имеющий IP-адрес 1.1.1.1.
Приступаем к решению задачи. Общая идея заключается в том что zabbix-сервер для отправки оповещений будет использовать внешний скрипт, который будет по сети передавать данные серверу и тот уже будет отправлять SMS. Автору этих строк не удалось найти готовых решений и потому пришлось создавать своё.
Начнём работу с создания сервера. Полноценную работу с GSM-модемом делать долго, потому в качестве промежуточного звена используем smstools. Установим их:
apt-get install smstools
Приведём файл /etc/smsd.conf к следующему виду:
devices = GSM1 outgoing = /var/spool/sms/outgoing checked = /var/spool/sms/checked incoming = /var/spool/sms/incoming logfile = /var/log/smstools/smsd.log infofile = /var/run/smstools/smsd.working pidfile = /var/run/smstools/smsd.pid outgoing = /var/spool/sms/outgoing checked = /var/spool/sms/checked failed = /var/spool/sms/failed incoming = /var/spool/sms/incoming sent = /var/spool/sms/sent stats = /var/log/smstools/smsd_stats receive_before_send = no autosplit = 3 [GSM1] device = /dev/ttyACM0 incoming = yes baudrate = 19200 decode_unicode_text = yes
Перезапускаем сервис:
invoke-rc.d smstools restart
Теперь для отправки SMS достаточно создать файл определённого формата в директории "/var/spool/sms/outgoing", чем мы и воспользуемся при создании сервера. Описание формата есть в документации smstools.
Собственно код сервера (на Perl):
#!/usr/bin/perl use strict; use warnings; use diagnostics; use POSIX; use IO::Socket; use XML::Simple; use Text::Iconv; use Data::Dumper; # Права, с которыми будет работать скрипт # Важно понимать что файлы он так же будет создавать с этими правами # Так что эти настройки должны учитывать аналогичные настройки для smsd my $settings = { 'user' => "smsd", 'group' => "smsd", 'port' => 32767, 'outgoing_dir' => '/var/spool/sms/outgoing/', 'logfile' => '/var/log/smstools/zabbix_smsd.log', }; # Резолвим идентификаторы пользователя и группы my $d_uid = getpwnam($settings->{'user'}); my $d_gid = getgrnam($settings->{'group'}); # Урезаем права setuid($d_uid); setgid($d_gid); # Создаём сокет my $sock = new IO::Socket::INET ( LocalPort => $settings->{'port'}, Proto => 'tcp', Listen => 1, Reuse => 1, ); # Обрабатываем входящие соединения while (my $client = $sock->accept()) { # IP-адрес клиента my $client_ip = $client->peerhost; # Считываем данные с клиента my $xml_data = ""; while (<$client>) { $xml_data .= $_; } # Пытаемся распарсить данные eval { my $data = XMLin($xml_data); # Если данные указаны if (defined($data->{'number'}) && defined($data->{'message'})) { # Имя файла для записи SMS my $uniq_name = time(); my $sms_file_name = $settings->{'outgoing_dir'} . $uniq_name; # Перекодируем сообщение my $converter = Text::Iconv->new('UTF-8', 'UCS-2BE'); my $message = $converter->convert($data->{'message'}); # Извлекаем номер my $number = $data->{'number'}; # Формируем SMS-сообщение my $sms_data = "To: $number\nAlphabet: UCS2\n\n$message"; # Печатаем сообщение в файл open SMSFILE, '>', $sms_file_name; print SMSFILE $sms_data; close SMSFILE; # Формируем сообщение для записи в лог my $logtime = strftime("%Y-%m-%d %H:%M:%S", localtime()); my $logline = "$logtime $client_ip $number $uniq_name\n"; # Пишем в лог open LOGFILE, '>>', $settings->{'logfile'}; flock LOGFILE, 2; print LOGFILE $logline; close LOGFILE; } }; # Если произошла ошибка то не расстраиваемся if (my $error = $@) { } } # Закрываем сокет close($sock);
Сохраним скрипт под именем "/usr/local/scripts/smsd.pl" и запустим его командой:
/usr/local/scripts/smsd.pl &
Эту же команду нужно добавить в файл "/etc/rc.local" для автоматического запуска сервера при загрузке. Поскольку скрипт не содержит средств авторизации нужно ограничить с помощью файрволла доступ к порту, который прослушивает сервер.
Переходим к написанию клиента. Поскольку в первую очередь он будет "заточен" для использования совместно с zabbix он должен принимать параметры командной строки в совместимом с zabbix-формате. А именно:
Параметр | Значение |
---|---|
1 | Адресат |
2 | Тема сообщения |
3 | Тело сообщения |
Поскольку SMS характеризуется только адресатом (номер телефона) и телом сообщения - тему мы будем просто отбрасывать. Листинг клиента:
#!/usr/bin/perl use strict; use warnings; use warnings; use IO::Socket; use XML::Simple; use Data::Dumper; # Настройки my $settings = { 'host' => '1.1.1.1', 'port' => 32767, }; # Если количество аргументов не равняется трём: exit 1 if @ARGV != 3; # Извлекаем данные my $number = shift @ARGV; my $subject = shift @ARGV; my $body = shift @ARGV; # Создаём структуру данных my $data = { 'number' => $number, 'message' => $body, }; # Создаём строку данных my $data_line = XMLout( $data, 'RootName' => 'xml', 'NoAttr' => 1 ); # Создаём сокет my $sock = new IO::Socket::INET ( PeerAddr => $settings->{'host'}, PeerPort => $settings->{'port'}, Proto => 'tcp', ); # Пишем строку данных в сокет print $sock $data_line; # Закрываем сокет close $sock;
Скрипт сохраним на сервере мониторинга под именем "zabbix_smsc.pl" в директорию, указанную параметров "AlertScriptsPath" в файле "/usr/local/etc/zabbix/zabbix_server.conf". Затем заходим в веб-интерфейс zabbix-сервера, выбираем в меню "Администрирование" -> "Способы оповещений" -> "Создать способ оповещения" и заполняем таблица следующим образом:
Параметр | Значение |
---|---|
Описание | Remote SMS |
Тип | Скрипт |
Название скрипта | zabbix_smsc.pl |
Результат будет выглядеть примерно так:
Теперь можно в настройках пользовательских аккаунтов использовать новый способ оповещений - "Remote SMS".
Разумеется клиентскую часть системы можно использовать и с другими системами мониторинга. А так же, поскольку клиент с сервером обмениваются данными в формате XML и используют весьма примитивный протокол, к серверной части можно подключить многие другие программные продукты с минимальной доработкой.
На этом всё. Приятной работы!
Anonymous 2011-09-13 22:50:32 (#)
Так же можно через scp класть файл в папку /var/spool/sms/outgoing/ на сервере.
С авторизацией по ключам.