Commit 3f348774 authored by Tomas Hlavacek's avatar Tomas Hlavacek

BIRD raw command I/O reimplemented, minor bugfixes

Raw I/O for BIRD implemented (inspiration taken from client.c of BIRD).

Bugfixes and more debug added to command thread body.

ULG cron now check age of sessions and deletes only sessions
older than 1 hour.
parent 76ec4678
...@@ -31,6 +31,7 @@ session_dir = '/tmp' ...@@ -31,6 +31,7 @@ session_dir = '/tmp'
usage_counter_file = '/tmp/ulg.lock' usage_counter_file = '/tmp/ulg.lock'
log_file = '/tmp/ulg.log' log_file = '/tmp/ulg.log'
default_bird_sock = '/var/run/bird.ctl' default_bird_sock = '/var/run/bird.ctl'
default_bird_sock_timeout = 30
# Template dir relative to the index.py script # Template dir relative to the index.py script
template_dir = 'templates' template_dir = 'templates'
...@@ -53,6 +54,7 @@ STRING_IPSUBNET = "IP subnet" ...@@ -53,6 +54,7 @@ STRING_IPSUBNET = "IP subnet"
STRING_MACADDRESS = "MAC address" STRING_MACADDRESS = "MAC address"
STRING_NONEORINTORIPADDRESS = "None or Interface or IP address" STRING_NONEORINTORIPADDRESS = "None or Interface or IP address"
STRING_INTERFACE = "Interface" STRING_INTERFACE = "Interface"
STRING_SOCKET_TIMEOUT = "Socket communication timed out. See log."
# URL generator functions # URL generator functions
def getASNURL(asn): def getASNURL(asn):
......
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
# Imports # Imports
import os, sys import os, os.path, sys
import random import random
import time import time, datetime
import pickle import pickle
import re import re
...@@ -47,11 +47,16 @@ class ULGCron: ...@@ -47,11 +47,16 @@ class ULGCron:
for file in os.listdir(defaults.session_dir): for file in os.listdir(defaults.session_dir):
if sre.match(file): if sre.match(file):
fp = defaults.session_dir+'/'+file fp = defaults.session_dir+'/'+file
ulgmodel.log('Removing file '+fp)
try: now = datetime.datetime.now()
os.unlink(fp) if(datetime.datetime.fromtimestamp(os.path.getmtime(fp)) < now+datetime.timedelta(hours=-1)):
except OSError as e: ulgmodel.log('Removing file '+fp)
ulgmodel.log('Error while removing file '+fp+' '+str(e)) try:
os.unlink(fp)
except OSError as e:
ulgmodel.log('Error while removing file '+fp+' '+str(e))
else:
ulgmodel.log('Not removing file '+fp+' because it is not at least 1 hour old.')
def run(self): def run(self):
ulgmodel.log('ULG cron run.') ulgmodel.log('ULG cron run.')
......
...@@ -301,16 +301,15 @@ class ULGCgi: ...@@ -301,16 +301,15 @@ class ULGCgi:
ulgmodel.debug("Running command: "+session.getCommand().getName()) ulgmodel.debug("Running command: "+session.getCommand().getName())
try: try:
session.setResult(session.getRouter().runCommand(session.getCommand(),session.getParameters(),self.decorator_helper)) session.setResult(session.getRouter().runCommand(session.getCommand(),session.getParameters(),self.decorator_helper))
session.setFinished()
except Exception as e: except Exception as e:
ulgmodel.log("ERROR: Exception occured while running a command:" + traceback.format_exc()) ulgmodel.log("ERROR: Exception occured while running a command:" + traceback.format_exc())
session.setPreResult(traceback.format_exc()) session.setPreResult("ERROR in commandThreadBody:\n"+traceback.format_exc())
session.setFinished()
finally: finally:
ulgmodel.debug("Command finished: "+session.getCommand().getName()) ulgmodel.debug("Command finished: "+session.getCommand().getName())
session.setFinished()
decreaseUsageMethod() decreaseUsageMethod()
# fork a daemon process (fork two time to decouple with parent) # fork a daemon process (fork two times to decouple with parent)
sys.stdout.flush() sys.stdout.flush()
child_pid = os.fork() child_pid = os.fork()
if(child_pid == 0): if(child_pid == 0):
......
...@@ -27,6 +27,129 @@ import defaults ...@@ -27,6 +27,129 @@ import defaults
import ulgmodel import ulgmodel
"""
This is the input parsing code from client.c of BIRD:
static void
server_got_reply(char *x)
{
int code;
int len = 0;
if (*x == '+') /* Async reply */
PRINTF(len, ">>> %s\n", x+1);
else if (x[0] == ' ') /* Continuation */
PRINTF(len, "%s%s\n", verbose ? " " : "", x+1);
else if (strlen(x) > 4 &&
sscanf(x, "%d", &code) == 1 && code >= 0 && code < 10000 &&
(x[4] == ' ' || x[4] == '-'))
{
if (code)
PRINTF(len, "%s\n", verbose ? x : x+5);
if (x[4] == ' ')
{
nstate = STATE_PROMPT;
skip_input = 0;
return;
}
}
else
PRINTF(len, "??? <%s>\n", x);
if (skip_input)
return;
if (interactive && input_initialized && (len > 0))
{
int lns = LINES ? LINES : 25;
int cls = COLS ? COLS : 80;
num_lines += (len + cls - 1) / cls; /* Divide and round up */
if ((num_lines >= lns) && (cstate == STATE_CMD_SERVER))
more();
}
}
"""
BIRD_SOCK_HEADER_REGEXP='^([0-9]+)[-\s](.+)$'
BIRD_SOCK_REPLY_END_REGEXP='^([0-9]+)\s*$'
bird_sock_header_regexp = re.compile(BIRD_SOCK_HEADER_REGEXP)
bird_sock_reply_end_regexp = re.compile(BIRD_SOCK_REPLY_END_REGEXP)
def isBirdSockTableStart(line):
if(bird_sock_header_regexp.match(line)):
return True
else:
return False
def getBirdSockCode(line):
m = bird_sock_header_regexp.match(line)
if(m):
return int(m.group(1))
else:
None
def getBirdSockData(line):
m = bird_sock_header_regexp.match(line)
if(m):
return m.group(2)
else:
None
def isBirdSockHeader(line):
if(isBirdSockTableStart(line) and getBirdSockCode(line) == 2002):
return True
else:
return False
def isBirdSockReplyEnd(line):
m = bird_sock_reply_end_regexp.match(line)
if(m):
if(int(m.group(1)) == 0):
return True
return False
def isBirdSockAsyncReply(line):
if(line[0] == '+'):
return True
else:
return False
def isBirdSockReplyCont(line):
if(line[0] == ' '):
return True
else:
return False
def normalizeBirdSockLine(line):
ulgmodel.debug("normalizeBirdSockLine: "+line)
if(isBirdSockAsyncReply(line)):
return ''
if(isBirdSockHeader(line)):
return getBirdSockData(line)
if(isBirdSockTableStart(line)):
return getBirdSockData(line)
if(isBirdSockReplyCont(line)):
return line[1:]
if(isBirdSockReplyEnd(line)):
return None
raise Exception("Can not normalize line: "+line)
class BirdRouterLocal(ulgmodel.LocalRouter): class BirdRouterLocal(ulgmodel.LocalRouter):
DefaultCommands = [ulgmodel.TextCommand('show protocols %s', [ulgmodel.TextParameter('.*')])] DefaultCommands = [ulgmodel.TextCommand('show protocols %s', [ulgmodel.TextParameter('.*')])]
...@@ -40,24 +163,45 @@ class BirdRouterLocal(ulgmodel.LocalRouter): ...@@ -40,24 +163,45 @@ class BirdRouterLocal(ulgmodel.LocalRouter):
self.setName('localhost') self.setName('localhost')
def runRawCommand(self,command): def runRawCommand(self,command):
# open socket to BIRD result=''
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(self.sock)
# cretate FD for the socket try:
sf=s.makefile() # open socket to BIRD
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.settimeout(defaults.default_bird_sock_timeout)
s.connect(self.sock)
# send the command string # cretate FD for the socket
s.send(command) sf=s.makefile()
# wait for initial header
l = sf.readline()
# send the command string
sf.write(command+"\n")
sf.flush()
# read and capture lines until the output delimiter string is hit
while(True):
l = sf.readline()
# process line according to rules take out from the C code
ulgmodel.debug("Raw received line: " + l)
nl = normalizeBirdSockLine(l)
if(nl == None):
# End of reply (0000 code)
ulgmodel.debug("End of reply.")
break
else:
ulgmodel.debug("Normalized line: " + nl)
result=result+nl+'\n'
# close the socket and return captured result
s.close()
except socket.timeout as e:
# catch only timeout exception, while letting other exceptions pass
result = STRING_SOCKET_TIMEOUT
# read and capture lines until the output delimiter string is hit
result=''
for l in sf:
if(re.compile('^0000').match(l)):
result=result+"BREAK\n"
break
result=result+l
# close the socket and return captured result
s.close()
return result return result
...@@ -302,6 +302,8 @@ class Router(object): ...@@ -302,6 +302,8 @@ class Router(object):
log("Bad params encountered in command "+str(command.getName())+" : "+str(parameters)) log("Bad params encountered in command "+str(command.getName())+" : "+str(parameters))
return self.returnError(defaults.STRING_BAD_PARAMS) return self.returnError(defaults.STRING_BAD_PARAMS)
debug("Going to run command "+c+" on router "+self.getName())
r = '' r = ''
if(defaults.debug): if(defaults.debug):
r = "<h3>DEBUG</h3><pre>Router.runCommand():\ncommand_name="+command.getName()+'\n' r = "<h3>DEBUG</h3><pre>Router.runCommand():\ncommand_name="+command.getName()+'\n'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment