Телеграмм-бот, опрашивающий linux-сервер

kick

Магистр Йода
Administrator
#1
Родилась идея создать бота, который бы запускал команды или скрипты на удаленном сервере (linux) и возвращал бы результат в телеграмм. Зачем? Удобно! Не надо логиниться на сервак, чтобы получить информацию о нагрузке на процессор, свободной памяти или объеме диска. Можно даже запускать скрипты.

И так изучаем python и api telegram bot, регистрируем своего бота в телеграмм, скачиваем готовые скрипты, запускаем их на своем серваке и меняем config.py под себя.

Поехали по порядку:

1) Регистрация бота телеграмм. Находим отца всех ботов – @BotFather. Пишем ему:

Код:
/newbot
В ответ на его сообщение вводим имя вашего нового бота. Оно обязательно должно иметь на конце слово bot.

Код:
moi_novii_bot
Если имя не занято и оно введено верно, то вы получите токкен – вам необходимо будет его скопировать в файл config.py скрипта:

Код:
token = ' '
2) Загружаем скрипт. Это первая тестовая версия скрипта – для того чтобы оценить возможности во-первых самого питона, во-вторых – бота telegram. Приветствуются любые пожелания и предложения – допилю. Можете сами что-то добавить – просьба тоже поделится. Каковы возможности программы (их можно посмотреть набрав в своем боте /help):

  • посмотреть сетевые настройки (запускает на сервере команду ifconfig)
  • получить информацию о дисковом пространстве (запускает на сервере команду df -h)
  • получить информацию о памяти (запускает на сервере команду free -m)
  • получить информацию о нагрузке на процессор (запускает на сервере команду mpstat)
  • получить информацию о размере папки, заданной в config.py (запускает на сервере команду du -sh имя папки)
  • проверяет наличие и размер файла в папке (запускает на сервере команду ls -lh файл). Делаю бэкап базы 1с в монтируемую сетевую папку с именем файла по дате – поэтому возникла такая необходимость.
Что еще планирую реализовать: запуск любого скрипта (возможно без вывода всего выполнения, а только конечного результата), улучшить вывод результата – более удобочитаемого, сбор статистики в базу данных и вывод графиков по нагрузкам и т.п.

Для запуска скрипта необходим python 3 и python-telegram-bot. У меня стоит centOS. Там уже стоит 2 версия питона. Ставим рядом 3 питон и библиотеку для работы бота:

Код:
wget http://www.python.org/ftp/python/3.3.2/Python-3.6.0.tar.xz
yum install xz
tar -xpJf Python-3.6.0.tar.xz
cd Python-3.6.0
yum groupinstall "Development tools"
./configure
make
make install
ln -s /usr/local/bin/python3 /usr/bin/python3
pip3 install python-telegram-bot --upgrade
Состав скрипта:


bot – файл bash-скрипта запускающего python3 bot.py
bot.py – непосредственно сам скрипт бота. Тем кто знаком с питоном – добро пожаловать внутрь.
config.py – хранит настройки. Туда вписываете токкен, полученный в телеграмме. Затем запускаете скрипт.

В приложение телеграмма вводите:

Код:
/id
Таким образом вы получаете ваш личный id. Его необходимо ввести в строку (вместо 123456789) admin = [‘123456789’]. Это сделано в целях безопасности, чтобы остальные команды могли вводить только пользователи с определенных аккаунтов телеграмма. Можно через запятую прописать несколько id: admin = [‘123456789’, ‘987654321’].

В строке dir1 прописываем путь к папке объем которого бы мы хотели контролировать (у меня это путь до папки с базами pgsql)

В строке dir_backup – путь к папке где лежит файл, объем (или наличие) которого необходимо контролировать. У меня это файл вида 20170218.tar.gz. По умолчанию именно вариант с названием файла годмесяцдата.tar.gz проверяется. Если вы хотите изменить маску проверяемого файла, то вам необходимо найти и отредактировать в файле bot.py строку

Код:
filebackup = config.dir_backup + cur_year + cur_month + cur_day + '.tar.gz'  #формируем имя файла для поиска
Имейте ввиду, что дальнейшем при исправлении файла config.py вам не нужно будет перезапускать скрипт. Все настройки перечитываются скриптом каждый раз заново.

Неплохо бы добавить этот скрипт в автозагрузку. Для CentOS 7:

