Telegram давно уже мой основной мессенжер, и вот, решил я разобраться, как отправлять сообщения из CLI себе в клиент TG, а попутно, понял что это можно использовать и как канал уведомлений от mikrotik'ов.


Cначала создаем бота в Telegram

Для этого надо в Telegram найти бота @BotFather,

Далее отправляем команду на создание нового /newbot,

Называем его как нравится, в данном примере - My CLI Bot.

Следующий вопрос: username для бота. Он должен заканчиваться на bot, и быть уникальным, для этого примера пусть будет mysuper_cli_uniq_test_bot

Итак, мы получили API ключ, который можно использовать дальше.

Есть потребность чтобы бот присылал сообщение не персонально, а в группу, чтобы другие участники могли видеть результаты? Организовываем! Создаем группу, добавляем туда нашего бота, добавляем туда бота RawDataBot, который нам сообщает id нашего группового чата.

В моем случае ответ от бота RawDataBot выглядел вот так:

Так, теперь мы знаем ID чата, (в моем примере: -703498699), и дальше уже добавленного бота RawDataBot можно удалить из группы, а номер чата будем использовать в следующих шагах.

Если группу создавать не требуется, то бот будет присылать сообщения Вам.
Для этого надо открыть диалог с этим ботом, и нажать кнопку Start.
А в настройках скриптов указывать в качестве ID номер ID аккаунта в Telegram, узнать его можно у того же бота @RawDataBot.

Отправка сообщений из bash

Самый простой, не особо полезный вариант:

curl -s "https://api.telegram.org/bot5595649065:AAHFJIBbd4a3c1a0cb3a98bjydfgbM1usj3g/sendMessage?chat_id=-703498699&text=simple_text"

Слегка изменим вариант:

curl -s -X POST https://api.telegram.org/bot5595649065:AAHFJIBbd4a3c1a0cb3a98bjydfgbM1usj3g/sendMessage -d chat_id=-703498699 -d text="кое что уже более-менее полезное"

Отправка файла:

curl -F document=@"./Pictures/Screenshot from 2022-07-11 17-13-56-obfuscated.png" "https://api.telegram.org/bot5595649065:AAHFJIBbd4a3c1a0cb3a98bjydfgbM1usj3g/sendDocument?chat_id=-703498699"

Надо либо использовать абсолютный путь, либо относительно текущего каталога, ( ~ не принимается).

Ещё удобнее, если добавить функции в shell.rc файл

Можно ещё упростить жизнь - добавим возможность исполнять желаемое в shell.rc файл (в моем случае это ~/.zshrc, в bash почти так же)
открываем ~/.bashrc (или ~/.zshrc) и добавляем туда вот это:

msg2tg() { 
				curl -s -X POST https://api.telegram.org/bot5595649065:AAHFJIBbd4a3c1a0cb3a98bjydfgbM1usj3g/sendMessage -d chat_id=-703498699 -d text="$1" > /dev/null 2>&1
        }
file2tg() {
				curl -F document=@"$1" https://api.telegram.org/bot5595649065:AAHFJIBbd4a3c1a0cb3a98bjydfgbM1usj3g/sendDocument\?chat_id=-703498699 > /dev/null 2>&1
        	} 

После этого в консоли перечитываем rc файл (или открываем новую консоль)
source ~/.bashrc

И в итоге можно отправлять сообщения по типу такого:

msg2tg "проверка отправки сообщения из консоли"
msg2tg "`uptime`"

или даже, как например:

msg2tg "`echo "1 BTC = $(curl -s 'https://api.binance.com/api/v1/ticker/price?symbol=BTCUSDT' | cut -d: -f3 | sed 's/"//g; s/}//g') USDT (Binance)"`"

Ну и файлы:

file2tg ./Pictures/429889.jpg

file2tg /var/spool/asterisk/monitor/2022/07/11/_some_name.wav

> /dev/null 2>&1

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

а в мой клиент пришел отправленный файл
а в мой клиент пришел отправленный файл

Не стоит забывать, что для ботов размер отправки файлов ограничен до 50 мегабайт, а сообщений - в количестве знаков. И не более 20 ботов на один аккаунт.
Ознакомиться с ограничениями в целом можно тут, ну и следует почитать и FAQ и документацию по API.


Ещё примеры как это использовать из bash скриптов.

