Уведомления

Группа в Telegram: @pythonsu

#1 Июнь 2, 2015 08:14:22

FessAectan
Зарегистрирован: 2015-06-02
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Демон проверки пинга до определенного IP.

Приветствую.

Написал небольшой скрипт, который проверяет пинг до определенного IP, после чего, на основе полученных данных, выполняет ряд действий. Если скрипт запустить руками, то все работает как должно.
Но мне захотелось оформить его в виде unix демона, и тут я решил идти к знающим камрадам, а не просто в гугл, ибо нет четкого понимания чего же вопросить у бездушного робота.
Итак, вот код скрипта:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# written by FessAectan (almost, ping_latency doesn't belong me ;) )
import sys, pexpect, time, datetime, os, re, paramiko
import smtplib
from email.mime.text import MIMEText
user = 'root'
secret_sc = 'some_password'
secret_ns1 = 'some_password_1'
port = 22
i = datetime.datetime.now()
log_file = 'check.' + i.strftime('%Y.%m.%d.%H.%M') + '.log'
def ConnectToSSH(ipaddr,commands,secret):
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect(hostname=ipaddr, username=user, password=secret, port=port)
    time.sleep(1)
    stdin, stdout, stderr = client.exec_command(commands)
    data = stdout.read() + stderr.read()
    client.close()
    write_to_file(log_file,data + '\n')
def CreateFileFlag(FileFlag):
    os.popen("touch " + FileFlag)
def DeleteFileFlag(FileFlag):
    os.popen("rm " + FileFlag)
def sendemail(subj,msg):
    me = 'root@server.example.com'
    you = 'admin@example.com'
    smtp_server = '127.0.0.1'
    msg = MIMEText(msg)
    msg['Subject'] = subj
    msg['From'] = me
    msg['To'] = you
    s = smtplib.SMTP(smtp_server)
    s.sendmail(me, [you], msg.as_string())
    s.quit()
def CheckPL(ipaddr,procent):
    """Функция принимает в качестве параметра ip адрес, проверяет есть ли с ним связь.
    Возвращает 0 если всё ОК, возвращает 1 если потерь больше чем procent"""
    StPingReq = os.popen("ping " + ipaddr + " -c10")
    StProcent = re.compile(r"[\d]+[%]")
    for line in StPingReq.readlines():
      StTotal=StProcent.search(line)
      if (StTotal != None):
        break
    result = StTotal.group(0).replace('%','')
    if (int(result) >= procent):
        return 1
    else:
        return 0
def write_to_file(file_to_write, message):
    fh = open(file_to_write, 'a')
    fh.write(message)
    fh.close()
def ping_or_not_ping(ping_destination):
    response = os.system("ping -c 5 " + ping_destination)
    return response
def ping_latency(ping_destination):
    latency = 0
    interval = 3
    threshold = 300
    count = 0
    line = 'Ping Interval: ' + str(interval) + ', Destination: ' + ping_destination + ', Threshold to Log (msec): ' + str(threshold) + '\n'
    #write_to_file(log_file, line)
    ping_command = 'ping -i ' + str(interval) + ' ' + ping_destination
    print line
    child = pexpect.spawn(ping_command)
    child.timeout=1200
    while 1:
        line = child.readline()
        if not line:
            break
        if line.startswith('ping: unknown host'):
            print 'Unknown host: ' + ping_destination
            write_to_file(log_file, 'Unknown host: ' + ping_destination)
            break
        if count > 0:
            ping_time = float(line[line.find('time=') + 5:line.find(' ms')])
            line = time.strftime("%m/%d/%Y %H:%M:%S") + ": " + str(ping_time)
            print str(count) + ": " + line
            latency = latency + ping_time
            if ping_time > threshold:
                write_to_file(log_file, line + '\n')
        if count > 4:
            break
        count += 1
    return (latency / count)
