Commit 9e163978 authored by Martín Ferrari's avatar Martín Ferrari

Add logging in different places

parent c59cd9d1
...@@ -56,8 +56,7 @@ except: ...@@ -56,8 +56,7 @@ except:
"continue.") "continue.")
def execute(cmd): def execute(cmd):
# FIXME: create a global debug variable debug("execute(%s)" % cmd)
#print "[pid %d]" % os.getpid(), " ".join(cmd)
null = open("/dev/null", "r+") null = open("/dev/null", "r+")
p = subprocess.Popen(cmd, stdout = null, stderr = subprocess.PIPE) p = subprocess.Popen(cmd, stdout = null, stderr = subprocess.PIPE)
out, err = p.communicate() out, err = p.communicate()
...@@ -65,6 +64,7 @@ def execute(cmd): ...@@ -65,6 +64,7 @@ def execute(cmd):
raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err)) raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err))
def backticks(cmd): def backticks(cmd):
debug("backticks(%s)" % cmd)
p = subprocess.Popen(cmd, stdout = subprocess.PIPE, p = subprocess.Popen(cmd, stdout = subprocess.PIPE,
stderr = subprocess.PIPE) stderr = subprocess.PIPE)
out, err = p.communicate() out, err = p.communicate()
...@@ -132,3 +132,15 @@ def info(message): ...@@ -132,3 +132,15 @@ def info(message):
logger(LOG_INFO, message) logger(LOG_INFO, message)
def debug(message): def debug(message):
logger(LOG_DEBUG, message) logger(LOG_DEBUG, message)
# Used to print extra info in nested exceptions
def _custom_hook(t, v, tb): # pragma: no cover
if hasattr(v, "child_traceback"):
sys.stderr.write("Nested exception, original traceback " +
"(most recent call last):\n")
sys.stderr.write(v.child_traceback + ("-" * 70) + "\n")
sys.__excepthook__(t, v, tb)
# XXX: somebody kill me, I deserve it :)
sys.excepthook = _custom_hook
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import os, weakref import os, weakref
import netns.iproute import netns.iproute
from netns.environ import *
__all__ = ['NodeInterface', 'P2PInterface', 'ImportedInterface', __all__ = ['NodeInterface', 'P2PInterface', 'ImportedInterface',
'ImportedNodeInterface', 'Switch'] 'ImportedNodeInterface', 'Switch']
...@@ -24,8 +25,11 @@ class Interface(object): ...@@ -24,8 +25,11 @@ class Interface(object):
def __init__(self, index): def __init__(self, index):
self._idx = index self._idx = index
debug("%s(0x%x).__init__(), index = %d" % (self.__class__.__name__,
id(self), index))
def __del__(self): def __del__(self):
debug("%s(0x%x).__del__()" % (self.__class__.__name__, id(self)))
self.destroy() self.destroy()
def destroy(self): def destroy(self):
...@@ -135,10 +139,12 @@ class NodeInterface(NSInterface): ...@@ -135,10 +139,12 @@ class NodeInterface(NSInterface):
return self._control return self._control
def destroy(self): def destroy(self):
if self._slave: if not self._slave:
if self.index in self._slave.get_if_data(): return
self._slave.del_if(self.index) debug("NodeInterface(0x%x).destroy()" % id(self))
self._slave = None if self.index in self._slave.get_if_data():
self._slave.del_if(self.index)
self._slave = None
class P2PInterface(NSInterface): class P2PInterface(NSInterface):
"""Class to create and handle point-to-point interfaces between name """Class to create and handle point-to-point interfaces between name
...@@ -174,10 +180,12 @@ class P2PInterface(NSInterface): ...@@ -174,10 +180,12 @@ class P2PInterface(NSInterface):
raise RuntimeError(P2PInterface.__init__.__doc__) raise RuntimeError(P2PInterface.__init__.__doc__)
def destroy(self): def destroy(self):
if self._slave: if not self._slave:
if self.index in self._slave.get_if_data(): return
self._slave.del_if(self.index) debug("P2PInterface(0x%x).destroy()" % id(self))
self._slave = None if self.index in self._slave.get_if_data():
self._slave.del_if(self.index)
self._slave = None
class ImportedNodeInterface(NSInterface): class ImportedNodeInterface(NSInterface):
"""Class to handle already existing interfaces inside a name space: """Class to handle already existing interfaces inside a name space:
...@@ -206,6 +214,7 @@ class ImportedNodeInterface(NSInterface): ...@@ -206,6 +214,7 @@ class ImportedNodeInterface(NSInterface):
def destroy(self): # override: restore as much as possible def destroy(self): # override: restore as much as possible
if not self._slave: if not self._slave:
return return
debug("ImportedNodeInterface(0x%x).destroy()" % id(self))
if self.index in self._slave.get_if_data(): if self.index in self._slave.get_if_data():
if self._migrate: if self._migrate:
self._slave.change_netns(self.index, os.getpid()) self._slave.change_netns(self.index, os.getpid())
...@@ -235,11 +244,13 @@ class TapNodeInterface(NSInterface): ...@@ -235,11 +244,13 @@ class TapNodeInterface(NSInterface):
return self._fd return self._fd
def destroy(self): def destroy(self):
if self._fd: if not self._fd:
try: return
os.close(self._fd) debug("TapNodeInterface(0x%x).destroy()" % id(self))
except: try:
pass os.close(self._fd)
except:
pass
class ExternalInterface(Interface): class ExternalInterface(Interface):
"""Add user-facing methods for interfaces that run in the main """Add user-facing methods for interfaces that run in the main
...@@ -317,6 +328,7 @@ class ImportedInterface(ExternalInterface): ...@@ -317,6 +328,7 @@ class ImportedInterface(ExternalInterface):
# FIXME: register somewhere for destruction! # FIXME: register somewhere for destruction!
def destroy(self): # override: restore as much as possible def destroy(self): # override: restore as much as possible
if self._original_state: if self._original_state:
debug("ImportedInterface(0x%x).destroy()" % id(self))
netns.iproute.set_if(self._original_state) netns.iproute.set_if(self._original_state)
self._original_state = None self._original_state = None
...@@ -368,6 +380,7 @@ class Switch(ExternalInterface): ...@@ -368,6 +380,7 @@ class Switch(ExternalInterface):
def destroy(self): def destroy(self):
if not self.index: if not self.index:
return return
debug("Switch(0x%x).destroy()" % id(self))
self.up = False self.up = False
for p in self._ports.values(): for p in self._ports.values():
try: try:
......
...@@ -15,13 +15,12 @@ class Node(object): ...@@ -15,13 +15,12 @@ class Node(object):
s = sorted(Node._nodes.items(), key = lambda x: x[0]) s = sorted(Node._nodes.items(), key = lambda x: x[0])
return [x[1] for x in s] return [x[1] for x in s]
def __init__(self, debug = 0, nonetns = False): def __init__(self, nonetns = False):
"""Create a new node in the emulation. Implemented as a separate """Create a new node in the emulation. Implemented as a separate
process in a new network name space. Requires root privileges to run. process in a new network name space. Requires root privileges to run.
If keepns is true, the network name space is not created and can be If keepns is true, the network name space is not created and can be
run as a normal user, for testing. If debug is true, details of the run as a normal user, for testing."""
communication protocol are printed on stderr."""
# Initialize attributes, in case something fails during __init__ # Initialize attributes, in case something fails during __init__
self._pid = self._slave = None self._pid = self._slave = None
...@@ -29,10 +28,10 @@ class Node(object): ...@@ -29,10 +28,10 @@ class Node(object):
self._interfaces = weakref.WeakValueDictionary() self._interfaces = weakref.WeakValueDictionary()
self._auto_interfaces = [] # just to keep them alive! self._auto_interfaces = [] # just to keep them alive!
fd, pid = _start_child(debug, nonetns) fd, pid = _start_child(nonetns)
self._pid = pid self._pid = pid
self._debug = debug debug("Node(0x%x).__init__(), pid = %s" % (id(self), pid))
self._slave = netns.protocol.Client(fd, fd, debug) self._slave = netns.protocol.Client(fd, fd)
Node._nodes[Node._nextnode] = self Node._nodes[Node._nextnode] = self
Node._nextnode += 1 Node._nextnode += 1
...@@ -42,14 +41,11 @@ class Node(object): ...@@ -42,14 +41,11 @@ class Node(object):
self.get_interface("lo").up = True self.get_interface("lo").up = True
def __del__(self): def __del__(self):
if self._debug: # pragma: no cover debug("Node(0x%x).__del__()" % id(self))
sys.stderr.write("*** Node(%s) __del__\n" % self.pid)
self.destroy() self.destroy()
def destroy(self): def destroy(self):
if self._debug: # pragma: no cover debug("Node(0x%x).destroy()" % id(self))
sys.stderr.write("*** Node(%s) destroy\n" % self.pid)
for p in self._processes.values(): for p in self._processes.values():
p.destroy() p.destroy()
self._processes.clear() self._processes.clear()
...@@ -126,8 +122,7 @@ class Node(object): ...@@ -126,8 +122,7 @@ class Node(object):
# by the way, clean up _interfaces # by the way, clean up _interfaces
for i in list(self._interfaces): # copy before deleting! for i in list(self._interfaces): # copy before deleting!
if i not in ifaces: if i not in ifaces:
if self._debug: notice("Node(0x%x): interface #%d went away." % (id(self), i))
sys.stderr.write("WARNING: interface #%d went away.\n" % i)
self._interfaces[i].destroy() self._interfaces[i].destroy()
del self._interfaces[i] del self._interfaces[i]
...@@ -159,7 +154,7 @@ class Node(object): ...@@ -159,7 +154,7 @@ class Node(object):
# Handle the creation of the child; parent gets (fd, pid), child creates and # Handle the creation of the child; parent gets (fd, pid), child creates and
# runs a Server(); never returns. # runs a Server(); never returns.
# Requires CAP_SYS_ADMIN privileges to run. # Requires CAP_SYS_ADMIN privileges to run.
def _start_child(debug, nonetns): def _start_child(nonetns):
# Create socket pair to communicate # Create socket pair to communicate
(s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) (s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
# Spawn a child that will run in a loop # Spawn a child that will run in a loop
...@@ -171,7 +166,7 @@ def _start_child(debug, nonetns): ...@@ -171,7 +166,7 @@ def _start_child(debug, nonetns):
# FIXME: clean up signal handers, atexit functions, etc. # FIXME: clean up signal handers, atexit functions, etc.
try: try:
s0.close() s0.close()
srv = netns.protocol.Server(s1, s1, debug) srv = netns.protocol.Server(s1, s1)
if not nonetns: if not nonetns:
# create new name space # create new name space
unshare.unshare(unshare.CLONE_NEWNET) unshare.unshare(unshare.CLONE_NEWNET)
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import base64, os, passfd, re, signal, sys, traceback, unshare import base64, os, passfd, re, signal, sys, traceback, unshare
import netns.subprocess_, netns.iproute import netns.subprocess_, netns.iproute
from netns.environ import *
try: try:
from cPickle import loads, dumps from cPickle import loads, dumps
...@@ -66,13 +67,12 @@ class Server(object): ...@@ -66,13 +67,12 @@ class Server(object):
"""Class that implements the communication protocol and dispatches calls """Class that implements the communication protocol and dispatches calls
to the required functions. Also works as the main loop for the slave to the required functions. Also works as the main loop for the slave
process.""" process."""
def __init__(self, rfd, wfd, debug = 0): def __init__(self, rfd, wfd):
debug("Server(0x%x).__init__()" % id(self))
# 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
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
...@@ -92,13 +92,11 @@ class Server(object): ...@@ -92,13 +92,11 @@ 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 > 1: # pragma: no cover debug("<Reply> %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 > 1: # pragma: no cover debug("<Reply> %s" % s)
sys.stderr.write("<S> %s" % s)
return return
def readline(self): def readline(self):
...@@ -107,8 +105,7 @@ class Server(object): ...@@ -107,8 +105,7 @@ class Server(object):
if not line: if not line:
self._closed = True self._closed = True
return None return None
if self._debug > 1: # pragma: no cover debug("<Query> %s" % line)
sys.stderr.write("<C> %s" % line)
return line.rstrip() return line.rstrip()
def readcmd(self): def readcmd(self):
...@@ -183,8 +180,7 @@ class Server(object): ...@@ -183,8 +180,7 @@ class Server(object):
j += 1 j += 1
func = getattr(self, funcname) func = getattr(self, funcname)
if self._debug > 2: # pragma: no cover debug("Command: %s, args: %s" % (cmdname, args))
sys.stderr.write("<cmd> %s, args: %s\n" % (cmdname, args))
return (func, cmdname, args) return (func, cmdname, args)
def run(self): def run(self):
...@@ -208,6 +204,7 @@ class Server(object): ...@@ -208,6 +204,7 @@ class Server(object):
self._wfd.close() self._wfd.close()
except: except:
pass pass
debug("Server(0x%x) exiting" % id(self))
# FIXME: cleanup # FIXME: cleanup
# Commands implementation # Commands implementation
...@@ -397,16 +394,15 @@ class Server(object): ...@@ -397,16 +394,15 @@ 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 = 0): def __init__(self, rfd, wfd):
self._debug = debug debug("Client(0x%x).__init__()" % id(self))
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): def __del__(self):
if self._debug: debug("Client(0x%x).__del__()" % id(self))
sys.stderr.write("*** Client(%d) __del__\n" % id(self))
self.shutdown() self.shutdown()
def _send_cmd(self, *args): def _send_cmd(self, *args):
...@@ -451,8 +447,7 @@ class Client(object): ...@@ -451,8 +447,7 @@ class Client(object):
"Tell the client to quit." "Tell the client to quit."
if not self._wfd: if not self._wfd:
return return
if self._debug: debug("Client(0x%x).shutdown()" % id(self))
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()
......
...@@ -409,14 +409,4 @@ try: ...@@ -409,14 +409,4 @@ try:
except: # pragma: no cover except: # pragma: no cover
MAXFD = 256 MAXFD = 256
# Used to print extra info in nested exceptions
def _custom_hook(t, v, tb): # pragma: no cover
if hasattr(v, "child_traceback"):
sys.stderr.write("Nested exception, original traceback " +
"(most recent call last):\n")
sys.stderr.write(v.child_traceback + ("-" * 70) + "\n")
sys.__excepthook__(t, v, tb)
# XXX: somebody kill me, I deserve it :)
sys.excepthook = _custom_hook
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import grp, os, pwd, select, time, unittest import grp, os, pwd, select, time, unittest
import netns, test_util import netns, test_util
netns.environ.set_log_level(netns.environ.LOG_DEBUG)
class TestConfigure(unittest.TestCase): class TestConfigure(unittest.TestCase):
def test_config_run_as_static(self): def test_config_run_as_static(self):
# Don't allow root as default user # Don't allow root as default user
......
...@@ -35,7 +35,7 @@ class TestServer(unittest.TestCase): ...@@ -35,7 +35,7 @@ class TestServer(unittest.TestCase):
(s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) (s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
def run_server(): def run_server():
netns.protocol.Server(s0, s0, debug = 0).run() netns.protocol.Server(s0, s0).run()
t = threading.Thread(target = run_server) t = threading.Thread(target = run_server)
t.start() t.start()
...@@ -57,7 +57,7 @@ class TestServer(unittest.TestCase): ...@@ -57,7 +57,7 @@ class TestServer(unittest.TestCase):
def test_basic_stuff(self): def test_basic_stuff(self):
(s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) (s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
srv = netns.protocol.Server(s0, s0, debug = 0) srv = netns.protocol.Server(s0, s0)
s1 = s1.makefile("r+", 1) s1 = s1.makefile("r+", 1)
def check_error(self, cmd, code = 500): def check_error(self, cmd, code = 500):
......
...@@ -123,7 +123,7 @@ class TestSubprocess(unittest.TestCase): ...@@ -123,7 +123,7 @@ class TestSubprocess(unittest.TestCase):
self.assertEquals(wait(p), 0) self.assertEquals(wait(p), 0)
def test_Subprocess_basic(self): def test_Subprocess_basic(self):
node = netns.Node(nonetns = True, debug = 0) node = netns.Node(nonetns = True)
# User does not exist # User does not exist
self.assertRaises(ValueError, Subprocess, node, self.assertRaises(ValueError, Subprocess, node,
['/bin/sleep', '1000'], user = self.nouser) ['/bin/sleep', '1000'], user = self.nouser)
...@@ -179,7 +179,7 @@ class TestSubprocess(unittest.TestCase): ...@@ -179,7 +179,7 @@ class TestSubprocess(unittest.TestCase):
self.assertEquals(p.wait(), -signal.SIGTERM) self.assertEquals(p.wait(), -signal.SIGTERM)
def test_Popen(self): def test_Popen(self):
node = netns.Node(nonetns = True, debug = 0) node = netns.Node(nonetns = True)
# repeat test with Popen interface # repeat test with Popen interface
r0, w0 = os.pipe() r0, w0 = os.pipe()
...@@ -269,7 +269,7 @@ class TestSubprocess(unittest.TestCase): ...@@ -269,7 +269,7 @@ class TestSubprocess(unittest.TestCase):
self.assertEquals(p.communicate(_longstring), (_longstring, ) * 2) self.assertEquals(p.communicate(_longstring), (_longstring, ) * 2)
def test_backticks(self): def test_backticks(self):
node = netns.Node(nonetns = True, debug = 0) node = netns.Node(nonetns = True)
self.assertEquals(backticks(node, "echo hello world"), "hello world\n") self.assertEquals(backticks(node, "echo hello world"), "hello world\n")
self.assertEquals(backticks(node, r"echo hello\ \ world"), self.assertEquals(backticks(node, r"echo hello\ \ world"),
"hello world\n") "hello world\n")
...@@ -281,7 +281,7 @@ class TestSubprocess(unittest.TestCase): ...@@ -281,7 +281,7 @@ class TestSubprocess(unittest.TestCase):
self.assertRaises(RuntimeError, backticks_raise, node, "kill $$") self.assertRaises(RuntimeError, backticks_raise, node, "kill $$")
def test_system(self): def test_system(self):
node = netns.Node(nonetns = True, debug = 0) node = netns.Node(nonetns = True)
self.assertEquals(system(node, "true"), 0) self.assertEquals(system(node, "true"), 0)
self.assertEquals(system(node, "false"), 1) self.assertEquals(system(node, "false"), 1)
......
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