Уведомление о запуске сервера
#! /bin/bash
#license : GNU GPL version 2
#author: 
#Telegram Section
TOKEN="5595649065:AAHFJIBbd4a3c1a0cb3a98bjydfgbM1usj3g"
ID="-703498699"
URL="https://api.telegram.org/bot$TOKEN/sendMessage"
#end of Telegram section

MSG="MyServer send hello after start"

curl -s -X POST $URL -d chat_id=$ID -d text="$(echo "$MSG")" > /dev/null 2>&1

Делаем некий after_start.sh, делаем для этого файла chmod + x, сохраняем его в какой нибудь типа /usr/local/bin/after_start.sh,
далее создаем например /etc/systemd/system/msg_after_start.service, в котором напишем:

[Unit]
Description=User's notification after system boot
After=systemd-user-sessions.service
After=network-online.target

[Service]
ExecStart=/usr/local/bin/after_start.sh

[Install]
WantedBy=multi-user.target

А затем, не забыть ещё включить сервис:

systemctl enable msg_after_start.service

Сбор данных
#! /bin/bash
#license : GNU GPL version 2
#author: 
#Telegram Section
TOKEN="5595649065:AAHFJIBbd4a3c1a0cb3a98bjydfgbM1usj3g"
ID="-703498699"
URL="https://api.telegram.org/bot$TOKEN/sendDocument"
#end of Telegram section

tmplog="/tmp/shell_mikrotik_stats_${today}_${RANDOM}"
LC_ALL=C date "+%F %T, %A, UTC %Z" >> "$tmplog"
echo "some_mikrotik_name" >> "$tmplog"

ssh user@some_mikrotik_name '/system resource print; /interface print stats-detail ; /log print ' | egrep -i -A 2 "uptime|lte|vpn" | egrep -v 'info|--' >> "$tmplog"
ssh user@some_mikrotik_name '/ip/dhcp-server/lease/print detail' >> "$tmplog"  2>&1
ssh user@some_mikrotik_name '/log print '|egrep -v "dhcp,info defconf|user user logged|publickey accepted for user" | tail -n 70 >> "$tmplog"  2>&1

curl -F document=@"$tmplog" $URL?chat_id=$ID > /dev/null 2>&1
rm "$tmplog"

После, такой скрипт добавляем к примеру в crontab и получаем искомое с какой-то периодичностью.

Borg Backup с отправкой уведомлений в Телеграм
#!/bin/sh
#Telegram Section
TOKEN="5595649065:AAHFJIBbd4a3c1a0cb3a98bjydfgbM1usj3g"
ID="-703498699"
URL="https://api.telegram.org/bot$TOKEN/sendMessage"
TG_URL2="https://api.telegram.org/bot$TOKEN/sendDocument?chat_id=$ID"
#end of Telegram section
umount /mnt/borg;
today=`date +%Y-%m-%d`
tmplog="/tmp/borg_out_${today}_${RANDOM}.log"
first_day_of_cur_month=`date +%Y%m01`
first_week_of_month=`date -d "$first_day_of_cur_month" +%W`
current_week=`date +%W`
current_week_of_month=`expr $current_week - $first_week_of_month`
#если в момент запуска скрипта на календаре в рамках одного месяца неделя под номером 3, то работаем с одним набором каталогов, если 1 - то с другим.
if [[ "$current_week_of_month" -eq 3 ]] ; then
	cd /mnt/smb.server1/share/Пользовательские\ данные;
	BackupPath=" Набор1     \
                     Папка2 \
                     ../Каталог3"
	BPreffix='auto-sh-rd-'
    elif [[ "$current_week_of_month" -eq 1 ]] ; then
	cd /mnt/smb.server2;
	BackupPath=" ./"
	BPreffix='auto-sh-nd-'
   else
   	BackupPath=" "
	exit 0;
fi

# Уведомление в Телеграм о начале работы скрипта
MSG="Backuping by Borg started "$(echo "$today")", in `pwd` for "$(echo "$BackupPath")" "
curl -s -X POST $URL -d chat_id=$ID -d text="$(echo  "$MSG")" > /dev/null 2>&1

# Setting this, so the repo does not need to be given on the commandline:
export BORG_REPO=/backup/borg/big-share

# See the section "Passphrase notes" for more infos.
export BORG_PASSPHRASE='=4Na=R>!SD^csp;Kcdc2s&M}?L-W7)2s_gWL54}4!sq6'