def Check(ipaddr):
    result = ping_or_not_ping(ipaddr)
    if result == 0:
        if os.path.exists("NotPingedFlag"):
            write_to_file(log_file, i.strftime('%Y.%m.%d.%H.%M') + ':' + '\n' + "IP 1.1.1.1 снова пингуется" +'\n'  + "Меняем IP на ns.example.com... " + '\n' + "Результат проверки:" + '\n')
            ConnectToSSH("123.4.5.6","""/root/sh/reload_httpd_first2second.sh""", secret_1)
            ConnectToSSH("ns1.example.com","""/root/sh/change_serial_ips_first2second_restart_named.sh""", secret_ns1)
            sendemail("""IP 1.1.1.1 снова пингуется""","""На ns1.example.com отправлена команда переключения ru/com сайтов на IP second""")
            DeleteFileFlag("NotPingedFlag")
        packetloss = CheckPL(ipaddr,30)
        if packetloss == 0:
            if os.path.exists("PacketLossFlag"):
                write_to_file(log_file, i.strftime('%Y.%m.%d.%H.%M') + ':' + '\n' + "Потерь до second IP 1.1.1.1 меньше 30%" +'\n' + "Меняем IP на ns1.example.com... " + '\n' + "Результат проверки:" + '\n')
                ConnectToSSH("123.4.5.6","""/root/sh/reload_httpd_first2second.sh""", secret_sc)
                ConnectToSSH("ns1.example.com","""/root/sh/change_serial_ips_first2second_restart_named.sh""", secret_ns1)
                sendemail("""Потерь пакетов до IP 1.1.1.1 не наблюдается""","""На ns1.example.com отправлена команда переключения ru/com сайтов на IP second""")
                DeleteFileFlag("PacketLossFlag")
            latency = ping_latency(ipaddr)
            if latency > 300:
                sendemail("""Задержка при пинге  IP 1.1.1.1 больше 300""","""Думайте сами, решайте сами - переключать DNS или нет""")
        elif packetloss == 1:
            if os.path.exists("PacketLossFlag") == False:
                write_to_file(log_file, i.strftime('%Y.%m.%d.%H.%M') + ':' + '\n' + "30%+ потерь до 1.1.1.1 IP" +'\n' + "Меняем IP на ns1.example.com... " + '\n' + "Результат проверки:" + '\n')
                ConnectToSSH("123.4.5.6","""/root/sh/reload_httpd_second2first.sh""", secret_sc)
                ConnectToSSH("ns1.example.com","""/root/sh/change_serial_ips_second2first_restart_named.sh""", secret_ns1)
                sendemail("""30%+ пакетов до IP 1.1.1.1 теряются""","""На ns1.example.com отправлена команда переключения ru/com сайтов на IP 123.4.5.x""")
                CreateFileFlag("PacketLossFlag")
    elif result > 0:
        if os.path.exists("NotPingedFlag") == False:
            write_to_file(log_file, i.strftime('%Y.%m.%d.%H.%M') + ':' + '\n' + "Не пингуется  IP 1.1.1.1" +'\n'  + "Меняем IP на ns1.example.com... " + '\n' + "Результат проверки:" + '\n')
            ConnectToSSH("123.4.5.6","""/root/sh/reload_httpd_second2first.sh""", secret_sc)
            ConnectToSSH("ns1.example.com","""/root/sh/change_serial_ips_second2first_restart_named.sh""", secret_ns1)
            sendemail("""IP 1.1.1.1 не пингуется""","""На ns1.example.com отправлена команда переключения ru/com сайтов на IP 123.4.5.x""")
            CreateFileFlag("NotPingedFlag")
def main():
    while True:
        Check('1.1.1.1')
        time.sleep(60)
if __name__ == "__main__":
    main()
