Користувальницькькі налаштування

Налаштування сайту


Сайдбар

Розділи

Загальний опис
Історія змін
Рекомендації до оновлення
Плани на майбутнє
Відомі проблеми
Онлайн демо
Допомога проекту
Люди
Трохи про безпеку

FAQ



Редагувати сайдбар

watchdog

Це стара версія документу!


Собака-спостерігака aka Watchdog

Собака-спостерігака призначена для собачення та спостерігання оперативного моніторингу навколишньої реальності. Вона надає гнучкий функціонал для опису позаштатних ситуацій практично будь-якої дивності, а також для сповіщення у разі їх виникнення. У тому числі, за допомогою відсилання SMS через послуги, що підтримуються собакою-посилакою, електронною поштою, месенджера Telegram а також може викликати запуск будь-якого зовнішнього скрипта при настанні якоїсь події. Для включення собаки-спостерігакт потрібна зміна опції WATCHDOG_ENABLED в alter.ini. Також для надсилання повідомлень, очевидно, на допомогу собаці-спостерігаці знадобиться Собака-посилака.

Можливі перевірки

Типи задач Дія Повертає
icmpping виконується ICMP ping хоста вказаного в параметрі bool
tcpping виконується спроба TCP з'єднання з хостом вказаним в параметрі у вигляді host:port bool
udpping виконується спроба UDP з'єднання з хостом вказаним в параметрі у вигляді host:port bool
hopeping Пінг надії. Тричі виконується ICMP ping хоста вказаного в параметрі, в надії, що хоч один з них повернеться bool
script запуск shell-скрипту за шляхом, вказаному в параметрі string
httpget отримання сирих даних з URL вказаного в параметрі string
getusertraff отримання кількості трафіку в байтах логіну користувача вказаного в параметрі int
fileexists перевірка на існування файлу по шляху вказаному в параметрі bool
opentickets кількість відкритих тікетів хелпдеску. Потребує вказання рандомного параметра int
onepunch Виконує запуск One-Punch скрипта з аліасом вказаним в параметрі. Результат очікується у вигляді змінної $watchdogCallbackResult string
snmpwalk Виконується snmpwalk по OID хоста що вказано в параметрі у форматі host:community:OID string
freediskspace Повертає кількість вільного місця на розділі (точці монтування) вказаній в параметрі. Повертає цифру в Гб. float

Можливі оператори для перевірок

Оператор Значення Потребує “Умову”?
=true Істинно
=false Хибно
== Рівне +
!= Не рівне +
> Більше +
< Менше +
> = Більше або рівне +
< = Менше або рівне +
empty Пустий результат
notempty Непустий результат
changed Змінилось
notchanged Не змінилось
like Містить +
notlike Не містить +
rised Збільшилось +-
decreased Зменшилось +-

Дії що будуть виконані у разі проходження умов

Дії Результат
log запис події в системний лог
sms надсилання SMS сповіщення на номери стільникових, вказаних в налаштуваннях Собаки-спостергаки. Додаткові номери стільникових можна вказати у форматі {номер,номер}.
noprimary у випадку наявності цієї дії, та дії sms та вказаних {додаткових номерах} - основні номери з налаштувань Собаки-спостерігаки будуть проігноровані.
email надсилання сповіщення електропоштою, на адреси вказані в налаштуваннях.
telegram надсилання повідомлення Telegram, додаткові chatid можна вказати в форматі (чат1,чат2).
no_tg_primary у випадку наявності цієї дії, та дії telegram та вказаних (додаткових чатах) - основні чати Telegram ігноруються.
andresult у разі вказаних дій sms, telegram чи email до тексту повідомлення буде додано поточний результат завдання
oldresult у разі вказаних дій sms, telegram чи email до тексту повідомлення буде додано попередній результат завдання
script запуск скрипта чи будь-якого додатку, за шляхом, вказаному у вигляді [/повний/шлях/до_скрипта]