# some helpers and error handling:
info() { printf "\n%s %s\n\n" "$( date )" "$*" >&2; }
trap 'echo $( date ) Backup interrupted >&2; exit 2' INT TERM

info "Starting backup"

# Backup the most important directories into an archive named after
# the machine this script is currently running on:

borg create                         \
    --stats                         \
    --verbose                       \
    --filter AME                    \
    --list                          \
    --stats                         \
    --show-rc                       \
    --compression  zstd,18          \
    --exclude-caches                \
    --exclude '*.avi'               \
    --exclude '*.AVI'               \
    --exclude '*.asf'               \
    --exclude '*.VOB'               \
    --exclude '*.MP4'               \
    --exclude '*.mp4'               \
    --exclude '*.MPG'               \
    --exclude '*.MPEG'              \
    --exclude '*.mpeg'              \
    --exclude '*.mpg'               \
    --exclude '*.mov'               \
    --exclude '*.MOV'               \
    --exclude '*.webm'              \
    --exclude '*/Thumbs.db'      \
    --exclude 'Thumbs.db'        \
    --exclude '*.tmp'            \
                                 \
    ::$BPreffix'{now}'            \
	$BackupPath 2>> "$tmplog"

backup_exit=$?

curdate2=`LC_ALL=C date "+%F %T, %A, UTC %Z"`
echo "Backup procedure ended at "$(echo "$curdate2")" " >> "$tmplog"


info "Pruning repository"

# Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly
# archives of THIS machine. The '{hostname}-' prefix is very important to
# limit prune's operation to this machine's archives and not apply to
# other machines' archives also:

borg prune                          \
    --list                          \
    --prefix 'auto-sh-'          \
    --show-rc                       \
    --keep-weekly   4               \
    --keep-monthly  6       2>> "$tmplog"

prune_exit=$?

#send log and info to Peoples in Telegram Chat
# Так как размер файла получается большой, то сначала сжимаем, а потом сжатое уже отправляется
xz -e -T0 -k $tmplog
curl -F document=@"$tmplog".xz $TG_URL2

MSG1="Backuping by Borg, which started "$(echo "$today")", is ended"
MSG2=`tail -n 60 $tmplog|grep "Backup procedure ended" -B22 -A2`
curl -s -X POST $URL -d chat_id=$ID -d text="$(echo  "$MSG2")" > /dev/null 2>&1
curl -s -X POST $URL -d chat_id=$ID -d text="$(echo  "$MSG1")" > /dev/null 2>&1

# Remove tmp file
rm "$tmplog"

# use highest exit code as global exit code
global_exit=$(( backup_exit > prune_exit ? backup_exit : prune_exit ))

if [ ${global_exit} -eq 0 ]; then
    info "Backup and Prune finished successfully"
elif [ ${global_exit} -eq 1 ]; then
    info "Backup and/or Prune finished with warnings"
else
    info "Backup and/or Prune finished with errors"
fi

exit ${global_exit}

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

Уведомления от MikroTik-ов (RouterOS)

Ну и тут я вспомнил про уведомления с микротиков, и подумал, может быть полезным..

Открываем WebUI или WinBox, или быть может консоль по ssh, короче заходит на нужный Mikrotik, и после Log in переходим system -> Scripts, создаем новый, назовем его например msg2tg

msg2tg
do { 
	:global text4tg
	:local telegramBotToken "5595649065:AAHFJIBbd4a3c1a0cb3a98bjydfgbM1usj3g";
	:local destination "-703498699";
	:local requestUrl "https://api.telegram.org/bot$telegramBotToken/sendMessage";
	# Тут указывается текст, который будет отправляться.
  :local httpData "{\"chat_id\": \"$destination\", \"text\": \"MyHome MikroTik-1 says ::
 $text4tg\"}";
	/tool fetch url=$requestUrl http-data=$httpData http-header-field=content-type:application/json http-method=post  keep-result=no
} on-error={
	/log info "msg2tg finished with error";
}
/log info "script for sending msg to tg is finished";

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

так это выглядит в WinBox
так это выглядит в WinBox

Таким образом, у нас получился скрипт, который будем вызывать из последующих (так сэкономим байты памяти, да и при необходимости поправить адреса́та будет легко это сделать для всех зависимых потомков).

Теперь, ну пусть будет скрипт для уведомлений о запуске операционной системы:

msg2tg_after_start.rsc
delay 20;
{
	:put [global text4tg "HELLO after START "];
	/system script run msg2tg;
}

