Matteo Vignoli

Sviluppatore Web Full-Stack autodidatta, curioso per natura,
attualmente impiegato a Milano presso ContactLab per conto di Anoki S.r.L.

Ricevere una notifica Telegram quando il servizio mysql è down

  Tempo di lettura:

Telegram, con i suoi bot e canali, è uno strumento estremamente versatile che si presta molto bene ad essere utilizzato come endpoint per ricevere warning e notifiche di diverso tipo, ad esempio quando un servizio importante come mysql smette di funzionare (per qualsiasi ragione, sono cose che purtroppo capitano e quando capitano sono dolori!).

In un'azienda, normalmente, il monitoraggio è affidato a strumenti appositi e sistemisti dedicati, che sanno come configurare al meglio le macchine e come mettere in piedi un sistema di alert come si deve.  

Ma se stiamo parlando di un progetto amatoriale (o di una piccolissima realtà) e non abbiamo troppo tempo e risorse da dedicare al monitoraggio possiamo mettere facilmente in piedi - in poco tempo - qualcosa che funziona, fa il suo dovere ed è abbastanza affidabile da dormire un po' più tranquilli la notte 😉

Python e Telegram to the rescue

Su Google o StackOverflow si possono trovare diversi metodi per verificare che mysql sia up, dal vedere se la porta di default (3306) è utilizzata, a fare una grep sulla lista di processi per cercare un mysql o mysqld oppure usando mysqladmin (che però richiede un'autenticazione). Il metodo che ho usato io, invece, è un po' meno affidabile ma decisamente più spiccio: eseguire un semplice mysql status e leggerne l'output [^1]

Il codice seguente è molto semplice: utilizzando la libreria nativa subprocess controlla lo status: se il servizio è down prova ad effettuare un restart (e manda un avvisio via Telegram), se il restart non funziona ci riprova X volte prima di mandare un ultimo avviso e poi attendere l'intervento "umano".
Tutto è dentro un loop continuo per mantenere il processo attivo (il controllo viene fatto ogni 30 secondi ma tutto è configurabile)

#!/usr/bin/env python3
import subprocess, time, requests

""" configuro i comandi da eseguire e i dati per connettermi
    a Telegram
"""
cmd_check = ["sudo", "service","mysql","status"]
cmd_restart = ["sudo", "service", "mysql", "restart"]
TELEGRAM_TOKEN = 'TOKEN-ID'
TELEGRAM_CHAT_ID = 'CHAT-ID'

default_sleep = 10;
iter_check = 0
first_warning = False
send = True
messaggi = {
				'terzo_tentativo' : 'Terzo tentativo, mysql è ancora down.',
				'invio_notifica' : 'Invio notifica...',
                'restart': 'Attenzione, mysql sembra down! Provo a fare il restart',
                'mysql_ok' : 'Mysql è ok',
                'restart_fatto': 'Restart tentato'
            }

def get_payload(messaggio):
	payload = { 'chat_id': TELEGRAM_CHAT_ID,'text': messaggio,'parse_mode': 'HTML'}
	return payload

def warn_telegram(messaggio):
	payload = get_payload(messaggio)
	return requests.post("https://api.telegram.org/bot{token}/sendMessage".format(token=TELEGRAM_TOKEN), data=payload)


while True:
	proc = subprocess.run(cmd_check, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
	
	if "(running)" not in str(proc.stdout):
		
		if iter_check >= 3:
			print(messaggi['terzo_tentativo'])
			if send:
                #Notifica "definitiva" la faccio solo una volta
				warn_telegram(messaggi['terzo_tentativo'])
				print(messaggi['invio_notifica'])				
				send = Fals
		else:
			print(messaggi['restart'])			
			if not first_warning:
                # anche in questo caso, mando un solo avviso al restart
				warn_telegram(messaggi['restart'])
				first_warning = True

			subprocess.run(cmd_restart, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
			warn_telegram(messaggi['restart_fatto'])
			iter_check += 1
	else:
		print(messaggi['mysql_ok'])
		# azzero il counter
		iter_check = 0
		send = True
    # durata del ciclo   
	time.sleep(default_sleep)

(Ho usato la libreria requests perchè era già installata sul server, ma anche le native urlib vanno benissimo, alla fine si tratta solo di fare una chiamata POST verso le API Telegram)

Questo sistema non è certamente dei migliori ma fa il suo dovere, e può essere esteso al monitoraggio di altri servizi (ad esempio sendmail, redis, ecc.) Ah, per quanto riguarda la creazione di un bot e di un canale di Telegram... ci sono decine di guide là fuori, in inglese ma anche in italiano, è al di fuori dello scope di questo articolo 👽

[^1] Questo comando, così come l'output, variano a seconda dell'OS e della versione di MySQL: può essere service mysql status per un Ubuntu 14.x oppure systemctl mysql status per Ubuntu > 16, ecc. Anche l'output della versione di MySQL sembra diverso, tra la 5.6 e la 5.7.* ho notato una differenza abissale.

Automazioni quotidiane: controllare un log remoto con python e paramiko

Una dei motivi per cui python mi appassiona sempre di più - oltre alla semplicità della sintassi - è la rapidità con cui si può buttare...

Algoritmo per i labirinti: Depth First Search in PHP

Vi sono molti algoritmi per la generazione di labirinti e traversamento di grafi, come il Depth First Search; qui illustro la mia soluzione in PHP creata per RosettaCode...

MatteoVignoli.it   Non perderti nulla da MatteoVignoli.it, ricevi aggiornamenti via mail.