Логіка роботи

Кожне завдання для Собаки-спостерігаки слід сприймати як “щось трапилося” або “ой яка подія” які трапляються у разі повернення “типом перевірки” за “параметром” результату передбаченого “оператором” з опціональною “умовою”. Як приклад, можна навести ось таке просте завдання:

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X Гугл не пингается icmpping 8.8.8.8 =false log,sms,email

При обнаружении того, что ping на адрес 8.8.8.8 вернул значение “ложно” собака-наблюдака заботливо отошлет вам СМС-ку, почту и запишет в лог уведомление о том, что “Гугл не пингается”.

А что делать, если мы не хотим, чтобы собака постоянно нам спамила при отсутствующем пинге куда-то? А очень просто.

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X Чего-то изменилось icmpping 192.168.0.22 changed log,sms,email,andresult

В принципе никто не запрещает нам делать и задачи такого плана:

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X В серверной пожар script /bin/gettemp > 22 log,sms,email, andresult

Вызывая внешний скрипт, снимающий температуру с термодатчиков и при превышении 22 градусов орать всеми известными способами также дописывая в сообщении о температуре вызвавшей панику.

Если творчески подойти к парсингу вывода внешнего ПО - можно мониторить много интересных вещей без дописывания внешних скриптов:

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X DNS сломался script nslookup ya.ru | tail -n 2 like find log,sms

Также мы можем очень просто и элегантно контролировать запущенность важных сервисов типа stargazer создав задачу такого плана:

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X Stargazer упал script /bin/ps aux | /usr/bin/grep stg notlike stargazer log,sms

Хотя ту же самую по сути задачу мы можем оформить как

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X Stargazer упал fileexists /var/run/stargazer.pid =false log,sms

Чтобы не сосредотачиваться на тривиальных вещах, мы можем предусмотреть ситуацию, когда у нас есть очень важный клиент с логином vipclient на прекращение трафика от которого нам следует таки отреагировать. Описать такое мы можем в виде:

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X Важный клиент подох getusertraff vipclient notchanged log,sms,email

Окей, а если мы хотим также эту же СМС-ку послать скажем администратору этого же важного клиента, чтобы он точно знал, что он подох?

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X Важный клиент подох getusertraff vipclient notchanged log,sms,email {+380509999999}

а если мы хотим послать СМС только на дополнительный номер? Да, без проблем:

log,sms,email {+380509999999} noprimary

а если мы хотим послать алерт только в дополнительный/е чат/ы Telegram? Да, так же без проблем:

log,telegram,email (ChatID1,ChatID2,ChatID3) no_tg_primary

а можно миксовать СМС и Telegram? Да вообще без проблем:

log,telegram,sms,email (ChatID1,ChatID2,ChatID3) no_tg_primary {+380509999999} noprimary

Хотя опять же никто не запрещает нам, скажем мониторить этого клиента скажем внешним скриптом запрашивающим по SNMP состояние порта или счетчик трафика на свиче, куда он воткнут, либо банально его дергать по какому-то TCP порту. Думаю вышеприведенных примеров достаточно для получения представления о гибкости собаки-наблюдаки и возможностях построения оповещений по практически любым внештатным ситуациям. Обработка задач собаки происходит при соответствующем вызове RemoteAPI. Рекомендуемым интервалом является 10 минут.

А еще мы, можем реагировать не только на изменения текущих значений относительно каких-то порогов, а также и относительно предыдущих значений полученных собакой. Резкость этих изменений мы можем опционально указывать в условии. А можем и не указывать. Тогда мы будем реагировать вообще на все изменения этих циферок в сторону увеличения или уменьшения. Например мы можем реагировать на увеличение роста ошибок на каком-то интерфейсе

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X Ошибки полезли onepunch uplinkerrors rised log,sms,telegram

Ну либо какой-то уровень роста ошибок мы считаем допустимым, и например, устанавливаем порог в 100 ошибок за 10 минут

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X Ошибки полезли резво onepunch uplinkerrors rised 100 log,sms,telegram

