Forum Programmation.python Ping multithread + bdd

Posté par . Licence CC by-sa
1
25
août
2015

Bonjour,

Mon problème est le suivant:

J'ai reçus pour tâche de mettre en place un script(langage de mon choix et j'ai choisis python) qui ping un certain nombre d'hôtes (100+) et re-insert en bdd la date du ping et incrémente un compteur (+1/j).

Vu le nombre d'hôtes l'utilisation du multithread est quasiment indispensable si je veux éviter que mon script tourne pendant plusieurs heures.

Ces hôtes sont stockés dans une bdd postgreSQL.

Mon problème se trouve ici, pour pouvoir les ping et re-insert correctement(car sinon seulement 1 hôte sur 2-3 est updated) le résultat en bdd , la seule solution que j'ai trouvé c'est de select les hôtes et de les mettre dans un tableau et ensuite d'interroger ce tableau.

Je trouve ce moyen de faire assez crade, je me tourne donc vers vous pour savoir si vous avez des suggestions/idées et même dans un autre langage, sachant que le script tourne sur FreeBSD.

Voici le code:

#!/usr/local/bin/python
from multiprocessing import Pool
import os
import psycopg2
import time
def check_ping(hostname):
    response = os.system("ping -c 4 %s " % (hostname))
        if str(day) != str(datej):
        if response == 0:
            hostname = str(hostname)    
            cur.execute("UPDATE ping SET dateping=%s,state='1',ispingok='1',compteur=compteur+1 WHERE netbiosname=%s",(day,str(hostname),))
            conn.commit()
        else:
                cur.execute("UPDATE ping SET state='0' , ispingok='0' WHERE netbiosname=%s",(str(hostname),))
                conn.commit()
    else:
        print "already updated"

