new project

This commit is contained in:
Ville Rantanen
2015-07-13 10:03:42 +03:00
commit 243ee69506
3 changed files with 363 additions and 0 deletions

116
nando Executable file
View 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
View 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
View 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)