Код:
touch /etc/systemd/system/telegram-bot.service chmod 664 /etc/systemd/system/telegram-bot.service
Содержимое этого файла:

Код:
[Unit]
Description=Telegram bot
After=network.target

[Service]
Type=simple
User= от имени кого запускать
ExecStart=путь к файлу bot.sh (в этом файле тогда надо прописать полный путь до bot.py)

[Install]
WantedBy=multi-user.target
Стартуем новый сервис:

Код:
systemctl start telegram-bot.service
Добавляем его в автозагрузку:

Код:
systemctl enable telegram-bot.service
Проверяем статус:

Код:
systemctl status telegram-bot.service
Можем вводить команды. Начинаем с /help.

#!/bin/bash
python3 bot.py
#!/usr/bin/python
import config #файл с настройками
import telegram
import os
import subprocess
import sys
import shlex
import datetime
from subprocess import Popen, PIPE
from telegram.ext import CommandHandler
from imp import reload #модуль для перезагрузки (обновления) других модулей
#bot = telegram.Bot(token = config.token)
#Проверка бота
#print(bot.getMe())
from telegram.ext import Updater
updater = Updater(token=config.token)
dispatcher = updater.dispatcher
#выполнение команды shell и вывод результата в телеграмм
def run_command(command):
process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
global textoutput
textoutput = ''
while True:
global output
output = process.stdout.readline()
output = output.decode('utf8')
if output == '' and process.poll() is not None:
break
if output:
print (output.strip())
textoutput = textoutput + '\n' + output.strip()
rc = process.poll()
return rc

#функция команады старт
def start(bot, update):
bot.sendMessage(chat_id=update.message.chat_id, text="Привет, я бот, жду команды")
#функция команады help
def help(bot, update):
reload(config)
bot.sendMessage(chat_id=update.message.chat_id, text='''список доступных команд:
/id - id пользователя
/ifconfig - сетевые настройки
/df - информация о дисковом пространстве (df -h)
/free - информация о памяти
/mpstat - информация о нагрузке на процессор
/dir1 - объем папки''' + config.dir1 + '''
/dirbackup - размер файла бэкапа за текущий день в папке ''' + config.dir_backup + '''

''')
#функция команады id
def myid(bot, update):
userid = update.message.from_user.id
bot.sendMessage(chat_id=update.message.chat_id, text=userid)

#функция команады ifconfig
def ifconfig(bot, update):
reload(config)
user = str(update.message.from_user.id)
if user in config.admin: #если пользовательский id в списке admin то команда выполняется
run_command("ifconfig")
bot.sendMessage(chat_id=update.message.chat_id, text=textoutput)
#функция команады df
def df(bot, update):
reload(config)
user = str(update.message.from_user.id)
if user in config.admin: #если пользовательский id в списке admin то команда выполняется
run_command("df -h")
bot.sendMessage(chat_id=update.message.chat_id, text=textoutput)
#функция команады free
def free(bot, update):
reload(config)
user = str(update.message.from_user.id)
if user in config.admin: #если пользовательский id в списке admin то команда выполняется
run_command("free -m")
bot.sendMessage(chat_id=update.message.chat_id, text=textoutput)
#функция команады mpstat
def mpstat(bot, update):
reload(config)
user = str(update.message.from_user.id)
if user in config.admin: #если пользовательский id в списке admin то команда выполняется
run_command("mpstat")
bot.sendMessage(chat_id=update.message.chat_id, text=textoutput)
#функция команады dir1
def dir1(bot, update):
reload(config)
user = str(update.message.from_user.id)
if user in config.admin: #если пользовательский id в списке admin то команда выполняется
dir1_command = "du -sh "+ config.dir1
run_command(dir1_command)
bot.sendMessage(chat_id=update.message.chat_id, text=textoutput)

#функция команады dirbackup - проверяет наличие файла по дате
def dirbackup(bot, update):
reload(config)
user = str(update.message.from_user.id)
if user in config.admin: #если пользовательский id в списке admin то команда выполняется
now_date = datetime.date.today() # Текущая дата
cur_year = str(now_date.year) # Год текущий
cur_month = now_date.month # Месяц текущий
if cur_month < 10:
cur_month = str(now_date.month)
cur_month = '0'+ cur_month
else:
cur_month = str(now_date.month)
cur_day = str(now_date.day) # День текущий
filebackup = config.dir_backup + cur_year + '-' + cur_month + '-' + cur_day + '.03.00.co.7z' #формируем имя файла для поиска
print (filebackup)
filebackup_command = "ls -lh "+ filebackup
run_command(filebackup_command)
bot.sendMessage(chat_id=update.message.chat_id, text=textoutput)



