From cff1dfea3cd7fcf30fa99432062b9221624a5de4 Mon Sep 17 00:00:00 2001 From: Ville Rantanen Date: Sun, 25 Oct 2020 10:41:13 +0200 Subject: [PATCH] python3 updates --- nando | 191 ++++++++++++++++++++++----------- nandod | 332 ++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 341 insertions(+), 182 deletions(-) diff --git a/nando b/nando index 37d9995..2916b28 100755 --- a/nando +++ b/nando @@ -1,44 +1,95 @@ #!/usr/bin/env python3 -import socket,sys,time,os,configobj +import socket, sys, time, os, configobj + +RC = "/etc/nandorc" +BLOCK_SIZE = 10240 -RC="/etc/nandorc" -BLOCK_SIZE=10240 def setup_options(): - ''' Setup the command line options ''' + """ Setup the command line options """ from argparse import ArgumentParser - parser=ArgumentParser(description="Alive notifier. Options first read from /etc/nandorc, and overriden by switches.") - parser.add_argument("--host",action='store', dest='HOST',type=str,default=None, - help="Host name/IP of the server") - parser.add_argument("--port", action='store', dest='PORT', default=None,type=int, - help="Port number of the server") - parser.add_argument("-t",action='store', dest='TIMEOUT',default=5, type=int, - help="Connection timeout") - parser.add_argument("-i",action='store', dest='INTERVAL',default=0, type=int, - help="Send signal every i seconds. If 0, send only once and exit.") - parser.add_argument("-m",action='store', dest='MSGFILE',type=str,default=None, - help="Read a text file as description. Max length 512 chars") - parser.add_argument("--query-ip",action='store', dest='QUERY_HOSTNAME',default=None,type=str, - help="Query the IP of a host name") - parser.add_argument("--query-host",action='store', dest='QUERY_IP',default=None,type=str, - help="Query the hostname of an IP") - parser.add_argument("command",type=str,action="store",default="",nargs="?", - choices=['','list','alive','lost'], - help="Command to send. If empty, send standard alive-notice. Commands: list, alive") - options=parser.parse_args() + parser = ArgumentParser( + description="Alive notifier. Options first read from /etc/nandorc, and overriden by switches." + ) + parser.add_argument( + "--host", + action="store", + dest="HOST", + type=str, + default=None, + help="Host name/IP of the server", + ) + parser.add_argument( + "--port", + action="store", + dest="PORT", + default=None, + type=int, + help="Port number of the server", + ) + parser.add_argument( + "-t", + action="store", + dest="TIMEOUT", + default=5, + type=int, + help="Connection timeout", + ) + parser.add_argument( + "-i", + action="store", + dest="INTERVAL", + default=0, + type=int, + help="Send signal every i seconds. If 0, send only once and exit.", + ) + parser.add_argument( + "-m", + action="store", + dest="MSGFILE", + type=str, + default=None, + help="Read a text file as description. Max length 512 chars", + ) + parser.add_argument( + "--query-ip", + action="store", + dest="QUERY_HOSTNAME", + default=None, + type=str, + help="Query the IP of a host name", + ) + parser.add_argument( + "--query-host", + action="store", + dest="QUERY_IP", + default=None, + type=str, + help="Query the hostname of an IP", + ) + parser.add_argument( + "command", + type=str, + action="store", + default="", + nargs="?", + choices=["", "list", "alive", "lost"], + help="Command to send. If empty, send standard alive-notice. Commands: list, alive", + ) + options = parser.parse_args() if os.path.exists(RC): - rc=configobj.ConfigObj(RC) + rc = configobj.ConfigObj(RC) if options.HOST is None: if "HOST" in rc.keys(): - options.HOST=rc['HOST'] + options.HOST = rc["HOST"] if options.PORT is None: if "PORT" in rc.keys(): - options.PORT=int(rc['PORT']) + options.PORT = int(rc["PORT"]) if options.MSGFILE is None: if "MSGFILE" in rc.keys(): - options.MSGFILE=rc['MSGFILE'] + options.MSGFILE = rc["MSGFILE"] if options.HOST is None: parser.error("Host name required") @@ -48,40 +99,53 @@ def setup_options(): def print_table(data): - lengths=[0,0,0,0] + lengths = [0, 0, 0, 0] for row in data.split("\n"): - cols=row.split("|",4) - if len(cols)!=4: + cols = row.split("|", 4) + if len(cols) != 4: continue for c in range(4): - lengths[c]=max(lengths[c], len(cols[c])) - lengths=[str(x) for x in lengths] + lengths[c] = max(lengths[c], len(cols[c])) + lengths = [str(x) for x in lengths] for row in data.split("\n"): - cols=row.split("|",4) - if len(cols)!=4: + cols = row.split("|", 4) + if len(cols) != 4: continue - print(("{0:<"+lengths[0]+"} | {1:<"+lengths[1]+"} | {2:>"+lengths[2]+"} | {3}").format(*cols)) + print( + ( + "{0:<" + + lengths[0] + + "} | {1:<" + + lengths[1] + + "} | {2:>" + + lengths[2] + + "} | {3}" + ).format(*cols) + ) -def query_ip(sock,opts): + +def query_ip(sock, opts): sock.sendto("list", (opts.HOST, opts.PORT)) received = sock.recv(BLOCK_SIZE) for row in received.split("\n"): - cols=row.split("|",4) - if cols[0]==opts.QUERY_HOSTNAME: + cols = row.split("|", 4) + if cols[0] == opts.QUERY_HOSTNAME: sys.stdout.write(cols[1]) sys.exit(0) sys.exit(1) -def query_host(sock,opts): + +def query_host(sock, opts): sock.sendto("list", (opts.HOST, opts.PORT)) received = sock.recv(BLOCK_SIZE) for row in received.split("\n"): - cols=row.split("|",4) - if cols[1]==opts.QUERY_IP: + cols = row.split("|", 4) + if cols[1] == opts.QUERY_IP: sys.stdout.write(cols[0]) sys.exit(0) sys.exit(1) + def read_desc(opts): if not opts.MSGFILE: @@ -89,47 +153,48 @@ def read_desc(opts): if not os.path.isfile(opts.MSGFILE): return "" - DESC=open(opts.MSGFILE,"rb").read(1024) - DESC=''.join([ str(c) for c in DESC.decode('utf-8') if c not in ['\n','\r','|'] ]) + DESC = open(opts.MSGFILE, "rb").read(1024) + DESC = "".join([str(c) for c in DESC.decode("utf-8") if c not in ["\n", "\r", "|"]]) return DESC -opts=setup_options() -errors=0 +opts = setup_options() + +errors = 0 while True: try: MYNAME = socket.gethostname() sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(opts.TIMEOUT) - sock.connect((opts.HOST,opts.PORT)) - MYIP=sock.getsockname()[0] + sock.connect((opts.HOST, opts.PORT)) + MYIP = sock.getsockname()[0] if opts.QUERY_HOSTNAME: - query_ip(sock,opts) + query_ip(sock, opts) if opts.QUERY_IP: - query_host(sock,opts) + query_host(sock, opts) - if opts.command=="": - DESC=read_desc(opts) - MSG="{0}|{1}|{2}\n".format(MYNAME,MYIP,DESC) + if opts.command == "": + DESC = read_desc(opts) + MSG = "{0}|{1}|{2}\n".format(MYNAME, MYIP, DESC) else: - MSG=opts.command + MSG = opts.command - sock.sendto(MSG.encode('utf8'), (opts.HOST, opts.PORT)) + sock.sendto(MSG.encode("utf8"), (opts.HOST, opts.PORT)) received = sock.recv(BLOCK_SIZE) - if opts.command!="": - print_table(received.decode('utf8')) - if opts.INTERVAL==0 and opts.command=="": - sock.sendto("list".encode('utf8'), (opts.HOST, opts.PORT)) + if opts.command != "": + print_table(received.decode("utf8")) + if opts.INTERVAL == 0 and opts.command == "": + sock.sendto("list".encode("utf8"), (opts.HOST, opts.PORT)) received = sock.recv(BLOCK_SIZE) - print_table(received.decode('utf8')) - errors=0 + print_table(received.decode("utf8")) + errors = 0 except socket.error: - print("Didn't get reply from {0}:{1}".format(opts.HOST,opts.PORT)) - errors=1 + print("Didn't get reply from {0}:{1}".format(opts.HOST, opts.PORT)) + errors = 1 except IndexError: print(received) - if opts.INTERVAL==0: + if opts.INTERVAL == 0: break time.sleep(opts.INTERVAL) diff --git a/nandod b/nandod index 79b87b5..1de171c 100755 --- a/nandod +++ b/nandod @@ -1,140 +1,197 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -import SocketServer,threading +import socketserver, threading import sqlite3 -import time,os,sys +import time, os, sys + +ALIVE = 60 * 30 +TABLE_HEAD = "Host|IP|Age(d h:m:s)|Description\n" -ALIVE=60*30 -TABLE_HEAD="Host|IP|Age(d h:m:s)|Description\n" def setup_options(): - ''' Setup the command line options ''' + """ Setup the command line options """ from argparse import ArgumentParser - parser=ArgumentParser(description="Alive notifier.") - parser.add_argument("--host",action='store', dest='HOST',default='0.0.0.0',type=str, - help="Bind to address: %(default)s") - parser.add_argument("--port", action='store', dest='PORT', default=13370,type=int, - help="Bind to port: %(default)s") - parser.add_argument("--html-port", action='store', dest='WEBPORT', default=13370,type=int, - help="Bind www server to port. 0 to disable, default: %(default)s") - parser.add_argument("--db",action='store', dest='DB',default='/tmp/nando.sqlite',type=str, - help="Sqlite file for database: %(default)s") - parser.add_argument("--quiet","-q",action='store_true', dest='quiet',default=False, - help="Quiet operation: %(default)s") - options=parser.parse_args() + parser = ArgumentParser(description="Alive notifier.") + parser.add_argument( + "--host", + action="store", + dest="HOST", + default="0.0.0.0", + type=str, + help="Bind to address: %(default)s", + ) + parser.add_argument( + "--port", + action="store", + dest="PORT", + default=13370, + type=int, + help="Bind to port: %(default)s", + ) + parser.add_argument( + "--html-port", + action="store", + dest="WEBPORT", + default=13370, + type=int, + help="Bind www server to port. 0 to disable, default: %(default)s", + ) + parser.add_argument( + "--db", + action="store", + dest="DB", + default="/tmp/nando.sqlite", + type=str, + help="Sqlite file for database: %(default)s", + ) + parser.add_argument( + "--quiet", + "-q", + action="store_true", + dest="quiet", + default=False, + help="Quiet operation: %(default)s", + ) + options = parser.parse_args() return options -class UDPHandler(SocketServer.BaseRequestHandler): +class UDPHandler(socketserver.BaseRequestHandler): def handle(self): - data = self.request[0].strip() + DB = DataBase(opts.DB) + data = self.request[0].decode("utf-8").strip() socket = self.request[1] if not opts.quiet: - print "{0} wrote: {1}".format(self.client_address[0],data) - if data=="list": - reply=DB.list_all() - elif data=="alive": - reply=DB.list_alive() - elif data=="lost": - reply=DB.list_lost() + print(("{0} wrote: {1}".format(self.client_address[0], data))) + if data == "list": + reply = DB.list_all() + elif data == "alive": + reply = DB.list_alive() + elif data == "lost": + reply = DB.list_lost() else: DB.update(data) - reply="OK" - socket.sendto(reply, self.client_address) + reply = "OK" + socket.sendto(reply.encode("utf-8"), self.client_address) + DB.close() -class TCPHandler(SocketServer.BaseRequestHandler): + +class TCPHandler(socketserver.BaseRequestHandler): def handle(self): + HTMLDB = DataBase(opts.DB) if not opts.quiet: - print "TCP request: {0}".format(self.client_address[0]) - self.data = self.request.recv(1024).strip() + print(("TCP request: {0}".format(self.client_address[0]))) + self.data = self.request.recv(1024).decode("utf-8").strip() method, path, _ = self.data.splitlines()[0].split() self.path = path.lstrip("/") - self.request.send('HTTP/1.0 200 OK\r\n') - self.request.send("Content-Type: text/html\r\n\r\n") - self.request.sendall(HTMLDB.HTML_list(self.path)) + self.request.send(b"HTTP/1.0 200 OK\r\n") + self.request.send(b"Content-Type: text/html\r\n\r\n") + self.request.sendall(HTMLDB.HTML_list(self.path).encode("utf-8")) self.request.close() + HTMLDB.close() + class DataBase: - def __init__(self,DB): - self.DBfile=DB - self.conn=None - self.db=None + def __init__(self, DB): + self.DBfile = DB + self.conn = None + self.db = None if not os.path.exists(self.DBfile): self.createDB() self.conn_init() + def close(self): + self.conn.close() + def conn_init(self): - self.conn=sqlite3.connect(self.DBfile) - self.db=self.conn.cursor() - self.conn.text_factory=str + self.conn = sqlite3.connect(self.DBfile) + self.db = self.conn.cursor() + self.conn.text_factory = str def conn_end(self): self.conn.commit() - #self.conn.close() + # self.conn.close() def createDB(self): self.conn_init() - self.db.execute('CREATE TABLE alive (id TEXT PRIMARY KEY,\ + self.db.execute( + "CREATE TABLE alive (id TEXT PRIMARY KEY,\ ip TEXT,\ desc TEXT,\ - date INTEGER)') + date INTEGER)" + ) self.conn_end() - def update(self,id): + def update(self, id): try: - host,ip,desc=id.split("|",3) - desc=''.join([ c for c in desc if c not in ['\n','\r','|'] ]) - if len(ip.split("."))!=4: + host, ip, desc = id.split("|", 3) + desc = "".join([c for c in desc if c not in ["\n", "\r", "|"]]) + if len(ip.split(".")) != 4: return 1 except: return - self.db=self.conn.cursor() + self.db = self.conn.cursor() if desc is "": - self.db.execute("INSERT OR REPLACE INTO alive(id,ip,date) \ - VALUES(?,?,?)",(host,ip,int(time.time()))) + self.db.execute( + "INSERT OR REPLACE INTO alive(id,ip,date) \ + VALUES(?,?,?)", + (host, ip, int(time.time())), + ) else: - self.db.execute("INSERT OR REPLACE INTO alive(id,ip,date,desc) \ - VALUES(?,?,?,?)",(host,ip,int(time.time()),desc)) + self.db.execute( + "INSERT OR REPLACE INTO alive(id,ip,date,desc) \ + VALUES(?,?,?,?)", + (host, ip, int(time.time()), desc), + ) self.conn_end() def list_all(self): - self.db=self.conn.cursor() - self.db.execute("SELECT id,ip,date,desc FROM alive ORDER BY id") - alive=[] - lost=[] + self.db = self.conn.cursor() + self.db.execute("SELECT id,ip,date,desc FROM alive ORDER BY date DESC") + alive = [] + lost = [] for row in self.db: - age=int(time.time())-row[2] - if age=ALIVE: - msg.append("{0}|{1}|{2}|{3}".format(row[0],row[1], humanize_time(age),row[3])) - return TABLE_HEAD+"\n".join(msg) + age = int(time.time()) - row[2] + if age >= ALIVE: + msg.append( + "{0}|{1}|{2}|{3}".format(row[0], row[1], humanize_time(age), row[3]) + ) + return TABLE_HEAD + "\n".join(msg) def HTML_list(self, name): # name = '' means do not filter by name - msg=[] - msg.append(''' + msg = [] + msg.append( + """ -

Alive

''') - self.db=self.conn.cursor() +

Alive

""" + ) + self.db = self.conn.cursor() self.db.execute("SELECT id,ip,date,desc FROM alive ORDER BY id") - msg.append(''.format('Host','IP','Age[d h:m:s]','Description')) + msg.append( + ''.format( + "Host", "IP", "Age[d h:m:s]", "Description" + ) + ) for row in self.db: - if name != '': + if name != "": if name != row[0]: continue - age=int(time.time())-row[2] + age = int(time.time()) - row[2] if age < ALIVE: - msg.append(''.format(row[0],row[1],humanize_time(age),row[3])) - msg.append('
{0}{1}{2}{3}
{0}{1}{2}{3}
{0}{1}{2}{3}

Lost

') - msg.append(''.format('Host','IP','Age[d h:m:s]','Description')) + msg.append( + ''.format( + row[0], row[1], humanize_time(age), row[3] + ) + ) + msg.append("
{0}{1}{2}{3}
{0}{1}{2}{3}

Lost

") + msg.append( + ''.format( + "Host", "IP", "Age[d h:m:s]", "Description" + ) + ) self.db.execute("SELECT id,ip,date,desc FROM alive ORDER BY id") for row in self.db: - if name != '': + if name != "": if name != row[0]: continue - age=int(time.time())-row[2] + age = int(time.time()) - row[2] if age >= ALIVE: - msg.append(''.format(row[0],row[1],humanize_time(age),row[3])) - msg.append('
{0}{1}{2}{3}
{0}{1}{2}{3}
') + msg.append( + '{0}{1}{2}{3}'.format( + row[0], row[1], humanize_time(age), row[3] + ) + ) + msg.append("") return "\n\r".join(msg) -def UDPserve(): - global DB - global server - DB=DataBase(opts.DB) - server = SocketServer.UDPServer((opts.HOST, opts.PORT), UDPHandler) - server.serve_forever() -def TCPserve(): - global HTMLDB - global HTMLserver - time.sleep(2) - try: - HTMLDB=DataBase(opts.DB) - HTMLserver = SocketServer.TCPServer((opts.HOST, opts.WEBPORT), TCPHandler) - HTMLserver.serve_forever() - except: - sys.exit(1) +class UDPServe: + def __init__(self, opts): + self.server = socketserver.UDPServer((opts.HOST, opts.PORT), UDPHandler) + + def start(self): + thread = threading.Thread(target=self.serve) + thread.daemon = True + thread.start() + + def serve(self): + self.server.serve_forever() + + def stop(self): + self.server.shutdown() + self.server.server_close() + + +class TCPServe: + def __init__(self, opts): + self.server = socketserver.TCPServer((opts.HOST, opts.WEBPORT), TCPHandler) + + def start(self): + thread = threading.Thread(target=self.serve) + thread.daemon = True + thread.start() + + def serve(self): + time.sleep(2) + self.server.serve_forever() + + def stop(self): + self.server.shutdown() + self.server.server_close() + + def humanize_time(secs): mins, secs = divmod(secs, 60) hours, mins = divmod(mins, 60) if hours < 24: - return '%02d:%02d:%02d' % (hours, mins, secs) + return "%02d:%02d:%02d" % (hours, mins, secs) else: days, hours = divmod(hours, 24) - return '%dd %02d:%02d:%02d' % (days, hours, mins, secs) + return "%dd %02d:%02d:%02d" % (days, hours, mins, secs) + if __name__ == "__main__": - opts=setup_options() + opts = setup_options() if not opts.quiet: - print("Starting NandoD UDP:{0}:{1}, TCP:{0}:{2}".format( - opts.HOST, - opts.PORT, - opts.WEBPORT - )) - UDP=threading.Thread(target=UDPserve) - UDP.daemon=True + print( + ( + "Starting NandoD UDP:{0}:{1}, TCP:{0}:{2}".format( + opts.HOST, opts.PORT, opts.WEBPORT + ) + ) + ) + UDP = UDPServe(opts) UDP.start() if opts.WEBPORT > 0: - TCP=threading.Thread(target=TCPserve) - TCP.daemon=True + TCP = TCPServe(opts) TCP.start() while True: try: time.sleep(1) except KeyboardInterrupt: print("Exiting..") - server.shutdown() + UDP.stop() if opts.WEBPORT > 0: - HTMLserver.shutdown() + TCP.stop() sys.exit(0)