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