start_handler = CommandHandler('start', start)
dispatcher.add_handler(start_handler)
ifconfig_handler = CommandHandler('ifconfig', ifconfig)
dispatcher.add_handler(ifconfig_handler)
df_handler = CommandHandler('df', df)
dispatcher.add_handler(df_handler)
free_handler = CommandHandler('free', free)
dispatcher.add_handler(free_handler)
mpstat_handler = CommandHandler('mpstat', mpstat)
dispatcher.add_handler(mpstat_handler)
dir1_handler = CommandHandler('dir1', dir1)
dispatcher.add_handler(dir1_handler)
dirbackup_handler = CommandHandler('dirbackup', dirbackup)
dispatcher.add_handler(dirbackup_handler)
myid_handler = CommandHandler('id', myid)
dispatcher.add_handler(myid_handler)
help_handler = CommandHandler('help', help)
dispatcher.add_handler(help_handler)
updater.start_polling()
# Этот токен
token = '12345678901234567890'
#Пользователи с доступом
admin = ['1234567890']
dir1 = '/var/lib/pgsql/9.4/data/base/'
dir_backup = '/mnt/distr/backup/1c/' #путь к папке с файлом бэкапа у которого название формируется год_месяц_дата
 
Последнее редактирование:

Evas

Пляшущий с бубном
Пользователь
#2
Спасибо, познавательно. Вообще у меня давно была идея сделать так, чтобы при ошибке в создании резервной копии на каком либо из наблюдаемых мною серверов приходила сообщенька в телеграм. Но руки пока не дошли чтобы изучить. Возможно реализовать такое вообще?
 

kick

Магистр Йода
Administrator
#3
Вообще вполне возможно что-то придумать, но надо посидеть подумать. Легче команду боту который бы возвращал результат о статусе
 

Evas

Пляшущий с бубном
Пользователь
#4
Вообще вполне возможно что-то придумать, но надо посидеть подумать. Легче команду боту который бы возвращал результат о статусе
создание резервной копии автоматическое, весь процесс состоит из нескольких команд, которые вписаны в bash скрипт. Я представляю себе так, что в скрипте после выполнения каждой команды проверяю её статус и если он не 0, то посылаю себе в телеграм сообщеньку. А бот, который будет работать по запросу это по факту тоже самое, что я зайду на сервер и сам посмотрю наличие резервной копии) Вообще бекапы ведь не нуждаются в ручной проверке, более того, мы даже не должны их замечать, до тех пор пока они не понадобятся и вот для того, чтобы быть уверенным в их целостности и хочется сделать автоматическое уведомление в случае ошибки.

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

P.S. - вы, кстати, сам скрипт не выложили в 1 сообщении)
 

Evas

Пляшущий с бубном
Пользователь
#6
Вот вам идея. В случае с л2 можно было бы сделать бота, который позволяет быстро и легко перегрузить сервер игровой без захода в игру, а также, например, и другие функции - бан, тюрьма ну и вообще всё, что душа пожелает. Но поддержка такого должна быть в ядре, на сколько я понимаю. Ещё как вариант при наличии телнета в сборке можно сделать бота, который будет связываться с локальным телнетом на серверной машине и уже туда посылать те или иные команды. Не знаю на счёт остального, но вот именно функция быстрого рестарта сервера без необходимости захода в игру будет очень удобной)
 

kick

Магистр Йода
Administrator
#7
Телнет и так есть в каждой сборке :/. И по телнету эти команды и так есть и даже больше с информацией о онлайне и прочем.
 

Evas

Пляшущий с бубном
Пользователь
#8
Вот только я не встречал включенный телнет в сборках последние много лет + открывать телнет в мир не есть безопасно, а значит в любое время и в любом месте к нему подключится не выйдет. В случае с ботом телеграма коннект к телнету будет локальный в пределах серверной машины, бота можно настроить на приём команд с конкретного id пользователя и телеграмом можно воспользоваться где угодно, даже находясь в транспорте, главное чтобы был интернет.
 
Сверху Снизу