Написал небольшой скрипт, который проверяет пинг до определенного 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
потоки вывода и ошибок направлены в файлы, ищу как научить функции в скрипте взаимодействовать с ними