LINUX.ORG.RU
решено ФорумAdmin

Мониторинг доступности интернета на bash

 , ,


1

1

Всем привет!

В академических целях занимаюсь велосипедостроением, поэтому не ищите много смысла в этом скрипте.

Нашел скрипт, который логирует недоступность заданного хоста и пишет об этом в лог. У меня есть gsm-шлюз, и я подключил отправку себе смс при падении интернета.

Выглядит все это вот так:

#!/bin/bash
PHONES="999999999"                                            
HTTP=http://192.168.1.221:9090/sendsms                          #адрес на шлюзе для запроса
USER=user                                                       #пользователь для авторизации на шлюзе
PASS=password
hostname=$(/bin/hostname -f)
send_bad_msg ()
{
for PHONE in $PHONES
do
curl -s -X POST -d "username=$USER&password=$PASS&phonenumber=$PHONE&message=$hostname Internet link is DOWN" $HTTP? > /dev/null
done
}
send_good_msg ()
{
for PHONE in $PHONES
do
curl -s -X POST -d "username=$USER&password=$PASS&phonenumber=$PHONE&message=$hostname Connection to Internet restored" $HTTP? > /dev/null
done
}
# Скрипт в бесконечном цикле пингует удалённый хост в инете с интервалом 60 сек
# при первой удачной или неудачной попытке пинга пишется соответствующее сообщение в лог
# следующая запись в лог делается только при изменении состояния связи
# инициализация переменной результата, по умолчанию считается, что связь уже есть
result=connected
# смена текущего каталога перед записью лога
cd /var/log
echo `date +%Y.%m.%d__%H:%M:%S`' Run script ' >> ping.log
# бесконечный цикл
while [ true ]; do
    # пинг хоста с последующей проверкой на ошибки
    errorscount="$(ping -c 2 -W 4 192.168.1.24 2<&1| grep -icE 'unknown|expired|unreachable|time out|100% packet loss')"
    # если предыдущий пинг был удачен, а текущий нет, т.е. вывод ping содержит ошибки, то
    if [ "$result" = connected -a "$errorscount" != 0 ]; then
    # запоминаем результат текущего пинга    # запоминаем результат текущего пинга
    result=disconnected
    # и пишем в лог время разрыва соединения
    echo `date +%Y.%m.%d__%H:%M:%S`' * connection break' >> ping.log 
	sleep 30
	if [ "$errorscount" != 0 ]; then 
		send_bad_msg
	fi
    fi
    # если предыдущий пинг был неудачен, а текущий успешен, то
    if [ "$result" = disconnected -a "$errorscount" = 0 ]; then
    # запоминаем результат текущего пинга
    result=connected
    # и пишем в лог время установки соединения
    echo `date +%Y.%m.%d__%H:%M:%S`' connection restore' >> ping.log && send_good_msg
    fi
	sleep 10
done

Иногда (чаще всего в 05:06 утра) Интернет отключается на 30 секунд, приходит смс, все как положено. Однако 30 секунд в 5 утра - это не критичное событие, и я хотел отложить отправку смс, если пинга нет менее 30 секунд.

Как понимаю, есть два пути решения - или увеличить кол-во пингов, необходимых для проверки соединения, либо ввести какой-то счетчик, который будет считать количество состояний для $errorscount, и отталкиваясь от счетчика, отправлять смс.

Однако сейчас я поставил просто таймаут.

    echo `date +%Y.%m.%d__%H:%M:%S`' * connection break' >> ping.log 
	sleep 30
	if [ "$errorscount" != 0 ]; then 
		send_bad_msg
	fi
    fi

Прошу подсказать, насколько это корректное решение, относительно решения текущего вопроса?

Странно, сделал code=Bash /code, а подсветки не появилось

Я бы на каждую итерацию с потерянным пингом увеличивал значение переменной и при достижении какого-либо значения, например 10 неудачных циклов проверки, отправлял бы сообщение. Ну и сброс переменной в 0 при возвращении инета. Таким путем будут сообщения только о длительной пропаже инета.

keir ★★ ()

Посылай сообщение если проверка проваливается два раза подряд, например.

Deleted ()
Ответ на: комментарий от Deleted

А как проверять кол-во проверок? Сейчас же она имеет только результат - да/нет.

