pythonでping監視

はじめに

  • あるプライベートネットワークの中に存在するクライアントにpingを打ち、常時監視するツールが欲しかった。
  • メールでの通知とかも分かりづらいのでいろんな通知の方法が使いたかった(今回はLine Botで通知)。
  • 良さげなツールが無かったので自分でプログラムを書いて実現することにした

PythonPingを打つ

pythonではsubprocessを使えばpingを打てるらしいです。

qiita.com

この関数をお借りしてpingを打ちます。

import subprocess
def is_connectable(host):
    ping = subprocess.Popen(["ping", "-w", "3", "-c", "1", host], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    ping.communicate()
    return ping.returncode == 0

今回監視したい対象は、あるセグメントの中で固定IPを振られて存在しているクライアントが対象なので、クライアントのIPアドレスcsvファイルから読み込みます。

取得したIPアドレスのリストをforループで回して全てにpingを打ち、NGだった場合は通知を送ります。
(今回はLine Botに通知させたいのでBotサーバのURLにリクエストしています。)

1,192.168.101.1
2,192.168.101.2
3,192.168.101.3
4,192.168.101.4
:
:
import csv, subprocess, requests

def is_connectable(host):
    ping = subprocess.Popen(["ping", "-W", "3", "-c", "1", host], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    ping.communicate()
    return ping.returncode == 0

while True:
    f = open('IPAdressTable.csv', 'r')
    reader = csv.reader(f)
    for index, row in enumerate(reader):
        print(row)
        result = is_connectable(row[1])
        if result is not True:
            url = "https://my-line-bot-url.com/alert" + row[0]
            requests.get(url)
    f.close()

これで、まずは機能としては完成ですが、同セグメント内に存在する100個近くのクライアントにpingを打っていると、一周するのも時間がかかってしまい、あまり常時監視している感じがしなくなってしまいます。

そこで並列処理を導入して、複数スレッドで処理させようと思います。

joblibで並列処理

qiita.com

pythonの並列処理にはjoblibが便利みたいです。

ここを参考にループ処理の部分を書き換えます。

import csv, subprocess, requests
from joblib import Parallel, delayed

def is_connectable(host):
    ping = subprocess.Popen(["ping", "-W", "3", "-c", "1", host], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    ping.communicate()
    return ping.returncode == 0

def send_connection_status(host, number):
    print(host)
    result = is_connectable(host)
    if result is not True:
        url = "https://my-line-bot-url.com/alert" + row[0]
        requests.get(url)

while True:
    f = open('IPAdressTable.csv', 'r')
    reader = csv.reader(f)
    header = next(reader)
    Parallel(n_jobs=-1)( [delayed(send_connection_status)(row[1], row[0]) for index, row in enumerate(reader)] )
    f.close()

これで複数スレッド立てて処理が出来るようです。
とりあえず実装しただけで細かいことはまだよくわかりませんが。

時間があるときにもう少し勉強したいと思います。