Тут показані розбіжності між вибраною ревізією та поточною версією сторінки.
| Порівняння попередніх версій Попередня ревізія | Попередня ревізія | ||
|
watchdog [2019/12/11 12:56] |
watchdog [2025/10/28 18:56] (поточний) nightfly [Відсилка Telegram] |
||
|---|---|---|---|
| Рядок 1: | Рядок 1: | ||
| + | ====== Собака-спостерігака aka Watchdog ====== | ||
| + | {{: | ||
| + | |||
| + | Собака-спостерігака призначена для < | ||
| + | |||
| + | ===== Можливі перевірки ===== | ||
| + | |||
| + | ^ Типи задач | ||
| + | | icmpping | ||
| + | | tcpping | ||
| + | | udpping | ||
| + | | hopeping | ||
| + | | script | ||
| + | | httpget | ||
| + | | getusertraff | отримання кількості трафіку в байтах логіну користувача вказаного в параметрі | ||
| + | | fileexists | ||
| + | | opentickets | ||
| + | | onepunch | ||
| + | | snmpwalk | ||
| + | | freediskspace | Повертає кількість вільного місця на розділі (точці монтування) вказаній в параметрі. Повертає цифру в Гб. | float | | ||
| + | |||
| + | |||
| + | ===== Можливі оператори для перевірок ===== | ||
| + | |||
| + | ^ Оператор | ||
| + | | =true | Істинно | ||
| + | | =false | ||
| + | | == | Рівне | ||
| + | | != | Не рівне | ||
| + | | > | Більше | ||
| + | | < | Менше | ||
| + | | > = | Більше або рівне | + | | ||
| + | | < = | Менше або рівне | ||
| + | | empty | Пустий результат | | | ||
| + | | notempty | ||
| + | | changed | ||
| + | | notchanged | ||
| + | | like | Містить | ||
| + | | notlike | ||
| + | | rised | Збільшилось | ||
| + | | decreased | ||
| + | |||
| + | |||
| + | ===== Дії що будуть виконані у разі проходження умов ===== | ||
| + | |||
| + | ^ Дії | ||
| + | | log | запис події в системний лог | ||
| + | | sms | надсилання SMS сповіщення на номери стільникових, | ||
| + | | noprimary | ||
| + | | email | надсилання сповіщення електропоштою, | ||
| + | | telegram | ||
| + | | no_tg_primary | ||
| + | | andresult | ||
| + | | oldresult | ||
| + | | script | ||
| + | |||
| + | ===== Логіка роботи ===== | ||
| + | |||
| + | Кожне завдання для Собаки-спостерігаки слід сприймати як " | ||
| + | |||
| + | ^ Ім`я | ||
| + | | Гугл не пінгається | icmpping | ||
| + | |||
| + | При настанні події, коли ping на адресу google.com поверне значення " | ||
| + | |||
| + | |||
| + | А що робити, | ||
| + | |||
| + | ^ Ім`я | ||
| + | | Щось змінилось | icmpping | ||
| + | |||
| + | |||
| + | В принципі, | ||
| + | |||
| + | ^ Ім`я | ||
| + | | В серверній пожежа | script | ||
| + | |||
| + | |||
| + | Викликаючи зовнішній скрипт, | ||
| + | |||
| + | Якщо творчо підійти до парсингу виведення зовнішнього ПЗ - можна моніторити багато цікавих речей без дописування зовнішніх скриптів: | ||
| + | |||
| + | ^ Ім`я | ||
| + | | DNS зламався | ||
| + | |||
| + | Також ми можемо дуже просто та елегантно контролювати запущеність важливих сервісів типу stargazer, створивши завдання такого плану: | ||
| + | |||
| + | ^ Ім`я | ||
| + | | Stargazer впав | ||
| + | |||
| + | Хоча те саме завдання ми можемо оформити як | ||
| + | |||
| + | ^ Ім`я | ||
| + | | Stargazer впав | ||
| + | |||
| + | |||
| + | Щоб не зосереджуватись на теоретичних речах, ми можемо передбачити ситуацію, | ||
| + | |||
| + | ^ Ім`я | ||
| + | | Важливий клієнт подох | hopeping | ||
| + | |||
| + | |||
| + | Окей, а якщо ми хочемо також цю ж СМС послати скажемо адміністратору цього ж важливого клієнта, | ||
| + | |||
| + | ^ Ім`я | ||
| + | | Важливий клієнт подох | hopeping | ||
| + | |||
| + | |||
| + | а якщо ми хочемо надіслати СМС лише на додатковий номер? Так, жодних проблем: | ||
| + | | ||
| + | log,sms {+380509999999} noprimary | ||
| + | |||
| + | |||
| + | |||
| + | а якщо ми хочемо надіслати алерт тільки в додатковий чат Telegram? Так, так само без проблем: | ||
| + | | ||
| + | log, | ||
| + | | ||
| + | |||
| + | |||
| + | а можна міксувати СМС та Telegram? Так, просто вказуємо в діях все що нам потрібно разом: | ||
| + | | ||
| + | log, | ||
| + | | ||
| + | Хоча знову ж таки ніхто не забороняє нам, скажімо моніторити цього клієнта наприклад зовнішнім скриптом, | ||
| + | |||
| + | < | ||
| + | */10 * * * * / | ||
| + | </ | ||
| + | |||
| + | А ще ми можемо реагувати не лише на зміни поточних значень щодо якихось порогів, | ||
| + | |||
| + | |||
| + | ^ Ім`я | ||
| + | | Помилки полізли | onepunch | ||
| + | |||
| + | |||
| + | Ну або якийсь рівень зростання помилок ми вважаємо припустимим, | ||
| + | |||
| + | ^ Ім`я | ||
| + | | Помилки полізли активно | onepunch | ||
| + | |||
| + | |||
| + | Також ми можемо у такий спосіб відловлювати або різкі сплески або падіння утилізації, | ||
| + | ^ Ім`я | ||
| + | | Канал якось розігнався | onepunch | ||
| + | |||
| + | |||
| + | Ну чи навпаки різкі падіння щодо попередніх значень (типу утилізація аплінку провалилася на 20 гіг від останнього запуску собаки) | ||
| + | |||
| + | ^ Ім`я | ||
| + | | Трафік рухнов якось сильно | onepunch | ||
| + | |||
| + | А ще ми можемо дуже просто перевіряти робочість сервісів, | ||
| + | |||
| + | ^ Ім`я | ||
| + | | http на хості | tcpping | ||
| + | |||
| + | |||
| + | ^ Ім`я | ||
| + | | https на хості | tcpping | ||
| + | |||
| + | ^ Ім`я | ||
| + | | syslogd на хості | udpping | ||
| + | |||
| + | |||
| + | А ще ми можемо отримувати та перевіряти будь-які дані з будь-якого OID за допомогою snmpwalk: | ||
| + | |||
| + | ^ Ім`я | ||
| + | | Версія OS змінилась | snmpwalk | ||
| + | |||
| + | Або банально нотифікувати себе про те, що у кореневому розділі закінчується місце | ||
| + | |||
| + | ^ Ім`я | ||
| + | | В корені закінчується місце | freediskspace | ||
| + | |||
| + | ===== Відправка SMS ===== | ||
| + | |||
| + | Весь функціонал відправлення реалізований за допомогою підсистеми [[senddog|" | ||
| + | |||
| + | |||
| + | ===== Відсилка Telegram ===== | ||
| + | |||
| + | Здійснюється також під час проходу " | ||
| + | |||
| + | |||
| + | ===== Приклади скриптів ===== | ||
| + | |||
| + | Як вже сказано вище, за допомогою собаки-спостерігаки, | ||
| + | |||
| + | ==== Отримання трафіку з порта комутатора ==== | ||
| + | <file php switch_traffic> | ||
| + | # | ||
| + | <?php | ||
| + | |||
| + | //config section | ||
| + | $port=' | ||
| + | $oid=' | ||
| + | $ip=' | ||
| + | $community=' | ||
| + | //end of config | ||
| + | |||
| + | $cmd='/ | ||
| + | $raw=shell_exec($cmd); | ||
| + | $newTime=time(); | ||
| + | if (!empty($raw)) { | ||
| + | $raw=explode(' | ||
| + | $raw=trim($raw[1]); | ||
| + | if (!empty($raw)) { | ||
| + | $cacheName=dirname(__FILE__).'/ | ||
| + | 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)/ | ||
| + | print(round($speed/ | ||
| + | } else { | ||
| + | print(' | ||
| + | } | ||
| + | file_put_contents($cacheName, | ||
| + | } else { | ||
| + | file_put_contents($cacheName, | ||
| + | print(' | ||
| + | } | ||
| + | } | ||
| + | |||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Зняття температури з ping3 ==== | ||
| + | |||
| + | <file php eping_temp> | ||
| + | # | ||
| + | <?php | ||
| + | |||
| + | $ip=' | ||
| + | $community=' | ||
| + | $oid=' | ||
| + | $result=0; | ||
| + | |||
| + | |||
| + | $command='/ | ||
| + | $resultRaw=shell_exec($command); | ||
| + | if (!empty($resultRaw)) { | ||
| + | $result=explode(' | ||
| + | $result=(isset($result[1])) ? $result[1] : 0; | ||
| + | $result=$result/ | ||
| + | } | ||
| + | |||
| + | print($result); | ||
| + | </ | ||
| + | |||
| + | ==== Наявність електомережі з ping3 ==== | ||
| + | |||
| + | <file php eping_power> | ||
| + | # | ||
| + | <?php | ||
| + | |||
| + | $ip=' | ||
| + | $community=' | ||
| + | $oid=' | ||
| + | $result=0; | ||
| + | |||
| + | |||
| + | $command='/ | ||
| + | $resultRaw=shell_exec($command); | ||
| + | if (!empty($resultRaw)) { | ||
| + | $result=explode(' | ||
| + | $result=(isset($result[1])) ? $result[1] : 0; | ||
| + | $result=($result==1) ? ' | ||
| + | } | ||
| + | |||
| + | print($result); | ||
| + | |||
| + | </ | ||
| + | |||
| + | ==== Кількість вільного місця в /var/ ==== | ||
| + | |||
| + | <file php var_stat> | ||
| + | # | ||
| + | <?php | ||
| + | $result=disk_free_space("/ | ||
| + | $result=$result/ | ||
| + | $result=round($result, | ||
| + | |||
| + | print($result); | ||
| + | ?> | ||
| + | </ | ||
| + | |||
| + | ==== Джиттер до гугла ==== | ||
| + | |||
| + | <file bash check_icmp_google> | ||
| + | #!/bin/sh | ||
| + | ping -c 1 8.8.8.8 | head -n 2 | tail -n 1 | awk -F " | ||
| + | </ | ||
| + | |||
| + | ==== Хешрейт на ethermine.org ==== | ||
| + | |||
| + | <file php ethereum_hashrate> | ||
| + | # | ||
| + | <?php | ||
| + | |||
| + | $wallet=' | ||
| + | $workersStatsUrl = ' | ||
| + | $jsonRaw = file_get_contents($workersStatsUrl); | ||
| + | $reportedHashrate = 0; | ||
| + | |||
| + | if (!empty($jsonRaw)) { | ||
| + | $workersStats = json_decode($jsonRaw, | ||
| + | if (!empty($workersStats)) { | ||
| + | foreach ($workersStats[' | ||
| + | $reportedHashrate+=$each[' | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | print(round($reportedHashrate/ | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== PPS на інтерфейсі ==== | ||
| + | |||
| + | <file bash stat_pps> | ||
| + | #!/bin/sh | ||
| + | / | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Утилізація CPU Linux хоста ==== | ||
| + | |||
| + | <file php lin_cpustats> | ||
| + | # | ||
| + | <?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=' | ||
| + | $ip=' | ||
| + | $community=' | ||
| + | //end of config | ||
| + | |||
| + | $cmd='/ | ||
| + | $raw=shell_exec($cmd); | ||
| + | $newTime=time(); | ||
| + | if (!empty($raw)) { | ||
| + | $raw=explode(' | ||
| + | $raw=trim($raw[1]); | ||
| + | if (!empty($raw)) { | ||
| + | print($raw); | ||
| + | } else { | ||
| + | print(' | ||
| + | } | ||
| + | |||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | ===== Використання One-Punch скриптів ===== | ||
| + | |||
| + | Ще більш доцільним є використання [[onepunch|One-Punch скриптів]] замість просто скриптів, | ||
| + | |||
| + | - Вони зберігаються у вашій БД і переїжджають завжди разом із нею | ||
| + | - Вони виконуються всередині Ubilling і мають прямий доступ до всього його функціоналу. | ||
| + | |||
| + | ===== Як це працює? | ||
| + | |||
| + | Допустимо беремо і створюємо [[onepunch|One-Punch]] скрипт наступного виду: | ||
| + | |||
| + | <code php> | ||
| + | $watchdogCallbackResult=' | ||
| + | </ | ||
| + | |||
| + | Ось якось так | ||
| + | |||
| + | {{: | ||
| + | |||
| + | І припустимо ми хочемо контролювати чи не зміняться дані, що повертаються цим скриптом (з чого б це? ;) | ||
| + | |||
| + | {{: | ||
| + | |||
| + | Сподіваюсь очевидно, | ||
| + | |||
| + | \\ | ||
| + | Також є ще одне невелике обмеження, | ||
| + | |||
| + | ==== Трафік з порта ==== | ||
| + | |||
| + | Ось наприклад те саме зняття даних про трафік з порту світча, | ||
| + | |||
| + | <code php> | ||
| + | //config section | ||
| + | $port=' | ||
| + | $oid=' | ||
| + | $ip=' | ||
| + | $community=' | ||
| + | //end of config | ||
| + | |||
| + | $cmd='/ | ||
| + | $raw=shell_exec($cmd); | ||
| + | $newTime=time(); | ||
| + | if (!empty($raw)) { | ||
| + | $raw=explode(' | ||
| + | $raw=trim($raw[1]); | ||
| + | if (!empty($raw)) { | ||
| + | $cacheName=' | ||
| + | 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)/ | ||
| + | $watchdogCallbackResult=round($speed/ | ||
| + | } else { | ||
| + | $watchdogCallbackResult=' | ||
| + | } | ||
| + | file_put_contents($cacheName, | ||
| + | } else { | ||
| + | file_put_contents($cacheName, | ||
| + | $watchdogCallbackResult=' | ||
| + | } | ||
| + | } | ||
| + | |||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Вільне місце на диску ==== | ||
| + | |||
| + | <code php> | ||
| + | $result=disk_free_space("/" | ||
| + | $result=$result/ | ||
| + | $watchdogCallbackResult=round($result, | ||
| + | </ | ||
| + | |||
| + | ==== Load Average віддаленого Linux хосту ==== | ||
| + | |||
| + | <code php> | ||
| + | $oid = ' | ||
| + | $ip = ' | ||
| + | $community = ' | ||
| + | |||
| + | |||
| + | $cmd = '/ | ||
| + | $raw = shell_exec($cmd); | ||
| + | $watchdogCallbackResult = ''; | ||
| + | if (!empty($raw)) { | ||
| + | $raw = explode(' | ||
| + | $raw = trim($raw[1]); | ||
| + | if (!empty($raw)) { | ||
| + | $watchdogCallbackResult .= $raw; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Моніторинг isc-dhcpd ==== | ||
| + | |||
| + | <code php> | ||
| + | $command=' | ||
| + | $result=shell_exec($command); | ||
| + | if (!empty($result)) { | ||
| + | $watchdogCallbackResult=' | ||
| + | } else { | ||
| + | $watchdogCallbackResult=' | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | ==== Моніторинг TrassirServer ==== | ||
| + | <code php> | ||
| + | $watchdogCallbackResult = ''; | ||
| + | $dvrs = new NyanORM(' | ||
| + | $dvrs-> | ||
| + | $allDvrs = $dvrs-> | ||
| + | |||
| + | if (!empty($allDvrs)) { | ||
| + | foreach ($allDvrs as $io => $each) { | ||
| + | $dvrName = $each[' | ||
| + | $trassir = new TrassirServer($each[' | ||
| + | $health = $trassir-> | ||
| + | if (!$health[' | ||
| + | $watchdogCallbackResult .= $dvrName . ' - FAILS '; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Моніторинг температури з Equicom PING3 ==== | ||
| + | |||
| + | <code php> | ||
| + | $ip = ' | ||
| + | $community = ' | ||
| + | $oid = ' | ||
| + | $correction = 0; | ||
| + | |||
| + | |||
| + | $snmp = new SNMPHelper(); | ||
| + | $resultRaw = $snmp-> | ||
| + | $watchdogCallbackResult = 0; | ||
| + | if (!empty($resultRaw)) { | ||
| + | $watchdogCallbackResult = zb_SanitizeSNMPValue($resultRaw) / 10; | ||
| + | $watchdogCallbackResult = $watchdogCallbackResult + $correction; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Моніторинг наявності живлення на Equicom PING3 === | ||
| + | <code php> | ||
| + | $ip = ' | ||
| + | $community = ' | ||
| + | $oid = ' | ||
| + | $result = 0; | ||
| + | |||
| + | |||
| + | $snmp = new SNMPHelper(); | ||
| + | $resultRaw = $snmp-> | ||
| + | $watchdogCallbackResult = 0; | ||
| + | if (!empty($resultRaw)) { | ||
| + | $watchdogCallbackResult = zb_SanitizeSNMPValue($resultRaw); | ||
| + | $watchdogCallbackResult = ($watchdogCallbackResult == 1) ? ' | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Моніторинг температур на OLT-ах === | ||
| + | |||
| + | <code php> | ||
| + | $criticalTemp = 70; | ||
| + | |||
| + | $watchdogCallbackResult = ''; | ||
| + | $tempPath = OLTAttractor:: | ||
| + | $tempExt = OLTAttractor:: | ||
| + | |||
| + | $switchesDb = new nya_switches(); | ||
| + | $switchesDb-> | ||
| + | $allOlt = $switchesDb-> | ||
| + | |||
| + | foreach ($allOlt as $io => $eachOltData) { | ||
| + | $tempData = $tempPath . $eachOltData[' | ||
| + | if (file_exists($tempData)) { | ||
| + | $oltTemp = file_get_contents($tempData); | ||
| + | if ($oltTemp >= $criticalTemp) { | ||
| + | $watchdogCallbackResult .= $eachOltData[' | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | | ||
| + | if (empty($watchdogCallbackResult)) { | ||
| + | $watchdogCallbackResult=' | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | ==== Нагадування про оплату TurboSMS === | ||
| + | |||
| + | <code php> | ||
| + | // ключ HTTP API | ||
| + | $apiKey = ' | ||
| + | // поріг коштів після якого нотифікувати | ||
| + | $lowerLimit = 4000; | ||
| + | |||
| + | $apiCallback = ' | ||
| + | $turboSmsApi = new OmaeUrl($apiCallback); | ||
| + | $turboSmsApi-> | ||
| + | $balanceRaw = $turboSmsApi-> | ||
| + | | ||
| + | $watchdogCallbackResult = ''; | ||
| + | if (!empty($balanceRaw)) { | ||
| + | @$balanceRaw = json_decode($balanceRaw, | ||
| + | if (!empty($balanceRaw)) { | ||
| + | if (isset($balanceRaw[' | ||
| + | if (isset($balanceRaw[' | ||
| + | $balance = $balanceRaw[' | ||
| + | if ($balance> | ||
| + | $watchdogCallbackResult.=' | ||
| + | } else { | ||
| + | $watchdogCallbackResult.=' | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | ==== Моніторинг живості OLT-ів === | ||
| + | |||
| + | <code php> | ||
| + | $watchdogCallbackResult = ' '; | ||
| + | $deadOltCount=0; | ||
| + | $deadSwitches = zb_SwitchesGetAllDead(); | ||
| + | |||
| + | if (!empty($deadSwitches)) { | ||
| + | $switchesDb=new NyanOrm(' | ||
| + | $switchesDb-> | ||
| + | $allOlts=$switchesDb-> | ||
| + | if (!empty($allOlts)) { | ||
| + | foreach ($allOlts as $oltIp=> | ||
| + | if (isset($deadSwitches[$oltIp])) { | ||
| + | $deadOltCount++; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | | ||
| + | if ($deadOltCount> | ||
| + | $watchdogCallbackResult .= $deadOltCount.' | ||
| + | } else { | ||
| + | $watchdogCallbackResult .= 'зі всіма наразі все гаразд.'; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Моніторинг BGP сесій === | ||
| + | |||
| + | <code php> | ||
| + | $watchdogCallbackResult = ''; | ||
| + | $deadPeersList = ''; | ||
| + | $bgpMon = new BGPMon(); | ||
| + | $allPeersStats = $bgpMon-> | ||
| + | $deadCount = 0; | ||
| + | if (!empty($allPeersStats)) { | ||
| + | foreach ($allPeersStats as $eachRouterId => $eachRouterStats) { | ||
| + | if (!empty($eachRouterStats)) { | ||
| + | foreach ($eachRouterStats as $io => $each) { | ||
| + | if ($each[' | ||
| + | $deadCount++; | ||
| + | $deadPeersList .= $each[' | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | if ($deadCount > 0) { | ||
| + | $watchdogCallbackResult .= ' | ||
| + | $watchdogCallbackResult .= $deadPeersList; | ||
| + | } else { | ||
| + | $watchdogCallbackResult .= 'Зі всіма BGP пірами все гаразд'; | ||
| + | } | ||
| + | |||
| + | deb($watchdogCallbackResult); | ||
| + | </ | ||