Получается, нужен цикл в цикле, где на вход будет результат от $result ?

Aborigen1020 ()

Моя версия (написал, когда провайдер не хотел признавать проблемы с оборудованием)

#!/bin/bash

PINGSERVER="ya.ru"

# Colors and control sequences
RED="\033[91m"
GREEN="\033[92m"
BOLD="\033[1m"
ENDCOLOR="\033[0m"

# errmesg ERR_MESSAGE [debug_info, more_debug info, ...]
errmsg() {
    ERR_MESSAGE="$1"
    shift
    echo -e "${BOLD}${RED}${ERR_MESSAGE}${ENDCOLOR} $@"
}

# okmsg OK_MESSAGE
okmsg() {
    OK_MESSAGE="$1"
    echo -e "${BOLD}${GREEN}${OK_MESSAGE}${ENDCOLOR}"
}

rewind () {
    local NCOL=`tput cols`
    let NCOL=$NCOL-1

    IFS=$'\n'
    tput cuu1
    tput el
}

# Terminal title
echo -e '\e]2;Netmon:  A command-line network health monitor\007\e]1;\007'

# Main loop
while(true); do
    ping -c1 $PINGSERVER >& /dev/null
    if [ $? != 0 ]; then
	rewind
	errmsg "Connection lost:" "`date +'%b %d, %Y at %r'`"
    else
	rewind
	okmsg "Connection OK"
    fi
    sleep 1
done

unanimous ★★★★★ ()
Ответ на: комментарий от Aborigen1020

В переменную запоминать, в файл писать, цикл сделать -
как больше нравится.

Deleted ()

echo >/dev/tcp/192.168.1.221/9090 || echo >/dev/tcp/192.168.1.221/9090 || echo "panic sms"

timeout-ы обычно 30-90 секунд, так что 2х раз будет достаточно

bass ★★★★★ ()
Последнее исправление: bass (всего исправлений: 1)

В академических целях занимаюсь велосипедостроением, поэтому не ищите много смысла в этом скрипте.

поставь nagios/icinga чтобы появился смысл

nagios размером меньше bash, а в даном контексте имеет много преимуществ: в логике проверки, в наличие плагинов, в логике отправки ыведомлений.

futurama ★★★★ ()
Ответ на: комментарий от futurama

Дело не в мониторинге, а в навыке применения bash. Я совершенно не умел и пока только учусь циклам, и вот этому всему сопутствующему.

Я изначально сделал другой скрипт, вот такой, пока еще недопиленный:

PHONES="9999999999"						
HTTP=http://192.168.1.221:9090/sendsms				#адрес на шлюзе для запроса
USER=user							#пользователь для авторизации на шлюзе
PASS=password							#пароль для авторизации на шлюзе
#Что пишем в смс
#msg_trouble="All hosts is unreachable"
#msg_problem="One or more host is lagged"
##Что пингуем
host1="192.168.1.1"
host2="192.168.10.1"
host3="92.92.92.92"
host4="92.92.92.92"
#Как пингуем
ping_cmd="fping -r0 -c 1 -t 250"
#Тело скрипта
while true; do
	for arg in "$host1" "$host2" "$host3" "$host4"
	do
		$ping_cmd $arg
	                case "$?" in
                        0)
                                echo "$arg without lagg"
                        ;;
                        1)
                                curl -s -X POST -d "username=$USER&password=$PASS&phonenumber=$PHONES&message=$arg is DOWN" $HTTP? > /dev/null
                        ;;
                        *)
				echo "$arg or more hosts is lagged"
                        ;;
	                esac ;
	done ;
sleep 5; done;
Однако, моему наставнику не понравилась схема работы, и он предложил переработать скрипт выше.

Aborigen1020 ()
Ответ на: комментарий от bass

Таймауты

А какие именно?

Дело в том, что нужно залогировать такое событие, как отключение интернета, но отправить смс только тогда, когда пройдет 30 секунд от начала события.

По логике я уже понял как надо сделать, а как описать в синтаксисе и совместить с предыдущим кодом - пока нет.

Aborigen1020 ()
Ответ на: комментарий от Aborigen1020

в данном случае tcp connection timeout и зависит от принимающей стороны просто это решение почти соответствует «на bash» из топика :)

