Производственная необходимость (да и любопытство) требует изучения сетевых возможностей python. Наткнулся на фреймворк Twisted, значительно упрощающий асинхронное сетевое программирование. Ням-нямка.
PS: Отдельное спасибо программистам IBM за добротные статьи, позволяющие быстро въехать в новую технологию.
понедельник, 6 декабря 2010 г.
Простой пингер с использованием джанго
Задача: периодически пинговать N произвольно заданных серверов, статус их доступности публиковать в вебе.
За добавление/редактирование/удаление хостов будет отвечать джанго с ее удобной админкой. Создаю джанго-приложение dpinger, в нем создаю две простые модели:
Для Host еще создаем простую админку, для Report она не нужна. Так же делаю простой view, выводящий последние N сообщений для каждого хоста:
Дальше немного интереснее - собственно пингер.
Джанго позволяет создавать собственные команды для manage.py, что является очень вкусной фичей, т.к. позволяет использовать всю мощь джанго в обычном скрипте.
В приложение dping создаем директорию management, в ней еще одну - commands, а там уже создаем скрипт ping.py. Соответственно команда наша будет называться ping и будет вызываться так:
python /path/to/project/manage.py ping
В ping.py обязательно должен быть класс Command, наследник BaseCommand, а в нем должен быть определен метод handle(), собственно срабатывающий при вызове команды.
Теперь нужно как-то отправлять пинги до хостов. В питоне реализован raw ICMP, но если пойти этим путем, то скрипту потребуются права рута (например, setuid root). Это меня несколько не устраивает, потому что ситуации разные бывают, да и помнить про это требование не хочется. Поэтому пошел более простым путем: вызываю комманду ping и читаю ее вывод.
Вот такой вот получился простенький пингер. Надеюсь кому-то эта информация окажется полезной.
За добавление/редактирование/удаление хостов будет отвечать джанго с ее удобной админкой. Создаю джанго-приложение dpinger, в нем создаю две простые модели:
class Host(models.Model):
domain_or_ip = models.CharField(u'Доменное имя или IP-адрес', max_length=255)
desc = models.TextField(u'Краткое описание')
full_desc = models.TextField(u'Полное описание', null = True, blank = True)
class Meta:
verbose_name = u'хост'
verbose_name_plural = u'хосты'
#сообщения о доступности хостов
class Report(models.Model):
host = models.ForeignKey(Host)
status = models.CharField(u'Статус', max_length=255)
date = models.DateTimeField(u'Дата/Время', auto_now = True)
class Meta:
verbose_name = u'сообщение'
verbose_name_plural = u'сообщения'
Для Host еще создаем простую админку, для Report она не нужна. Так же делаю простой view, выводящий последние N сообщений для каждого хоста:
from django.shortcuts import render_to_response
from django.db.models import Q
from models import *
def lastreports(request, count):
hcount = int(count) * Host.objects.count()
reports = Report.objects.all().order_by('-date')[:hcount]
return render_to_response('lastreports.html', {'reports' : reports, 'count' : hcount})
Дальше немного интереснее - собственно пингер.
Джанго позволяет создавать собственные команды для manage.py, что является очень вкусной фичей, т.к. позволяет использовать всю мощь джанго в обычном скрипте.
В приложение dping создаем директорию management, в ней еще одну - commands, а там уже создаем скрипт ping.py. Соответственно команда наша будет называться ping и будет вызываться так:
python /path/to/project/manage.py ping
В ping.py обязательно должен быть класс Command, наследник BaseCommand, а в нем должен быть определен метод handle(), собственно срабатывающий при вызове команды.
Теперь нужно как-то отправлять пинги до хостов. В питоне реализован raw ICMP, но если пойти этим путем, то скрипту потребуются права рута (например, setuid root). Это меня несколько не устраивает, потому что ситуации разные бывают, да и помнить про это требование не хочется. Поэтому пошел более простым путем: вызываю комманду ping и читаю ее вывод.
# -*- coding:utf-8 -*-
from django.core.management.base import BaseCommand, CommandError
from dping.dpinger.models import Host, Report
import subprocess
class Command(BaseCommand):
args = 'None'
help = 'Ping hosts and write reports'
def ping(self, domain_or_ip):
all_is_good = " 0% packet loss"
all_is_bad = "100% packet loss"
dns_error = "ping: unknown host"
ping = subprocess.Popen(
["ping", "-c", "1", domain_or_ip],
stdout = subprocess.PIPE,
stderr = subprocess.PIPE
)
out, error = ping.communicate()
if all_is_good in out:
return u'Все отлично'
elif all_is_bad in out or dns_error in out:
return u'Невозможно достучаться'
else:
return u'Куда-то пропадают пакеты'
def handle(self, *args, **options):
hosts = Host.objects.all()
for host in hosts:
report = Report.objects.create(host=host, status='')
report.status = self.ping(host.domain_or_ip)
print host.domain_or_ip + ": " + report.status #на всякий случай
report.save()
Вот такой вот получился простенький пингер. Надеюсь кому-то эта информация окажется полезной.
Подписаться на:
Сообщения (Atom)