📄 pping.py
字号:
#!/usr/bin/env python# -*- coding: ISO-8859-1 -*-## Copyright 2002-2004 Norwegian University of Science and Technology## This file is part of Network Administration Visualized (NAV)## NAV is free software; you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation; either version 2 of the License, or# (at your option) any later version.## NAV is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with NAV; if not, write to the Free Software# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA### $Id: $# Authors: Magnus Nordseth <magnun@itea.ntnu.no>#"""Pings multiple hosts in parallel"""import osimport signalimport getoptimport timeimport pwdfrom nav.statemon import rrdfrom nav.statemon import megapingfrom nav.statemon import dbfrom nav.statemon import configfrom nav.statemon import circbuffrom nav.statemon import debugfrom nav.statemon.event import Eventfrom nav.statemon.netbox import Netboxclass pinger: def __init__(self, **kwargs): signal.signal(signal.SIGHUP, self.signalhandler) signal.signal(signal.SIGTERM, self.signalhandler) self.config=config.pingconf() debug.setDebugLevel(int(self.config.get("debuglevel",5))) debug.debug("Setting debuglevel=%s "% self.config.get("debuglevel",5)) self._isrunning=1 self._looptime=int(self.config.get("checkinterval",60)) debug.debug("Setting checkinterval=%i" %self._looptime) self._debuglevel=0 self.dbconf=config.dbconf() self.db=db.db(self.dbconf) sock = kwargs.get("socket",None) self.pinger=megaping.MegaPing(sock) self._nrping = int(self.config.get("nrping" ,3)) # To keep status... self.netboxmap = {} # hash netboxid -> netbox self.down = [] # list of netboxids down self.replies = {} # hash netboxid -> circbuf self.ipToNetboxid = {} def updateHostList(self): """ Fetches all netboxes from the NAVdb, and updates internal data structures. """ debug.debug("Getting hosts from database...",7) hosts = self.db.hostsToPing() netboxmap = {} self.ipToNetboxid = {} for host in hosts: netboxid, deviceid, sysname, ip, up = host netbox = Netbox(netboxid, deviceid, sysname, ip, up) if not self.netboxmap.has_key(netbox.netboxid): # new netbox. Be sure to get it's state if netbox.up != 'y': debug.debug("Got new netbox, %s, currently " "marked down in navDB" % netbox.ip, 7) self.down.append(netbox.netboxid) if not self.replies.has_key(netbox.netboxid): self.replies[netbox.netboxid] = circbuf.CircBuf() if netbox.up != 'y': buf = self.replies[netbox.netboxid] # This genious line marks all-down for the whole buf map(buf.push, [-1]*len(buf)) netboxmap[netbox.netboxid]=netbox self.ipToNetboxid[netbox.ip] = netbox.netboxid # Update netboxmap self.netboxmap = netboxmap debug.debug("We now got %i hosts in our list to ping" % len(self.netboxmap), 7) #then update our pinger object self.pinger.setHosts(self.ipToNetboxid.keys()) def generateEvents(self): """ Report state changes to event engine. """ debug.debug("Checks which hosts didn't answer",7) answers = self.pinger.results() for ip, rtt in answers: # rtt = round trip time (-1 => host didn't reply) netboxid = self.ipToNetboxid.get(ip) self.replies[netboxid].push(rtt) netbox = self.netboxmap[netboxid] if rtt != -1: rrd.update(netbox.netboxid, netbox.sysname, 'N', 'UP', rtt) else: # ugly... rrd.update(netbox.netboxid, netbox.sysname, 'N', 'DOWN', 5) downNow = [] # Find out which netboxes to consider down for (netboxid, replies) in self.replies.items(): if replies[:self._nrping] == [-1]*self._nrping: downNow.append(netboxid) debug.debug("No answer from %i hosts" %len(downNow),7) # Detect state changes since last run reportDown = filter(lambda x: x not in self.down, downNow) reportUp = filter(lambda x: x not in downNow, self.down) self.down = downNow # Reporting netboxes as down debug.debug("Starts reporting %i hosts as down" % len(reportDown),7) for netboxid in reportDown: netbox = self.netboxmap[netboxid] newEvent = Event(0, netbox.netboxid, netbox.deviceid, Event.boxState, "pping", Event.DOWN ) self.db.newEvent(newEvent) debug.debug("%s marked as down." % netbox) # Reporting netboxes as up debug.debug("Starts reporting %i hosts as up" % len(reportUp),7) for netboxid in reportUp: try: netbox = self.netboxmap[netboxid] except: debug.debug("Netbox %s is no longer with us..." % netboxid) continue newEvent = Event(0, netbox.netboxid, netbox.deviceid, Event.boxState, "pping", Event.UP ) self.db.newEvent(newEvent) debug.debug( "%s marked as up." % netbox) def main(self): """ Loops until SIGTERM is caught. """ self.db.start() while self._isrunning: start=time.time() debug.debug("Starts pinging....", 7) self.updateHostList() elapsedtime=self.pinger.ping() self.generateEvents() debug.debug("%i hosts checked in %03.3f secs. %i hosts " "currently marked as down." % (len(self.netboxmap), elapsedtime, len(self.down))) wait=self._looptime-elapsedtime if wait > 0: debug.debug("Sleeping %03.3f secs" % wait,6) else: wait=abs(self._looptime + wait) debug.debug("Check lasted longer than looptime. " "Delaying next check for %03.3f secs" % wait,2) time.sleep(wait) def signalhandler(self, signum, frame): if signum == signal.SIGTERM: debug.debug("Caught SIGTERM. Exiting.",1) os.sys.exit(0) elif signum == signal.SIGHUP: # reopen the logfile logfile=self.config.get("logfile", "pping.log") debug.debug("Caught SIGHUP. Reopening logfile...") os.sys.stdout.close() os.sys.stderr.close() os.sys.stdout = open(logfile,'a') os.sys.stderr = open(logfile,'a') debug.debug("Reopened logfile: %s" % logfile) else: debug.debug( "Caught %s. Resuming operation." % (signum),2)def help(): print """Paralell pinger for NAV (Network Administration Visualized). Usage: %s [OPTIONS] -h --help Displays this message -n --nofork Run in foreground -v --version Display version and exit Written by Stian S鴌land and Magnus Nordseth, 2002 """ % os.path.basename(os.sys.argv[0])def start(nofork): """ Forks a new prosess, letting the service run as a daemon. """ conf = config.pingconf() if not nofork: pid=os.fork() if pid > 0: os.sys.exit() # Decouple from parent environment os.chdir('/') # In case the cwd we started in is removed os.setsid() # Do second fork # (prevent us from accidentally reacquiring a controlling terminal) pid=os.fork() if pid > 0: os.sys.exit() # Close the underlying OS file descriptors os.sys.stdout.flush() os.sys.stderr.flush() os.close(os.sys.stdin.fileno()) os.close(os.sys.stdout.fileno()) os.close(os.sys.stderr.fileno()) logfile = conf.get("logfile","pping.log") os.sys.stdout = open(logfile,"a") os.sys.stderr = open(logfile,"a") pidfilename = conf.get("pidfile","/usr/local/nav/var/run/pping.pid") pidfile = open(pidfilename, 'w') pidfile.write(str(os.getpid())) pidfile.close() myPinger=pinger(socket=sock) myPinger.main()def setUser(): conf = config.pingconf() username = conf.get("user", "nobody") try: uid = pwd.getpwnam(username)[2] gid = pwd.getpwnam(username)[3] except KeyError: print "User %s not found" % username print "Exiting" os.sys.exit() os.setegid(gid) os.seteuid(uid) # Make things read/write for user and group os.umask(0002)if __name__=="__main__": nofork=0 try: opts, args = getopt.getopt(os.sys.argv[1:], "hnv", ["help","nofork", "version"]) for opt, val in opts: if opt in ("-h","--help"): help() os.sys.exit() elif opt in ("-n","--nofork"): nofork=1 elif opt in ("-v","--version"): print __version__ os.sys.exit(0) except (getopt.error): help() os.sys.exit(2) if os.getuid() != 0: print "Must be started as root" os.exit(0) sock = megaping.makeSocket() setUser() start(nofork)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -