lainmonitor/lainmonitor.py
2024-10-05 00:53:58 +05:00

93 lines
No EOL
4 KiB
Python

#description: telegram bot for monitoring the system
#dependencies: telebot
#usage: python3 lainmonitor.py | or run it as a service
#author: hornetmaidan
import subprocess
import threading
import telebot
#define the variables
status, hostname, uptime, zerotier, prosody, postgres, tailscale, disk, ping = 'unknown', 'unknown', 'unknown', 'unknown', 'unknown', 'unknown', 'unknown', 'unknown', 'unknown'
nodes, hostnames, reach, threads = [], [], [], []
#telegram bot token
TOKEN = 'PLACE_YOUR_TOKEN_HERE'
#bot init
bot = telebot.TeleBot(TOKEN)
#get system info
def getinfo():
global status, hostname, uptime, zerotier, prosody, postgres, tailscale, disk
hostname = subprocess.check_output(['hostname']).decode().strip()
uptime = subprocess.check_output(['uptime', '-p']).decode().strip()
#systemd-only services
zerotier = subprocess.Popen("sudo systemctl status zerotier-one | grep 'Active'", shell=True, stdout=subprocess.PIPE).stdout.read().decode().strip()
prosody = subprocess.Popen("sudo systemctl status prosody | grep 'Active'", shell=True, stdout=subprocess.PIPE).stdout.read().decode().strip()
postgres = subprocess.Popen("sudo systemctl status postgresql | grep 'Active'", shell=True, stdout=subprocess.PIPE).stdout.read().decode().strip()
tailscale = subprocess.Popen("sudo systemctl status tailscaled | grep 'Active'", shell=True, stdout=subprocess.PIPE).stdout.read().decode().strip()
disk = subprocess.check_output(['df', '-h']).decode().strip()
if hostname == 'unknown':
status = 'offline'
else:
status = 'online'
return hostname, uptime, zerotier, prosody, postgres, tailscale, disk
#function to ping tailscale nodes
def ping_node(node, hostname):
ping = subprocess.Popen(f"ping {node} -c 1 | grep '1 packets'", shell=True, stdout=subprocess.PIPE).stdout.read().decode().strip()
if '1 received' in ping:
reach.append(f'{node}/{hostname} is reachable')
else:
reach.append(f'{node}/{hostname} is unreachable')
#ping tailscale nodes
def check_tailscale():
global nodes, hostnames, reach, threads, ping
nodes_output = subprocess.Popen("tailscale status | grep '100'", shell=True, stdout=subprocess.PIPE).stdout.read().decode().strip()
nodes = [line.split()[0] for line in nodes_output.split('\n') if line]
hostnames = [line.split()[1] for line in nodes_output.split('\n') if line]
for node, hostname in zip(nodes, hostnames):
thread = threading.Thread(target=ping_node, args=(node, hostname))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
return reach
#debug handler
def check():
global status, hostname, uptime, zerotier, prosody, postgres, tailscale, disk
getinfo()
print('system status:', status)
print('hostname:', hostname)
print('uptime:', uptime)
print('zerotier:', zerotier)
print('prosody:', prosody)
print('postgres:', postgres)
print('tailscale:', tailscale)
print('disk:', disk)
return status, hostname, uptime, zerotier, prosody, postgres, tailscale, disk
#message handling
@bot.message_handler(commands=['start', 'help', 'status', 'reboot', 'ping'])
def handle(message):
if message.text == '/start':
bot.reply_to(message, 'lainmonitor v1.0 --- standing by...')
elif message.text == '/help':
bot.reply_to(message, 'commands: /start, /help, /status, /reboot, /ping')
elif message.text == '/status':
check()
status_message = f'hostname: {hostname}\nsystem status: {status}\nuptime: {uptime}\nzerotier: {zerotier}\nprosody: {prosody}\npostgres: {postgres}\ntailscale: {tailscale}'
bot.reply_to(message, status_message)
bot.reply_to(message, f'filesystem info for {hostname}: \n\n{disk}')
elif message.text == '/reboot':
bot.reply_to(message, 'work in progress...')
elif message.text == '/ping':
check_tailscale()
ping_status = '\n'.join(reach)
bot.reply_to(message, f'ping status:\n\n{ping_status}')
#polling
bot.polling()