====== Собака-спостерігака aka Watchdog ====== {{:nablyudaka.png?300 |}} Собака-спостерігака призначена для собачення та спостерігачення оперативного моніторингу навколишньої реальності. Вона надає гнучкий функціонал для опису позаштатних ситуацій практично будь-якої дивності, а також для сповіщення у разі їх виникнення. У тому числі, за допомогою відсилання SMS через послуги, що підтримуються собакою-посилакою, електронною поштою, месенджера Telegram а також може викликати запуск будь-якого зовнішнього скрипта при настанні якоїсь події. Для ввімкнення собаки-спостерігаки, потрібна зміна опції WATCHDOG_ENABLED в [[alteriniconf|alter.ini]]. Також для надсилання повідомлень, очевидно, на допомогу собаці-спостерігаці знадобиться [[senddog|Собака-посилака]]. ===== Можливі перевірки ===== ^ Типи задач ^ Дія ^ Повертає ^ | 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 | Виконує запуск [[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 | запуск скрипта чи будь-якого додатку, за шляхом, вказаному у вигляді [/повний/шлях/до_скрипта] | ===== Логіка роботи ===== Кожне завдання для Собаки-спостерігаки слід сприймати як "щось трапилося" або "ой яка подія" які трапляються у разі повернення "типом перевірки" за "параметром" результату передбаченого "оператором" з опціональною "умовою". Як приклад, можна навести ось таке просте завдання: ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | Гугл не пінгається | icmpping | google.com | =false | | log,sms,email | При настанні події, коли ping на адресу google.com поверне значення "хибно" собака-спостерігака стурбовано надішле вам СМС-ку, почту та запише в лог сповіщення, про те, що "Гугл не пінгається". Власне і продовжить це робити, допоки перевірка icmpping не перестане повертати значення "хибно". А що робити, якщо ми не хочемо, щоб собака постійно нам спамила за відсутнього пінгу кудись? А дуже просто. ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | Щось змінилось | icmpping | 192.168.0.22 | changed | | log,sms,email,andresult | В принципі, ніхто не забороняє нам робити і завдання такого плану: ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | В серверній пожежа | script | /bin/gettemp | > | 22 | log,sms,email, andresult | Викликаючи зовнішній скрипт, що знімає температуру з термодатчиків і при перевищенні 22 градусів кричати всіма відомими способами також дописуючи в повідомленні про температуру що викликає паніку. Якщо творчо підійти до парсингу виведення зовнішнього ПЗ - можна моніторити багато цікавих речей без дописування зовнішніх скриптів: ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | DNS зламався | script | nslookup google.com %%|%% tail -n 2 | like | find | log,sms | Також ми можемо дуже просто та елегантно контролювати запущеність важливих сервісів типу stargazer, створивши завдання такого плану: ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | Stargazer впав | script | /bin/ps aux %%|%% /usr/bin/grep stg | notlike | stargazer | log,sms | Хоча те саме завдання ми можемо оформити як ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | Stargazer впав | fileexists | /var/run/stargazer.pid | =false | | log,sms | Щоб не зосереджуватись на теоретичних речах, ми можемо передбачити ситуацію, коли у нас є дуже важливий клієнт на падіння якого, нам слід таки відреагувати. Описати таке ми можемо у вигляді: ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | Важливий клієнт подох | hopeping | 172.16.78.42 | changed | | log,sms andresult | Окей, а якщо ми хочемо також цю ж СМС послати скажемо адміністратору цього ж важливого клієнта, щоб він точно знав, що він здох? ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | Важливий клієнт подох | hopeping | 172.16.78.42 | changed | | log,sms andresult {+380509999999} | а якщо ми хочемо надіслати СМС лише на додатковий номер? Так, жодних проблем: log,sms {+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 порту. Думаю вищенаведених прикладів достатньо для отримання уявлення про гнучкість собаки-спостерігаки та можливості побудови сповіщень при практично, будь-яких позаштатних ситуаціях. Обробка завдань собаки відбувається при виклику **watchdog** з [[remoteapi|RemoteAPI]]. Інтервалом, що рекомендується, є 10 хвилин. В crontab це виглядає наступним чином: */10 * * * * /bin/ubapi "watchdog" А ще ми можемо реагувати не лише на зміни поточних значень щодо якихось порогів, а також і відносно попередніх значень, отриманих собакою. Різкість цих змін ми можемо опціонально вказувати в "умові". А можемо й не вказувати. Тоді ми реагуватимемо взагалі на всі зміни цих циферок у бік збільшення або зменшення. Наприклад, ми можемо реагувати на збільшення зростання помилок на якомусь інтерфейсі. ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | Помилки полізли | onepunch | uplinkerrors | rised | | log,sms,telegram | Ну або якийсь рівень зростання помилок ми вважаємо припустимим, і наприклад, встановлюємо поріг у 100 помилок за 10 хвилин ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | Помилки полізли активно | onepunch | uplinkerrors | rised | 100 | log,sms,telegram | Також ми можемо у такий спосіб відловлювати або різкі сплески або падіння утилізації, наприклад, того ж каналу. Типу, ми вважаємо, що якщо утилізація каналу за останні 10 хвилин зросла на вісім гіг.. типу щось пішло не так ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | Канал якось розігнався | onepunch | uplinktraffic | rised | 8000 | log,sms,telegram | Ну чи навпаки різкі падіння щодо попередніх значень (типу утилізація аплінку провалилася на 20 гіг від останнього запуску собаки) ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | Трафік рухнов якось сильно | onepunch | uplinktraffic | decreased | 20000 | log,sms,telegram | А ще ми можемо дуже просто перевіряти робочість сервісів, які повинні слухати з'єднання на якісь TCP або UDP порти, типу так ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | http на хості | tcpping | 192.168.42.18:80 | changed | | log,sms,telegram andresult | ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | https на хості | tcpping | 192.168.42.18:443 | changed | | log,sms,telegram andresult | ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | syslogd на хості | udpping | 192.168.42.18:514 | changed | | log,sms,telegram andresult | А ще ми можемо отримувати та перевіряти будь-які дані з будь-якого OID за допомогою snmpwalk: ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | Версія OS змінилась | snmpwalk | 192.168.42.18:changeme:.1.3.6.1.2.1.1.1.0 | changed | | log,sms,telegram andresult | Або банально нотифікувати себе про те, що у кореневому розділі закінчується місце ^ Ім`я ^ Тип перевірки ^ Параметр ^ Оператор ^ Умова ^ Дії ^ | В корені закінчується місце | freediskspace | / | < | 100 | log,sms,telegram andresult | ===== Відправка SMS ===== Весь функціонал відправлення реалізований за допомогою підсистеми [[senddog|"Собака-посилака"]]. Номери для відсилання розділяються комами та вказуються у міжнародному форматі (наприклад +380509999999) в налаштуваннях "Собаки-спостерігаки". Їх як основних так і додаткових може бути скільки завгодно. ===== Відсилка Telegram ===== Здійснюється також під час проходу "Собаки-посилаки". Як налаштувати свого бота для розсилки, можна почитати [[ubillingtelegram|тут]]. ===== Приклади скриптів ===== Як вже сказано вище, за допомогою собаки-спостерігаки, можливо заскриптувати і контролювати взагалі все, що завгодно - це обмежено тільки вашою фантазією та радіусом кривизни рук. Ми рекомендуємо зберігати кастомні скрипти такого плану в **content/documents/myscripts/** - таким чином вони нормально переживатимуть оновлення. Ось кілька простих прикладів: ==== Отримання трафіку з порта комутатора ==== #!/usr/local/bin/php ==== Зняття температури з ping3 ==== #!/usr/local/bin/php ==== Наявність електомережі з ping3 ==== #!/usr/local/bin/php ==== Кількість вільного місця в /var/ ==== #!/usr/local/bin/php ==== Джиттер до гугла ==== #!/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 ==== #!/usr/local/bin/php $each) { $reportedHashrate+=$each['reportedHashrate']; } } } print(round($reportedHashrate/1000000,2)); ==== PPS на інтерфейсі ==== #!/bin/sh /usr/bin/netstat -w 1 -I bridge0 -q 1 | /usr/bin/tail -n 1 | /usr/bin/awk {'print $1'} ==== Утилізація CPU Linux хоста ==== #!/usr/local/bin/php ===== Використання One-Punch скриптів ===== Ще більш доцільним є використання [[onepunch|One-Punch скриптів]] замість просто скриптів, котрі лежать десь на вашій ФС. Використовуючи їх, ви отримуєте одразу дві головні переваги: - Вони зберігаються у вашій БД і переїжджають завжди разом із нею - Вони виконуються всередині Ubilling і мають прямий доступ до всього його функціоналу. ===== Як це працює? ===== Допустимо беремо і створюємо [[onepunch|One-Punch]] скрипт наступного виду: $watchdogCallbackResult='sometest data'; Ось якось так {{:wdonepunch0.png?|}} І припустимо ми хочемо контролювати чи не зміняться дані, що повертаються цим скриптом (з чого б це? ;) {{:wdonepunch1.png?|}} Сподіваюсь очевидно, що собака-спостерігака сприйматиме як результат виконання скрипта лише дані, що знаходяться в змінній **$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.=' - добре би поповнити! '; } } } } } ==== Моніторинг живості OLT-ів === $watchdogCallbackResult = ' '; $deadOltCount=0; $deadSwitches = zb_SwitchesGetAllDead(); if (!empty($deadSwitches)) { $switchesDb=new NyanOrm('switches'); $switchesDb->where('desc','LIKE','%OLT%'); $allOlts=$switchesDb->getAll('ip'); if (!empty($allOlts)) { foreach ($allOlts as $oltIp=>$eachOltData) { if (isset($deadSwitches[$oltIp])) { $deadOltCount++; } } } } if ($deadOltCount>0) { $watchdogCallbackResult .= $deadOltCount.' завернулись шубою. Можна починати панікувати!'; } else { $watchdogCallbackResult .= 'зі всіма наразі все гаразд.'; }