if __name__ == '__main__':
    try:
        conn = psycopg2.connect("dbname='postes' user='pgsql' host='localhost'")
    except:
        print "Can't connect to the database"

        cur = conn.cursor()
    cur.execute("SELECT netbiosname,to_char(dateping,'dd/mm/yyyy') FROM ping ")
    rows = cur.fetchall()
    maliste=[]
        for i in rows:
            day=time.strftime("%d/%m/%Y")
            datej=str(i[1])
            hostname=str(i[0]) 
            maliste.append(hostname)
        p = Pool(5)
        print(p.map(check_ping, maliste))
  • # Compromis

    Posté par . Évalué à 2. Dernière modification le 25/08/15 à 11:51.

    Tout est toujours une question de compromis.

    Effectivement, charger tout un resultat de requete en mémoire c'est un peu crade. Ceci dit, c'est pratique. Par contre, le tri sur la date dans le code python me perturbe un peu (surtout que dans la sortie, on a juste un "already update" et pas le nom d'hote), je l'aurai fait dans la requete de selection.

    Et pour être sur de ne pas mettre à jour deux fois le meme host (apres tout, le script peut etre lancé plusieurs fois en meme temps par erreur) j'aurai rajouté un controle lors des update : UPDATE [...] WHERE netbiosname=hostname AND dateping < day.

    Du coup, effectivement, on charge tout un tableau de resultat au debut du script, mais 1) tu es multithreadé 2) tu vérifie que tu ne met pas un jour un truc deja à jour au plus prés de l'update.

    A mon sens, ca contrebalance la partie un peu crade du début.

    • [^] # Re: Compromis

      Posté par . Évalué à 1. Dernière modification le 25/08/15 à 12:07.

      Salut,

      merci pour ta réponse.

      surtout que dans la sortie, on a juste un "already update" et pas le nom d’hôte

      Ca pour le coup c'est pas bien grave vu que le script est destiné a tourner tout seul c’était plus pour troubleshoot les problèmes, voir si ça interagit bien avec la bdd etc…. Et pour le tris sur la date, oui en effet j'aurais pu mettre dans la requête SQL, ça aurait été plus pratique aussi mais c'etait pas ma 1ere priorité.

      apres tout, le script peut etre lancé plusieurs fois en meme temps par erreur

      En fait j'execute le script tout les jours a une certaine heure via une tâche cron, cela peut-il quand même par erreur se lancer plusieurs fois?

      Ceci dit, oui, je vais ajouter un check date dans la requete de l'update, une ptite sécurité en plus ne fait jamais de mal.

      Merci pour tes conseils

      Cordialement

      • [^] # Re: Compromis

        Posté par . Évalué à 2.

        En fait j'execute le script tout les jours a une certaine heure via une tâche cron, cela peut-il quand même par erreur se lancer plusieurs fois?

        Un classsqque : qqn lance le script manuellement pdt que le cron l'erxécute.

  • # optimisations possibles

    Posté par (page perso) . Évalué à 3.

    Faire deux ensembles de hostnames (les hostnames valides et ceux qui ont raté leur épreuve du ping), qui seront mis à jour dans chaque thread.
    Il y a des structures adaptées pour ça (pour éviter les conflits).

    Ensuite, quand tous les thread ont fini, tu fais "UPDATE ping SET dateping=%s,state='1',ispingok='1',compteur=compteur+1 WHERE (netbiosname=%s) or (netbiosname=%s) or …" avec tous les hostnames qui ont réussi, puis une seconde requête avec tous ceux qui ont raté. S'il y a trop de hostnames, tu peux découper pour faire du traitement par lots de 1000 hostnames.

    Tu peux également faire plus de 5 threads (100 restent raisonnables).

    • [^] # Re: optimisations possibles

      Posté par . Évalué à 1.

      Salut,

      merci pour ta réponse.

      Pour les deux groupes de hostname, au final c'est plus ou moins ce qui est fait, j'ai corrigé mon code avec le poste plus haut et mis un filtre dans la requête en fonction de la date donc seul les "invalides" au final seront selectionnés.

      Quand aux 2 requetes, je les ai deja:

      ici je met la date a jour ainsi que state et ispingok(ces deux derniers ne servant pas a grande chose au final) donc il est valide

      UPDATE ping SET dateping=%s ,state='1',ispingok='1',compteur=compteur+1 WHERE netbiosname=%s

      ici rien n'est mis a jour donc il passe dans la catégories des invalides en quelque sorte

      UPDATE ping SET state='0' , ispingok='0' WHERE netbiosname=%s

      ou alors j'ai juste mal compris ce que tu veux me dire.

      Pour les threads, j'avais pas d'ordre d'idée donc j'ai update comme tu m'a conseillé.

      Cordialement

      • [^] # Re: optimisations possibles

        Posté par . Évalué à 2.

        Et plus sur le modèle de donné, à quoi sert le state par rapport au ispingok et est-ce que ca ne vaudrait pas le coup de garder, même sur le cas d'échec, la date de dernière mise à jour ? Si tu as beaucoup de host et que le script est long, c'est toujours utile de savoir si c'est en échec car il n'a pas encore tester aujourd'hui ou si ça fait vraiment deux jours que c'est planté.

        • [^] # Re: optimisations possibles

          Posté par . Évalué à 1.

          Pour le "state" et le "ispingok", ils ne servent a rien au niveau de ce scripts, on m'avait demandé une interface web ou voir les postes en ligne/hors ligne et ce depuis combien de temps etc… et ces deux champs devaient servir a dire si le poste est allumé et balancer un output du ping, mais au final je fais sans, donc il faut pas en tenir compte.

          Quand a la date de dernière mise a jour elle est en bdd, si ça fait 4 jours que le poste est éteint j'aurais la date n-4.

          Si tu as beaucoup de host et que le script est long, c'est toujours utile de savoir si c'est en échec car il n'a pas encore tester aujourd'hui ou si ça fait vraiment deux jours que c'est planté.

          Il faut aussi savoir que le check par l'admin des postes allumés/éteins ne se fera pas tout les jours et encore moins juste après que le script soit lancé (j'aurais du le preciser a la base), donc au final ce n'est pas si important que ça, le but n'étant pas de monitorer mais de connaitre les postes inutilisés depuis un certain temps.

          Cordialement

  • # Pour savoir si une ip est utilisée, je laisse faire les pros.

    Posté par . Évalué à 3.

    ou j'utilise nmap. Ce qui revient au même. Pour checker les hôtes UP ou les IPs utilisées dans un range d'IP, je fais :

    nmap -nsP -PS22,80,443,25,3306 -PU53,161 -PE 8.8.8.0/24
    Starting Nmap 5.00 ( http://nmap.org ) at 2015-08-25 16:53 CEST
    Host 8.8.8.8 is up (0.022s latency).
    Nmap done: 256 IP addresses (1 host up) scanned in 14.04 seconds

    Puis j'analyse les résultats tranquillement après ou la mets en cache. La commande prends entre 15s et 60s mais l'on peut facilement en lancer un paquet d'un coup.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.