Commit cd3bdb55 authored by Martín Ferrari's avatar Martín Ferrari

protocol.py: improve debugging, attribute naming. Fix shutdown() issues.

t/test_interfaces: use import_if api(), add some more tests.
parent a69a8cbf
# vim:ts=4:sw=4:et:ai:sts=4
import os, re, socket, subprocess, sys
import copy, os, re, socket, subprocess, sys
# helpers
def _any_to_bool(any):
......@@ -114,6 +114,9 @@ class interface(object):
return self.__class__(self.index, name, up, mtu, lladdr, broadcast,
multicast, arp)
def copy(self):
return copy.copy(self)
class bridge(interface):
changeable_attributes = interface.changeable_attributes + ["stp",
"forward_delay", "hello_time", "ageing_time", "max_age"]
......
......@@ -67,13 +67,13 @@ class Server(object):
"""Class that implements the communication protocol and dispatches calls to
the required functions. Also works as the main loop for the slave
process."""
def __init__(self, rfd, wfd, debug = False):
def __init__(self, rfd, wfd, debug = 0):
# Dictionary of valid commands
self.commands = _proto_commands
self._commands = _proto_commands
# Flag to stop the server
self.closed = False
self._closed = False
# Print debug info
self.debug = debug
self._debug = debug
# Set to keep track of started processes
self._children = set()
# Buffer and flag for PROC mode
......@@ -93,22 +93,22 @@ class Server(object):
for i in range(len(clean) - 1):
s = str(code) + "-" + clean[i] + "\n"
self._wfd.write(s)
if self.debug: # pragma: no cover
if self._debug > 1: # pragma: no cover
sys.stderr.write("<ans> %s" % s)
s = str(code) + " " + clean[-1] + "\n"
self._wfd.write(s)
if self.debug: # pragma: no cover
sys.stderr.write("<ans> %s" % s)
if self._debug > 1: # pragma: no cover
sys.stderr.write("<S> %s" % s)
return
def readline(self):
"Read a line from the socket and detect connection break-up."
line = self._rfd.readline()
if not line:
self.closed = True
self._closed = True
return None
if self.debug: # pragma: no cover
if self._debug > 1: # pragma: no cover
sys.stderr.write("<C> %s" % line)
return line.rstrip()
......@@ -121,13 +121,13 @@ class Server(object):
return None
args = line.split()
cmd1 = args[0].upper()
if cmd1 not in self.commands:
if cmd1 not in self._commands:
self.reply(500, "Unknown command %s." % cmd1)
return None
del args[0]
cmd2 = None
subcommands = self.commands[cmd1]
subcommands = self._commands[cmd1]
if subcommands.keys() != [ None ]:
if len(args) < 1:
......@@ -185,7 +185,7 @@ class Server(object):
j += 1
func = getattr(self, funcname)
if self.debug: # pragma: no cover
if self._debug > 2: # pragma: no cover
sys.stderr.write("<cmd> %s, args: %s\n" % (cmdname, args))
return (func, cmdname, args)
......@@ -193,7 +193,7 @@ class Server(object):
"""Main loop; reads commands until the server is shut down or the
connection is terminated."""
self.reply(220, "Hello.");
while not self.closed:
while not self._closed:
cmd = self.readcmd()
if cmd == None:
continue
......@@ -215,8 +215,8 @@ class Server(object):
def do_HELP(self, cmdname):
reply = ["Available commands:"]
for c in sorted(self.commands):
for sc in sorted(self.commands[c]):
for c in sorted(self._commands):
for sc in sorted(self._commands[c]):
if sc:
reply.append("%s %s" % (c, sc))
else:
......@@ -225,11 +225,11 @@ class Server(object):
def do_QUIT(self, cmdname):
self.reply(221, "Sayounara.");
self.closed = True
self._closed = True
def do_PROC_CRTE(self, cmdname, executable, *argv):
self._proc = { 'executable': executable, 'argv': argv }
self.commands = _proc_commands
self._commands = _proc_commands
self.reply(200, "Entering PROC mode.")
def do_PROC_USER(self, cmdname, user):
......@@ -276,7 +276,7 @@ class Server(object):
params = self._proc
params['close_fds'] = True # forced
self._proc = None
self.commands = _proto_commands
self._commands = _proto_commands
try:
chld = netns.subprocess_.spawn(**params)
......@@ -291,7 +291,7 @@ class Server(object):
def do_PROC_ABRT(self, cmdname):
self._proc = None
self.commands = _proto_commands
self._commands = _proto_commands
self.reply(200, "Aborted.")
def do_PROC_POLL(self, cmdname, pid):
......@@ -398,19 +398,29 @@ class Server(object):
class Client(object):
"""Client-side implementation of the communication protocol. Acts as a RPC
service."""
def __init__(self, rfd, wfd, debug = False):
def __init__(self, rfd, wfd, debug = 0):
self._debug = debug
self._rfd = _get_file(rfd, "r")
self._wfd = _get_file(wfd, "w")
# Wait for slave to send banner
self._read_and_check_reply()
def __del__(self):
if self._debug:
sys.stderr.write("*** Client(%d) __del__\n" % id(self))
self.shutdown()
def _send_cmd(self, *args):
if not self._wfd:
raise RuntimeError("Client already shut down.")
s = " ".join(map(str, args)) + "\n"
self._wfd.write(s)
def _read_reply(self):
"""Reads a (possibly multi-line) response from the server. Returns a
tuple containing (code, text)"""
if not self._rfd:
raise RuntimeError("Client already shut down.")
text = []
while True:
line = self._rfd.readline().rstrip()
......@@ -440,8 +450,17 @@ class Client(object):
def shutdown(self):
"Tell the client to quit."
if not self._wfd:
return
if self._debug:
sys.stderr.write("*** Client(%d) shutdown\n" % id(self))
self._send_cmd("QUIT")
self._read_and_check_reply()
self._rfd.close()
self._rfd = None
self._wfd.close()
self._wfd = None
def _send_fd(self, name, fd):
"Pass a file descriptor"
......
......@@ -125,41 +125,33 @@ class TestWithDummy(unittest.TestCase):
"Test trigger a kernel bug on 2.6.34")
def test_interface_migration(self):
node = netns.Node()
dummyname = "dummy%d" % os.getpid()
self.dummyname = "dummy%d" % os.getpid()
self.assertEquals(
os.system("ip link add name %s type dummy" % dummyname), 0)
os.system("ip link add name %s type dummy" % self.dummyname), 0)
devs = get_devs()
self.assertTrue(dummyname in devs)
dummyidx = devs[dummyname]['idx']
self.assertTrue(self.dummyname in devs)
dummyidx = devs[self.dummyname]['idx']
self.cleanup += [(dummyidx, None)]
# Move manually
netns.iproute.change_netns(dummyidx, node.pid)
self.cleanup.remove((dummyidx, None))
self.cleanup += [(dummyidx, node)]
if0 = node.import_if(self.dummyname)
self.assertTrue(self.dummyname not in get_devs())
node_devs = dict([(i.index, i) for i in node.get_interfaces()])
self.assertTrue(devs[dummyname]['idx'] in node_devs)
self.assertTrue(dummyidx in node_devs)
if0 = node_devs[devs[dummyname]['idx']]
if0.lladdr = '42:71:e0:90:ca:43'
if0.mtu = 1400
devs = get_devs_netns(node)
self.assertTrue(if0.name in devs)
self.assertEquals(devs[if0.name]['lladdr'], if0.lladdr)
self.assertEquals(devs[if0.name]['mtu'], if0.mtu)
self.assertEquals(devs[if0.name]['lladdr'], '42:71:e0:90:ca:43')
self.assertEquals(devs[if0.name]['mtu'], 1400)
node.destroy()
self.assertTrue(self.dummyname in get_devs())
def tearDown(self):
for (i, n) in self.cleanup:
if n:
j = [j for j in n.get_interfaces() if j.index == i][0]
n.del_if(j)
n._slave.change_netns(i, os.getpid())
iface = netns.iproute.get_if(i)
# oops here
os.system("ip link del %s" % iface.name)
# oops here
os.system("ip link del %s" % self.dummyname)
# FIXME: Links
......
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