Этот скрипт, с помощью вот такого класса
#!/usr/bin/python
import sys, os, time, atexit
from signal import SIGTERM
class Daemon:
        """
        A generic daemon class.
        Usage: subclass the Daemon class and override the run() method
        """
        def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
                self.stdin = stdin
                self.stdout = stdout
                self.stderr = stderr
                self.pidfile = pidfile
        def daemonize(self):
                """
                do the UNIX double-fork magic, see Stevens' "Advanced
                Programming in the UNIX Environment" for details (ISBN 0201563177)
                http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
                """
                try:
                        pid = os.fork()
                        if pid > 0:
                                # exit first parent
                                sys.exit(0)
                except OSError, e:
                        sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
                        sys.exit(1)
                # decouple from parent environment
                os.chdir("/")
                os.setsid()
                os.umask(0)
                # do second fork
                try:
                        pid = os.fork()
                        if pid > 0:
                                # exit from second parent
                                sys.exit(0)
                except OSError, e:
                        sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
                        sys.exit(1)
                # redirect standard file descriptors
                sys.stdout.flush()
                sys.stderr.flush()
                si = file(self.stdin, 'r')
                so = file(self.stdout, 'a+')
                se = file(self.stderr, 'a+', 0)
                os.dup2(si.fileno(), sys.stdin.fileno())
                os.dup2(so.fileno(), sys.stdout.fileno())
                os.dup2(se.fileno(), sys.stderr.fileno())
                # write pidfile
                atexit.register(self.delpid)
                pid = str(os.getpid())
                file(self.pidfile,'w+').write("%s\n" % pid)
        def delpid(self):
                os.remove(self.pidfile)
        def start(self):
                """
                Start the daemon
                """
                # Check for a pidfile to see if the daemon already runs
                try:
                        pf = file(self.pidfile,'r')
                        pid = int(pf.read().strip())
                        pf.close()
                except IOError:
                        pid = None
                if pid:
                        message = "pidfile %s already exist. Daemon already running?\n"
                        sys.stderr.write(message % self.pidfile)
                        sys.exit(1)
                # Start the daemon
                self.daemonize()
                self.run()
        def stop(self):
                """
                Stop the daemon
                """
                # Get the pid from the pidfile
                try:
                        pf = file(self.pidfile,'r')
                        pid = int(pf.read().strip())
                        pf.close()
                except IOError:
                        pid = None
                if not pid:
                        message = "pidfile %s does not exist. Daemon not running?\n"
                        sys.stderr.write(message % self.pidfile)
                        return # not an error in a restart
                # Try killing the daemon process
                try:
                        while 1:
                                os.kill(pid, SIGTERM)
                                time.sleep(0.1)
                except OSError, err:
                        err = str(err)
                        if err.find("No such process") > 0:
                                if os.path.exists(self.pidfile):
                                        os.remove(self.pidfile)
                        else:
                                print str(err)
                                sys.exit(1)
        def restart(self):
                """
                Restart the daemon
                """
                self.stop()
                self.start()
def run(self):
                """
                You should override this method when you subclass Daemon. It will be called after the process has been
                daemonized by start() or restart().
        """
я хочу оформить в виде демона.
Вызываю вот так:
#!/usr/bin/python
#-*- coding: utf-8 -*-                                                                                                                           
import sys
sys.path.append("/root/sh/python")
from daemon import Daemon
import check #первый скрипт в  посте
class ip_checker(Daemon):
            def run(self):
                while True:
                    check.main()
if __name__ == "__main__":
            daemon = ip_checker('/var/run/ip_checker.pid',stdout='/var/log/ip_checker.log',stderr='/var/log/ip_checker.err.log')
            if len(sys.argv) == 2:
                    if 'start' == sys.argv[1]:
                            daemon.start()
                    elif 'stop' == sys.argv[1]:
                            daemon.stop()
                    elif 'restart' == sys.argv[1]:
                            daemon.restart()
                    else:
                            print "Unknown command"
                            sys.exit(2)
                    sys.exit(0)
            else:
                    print "usage: %s start|stop|restart" % sys.argv[0]
                    sys.exit(2)

Вероятнее всего нужно смотреть в сторону stdout, stderr и как-то их в скрипте обрабатывать.
Ведь когда в терминале запускаю, то скрипт взаимодействует с ним, а если демоном, то он форкается.
В общем просьба направить в нужном направлении, может статью или книгу какую посоветуете.

Благодарю.

ps
потоки вывода и ошибок направлены в файлы, ищу как научить функции в скрипте взаимодействовать с ними

Отредактировано FessAectan (Июнь 2, 2015 08:33:01)

Офлайн

#2 Июнь 2, 2015 10:23:55

Shaman
Зарегистрирован: 2013-03-15
Сообщения: 1369
Репутация: +  88  -
Профиль   Отправить e-mail  

Демон проверки пинга до определенного IP.

FessAectan
а не просто в гугл, ибо нет четкого понимания чего же вопросить у бездушного робота.
Это всё от того, что нет понимания о чем спросить вообще.
https://www.google.ru/search?q=how+unix+daemons

Офлайн

#3 Июнь 2, 2015 17:42:20

FessAectan
Зарегистрирован: 2015-06-02
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Демон проверки пинга до определенного IP.

Shaman
Кажется именно об этом я и написал.
Почитаю то, что вы предложили, спасибо.

Отредактировано FessAectan (Июнь 2, 2015 17:42:53)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version