new project
This commit is contained in:
116
nando
Executable file
116
nando
Executable file
@@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import socket,sys,time,os
|
||||||
|
|
||||||
|
def setup_options():
|
||||||
|
''' Setup the command line options '''
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
|
parser=ArgumentParser(description="Alive notifier.")
|
||||||
|
parser.add_argument("--host",action='store', dest='HOST',type=str,required=True,
|
||||||
|
help="Host name/IP of the server")
|
||||||
|
parser.add_argument("--port", action='store', dest='PORT', default=13370,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=False,
|
||||||
|
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()
|
||||||
|
return options
|
||||||
|
|
||||||
|
def print_table(data):
|
||||||
|
lengths=[0,0,0,0]
|
||||||
|
for row in data.split("\n"):
|
||||||
|
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]
|
||||||
|
for row in data.split("\n"):
|
||||||
|
cols=row.split("|",4)
|
||||||
|
if len(cols)!=4:
|
||||||
|
continue
|
||||||
|
print(("{0:<"+lengths[0]+"} | {1:<"+lengths[1]+"} | {2:>"+lengths[2]+"} | {3:<"+lengths[3]+"}").format(*cols))
|
||||||
|
|
||||||
|
def query_ip(sock,opts):
|
||||||
|
sock.sendto("list", (opts.HOST, opts.PORT))
|
||||||
|
received = sock.recv(1024)
|
||||||
|
for row in received.split("\n"):
|
||||||
|
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):
|
||||||
|
sock.sendto("list", (opts.HOST, opts.PORT))
|
||||||
|
received = sock.recv(1024)
|
||||||
|
for row in received.split("\n"):
|
||||||
|
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:
|
||||||
|
return ""
|
||||||
|
if not os.path.isfile(opts.MSGFILE):
|
||||||
|
return ""
|
||||||
|
|
||||||
|
DESC=open(opts.MSGFILE,"rb").read(512)
|
||||||
|
DESC=''.join([ c for c in DESC if c not in ['\n','\r','|'] ])
|
||||||
|
return DESC
|
||||||
|
|
||||||
|
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]
|
||||||
|
|
||||||
|
if opts.QUERY_HOSTNAME:
|
||||||
|
query_ip(sock,opts)
|
||||||
|
if opts.QUERY_IP:
|
||||||
|
query_host(sock,opts)
|
||||||
|
|
||||||
|
if opts.command=="":
|
||||||
|
DESC=read_desc(opts)
|
||||||
|
MSG="{0}|{1}|{2}\n".format(MYNAME,MYIP,DESC)
|
||||||
|
else:
|
||||||
|
MSG=opts.command
|
||||||
|
|
||||||
|
sock.sendto(MSG, (opts.HOST, opts.PORT))
|
||||||
|
received = sock.recv(1024)
|
||||||
|
if opts.command!="":
|
||||||
|
print_table(received)
|
||||||
|
if opts.INTERVAL==0 and opts.command=="":
|
||||||
|
sock.sendto("list", (opts.HOST, opts.PORT))
|
||||||
|
received = sock.recv(1024)
|
||||||
|
print_table(received)
|
||||||
|
errors=0
|
||||||
|
except socket.error:
|
||||||
|
print("Didn't get reply from {0}:{1}".format(opts.HOST,opts.PORT))
|
||||||
|
errors=1
|
||||||
|
except IndexError:
|
||||||
|
print(received)
|
||||||
|
if opts.INTERVAL==0:
|
||||||
|
break
|
||||||
|
time.sleep(opts.INTERVAL)
|
||||||
|
|
||||||
|
sys.exit(errors)
|
||||||
43
nando-desc
Executable file
43
nando-desc
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#~ [ $UID = 0 ] || {
|
||||||
|
#~ echo Must be run as root
|
||||||
|
#~ exit 1
|
||||||
|
#~ }
|
||||||
|
function filesize {
|
||||||
|
# Return a human readable size from integer of bytes
|
||||||
|
# Usage: filesize 10000
|
||||||
|
|
||||||
|
[ "$1" = "0" ] && {
|
||||||
|
echo "0 B"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
awk 'BEGIN{ x = '$1'
|
||||||
|
split("B KB MB GB TB PB",type)
|
||||||
|
for(i=5;y < 1;i--)
|
||||||
|
y = x / (2^(10*i))
|
||||||
|
str=int(y*10)/10 " " type[i+2]
|
||||||
|
if (x==0) { str = "0 B" }
|
||||||
|
print str
|
||||||
|
}' || return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Gather list of last user of machine
|
||||||
|
|
||||||
|
LASTUSER=$( who | tail -n 1 | awk '{ print $1 }' )
|
||||||
|
FULLNAME=$( getent passwd "$LASTUSER" | cut -d ':' -f 5 )
|
||||||
|
|
||||||
|
DESC_CORES=$( grep -c ^processor /proc/cpuinfo | tr -d -c [:digit:] )
|
||||||
|
DESC_TYPE=$( grep -m 1 "model name" /proc/cpuinfo | cut -d: -f2 | sed -e 's/^ *//' )
|
||||||
|
DESC_MEM=$( grep MemTotal /proc/meminfo | cut -f2 -d: | tr -d -c [:digit:] )
|
||||||
|
DESC_MEM=$( filesize $(( ${DESC_MEM}*1024 )) )
|
||||||
|
DESC_VERS=$( lsb_release -r | awk '{print $2}' )
|
||||||
|
DESC_UP=$( uptime | sed s/,.*// )
|
||||||
|
DESC_SERIAL=$( dmidecode | grep "Serial Number:" | head -n 1 | cut -d: -f2 | sed -e 's/^ *//' )
|
||||||
|
DESC="$LASTUSER/$FULLNAME/${DESC_CORES}x ${DESC_TYPE}/RAM ${DESC_MEM}/v.${DESC_VERS}/${DESC_UP}/SN ${DESC_SERIAL}"
|
||||||
|
echo "$DESC"
|
||||||
|
|
||||||
|
# exit okay
|
||||||
|
true
|
||||||
204
nandod
Executable file
204
nandod
Executable file
@@ -0,0 +1,204 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import SocketServer,threading
|
||||||
|
import sqlite3
|
||||||
|
import time,os,sys
|
||||||
|
|
||||||
|
ALIVE=60*30
|
||||||
|
TABLE_HEAD="Host|IP|Age(d h:m:s)|Description\n"
|
||||||
|
|
||||||
|
def setup_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")
|
||||||
|
parser.add_argument("--port", action='store', dest='PORT', default=13370,type=int,
|
||||||
|
help="Bind to port")
|
||||||
|
parser.add_argument("--db",action='store', dest='DB',default='/tmp/nando.sqlite',type=str,
|
||||||
|
help="Sqlite file for database.")
|
||||||
|
parser.add_argument("--quiet","-q",action='store_true', dest='quiet',default=False,
|
||||||
|
help="Quiet operation.")
|
||||||
|
options=parser.parse_args()
|
||||||
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
class UDPHandler(SocketServer.BaseRequestHandler):
|
||||||
|
def handle(self):
|
||||||
|
data = self.request[0].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()
|
||||||
|
else:
|
||||||
|
DB.update(data)
|
||||||
|
reply="OK"
|
||||||
|
socket.sendto(reply, self.client_address)
|
||||||
|
|
||||||
|
class TCPHandler(SocketServer.BaseRequestHandler):
|
||||||
|
def handle(self):
|
||||||
|
if not opts.quiet:
|
||||||
|
print "TCP request: {0}".format(self.client_address[0])
|
||||||
|
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.request.close()
|
||||||
|
|
||||||
|
class DataBase:
|
||||||
|
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 conn_init(self):
|
||||||
|
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()
|
||||||
|
|
||||||
|
def createDB(self):
|
||||||
|
self.conn_init()
|
||||||
|
self.db.execute('CREATE TABLE alive (id TEXT PRIMARY KEY,\
|
||||||
|
ip TEXT,\
|
||||||
|
desc TEXT,\
|
||||||
|
date INTEGER)')
|
||||||
|
self.conn_end()
|
||||||
|
|
||||||
|
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:
|
||||||
|
return 1
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
self.db=self.conn.cursor()
|
||||||
|
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=[]
|
||||||
|
for row in self.db:
|
||||||
|
age=int(time.time())-row[2]
|
||||||
|
if age<ALIVE:
|
||||||
|
alive.append("{0}|{1}|{2}|{3}".format(row[0],row[1], humanize_time(age),row[3]))
|
||||||
|
else:
|
||||||
|
lost.append( "{0}|{1}|{2}|{3}".format(row[0],row[1], humanize_time(age),row[3]))
|
||||||
|
return TABLE_HEAD+"\n".join(alive)+"\n---|---|---|---\n"+"\n".join(lost)
|
||||||
|
|
||||||
|
def list_alive(self):
|
||||||
|
self.db=self.conn.cursor()
|
||||||
|
self.db.execute("SELECT id,ip,date,desc FROM alive ORDER BY date DESC")
|
||||||
|
msg=[]
|
||||||
|
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)
|
||||||
|
|
||||||
|
def list_lost(self):
|
||||||
|
self.db=self.conn.cursor()
|
||||||
|
self.db.execute("SELECT id,ip,date,desc FROM alive ORDER BY date")
|
||||||
|
msg=[]
|
||||||
|
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)
|
||||||
|
|
||||||
|
def HTML_list(self):
|
||||||
|
msg=[]
|
||||||
|
msg.append('''<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
background-color: gray;
|
||||||
|
}
|
||||||
|
td, th {
|
||||||
|
text-align: left;
|
||||||
|
background-color: lightgray;
|
||||||
|
padding: 0.5ex;
|
||||||
|
}
|
||||||
|
.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body><h1>Alive</h1><table>''')
|
||||||
|
self.db=self.conn.cursor()
|
||||||
|
self.db.execute("SELECT id,ip,date,desc FROM alive ORDER BY id")
|
||||||
|
msg.append('<tr><th>{0}</th><th>{1}</th><th class="right">{2}</th><th>{3}</th></tr>'.format('Host','IP','Age[d h:m:s]','Description'))
|
||||||
|
for row in self.db:
|
||||||
|
age=int(time.time())-row[2]
|
||||||
|
if age <ALIVE:
|
||||||
|
msg.append('<tr><td>{0}</td><td>{1}</td><td class="right">{2}</td><td>{3}</td></tr>'.format(row[0],row[1],humanize_time(age),row[3]))
|
||||||
|
msg.append('</table><h1>Lost</h1><table>')
|
||||||
|
msg.append('<tr><th>{0}</th><th>{1}</th><th class="right">{2}</th><th>{3}</th></tr>'.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:
|
||||||
|
age=int(time.time())-row[2]
|
||||||
|
if age >=ALIVE:
|
||||||
|
msg.append('<tr><td>{0}</td><td>{1}</td><td class="right">{2}</td><td>{3}</td></tr>'.format(row[0],row[1],humanize_time(age),row[3]))
|
||||||
|
msg.append('</table></body></html>')
|
||||||
|
|
||||||
|
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
|
||||||
|
HTMLDB=DataBase(opts.DB)
|
||||||
|
HTMLserver = SocketServer.TCPServer((opts.HOST, opts.PORT), TCPHandler)
|
||||||
|
HTMLserver.serve_forever()
|
||||||
|
|
||||||
|
def humanize_time(secs):
|
||||||
|
mins, secs = divmod(secs, 60)
|
||||||
|
hours, mins = divmod(mins, 60)
|
||||||
|
if hours < 24:
|
||||||
|
return '%02d:%02d:%02d' % (hours, mins, secs)
|
||||||
|
else:
|
||||||
|
days, hours = divmod(hours, 24)
|
||||||
|
return '%dd %02d:%02d:%02d' % (days, hours, mins, secs)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
opts=setup_options()
|
||||||
|
if not opts.quiet:
|
||||||
|
print("Starting NandoD {0}:{1}".format(opts.HOST,opts.PORT))
|
||||||
|
UDP=threading.Thread(target=UDPserve)
|
||||||
|
TCP=threading.Thread(target=TCPserve)
|
||||||
|
UDP.daemon=True
|
||||||
|
TCP.daemon=True
|
||||||
|
UDP.start()
|
||||||
|
TCP.start()
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
time.sleep(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("Exiting..")
|
||||||
|
server.shutdown()
|
||||||
|
HTMLserver.shutdown()
|
||||||
|
sys.exit(0)
|
||||||
Reference in New Issue
Block a user