Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bot localization #10

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 46 additions & 72 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,89 +1,63 @@
# Server Manager Bot
# SERVER MANAGER BOT
Команды и возможности бота:

A Telegram Bot:
| Команда | Описание |
| ------ | ------ |
| `/stats` | дает обобщенную статистику о памяти \ диске \ процессах, а также общую нагрузку за определнный период времени |
| `/shell` | позволяет использовать бот в режиме Shell |
| `/memgraph` | строит график использования памяти за прошедший период |
| `/setmem` | возможность установить порог оперативной памяти (%) для мониторинга |
| `/setpoll` | интервал опроса в секундах (выше 10) |

* Commands
* `/stats` - gives summed statistics about memory \ disk \ processes (will improve)
* `/shell` - goes into the mode of executing shell commands & sends you the output
* `/memgraph` - plots a graph of memory usage for a past period and sends you a picture of the graph
* `/setmem` - set memory threshold (%) to monitor and notify if memory usage goes above it
* `/setpoll` - set polling interval in seconds (higher than 10)
* Monitors memory usage and if it reaches above the set threshold = sends you warning message
------------
**Как это работает**: [Смотреть GIF](https://i.13.wf/2019/08/17/1566074720-2541.gif)

![Вывод изображения ](https://i.13.yt/2019/08/19/1566205847-6575.png)

Example summary: [Gif](http://i.imgur.com/AhCvy9W.gifv)
**Пример графика**:

![Bot](http://i.imgur.com/hXT0drx.png)
![Пример графика](https://i.13.wf/2019/08/19/1566205949-2775.jpg)

------------

Example shell command output as a message from the bot:
## Установка

![Shell](https://i.imgur.com/PtvcaSD.png)
```sh
$ git https://github.com/vladios13/ServerStatsBot.git
$ cd ServerStatsBot
$ sudo pip3 install -r requirements.txt
```

* Все ключи и токены сохраняйте в `tokens.py`.
* Получить токен для бота можно в [Bot Father](https://t.me/BotFather)
* В этот файл поместите строковую переменную `telegrambot` токен вашего бота.
* Пример: `telegrambot = "000000000:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"`
Вы должны установить переменную. `adminchatid` в `tokens.py`. Вы так же можете указать несколько пользователей.
**Пример**:
* `adminchatid = [443355]`
* `adminchatid = [443355, 55667788, 99884433]`

Example graph sent by bot: [Gif](http://i.imgur.com/anX7rJR.gifv)

![Graph](http://i.imgur.com/K8mG3aM.jpg?1)

# Usage

## Requirements

* Python 3+
* [Telepot](https://github.com/nickoala/telepot)
* [Psutil](https://github.com/giampaolo/psutil)
* Make sure to install it for Python 3+
* In order to make sure that `pip` installs packages for the 3+ version:
* `curl -O https://bootstrap.pypa.io/get-pip.py`
* `sudo python3 get-pip.py`
* After that `pip install psutil`
* Also Stackoverflow question about that [here](http://stackoverflow.com/questions/11268501/how-to-use-pip-with-python-3-x-alongside-python-2-x)
* [matplotlib](http://matplotlib.org/)
* `sudo apt-get install python3-matplotlib`
* Bot key & `tokens.py`
* Hide all the keys and admin variables in `tokens.py`. Use it only for sensitive variables. Avoid creating functions not to clutter the namespaces through the import.
* Get a key from the [Bot Father](https://telegram.me/BotFather)
* Clone that repo
* In the folder with the cloned repo create a file `tokens.py`
* It's added to the `.gitignore` so you don't commit your own (and I don't commit mine:)
* In that file put a string variable `telegrambot` which equals your key
* For example: `telegrambot = "000000000:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"`

## Running the bot

`python3 servstatsbot.py`
------------

## Running the bot as "daemon"
## Запуск

* See included file in the repo: `servstatsbot.conf`
* Open it and edit the path as mentiond in the comments there
* Place that file in `/etc/init/`
* Start the "daemon" with: `start servstatsbot`
* You can start|stop|restart
* If bot crashes it'll be automatically restarted
* It will also start after reboot
Выполните: `python3 servstatsbot.py`

## Setting an admin
------------

You have to set a variable `adminchatid` in `tokens.py` to be equal your chat_id or multiple chat_id (if more people will use your bot).
For example:
## Запуск в режиме "daemon"

* `adminchatid = [443355]`
* `adminchatid = [443355, 55667788, 99884433]`
* Вся нужная информация находится в: `servstatsbot.conf`
* Откройте его и отредактируйте путь, как указано в комментариях к нему.
* Поместите файл в папку `/etc/init/`
* Запустите как "daemon" : `start servstatsbot`
* Используйте `start|stop|restart`
* Если произойдет сбой, он будет автоматически перезапущен.
* Он также заработает после перезагрузки.
------------
# Разработчики бота

I will reimplement this differently later.


# PLEASE CONTRIBUTE :)
I threw this code together within 10 minutes or so as a mockup to work on it later. But I think it's a nice bot idea and some of you guys might like this too. So please feel free to fork, pull, requests features!
Can give contributors access!
Would really love to see this bot grow some fat and brain:)


# Other bot development

## Alfred
### Alfred - разрботчик
[http://alfredthebot.com](http://alfredthebot.com)


GB
### vladios13 - локализация и доработка 🌚
[Blog vladios13](http://blog.vladios13.com)
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
psutil
telepot
matplotlib
80 changes: 48 additions & 32 deletions servstatsbot.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from tokens import *
import matplotlib
matplotlib.use("Agg") # has to be before any other matplotlibs imports to set a "headless" backend
Expand All @@ -12,14 +14,14 @@
# import threading
# import random
import telepot
# from telepot.namedtuple import ReplyKeyboardMarkup, KeyboardButton, ReplyKeyboardHide, ForceReply
from telepot.namedtuple import ReplyKeyboardMarkup, KeyboardButton
# from telepot.namedtuple import InlineKeyboardMarkup, InlineKeyboardButton
# from telepot.namedtuple import InlineQueryResultArticle, InlineQueryResultPhoto, InputTextMessageContent



memorythreshold = 85 # If memory usage more this %
poll = 300 # seconds
memorythreshold = 85 # Если потребляется больше памяти, то этот % равен:
poll = 300 # значения в секундах

shellexecution = []
timelist = []
Expand All @@ -29,7 +31,8 @@
setpolling = []
graphstart = datetime.now()

stopmarkup = {'keyboard': [['Stop']]}
stopmarkup = ReplyKeyboardMarkup(keyboard=[[KeyboardButton(text="Stop Shell")]],resize_keyboard=True)
# stopmarkup = {'keyboard': [['Stop']]}
hide_keyboard = {'hide_keyboard': True}

def clearall(chat_id):
Expand All @@ -44,17 +47,17 @@ def plotmemgraph(memlist, xaxis, tmperiod):
# print(memlist)
# print(xaxis)
plt.xlabel(tmperiod)
plt.ylabel('% Used')
plt.title('Memory Usage Graph')
plt.text(0.1*len(xaxis), memorythreshold+2, 'Threshold: '+str(memorythreshold)+ ' %')
plt.ylabel('% использовано')
plt.title('График использования ОЗУ')
plt.text(0.1*len(xaxis), memorythreshold+2, 'Порог: '+str(memorythreshold)+ ' %')
memthresholdarr = []
for xas in xaxis:
memthresholdarr.append(memorythreshold)
plt.plot(xaxis, memlist, 'b-', xaxis, memthresholdarr, 'r--')
plt.axis([0, len(xaxis)-1, 0, 100])
plt.savefig('/tmp/graph.png')
plt.close()
f = open('/tmp/graph.png', 'rb') # some file on local disk
f = open('/tmp/graph.png', 'rb') # файл изображние на локальном диске
return f


Expand All @@ -67,20 +70,30 @@ def __init__(self, *args, **kwargs):
def on_chat_message(self, msg):
content_type, chat_type, chat_id = telepot.glance(msg)
# Do your stuff according to `content_type` ...
print("Your chat_id:" + str(chat_id)) # this will tell you your chat_id
if chat_id in adminchatid: # Store adminchatid variable in tokens.py
print("Ваш chat_id:" + str(chat_id)) # узнать chat_id
if chat_id in adminchatid: # Переменная adminchatid хранится в tokens.py
if content_type == 'text':
if msg['text'] == '/stats' and chat_id not in shellexecution:
bot.sendChatAction(chat_id, 'typing')
memory = psutil.virtual_memory()
disk = psutil.disk_usage('/')
cpuget = psutil.getloadavg()
сpu_countF = psutil.cpu_count(logical=False)
сpu_countL = psutil.cpu_count(logical=True)
cpufr = psutil.cpu_freq(percpu=False)
boottime = datetime.fromtimestamp(psutil.boot_time())
now = datetime.now()
timedif = "Online for: %.1f Hours" % (((now - boottime).total_seconds()) / 3600)
memtotal = "Total memory: %.2f GB " % (memory.total / 1000000000)
memavail = "Available memory: %.2f GB" % (memory.available / 1000000000)
memuseperc = "Used memory: " + str(memory.percent) + " %"
diskused = "Disk used: " + str(disk.percent) + " %"
cpuget = "<b>Средняя нагрузка CPU</b>: " + str(cpuget)
cpufr = "<b>Текущая частота CPU</b>: " + str(cpufr.current) + "Mhz"
сpu_countF = "<b>Физических ядер</b>: " + str(сpu_countF)
сpu_countL = "<b>Логических ядер</b>: " + str(сpu_countL)
timedif = "<b>Сервер работает уже</b>: %.1f часов" % (((now - boottime).total_seconds()) / 3600)
memtotal = "<b>Всего ОЗУ</b>: %.2f GB " % (memory.total / 1000000000)
memavail = "<b>Свободно ОЗУ</b>: %.2f GB" % (memory.available / 1000000000)
memuseperc = "<b>Используется ОЗУ</b>: " + str(memory.percent) + " %"
diskused = "<b>Использовано HDD</b>: " + str(disk.percent) + " %"
pidsinf = "<u>Текущие процессы:</u>"

pids = psutil.pids()
pidsreply = ''
procs = {}
Expand All @@ -94,24 +107,29 @@ def on_chat_message(self, msg):
else:
procs[p.name()] = pmem
except:
print("Hm")
print("ХМ?")
sortedprocs = sorted(procs.items(), key=operator.itemgetter(1), reverse=True)
for proc in sortedprocs:
pidsreply += proc[0] + " " + ("%.2f" % proc[1]) + " %\n"
reply = timedif + "\n" + \
cpuget + "\n" + \
cpufr + "\n" + \
memtotal + "\n" + \
сpu_countF + "\n" + \
сpu_countL + "\n" + \
memavail + "\n" + \
memuseperc + "\n" + \
diskused + "\n\n" + \
pidsinf + "\n" + \
pidsreply
bot.sendMessage(chat_id, reply, disable_web_page_preview=True)
bot.sendMessage(chat_id, reply, disable_web_page_preview=True, parse_mode='HTML')
elif msg['text'] == "Stop":
clearall(chat_id)
bot.sendMessage(chat_id, "All operations stopped.", reply_markup=hide_keyboard)
bot.sendMessage(chat_id, "Все операции остановлены", reply_markup=hide_keyboard)
elif msg['text'] == '/setpoll' and chat_id not in setpolling:
bot.sendChatAction(chat_id, 'typing')
setpolling.append(chat_id)
bot.sendMessage(chat_id, "Send me a new polling interval in seconds? (higher than 10)", reply_markup=stopmarkup)
bot.sendMessage(chat_id, "Отправьте мне новый интервал проверки в секундах? (выше 10)", reply_markup=stopmarkup)
elif chat_id in setpolling:
bot.sendChatAction(chat_id, 'typing')
try:
Expand All @@ -123,26 +141,26 @@ def on_chat_message(self, msg):
else:
1/0
except:
bot.sendMessage(chat_id, "Please send a proper numeric value higher than 10.")
bot.sendMessage(chat_id, "Отправьте числовое значение выше 10.")
elif msg['text'] == "/shell" and chat_id not in shellexecution:
bot.sendMessage(chat_id, "Send me a shell command to execute", reply_markup=stopmarkup)
bot.sendMessage(chat_id, "Отправьте мне Shell-комманду", reply_markup=stopmarkup)
shellexecution.append(chat_id)
elif msg['text'] == "/setmem" and chat_id not in settingmemth:
bot.sendChatAction(chat_id, 'typing')
settingmemth.append(chat_id)
bot.sendMessage(chat_id, "Send me a new memory threshold to monitor?", reply_markup=stopmarkup)
bot.sendMessage(chat_id, "Установите новый порог памяти для мониторинга", reply_markup=stopmarkup)
elif chat_id in settingmemth:
bot.sendChatAction(chat_id, 'typing')
try:
global memorythreshold
memorythreshold = int(msg['text'])
if memorythreshold < 100:
bot.sendMessage(chat_id, "All set!")
bot.sendMessage(chat_id, "Все получилось!")
clearall(chat_id)
else:
1/0
except:
bot.sendMessage(chat_id, "Please send a proper numeric value below 100.")
bot.sendMessage(chat_id, "Пожалуйста, отправьте числовое значение ниже 100.")

elif chat_id in shellexecution:
bot.sendChatAction(chat_id, 'typing')
Expand All @@ -151,14 +169,12 @@ def on_chat_message(self, msg):
if output != b'':
bot.sendMessage(chat_id, output, disable_web_page_preview=True)
else:
bot.sendMessage(chat_id, "No output.", disable_web_page_preview=True)
bot.sendMessage(chat_id, "Упс.", disable_web_page_preview=True)
elif msg['text'] == '/memgraph':
bot.sendChatAction(chat_id, 'typing')
tmperiod = "Last %.2f hours" % ((datetime.now() - graphstart).total_seconds() / 3600)
bot.sendChatAction(chat_id, 'upload_photo')
tmperiod = "За %.2f часа" % ((datetime.now() - graphstart).total_seconds() / 3600)
bot.sendPhoto(chat_id, plotmemgraph(memlist, xaxis, tmperiod))



TOKEN = telegrambot

bot = YourBot(TOKEN)
Expand All @@ -184,11 +200,11 @@ def on_chat_message(self, msg):
memlist.append(mempercent)
memfree = memck.available / 1000000
if mempercent > memorythreshold:
memavail = "Available memory: %.2f GB" % (memck.available / 1000000000)
memavail = "Доступно ОЗУ: %.2f GB" % (memck.available / 1000000000)
graphend = datetime.now()
tmperiod = "Last %.2f hours" % ((graphend - graphstart).total_seconds() / 3600)
tmperiod = "За последние %.2f часов" % ((graphend - graphstart).total_seconds() / 3600)
for adminid in adminchatid:
bot.sendMessage(adminid, "CRITICAL! LOW MEMORY!\n" + memavail)
bot.sendMessage(adminid, "ВНИМАНИЕ! МАЛО ОПЕРАТИВНОЙ ПАМЯТИ!\n" + memavail)
bot.sendPhoto(adminid, plotmemgraph(memlist, xaxis, tmperiod))
time.sleep(10) # 10 seconds
tr += 10
5 changes: 2 additions & 3 deletions tokens.py_example
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# A token you get from the Telegram's botfather
# Токен бота
telegrambot = '9999999:6666aaaaaa666666a6aaa'

# A chat_id of your client
# Введите chat_id канала/группы/пользователя. Можно использовать несколько значений, подробнее в readme.md
adminchatid = [99999999]