нужно залогировать такое событие, как отключение интернета, но отправить смс только тогда, когда пройдет 30 секунд от начала события

ping -c 1 $dst >/dev/null || (sleep 30; ping -c 1 $dst >/dev/null) || echo fail

если нет ответа на пинг, то спать 30 секунд и пингануть ещё раз, если и теперь ничего, то сообщить

bass ★★★★★ ()

Как понимаю, есть два пути решения

Третий путь - сделать конечный автомат с тремя состояниями - хорошо, плохо и непонятно.

legolegs ★★★★★ ()
Ответ на: комментарий от bass

если нет ответа на пинг, то спать 30 секунд и пингануть ещё раз, если и теперь ничего, то сообщить

Лаконично и наглядно.

Спасибо.

Aborigen1020 ()

Дежавю. Тема пинговалок обсуждалась прямо здесь больше одного раза, воспользуйтесь поиском. Это не подкол, просто нет особого смысла обсуждать то что уже не раз обсудили :)

anc ★★★★★ ()
Ответ на: комментарий от Aborigen1020

Дело не в мониторинге, а в навыке применения bash.

Однако, моему наставнику не понравилась схема работы, и он предложил переработать скрипт выше.

Вы уж определитесь. В навыках bash или в схеме. А о фиг поймёшь, что вы собственно спрашиваете.

vodz ★★★★★ ()
Ответ на: комментарий от anc

Суть скорее не в пинговалке, представьте, что она проверяет, например, наличие файла.

Я больше спрашивал про логику и синтаксис, а сферу применения - указал явно, иначе бы было бы совсем ничего не ясно.

Aborigen1020 ()
Ответ на: комментарий от bass

просто это решение почти соответствует

В топике оповещение при отключении, т.е. один раз когда вырубили, а не при недоступности каждые 30 секунд оповещаем, «таджык копать. кабель рубить. интернет мало мало. админ телефон перегреться от смс раз в 30 секунд»

anc ★★★★★ ()
FAILCOUNT=0
SMS=0
while (true); do
 /bin/ping -c 1 -W 1 ya.ru >/dev/null 2>/dev/null
 if [[ "$?" -eq "0" ]]; then
  echo "Inet OK - $FAILCOUNT"
  FAILCOUNT=0
  if [[ "$SMS" -eq "1" ]]; then
   echo 'SMS about internet';
   SMS=0;
  fi
 else
  echo "No Inet - $FAILCOUNT";
  ((FAILCOUNT++))
 fi
 if [[ "$FAILCOUNT" -gt "10" ]]; then
  if [[ "$SMS" -eq "0" ]]; then
   echo 'SMS about FAIL!';
   SMS=1;
  fi
  FAILCOUNT=0
 fi
 sleep 1;
done;
keir ★★ ()
Ответ на: комментарий от Aborigen1020

пора применять к ней имеющиеся навыки bash

И всё же, мне кажется, что вы путаете алгоритм и знания высококачественного кодирования на каком-либо языке. Ведь если ваш скрипт работает, не жрет уйму ресурсов и не тормозит, то и задача — выполнена. А обучаться желательно на задачах, где не требуется решения прямо сейчас и можно раз 10 всё переписать, сравнить потребляемые ресурсы, время и красивость кода.

vodz ★★★★★ ()
Ответ на: комментарий от bass

Возможно я не правильно распарсил вот это?

ping -c 1 $dst >/dev/null || (sleep 30; ping -c 1 $dst >/dev/null) || echo fail
Тогда поправьте меня.

anc ★★★★★ ()
Ответ на: комментарий от vodz

Сорри смайл забыл в конце поставить :)

anc ★★★★★ ()
Ответ на: комментарий от keir

чем ужасно

Ну вот автор хочет (хоть и странным способом) увидеть улучшения своего кода. А вы дали пример ещё хуже его кода.

vodz ★★★★★ ()
Ответ на: комментарий от vodz

А вы дали пример ещё хуже его кода.

Не согласен. Грепать выхлоп пинга! , и всякие
if [ "$result" = connected -a "$errorscount" != 0 ]; then
куда уж хуже? Но это опять дежавю, мне кажется это уже осуждалось вами.

anc ★★★★★ ()

Делай sleep в отдельном процессе и прибивай по pid'у, если интернет появился.

IPR ★★★★★ ()
Ответ на: комментарий от Aborigen1020