Задержка в начале нужна, чтобы соединения с интернетом уже поднялись, и только уже после этого выполнять отправку сообщения.

Примерно такое можно получать от настроенного планировщика.
Примерно такое можно получать от настроенного планировщика.

И ещё один скрипт, например, для мониторинга за доступностью оборудования:

Check_ip-cams.rsc
:local ipcamGates "192.168.1.100";
:if ([/ping $ipcamGates interval=5 count=3] <=0) do={
	delay 180;
	:if ([/ping $ipcamGates interval=5 count=6] <=0) do={
		delay 300;
		:if ([/ping $ipcamGates interval=5 count=10] <=0) do={
			/log warning "IP-Cam to Gates is not available";
			:put [global text4tg "$ipcamGates in not available for more than 5 minutes "];
			/system script run msg2tg;
			}
		}
	};

:local ipcamGarden "192.168.1.101";
:if ([/ping $ipcamGar interval=5 count=3] <=0) do={
	delay 180;
	:if ([/ping $ipcamGar interval=5 count=6] <=0) do={
		delay 300;
		:if ([/ping $ipcamGar interval=5 count=10] <=0) do={
			/log warning "IP-Cam to Gar is not available";
			:put [global text4tg  "$ipcamGar not available for more than 5 minutes "];
			/system script run msg2tg;
			}
		};
};

/log info "script for checking available of IP-Cams is finished";


А теперь настроим планировщик. Переходим System -> Scheduler, и создаем новое задание
msg2tg_after_start_plan, где в поле "On Event" прописываем название созданного скрипта, как это выше было - msg2tg_after_start.rsc, время запуска (Start Time), для этого скрипта указываем Startup, а интервал будет равен 0, таким образом оно будет запускаться лишь единожды, после старта системы.

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

Установка планировщика через webui
Установка планировщика через webui

Теперь, когда вдруг оборудование будет не в сети, то в клиент телеграма прилетит уведомление:

Более интересный текст следует представить в голове
Более интересный текст следует представить в голове

Для начала уже то, что получилось вроде бы хорошо.

Комментарии (10)


  1. ramiil
    21.07.2022 13:56

    /tool fetch url="https://api.telegram.org/$botid:$apikey/sendMessage?chat_id=$chatid&text=$message" output=none

    Я отправляю сообщения так. Всё работает. Не забудьте объявить переменные $botid, $apikey, $chatid и $message


  1. Arsmerk_true
    21.07.2022 14:22

    zabbix также исправно шлет алармы боту


  1. RC_Cat
    21.07.2022 15:06

    и дальше уже добавленного бота RawDataBot можно удалить из группы

    Я удалил и, как и ожидалось, бот перестал слать сообщения


  1. Andrey053
    21.07.2022 16:43
    +2

    вместо ... > /dev/null 2>&1
    использую опцию curl-а -o, --output Write to file instead of stdout
    curl -s -o /dev/null ...


  1. net_racoon
    21.07.2022 17:53
    +1

    Костыльные костыли. Для мониторинга есть NMS. А всякие скрипты на коленке- это для домашней сети может и ОК, а для корпоративной (любого размера) это превращается в зверя, который потом обрастает еще большими костылями. Не делайте так. Лучше сразу сделать хорошо, чем потом это все разгребать!


    1. typ6o0jiehb Автор
      21.07.2022 23:11

      Конечно костыли, это ни разу не энтерпрайс, решение именно что для дома, как и тутариал - для энтузиастов.


  1. A1EF
    21.07.2022 21:12

    Б - Безопасность


    1. typ6o0jiehb Автор
      21.07.2022 23:10

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


  1. uhm
    21.07.2022 23:35

    Для "мониторинга оборудования" у Mikrotik есть встроенный Tools > Netwatch, который умеет выполнять произвольную команду при появлении (On Up) или исчезновении (On Down) связи с заданным IP. При его использовании весь длинный скрипт с пингами не нужен, достаточно прописать /tool fetch с разными сообщениями в On Up и On Down.


  1. uoak
    22.07.2022 09:08
    +1

    А можно вопрос немножко в сторону — как отправлять сообщения с телеграма на почту ? Хочется интегрировать зоопарк мессенджеров в одном месте, причём именно в почте. Пытался гуглить, обычно предлагают либо какие-то боты трёхлетней давности , либо написать такой бот самому… Вдруг есть альтернатива ?