Также мы можем таким способом отлавливать либо резкие всплески либо падения утилизации, например все того же канала. Типа, мы считаем, что если утилизация канала за последние 10 минут выросла на восемь гиг.. типа что-то пошло не так

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X Канал разогнался как-то onepunch uplinktraffic rised 8000 log,sms,telegram

Ну или наоборот резкие падения относительно предыдущих значений (типа утилизация аплинка провалилась на 20 гиг от последнего запуска собаки)

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X Трафик рухнул куда-то onepunch uplinktraffic decreased 20000 log,sms,telegram

А еще мы можем очень просто проверять рабочесть сервисов которые должны слушать соединения на какие-то TCP или UDP порты, типа так

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X http на хосте tcpping 192.168.42.18:80 changed log,sms,telegram andresult
Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X https на хосте tcpping 192.168.42.18:443 changed log,sms,telegram andresult
Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X syslogd на хосте udpping 192.168.42.18:514 changed log,sms,telegram andresult

А еще мы можем получать и проверять любые данные, из любого OID при помощи snmpwalk:

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X Версия OS snmpwalk 192.168.42.18:changeme:.1.3.6.1.2.1.1.1.0 changed log,sms,telegram andresult

Или банально нотифицировать себя о том, что в корневом разделе заканчивается место

Активний Ім`я Тип перевірки Параметр Оператор Умова Дії
X Место в корне заканчивается freediskspace / < 100 log,sms,telegram andresult

Отсылка SMS

Не требует включенного модуля рассылки TurboSMS. Весь функционал отправки реализован посредством подсистемы "собака-посылака". Номера для отсылки разделяются запятыми и указываются в международном формате (например +380509999999). Их, как основных так и дополнительных может быть сколько угодно.

Отсылка Telegram

Осуществляется тоже при проходе “собаки-посылаки”. Как настроить своего бота для рассылки, можно почитать тут.

Примеры скриптов

Как уже говорилось выше, при помощи собаки-наблюдаки, возможно заскриптовать и контролировать вообще все что угодно - это ограничено только вашей фантазией и радиусом кривизны рук. Мы рекомендуем хранить кастомные скрипты такого плана в content/documents/myscripts/ - таким образом они будут нормально переживать обновления. Вот несколько, простых примеров:

Получение трафика с порта свитча

switch_traffic
#!/usr/local/bin/php
<?php
 
//config section
$port='24';
$oid='.1.3.6.1.2.1.31.1.1.1.6';
$ip='192.168.0.15';
$community='yourcommunity';
//end of config
 
$cmd='/usr/local/bin/snmpwalk -v2c -On  -c '.$community.' '.$ip.' '.$oid.'.'.$port;
$raw=shell_exec($cmd);
$newTime=time();
if (!empty($raw)) {
$raw=explode('Counter64:',$raw);
$raw=trim($raw[1]);
if (!empty($raw)) {
        $cacheName=dirname(__FILE__).'/octets_'.$ip.'_'.$port;
        if (file_exists($cacheName)) {
                $oldTime=filemtime($cacheName);
                $oldOctets=file_get_contents($cacheName);
                $traffDiff=$raw-$oldOctets;
                $timeDiff=$newTime-$oldTime;
                if ($timeDiff!=0) {
                $speed=($traffDiff*8*100)/($timeDiff*10000);
                print(round($speed/10000));
                } else {
                print('-1');
                }
            file_put_contents($cacheName,$raw);
        } else {
                file_put_contents($cacheName,$raw);
                print('0');
        }
}
 
}

Снятие температуры с eping3

eping_temp
#!/usr/local/bin/php
<?php
 
$ip='192.168.0.89';
$community='yourcommunity';
$oid='1.3.6.1.4.1.35160.1.16.1.13.1';
$result=0;
 
 
$command='/usr/local/bin/snmpwalk -On -r 1 -t 1 -v2c -c '.$community.' '.$ip.' '.$oid;
$resultRaw=shell_exec($command);
        if (!empty($resultRaw)) {
                $result=explode('INTEGER:',$resultRaw);
                $result=(isset($result[1])) ? $result[1] : 0;
                $result=$result/10;
        }
 
print($result);

Наличие электропитания с eping3

eping_power
#!/usr/local/bin/php
<?php
 
$ip='192.168.0.89';
$community='yourcommunity';
$oid='1.3.6.1.4.1.35160.1.26.0';
$result=0;
 
 
$command='/usr/local/bin/snmpwalk -On -r 1 -t 1 -v2c -c '.$community.' '.$ip.' '.$oid;
$resultRaw=shell_exec($command);
        if (!empty($resultRaw)) {
                $result=explode('INTEGER:',$resultRaw);
                $result=(isset($result[1])) ? $result[1] : 0;
                $result=($result==1) ? 'OK' : 'FAILED!';
        }
 
print($result);

Количество свободного места в /var/

var_stat
#!/usr/local/bin/php
<?php
$result=disk_free_space("/var/");
$result=$result/1024/1024/1024;
$result=round($result,2);
 
print($result);
?>

Джиттер до гугла

check_icmp_google
#!/bin/sh
ping -c 1 8.8.8.8 | head -n 2 | tail -n 1 | awk -F "=" '{print $4}' | awk -F " " '{print $1}

Хешрейт на ethermine.org

ethereum_hashrate
#!/usr/local/bin/php
<?php
 
$wallet='72F7B047C192178B1cef591Bc7e960aAD333B822';
$workersStatsUrl = 'https://api.ethermine.org/miner/:'.$wallet.'/workers';
$jsonRaw = file_get_contents($workersStatsUrl);
$reportedHashrate = 0;
 
if (!empty($jsonRaw)) {
    $workersStats = json_decode($jsonRaw, true);
    if (!empty($workersStats)) {
        foreach ($workersStats['data'] as $io => $each) {
                $reportedHashrate+=$each['reportedHashrate'];
        }
    }
}
 
print(round($reportedHashrate/1000000,2));

PPS на интерфейсе

stat_pps
#!/bin/sh
/usr/bin/netstat -w 1 -I bridge0  -q 1 | /usr/bin/tail -n 1 | /usr/bin/awk {'print $1'}

Утилизация CPU Linux хоста

lin_cpustats
#!/usr/local/bin/php
<?php
 
/**
CPU Statistics
 
Load
1 minute Load: .1.3.6.1.4.1.2021.10.1.3.1
5 minute Load: .1.3.6.1.4.1.2021.10.1.3.2
15 minute Load: .1.3.6.1.4.1.2021.10.1.3.3
 
CPU
percentage of user CPU time: .1.3.6.1.4.1.2021.11.9.0
raw user cpu time: .1.3.6.1.4.1.2021.11.50.0
percentages of system CPU time: .1.3.6.1.4.1.2021.11.10.0
raw system cpu time: .1.3.6.1.4.1.2021.11.52.0
percentages of idle CPU time: .1.3.6.1.4.1.2021.11.11.0
raw idle cpu time: .1.3.6.1.4.1.2021.11.53.0
raw nice cpu time: .1.3.6.1.4.1.2021.11.51.0
 
*/
$oid='.1.3.6.1.4.1.2021.10.1.3.3';
$ip='192.168.0.70';
$community='yourcommunity';
//end of config
 
$cmd='/usr/local/bin/snmpwalk -v2c -On  -c '.$community.' '.$ip.' '.$oid;
$raw=shell_exec($cmd);
$newTime=time();
if (!empty($raw)) {
$raw=explode('STRING:',$raw);
$raw=trim($raw[1]);
if (!empty($raw)) {
	print($raw);
} else {
	print('FAIL');
}
 
}

Использование One-Punch скриптов

Еще более предпочтительным, является использование One-Punch скриптов вместо просто скриптов лежащих где-то на вашей ФС. Используя их, вы получаете сразу два главных преимущества:

  1. Они храняться в вашей БД и переезжают всегда вместе с ней
  2. Они выполняются внутри Ubilling и имеют прямой доступ ко всему его функционалу

Как это работает?

Допустим берем и создаем One-Punch скрипт следующего вида:

$watchdogCallbackResult='sometest data';

Вот как-то так

И допустим мы хотим контролировать не изменятся ли данные возвращаемые этим скриптом (с чего-бы это? ;)

Надеюсь очевидно, что собака-наблюдака будет воспринимать как результат выполнения только данные находящиеся в переменной $watchdogCallbackResult?
Также есть еще одно небольшое ограничение относящееся не только к данным возвращаемым One-Punch скриптами, а также и к таким типам проверок как script и httpget. Ограничение заключается в том, что операторы changed и notchanged не работают адекватно если объем возвращаемых этими проверками данных составляет более 255 байт. Поэтому если вы собираетесь использовать эти операторы для контроля измений в данных возвращаемых вышеуказанными типами проверок, вам следует это учитывать при разработке ваших скриптов. Для проверок типа like или скажем notempty это не важно.

Трафик с порта

Вот например то же самое снятие данных о трафике с порта, но в виде One-Punch скрипта:

//config section
$port='8';
$oid='.1.3.6.1.2.1.31.1.1.1.6';
$ip='192.168.18.234';
$community='changeme';
//end of config
 
$cmd='/usr/local/bin/snmpwalk -v2c -On  -c '.$community.' '.$ip.' '.$oid.'.'.$port;
$raw=shell_exec($cmd);
$newTime=time();
if (!empty($raw)) {
$raw=explode('Counter64:',$raw);
$raw=trim($raw[1]);
if (!empty($raw)) {
	$cacheName='content/documents/myscripts/octets_'.$ip.'_'.$port;
	if (file_exists($cacheName)) {
		$oldTime=filemtime($cacheName);
		$oldOctets=file_get_contents($cacheName);
		$traffDiff=$raw-$oldOctets;
		$timeDiff=$newTime-$oldTime;
		if ($timeDiff!=0) {
		$speed=($traffDiff*8*100)/($timeDiff*10000);
		$watchdogCallbackResult=round($speed/10000);
		} else {
		$watchdogCallbackResult='-1';
		}
	    file_put_contents($cacheName,$raw);
	} else {
		file_put_contents($cacheName,$raw);
		$watchdogCallbackResult='0';
	}
}
 
}

Свободное место на диске

$result=disk_free_space("/");
$result=$result/1024/1024/1024;
$watchdogCallbackResult=round($result,2);

Load Average удаленного Linux хоста

$oid = '.1.3.6.1.4.1.2021.10.1.3.3';
$ip = '192.168.0.70';
$community = 'yoursnmpcommunity';
 
 
$cmd = '/usr/local/bin/snmpwalk -v2c -On  -c ' . $community . ' ' . $ip . ' ' . $oid;
$raw = shell_exec($cmd);
$watchdogCallbackResult = '';
if (!empty($raw)) {
    $raw = explode('STRING:', $raw);
    $raw = trim($raw[1]);
    if (!empty($raw)) {
        $watchdogCallbackResult .= $raw;
    }
}

Мониторинг isc-dhcpd

$command='ps aux | grep dhcpd | grep -v grep';
$result=shell_exec($command);
if (!empty($result)) {
  $watchdogCallbackResult='запущено';
} else {
  $watchdogCallbackResult='впав нахрін';
}

Мониторинг TrassirServer

        $watchdogCallbackResult = '';
        $dvrs = new NyanORM('visor_dvrs');
        $dvrs->where('type', '=', 'trassir');
        $allDvrs = $dvrs->getAll();
 
        if (!empty($allDvrs)) {
            foreach ($allDvrs as $io => $each) {
                $dvrName = $each['name'];
                $trassir = new TrassirServer($each['ip'], $each['login'], $each['password'], $each['apikey'], $each['port']);
                $health = $trassir->getHealth();
                if (!$health['disks'] OR ! $health['database'] OR ! $health['network']) {
                    $watchdogCallbackResult .= $dvrName . ' - FAILS ';
                }
            }
        }

Мониторинг температуры на Equicom PING3

    $ip = '192.168.0.89';
    $community = 'yourcommunity';
    $oid = '1.3.6.1.4.1.35160.1.16.1.13.1';
    $correction = 0;
 
 
    $snmp = new SNMPHelper();
    $resultRaw = $snmp->walk($ip, $community, $oid, false);
    $watchdogCallbackResult = 0;
    if (!empty($resultRaw)) {
        $watchdogCallbackResult = zb_SanitizeSNMPValue($resultRaw) / 10;
        $watchdogCallbackResult = $watchdogCallbackResult + $correction;
    }

Мониторинг наличия питания на Equicom PING3

    $ip = '192.168.0.89';
    $community = 'yourcommunity';
    $oid = '1.3.6.1.4.1.35160.1.26.0';
    $result = 0;
 
 
    $snmp = new SNMPHelper();
    $resultRaw = $snmp->walk($ip, $community, $oid, false);
    $watchdogCallbackResult = 0;
    if (!empty($resultRaw)) {
        $watchdogCallbackResult = zb_SanitizeSNMPValue($resultRaw);
        $watchdogCallbackResult = ($watchdogCallbackResult == 1) ? 'OK' : 'FAILED!';
    }

Мониторинг температур на OLT-ах

    $criticalTemp = 70;
 
    $watchdogCallbackResult = '';
    $tempPath = OLTAttractor::TEMPERATURE_PATH;
    $tempExt = OLTAttractor::TEMPERATURE_EXT;
 
    $switchesDb = new nya_switches();
    $switchesDb->where('desc', 'LIKE', '%OLT%');
    $allOlt = $switchesDb->getAll();
 
    foreach ($allOlt as $io => $eachOltData) {
        $tempData = $tempPath . $eachOltData['id'] .'_'. $tempExt;
        if (file_exists($tempData)) {
            $oltTemp = file_get_contents($tempData);
            if ($oltTemp >= $criticalTemp) {
                $watchdogCallbackResult .= $eachOltData['location'] . ' - ' . $oltTemp . ' °C ';
            }
        }
    }
 
    if (empty($watchdogCallbackResult)) {
        $watchdogCallbackResult='Всі температури OLT в порядку';
    }

Нагадування про оплату TurboSMS

    // ключ HTTP API
    $apiKey = 'xxxxxxxxxxxxxxxxxx';
    // поріг коштів після якого нотифікувати
    $lowerLimit = 4000; 
 
    $apiCallback = 'http://api.turbosms.ua/user/balance.json';
    $turboSmsApi = new OmaeUrl($apiCallback);
    $turboSmsApi->dataGet('token', $apiKey);
    $balanceRaw = $turboSmsApi->response();
 
    $watchdogCallbackResult = '';
    if (!empty($balanceRaw)) {
        @$balanceRaw = json_decode($balanceRaw, true);
        if (!empty($balanceRaw)) {
             if (isset($balanceRaw['response_result'])) {
                    if (isset($balanceRaw['response_result']['balance'])) {
                        $balance = $balanceRaw['response_result']['balance'];
                        if ($balance>=$lowerLimit) {
                            $watchdogCallbackResult.=' - коштів достатньо. ';
                        } else {
                            $watchdogCallbackResult.=' - добре би поповнити! ';
                        }
                    }
             }
        }
    }
 
watchdog.1674374676.txt.gz · Востаннє змінено: 2023/01/22 10:04 повз nightfly