Это выяснение ширины строки терминала и потом откат на одну строку назад. Хотел, чтобы все сообщения выводились в одну и ту же строку, а не добавлялись в конец.

tput это команда позволяющая в некоторой степени управлять позицией курсора (каретки вывода) в терминале.

unanimous ★★★★★ ()
Последнее исправление: unanimous (всего исправлений: 1)

Ну чтож, совместными усилиями родили дополнительную проверку. Теперь все это выглядит так:

#!/bin/bash
PHONES="9999999999"                                            #список телефонов через пробел
HTTP=http://192.168.1.221:9090/sendsms                          #адрес на шлюзе для запроса
USER=user                                                       #пользователь для авторизации на шлюзе
PASS=password
hostname=$(/bin/hostname -f)
send_bad_msg ()
{
for PHONE in $PHONES
do
curl -s -X POST -d "username=$USER&password=$PASS&phonenumber=$PHONE&message=$hostname Internet link is DOWN" $HTTP? > /dev/null
done
}
send_good_msg ()
{
for PHONE in $PHONES
do
curl -s -X POST -d "username=$USER&password=$PASS&phonenumber=$PHONE&message=$hostname Connection to Internet restored" $HTTP? > /dev/null
done
}

send_sms=1
result=connected
# смена текущего каталога перед записью лога
cd /var/log
echo `date +%Y.%m.%d__%H:%M:%S`' Run script ' >> ping.log
# бесконечный цикл
while [ true ]; do
        sleep 5
    errorscount="$(ping -c 2 -W 4 192.168.1.24 2<&1| grep -icE 'unknown|expired|unreachable|time out|100% packet loss')"
if [ "$errorscount" -eq 0 -a "$result" = connected ]; then
continue
fi
        if [ "$result" = disconnected -a "$send_sms" = 1 ]; then
                echo `date +%Y.%m.%d__%H:%M:%S`' * Send SMS' >> ping.log && send_bad_msg
                send_sms=0
        fi
if [ "$result" = connected -a "$errorscount" != 0 ]; then
    result=disconnected
    echo `date +%Y.%m.%d__%H:%M:%S`' * connection break' >> ping.log
    fi
        if [ "$result" = disconnected -a "$errorscount" = 0 ]; then
    result=connected
        send_sms=1
    echo `date +%Y.%m.%d__%H:%M:%S`' connection restore' >> ping.log && send_good_msg
    fi
sleep 20
done

Спасибо большое всем откликнувшимся.

Aborigen1020 ()
Ответ на: комментарий от Aborigen1020

«Быдлокод шагает по интернету». Потом следующий «наставник» скопипастит уже этот вариант и начнет допиливать под свои задачи. Самое забавное, что задачу поставленную в топике вы так и не решили.

anc ★★★★★ ()
Ответ на: комментарий от Aborigen1020

ну мля, грепать выхлоп пинга, серьезно?

if ping -c 1 -s 1 -W 1 $HOST >> /dev/null
   then
      echo "good"
   else
      echo "lost"
fi

переделать по вкусу

anonymous ()
Ответ на: комментарий от anonymous

Когда-нибудь я перепишу все по уму, но это будет совсем другая история... (с)

Дело сейчас не в правильности получения результата команды, я знаю, что ее можно (и скорее всего нужно получать) по коду завершения.

Дело сейчас в логике, которая у меня уже теряется в этом велосипеде.

Aborigen1020 ()
Ответ на: комментарий от Aborigen1020

ну Ё мое, я там уже написал про kiss. иди гугли, что это. и тогда не будет проблем с логикой и путаницей, код будет чище и понятней, когда в нем не будет лишних сущностей.

выше по топику был вариант с пайпами, еще короче чем мой, в принципе очень хорош если ты к ним привык

anonymous ()
Ответ на: комментарий от Aborigen1020

давай еще абстрактней, переносимость твоего велосипеда :) предположим кто-то упоролся и впилил локализованную версию утилиты ping. велосипед превращается, превращается велосипед, в элегантную тыкву.

anonymous ()
Ответ на: комментарий от anonymous

Даю подсказку, имя на Л фамилия на П он любит все переписывать, вот не исключаю что и до ping-а доберется и QR код в него встроит до кучи :)

anc ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.