[PATCH 1/7] logs: add netns information to logs
by Ondrej Lichtner
From: Ondrej Lichtner <olichtne(a)redhat.com>
All log messages now contain information about what network namespace
they've originated in. Since xml result files are generated
automatically, the information about the network namespace is already
present in them.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
lnst/Common/LoggingHandler.py | 6 ++++++
lnst/Common/Logs.py | 28 ++++++++++++++++++++++------
lnst/Common/NetTestCommand.py | 22 +++++++++++++++++++---
lnst/Slave/NetTestSlave.py | 1 +
4 files changed, 48 insertions(+), 9 deletions(-)
diff --git a/lnst/Common/LoggingHandler.py b/lnst/Common/LoggingHandler.py
index 3fd8919..22d58f5 100644
--- a/lnst/Common/LoggingHandler.py
+++ b/lnst/Common/LoggingHandler.py
@@ -66,12 +66,18 @@ class TransmitHandler(logging.Handler):
def __init__(self, target):
logging.Handler.__init__(self)
self.target = target
+ self._origin_name = None
+
+ def set_origin_name(self, name):
+ self._origin_name = name
def emit(self, record):
r = dict(record.__dict__)
r['msg'] = record.getMessage()
r['args'] = None
r['exc_info'] = None
+ if self._origin_name != None:
+ r['origin_name'] = self._origin_name
data = {"type": "log", "record": r}
diff --git a/lnst/Common/Logs.py b/lnst/Common/Logs.py
index b891439..89118c1 100644
--- a/lnst/Common/Logs.py
+++ b/lnst/Common/Logs.py
@@ -24,11 +24,12 @@ def log_exc_traceback():
class MultilineFormatter(Formatter): # addr:17 level:7
_ADDR_WIDTH = 17
+ _NETNS_WIDTH = 8
_LEVEL_WIDTH = 7
_coloured = False
def __init__(self, coloured=False):
- fmt = "%(asctime)s %(address)s %(levelname)s: %(message)s"
+ fmt = "%(asctime)s %(address)s %(netns)s %(levelname)s: %(message)s"
datefmt = "%Y-%m-%d %H:%M:%S"
self.linefmt = " "
self._coloured = coloured
@@ -44,12 +45,12 @@ class MultilineFormatter(Formatter): # addr:17 level:7
def _format_addr(self, record):
if not "address" in record.__dict__:
- addr = "(localhost)".rjust(17)
+ addr = "(localhost)"
else:
- addr = record.address.rjust(17)
+ addr = "(" + record.address + ")"
- just = " " * (self._ADDR_WIDTH - len(addr))
- return just + self._decorate_value(addr, "log_header")
+ addr = addr.rjust(self._ADDR_WIDTH)
+ return self._decorate_value(addr, "log_header")
def _format_level(self, record):
level = record.levelname
@@ -66,6 +67,12 @@ class MultilineFormatter(Formatter): # addr:17 level:7
values["address"] = self._format_addr(record)
values["levelname"] = self._format_level(record)
+ try:
+ values["netns"] = record.__dict__["origin_name"]
+ except:
+ values["netns"] = "-"
+ values["netns"] = values["netns"].rjust(self._NETNS_WIDTH)
+
msg = ""
level = record.levelname
lines = record.getMessage().split("\n")
@@ -95,6 +102,8 @@ class LoggingCtl:
transmit_handler = None
def __init__(self, debug=False, log_dir=None, log_subdir="", colours=True):
+ self._origin_name = None
+
if log_dir != None:
self.log_folder = os.path.abspath(os.path.join(log_dir, log_subdir))
else:
@@ -171,7 +180,7 @@ class LoggingCtl:
def add_client_log(self, slave_id, log_record):
logger = logging.getLogger(slave_id)
- log_record['address'] = '(' + slave_id + ')'
+ log_record['address'] = slave_id
record = logging.makeLogRecord(log_record)
logger.handle(record)
@@ -180,6 +189,8 @@ class LoggingCtl:
self.cancel_connection()
self.transmit_handler = TransmitHandler(target)
+ self.transmit_handler.set_origin_name(self._origin_name)
+
logger = logging.getLogger()
logger.addHandler(self.transmit_handler)
@@ -224,3 +235,8 @@ class LoggingCtl:
def get_recipe_log_path(self):
return self.recipe_log_path
+
+ def set_origin_name(self, name):
+ self._origin_name = name
+ if self.transmit_handler != None:
+ self.transmit_handler.set_origin_name(name)
diff --git a/lnst/Common/NetTestCommand.py b/lnst/Common/NetTestCommand.py
index 6b6db0b..c1b39d9 100644
--- a/lnst/Common/NetTestCommand.py
+++ b/lnst/Common/NetTestCommand.py
@@ -349,7 +349,12 @@ class NetTestCommandGeneric:
raise CommandException(msg)
def _format_cmd_res_header(self):
- return "%-9s" % self._command["type"]
+ if "netns" in self._command and self._command["netns"] != None:
+ netns = "(%s) " % self._command["netns"]
+ else:
+ netns = ""
+
+ return "%-9s" % (self._command["type"] + netns)
def set_handle_intr(self):
pass
@@ -392,7 +397,12 @@ class NetTestCommandExec(NetTestCommandGeneric):
else:
bg_id = ""
- cmd = "%-9s%scmd: \"%s\"" %(cmd_type, bg_id, cmd_val)
+ if "netns" in self._command and self._command["netns"] != None:
+ netns = "(%s) " % self._command["netns"]
+ else:
+ netns = ""
+
+ cmd = "%-9s%scmd: \"%s\"" %(cmd_type + netns, bg_id, cmd_val)
return cmd
class NetTestCommandConfig(NetTestCommandGeneric):
@@ -459,7 +469,13 @@ class NetTestCommandControl(NetTestCommandGeneric):
def _format_cmd_res_header(self):
cmd_type = self._command["type"]
cmd_val = self._command["proc_id"]
- cmd = "%-9sid: %s" % (cmd_type, cmd_val)
+
+ if "netns" in self._command and self._command["netns"] != None:
+ netns = "(%s) " % self._command["netns"]
+ else:
+ netns = ""
+
+ cmd = "%-9s id: %s" % (cmd_type + netns, cmd_val)
return cmd
class NetTestCommandWait(NetTestCommandControl):
diff --git a/lnst/Slave/NetTestSlave.py b/lnst/Slave/NetTestSlave.py
index 0fbbcff..74ffba0 100644
--- a/lnst/Slave/NetTestSlave.py
+++ b/lnst/Slave/NetTestSlave.py
@@ -542,6 +542,7 @@ class SlaveMethods:
self._server_handler.set_ctl_sock((write_pipe, "root_netns"))
self._log_ctl.disable_logging()
+ self._log_ctl.set_origin_name(netns)
self._log_ctl.set_connection(write_pipe)
self._if_manager.rescan_devices()
--
1.9.3
9 years, 7 months
[lnst] RecipeParser: fix tag reference in a vlan exception
by Jiří Pírko
commit 05c4aa67645270cf106aec7b9c4c71243ec94340
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Tue Sep 9 15:59:28 2014 +0200
RecipeParser: fix tag reference in a vlan exception
The vlan variable is undefined, the iface_tag variable should be used
instead.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Controller/RecipeParser.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
---
diff --git a/lnst/Controller/RecipeParser.py b/lnst/Controller/RecipeParser.py
index c68fe54..3201719 100644
--- a/lnst/Controller/RecipeParser.py
+++ b/lnst/Controller/RecipeParser.py
@@ -163,7 +163,7 @@ class RecipeParser(XmlParser):
if slaves_tag is None or len(slaves_tag) != 1:
msg = "VLAN '%s' need exactly one slave definition."\
% iface["id"]
- raise RecipeError(msg, vlan)
+ raise RecipeError(msg, iface_tag)
iface["slaves"] = XmlCollection(slaves_tag)
9 years, 7 months
[lnst] Machine: fix use of get_remaining_time method call
by Jiří Pírko
commit e500bfc513b6024b81b4be1618153bcceb936258
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Tue Sep 9 15:59:27 2014 +0200
Machine: fix use of get_remaining_time method call
If the background command was running in a non-root network namespace,
the method call would fail. This commit fixes that problem.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Controller/Machine.py | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
---
diff --git a/lnst/Controller/Machine.py b/lnst/Controller/Machine.py
index 62a23e3..33d1795 100644
--- a/lnst/Controller/Machine.py
+++ b/lnst/Controller/Machine.py
@@ -258,7 +258,13 @@ class Machine(object):
if command["type"] == "wait":
logging.debug("Get remaining time of bg process with bg_id == %s"
% command["proc_id"])
- remaining_time = self._rpc_call("get_remaining_time", command["proc_id"])
+ if command["netns"] != None:
+ remaining_time = self._rpc_call_to_netns(command["netns"],
+ "get_remaining_time",
+ command["proc_id"])
+ else:
+ remaining_time = self._rpc_call("get_remaining_time",
+ command["proc_id"])
logging.debug("Setting timeout to %d", remaining_time)
if remaining_time > 0:
signal.alarm(remaining_time)
9 years, 7 months
[lnst] signal commands no longer use the netns attribute
by Jiří Pírko
commit e640b88ae10dfdbd85bd937bf42132f41d76fe11
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Tue Sep 9 15:59:26 2014 +0200
signal commands no longer use the netns attribute
This patch improves the usability of signal commands by storing
information about running background commands of the machine. The
controller can then use this information to send the signal command to
the correct network namespace without requiring this information from
the user. Because of this the 'netns' attribute (recipe) is no longer
accepted for signal commands.
RecipeParser also sets the 'netns' attribute of the internal command
structure to the default value 'None'.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Controller/Machine.py | 8 ++++++++
lnst/Controller/RecipeParser.py | 1 +
schema-recipe.rng | 4 ----
3 files changed, 9 insertions(+), 4 deletions(-)
---
diff --git a/lnst/Controller/Machine.py b/lnst/Controller/Machine.py
index 1fab2ac..62a23e3 100644
--- a/lnst/Controller/Machine.py
+++ b/lnst/Controller/Machine.py
@@ -71,6 +71,7 @@ class Machine(object):
self._interfaces = []
self._namespaces = []
+ self._bg_cmds = {}
def _add_interface(self, if_id, if_type, cls):
if if_id != None:
@@ -247,6 +248,13 @@ class Machine(object):
prev_handler = signal.signal(signal.SIGALRM, self._timeout_handler)
+ if 'bg_id' in command:
+ self._bg_cmds[command['bg_id']] = command
+ if command["type"] in ["wait", "intr", "kill"]:
+ bg_cmd = self._bg_cmds[command["proc_id"]]
+ if bg_cmd["netns"] != None:
+ command["netns"] = bg_cmd["netns"]
+
if command["type"] == "wait":
logging.debug("Get remaining time of bg process with bg_id == %s"
% command["proc_id"])
diff --git a/lnst/Controller/RecipeParser.py b/lnst/Controller/RecipeParser.py
index 159b1bc..c68fe54 100644
--- a/lnst/Controller/RecipeParser.py
+++ b/lnst/Controller/RecipeParser.py
@@ -396,4 +396,5 @@ class RecipeParser(XmlParser):
cmd["type"] = cmd_tag.tag
cmd["host"] = self._get_attribute(cmd_tag, "host")
cmd["bg_id"] = self._get_attribute(cmd_tag, "bg_id")
+ cmd["netns"] = None
return cmd
diff --git a/schema-recipe.rng b/schema-recipe.rng
index 490b86b..2391085 100644
--- a/schema-recipe.rng
+++ b/schema-recipe.rng
@@ -578,10 +578,6 @@
<define name="signal_command">
<attribute name="host"/>
<attribute name="bg_id"/>
-
- <optional>
- <attribute name="netns"/>
- </optional>
</define>
<define name="ctl_wait">
9 years, 7 months
[lnst] TaskAPI: add support for network namespaces
by Jiří Pírko
commit 349c333081d244d39849f96035fb0b38a4a74c0f
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Tue Sep 9 15:59:25 2014 +0200
TaskAPI: add support for network namespaces
Python tasks now support using network namespaces via the optional
'netns' argument of the 'run' and 'config' methods. If the command is
running in the background, running the wait/intr/kill methods of the
ProcessAPI object will automatically use the namespace of the associated
namespace.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Controller/Task.py | 21 +++++++++++++++------
1 files changed, 15 insertions(+), 6 deletions(-)
---
diff --git a/lnst/Controller/Task.py b/lnst/Controller/Task.py
index e97327d..9968e26 100644
--- a/lnst/Controller/Task.py
+++ b/lnst/Controller/Task.py
@@ -100,7 +100,7 @@ class HostAPI(object):
self._bg_id_seq = 0
- def config(self, option, value, persistent=False):
+ def config(self, option, value, persistent=False, netns=None):
"""
Configure an option in /sys or /proc on the host.
@@ -110,6 +110,8 @@ class HostAPI(object):
:type value: string
:param persistent: A flag.
:type persistent: bool
+ :param netns: LNST created namespace to configure.
+ :type netns: string
:return: Command result.
:rtype: dict
@@ -141,6 +143,7 @@ class HostAPI(object):
"""
cmd = {"host": str(self._id)}
bg_id = None
+ cmd["netns"] = None
for arg, argval in kwargs.iteritems():
if arg == "bg" and argval == True:
@@ -167,6 +170,8 @@ class HostAPI(object):
raise TaskError(msg)
elif arg == "desc":
cmd["desc"] = argval
+ elif arg == "netns":
+ cmd["netns"] = argval
else:
msg = "Argument '%s' not recognised by the run() method." % arg
raise TaskError(msg)
@@ -182,7 +187,7 @@ class HostAPI(object):
raise TaskError("Unable to run '%s'." % str(what))
cmd_res = self._ctl._run_command(cmd)
- return ProcessAPI(self._ctl, self._id, cmd_res, bg_id)
+ return ProcessAPI(self._ctl, self._id, cmd_res, bg_id, cmd["netns"])
def get_devname(self, interface_id):
"""
@@ -282,11 +287,12 @@ class ModuleAPI(object):
class ProcessAPI(object):
""" An API class representing either a running or finished process. """
- def __init__(self, ctl, h_id, cmd_res, bg_id):
+ def __init__(self, ctl, h_id, cmd_res, bg_id, netns):
self._ctl = ctl
self._host = h_id
self._cmd_res = cmd_res
self._bg_id = bg_id
+ self._netns = netns
def passed(self):
"""
@@ -311,7 +317,8 @@ class ProcessAPI(object):
if self._bg_id:
cmd = {"host": self._host,
"type": "wait",
- "proc_id": self._bg_id}
+ "proc_id": self._bg_id,
+ "netns": self._netns}
self._res = self._ctl._run_command(cmd)
def intr(self):
@@ -319,7 +326,8 @@ class ProcessAPI(object):
if self._bg_id:
cmd = {"host": self._host,
"type": "intr",
- "proc_id": self._bg_id}
+ "proc_id": self._bg_id,
+ "netns": self._netns}
self._res = self._ctl._run_command(cmd)
def kill(self):
@@ -333,7 +341,8 @@ class ProcessAPI(object):
if self._bg_id:
cmd = {"host": self._host,
"type": "kill",
- "proc_id": self._bg_id}
+ "proc_id": self._bg_id,
+ "netns": self._netns}
self._res = self._ctl._run_command(cmd)
class ValueAPI(object):
9 years, 7 months
[lnst] add loopback support
by Jiří Pírko
commit 8d0735e339cbe37c7f932b7738c47ff9ce22cbde
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Tue Sep 9 15:59:24 2014 +0200
add loopback support
This patch adds support for loopback devices. It doesn't do any loopback
configuration at the moment (except adding ip addresses), but it does
enable users to work with loopback devices in their recipes.
Important notes:
* Loopback devices are not part of the matching algorithm, it is assumed
that they already exist on every host.
* You can only define _ONE_ loopback device per host per network
namespace, LNST checks for this and will raise an exception if you
specify more.
recipe example:
<lo id="lo_secure" netns="secure">
<addresses>
<address>192.168.1.1/24</address>
</addresses>
</lo>
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Controller/Machine.py | 68 ++++++++++++++++++++++++++++++++++
lnst/Controller/NetTestController.py | 5 ++-
lnst/Controller/RecipeParser.py | 15 ++++++-
lnst/Slave/NetConfigDevice.py | 7 +++-
lnst/Slave/NmConfigDevice.py | 9 ++++-
schema-recipe.rng | 23 +++++++++++
6 files changed, 122 insertions(+), 5 deletions(-)
---
diff --git a/lnst/Controller/Machine.py b/lnst/Controller/Machine.py
index c070d26..1fab2ac 100644
--- a/lnst/Controller/Machine.py
+++ b/lnst/Controller/Machine.py
@@ -109,6 +109,9 @@ class Machine(object):
def new_soft_interface(self, if_id, if_type):
return self._add_interface(if_id, if_type, SoftInterface)
+ def new_loopback_interface(self, if_id):
+ return self._add_interface(if_id, 'lo', LoopbackInterface)
+
def get_interface(self, if_id):
for iface in self._interfaces:
if iface.get_id != None and if_id == iface.get_id():
@@ -657,6 +660,71 @@ class StaticInterface(Interface):
def __init__(self, machine, if_id, if_type):
super(StaticInterface, self).__init__(machine, if_id, if_type)
+class LoopbackInterface(Interface):
+ """ Static interface
+
+ This class represents interfaces that are present on the
+ machine. LNST will only use them for testing without performing
+ any special actions.
+
+ This type is suitable for physical interfaces.
+ """
+ def __init__(self, machine, if_id, if_type):
+ super(LoopbackInterface, self).__init__(machine, if_id, if_type)
+
+ def initialize(self):
+ pass
+
+ def configure(self):
+ self._hwaddr = '00:00:00:00:00:00'
+ if self._netns:
+ phys_devs = self._machine._rpc_call_to_netns(self._netns,
+ "map_if_by_hwaddr", self._id, self._hwaddr)
+ else:
+ phys_devs = self._machine._rpc_call("map_if_by_hwaddr",
+ self._id, self._hwaddr)
+
+ if len(phys_devs) == 1:
+ self.set_devname(phys_devs[0]["name"])
+ elif len(phys_devs) < 1:
+ msg = "Device %s not found on machine %s" \
+ % (self.get_id(), self._machine.get_id())
+ raise MachineError(msg)
+ elif len(phys_devs) > 1:
+ msg = "More than one device with hwaddr %s found on machine %s" \
+ % (self._hwaddr, self._machine.get_id())
+ raise MachineError(msg)
+
+ self.down()
+
+ if self._configured:
+ msg = "Unable to configure interface %s on machine %s. " \
+ "It has been configured already." % (self.get_id(),
+ self._machine.get_id())
+ raise MachineError(msg)
+
+ logging.info("Configuring interface %s on machine %s", self.get_id(),
+ self._machine.get_id())
+
+ if self._netns != None:
+ self._machine._rpc_call_to_netns(self._netns, "configure_interface",
+ self.get_id(), self._get_config())
+ else:
+ self._machine._rpc_call("configure_interface", self.get_id(),
+ self._get_config())
+ self._configured = True
+
+ def deconfigure(self):
+ if not self._configured:
+ return
+
+ if self._netns != None:
+ self._machine._rpc_call_to_netns(self._netns,
+ "deconfigure_interface", self.get_id())
+ else:
+ self._machine._rpc_call("deconfigure_interface", self.get_id())
+ self._configured = False
+
class VirtualInterface(Interface):
""" Dynamically created interface
diff --git a/lnst/Controller/NetTestController.py b/lnst/Controller/NetTestController.py
index 56649a3..04c67da 100644
--- a/lnst/Controller/NetTestController.py
+++ b/lnst/Controller/NetTestController.py
@@ -283,7 +283,10 @@ class NetTestController:
try:
iface = machine.get_interface(if_id)
except MachineError:
- iface = machine.new_soft_interface(if_id, if_type)
+ if if_type == 'lo':
+ iface = machine.new_loopback_interface(if_id)
+ else:
+ iface = machine.new_soft_interface(if_id, if_type)
if "slaves" in iface_xml_data:
for slave in iface_xml_data["slaves"]:
diff --git a/lnst/Controller/RecipeParser.py b/lnst/Controller/RecipeParser.py
index 12b1214..159b1bc 100644
--- a/lnst/Controller/RecipeParser.py
+++ b/lnst/Controller/RecipeParser.py
@@ -64,9 +64,20 @@ class RecipeParser(XmlParser):
interfaces_tag = machine_tag.find("interfaces")
if interfaces_tag is not None and len(interfaces_tag) > 0:
machine["interfaces"] = XmlCollection(interfaces_tag)
+
+ lo_netns = []
for interface_tag in interfaces_tag:
- interface = self._process_interface(interface_tag)
- machine["interfaces"].extend(interface)
+ interfaces = self._process_interface(interface_tag)
+
+ for interface in interfaces:
+ if interface['type'] != 'lo':
+ continue
+ elif interface['netns'] in lo_netns:
+ msg = "Only one loopback device per netns is allowed."
+ raise RecipeError(msg, interface_tag)
+ else:
+ lo_netns.append(interface['netns'])
+ machine["interfaces"].extend(interfaces)
return machine
diff --git a/lnst/Slave/NetConfigDevice.py b/lnst/Slave/NetConfigDevice.py
index 0d88ce8..11f39d5 100644
--- a/lnst/Slave/NetConfigDevice.py
+++ b/lnst/Slave/NetConfigDevice.py
@@ -87,6 +87,10 @@ class NetConfigDeviceEth(NetConfigDeviceGeneric):
exec_cmd("ip addr flush %s" % config["name"])
exec_cmd("ethtool -A %s rx off tx off" % config["name"], die_on_err=False, log_outputs=False)
+class NetConfigDeviceLoopback(NetConfigDeviceGeneric):
+ def configure(self):
+ config = self._dev_config
+
class NetConfigDeviceBond(NetConfigDeviceGeneric):
_modulename = "bonding"
_moduleparams = "max_bonds=0"
@@ -459,7 +463,8 @@ type_class_mapping = {
"team": NetConfigDeviceTeam,
"ovs_bridge": NetConfigDeviceOvsBridge,
"veth": NetConfigDeviceVEth,
- "vti": NetConfigDeviceVti
+ "vti": NetConfigDeviceVti,
+ "lo": NetConfigDeviceLoopback
}
def NetConfigDevice(dev_config, if_manager):
diff --git a/lnst/Slave/NmConfigDevice.py b/lnst/Slave/NmConfigDevice.py
index 4e4f9bf..0d4af2d 100644
--- a/lnst/Slave/NmConfigDevice.py
+++ b/lnst/Slave/NmConfigDevice.py
@@ -817,6 +817,12 @@ class NmConfigDeviceVti(NmConfigDeviceGeneric):
def is_nm_managed(cls, dev_config, if_manager):
return False
+class NmConfigDeviceLoopback(NmConfigDeviceGeneric):
+ #Not supported by NetworkManager
+ @classmethod
+ def is_nm_managed(cls, dev_config, if_manager):
+ return False
+
type_class_mapping = {
"eth": NmConfigDeviceEth,
"bond": NmConfigDeviceBond,
@@ -826,7 +832,8 @@ type_class_mapping = {
"team": NmConfigDeviceTeam,
"ovs_bridge": NmConfigDeviceOvsBridge,
"veth": NmConfigDeviceVEth,
- "vti": NmConfigDeviceVti
+ "vti": NmConfigDeviceVti,
+ "lo": NmConfigDeviceLoopback
}
def is_nm_managed(dev_config, if_manager):
diff --git a/schema-recipe.rng b/schema-recipe.rng
index 594ec5b..490b86b 100644
--- a/schema-recipe.rng
+++ b/schema-recipe.rng
@@ -137,6 +137,7 @@
<ref name="ovs_bridge"/>
<ref name="veth_pair"/>
<ref name="vti"/>
+ <ref name="lo"/>
</choice>
</zeroOrMore>
</element>
@@ -383,6 +384,28 @@
</element>
</define>
+ <define name="lo">
+ <element name="lo">
+ <attribute name="id"/>
+ <optional>
+ <attribute name="netns"/>
+ </optional>
+ <interleave>
+ <optional>
+ <ref name="define"/>
+ </optional>
+
+ <zeroOrMore>
+ <ref name="options"/>
+ </zeroOrMore>
+
+ <optional>
+ <ref name="addresses"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
<define name="options">
<element name="options">
<interleave>
9 years, 7 months
[lnst] add vti support
by Jiří Pírko
commit e4bbb8059a88963adb3d574df40ef3a65e3f771a
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Tue Sep 9 15:59:23 2014 +0200
add vti support
This patch adds support for vti devices. There is no configuration
supported beyond purely creating the device. The recipe format is:
<vti id="xyz" netns="aa">
<options>
<option name="local" value="1.1.1.1"/>
<option name="remote" value="1.1.1.2"/>
<option name="key" value="1"/>
</options>
</vti>
Where the key option is mandatory and local and remote options are
optional (though I don't know if such a device is usable). The netns
attribute is optional as usual.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Controller/RecipeParser.py | 5 +++++
lnst/Slave/InterfaceManager.py | 2 ++
lnst/Slave/NetConfigDevice.py | 39 ++++++++++++++++++++++++++++++++++++++-
lnst/Slave/NmConfigDevice.py | 9 ++++++++-
schema-recipe.rng | 19 +++++++++++++++++++
5 files changed, 72 insertions(+), 2 deletions(-)
---
diff --git a/lnst/Controller/RecipeParser.py b/lnst/Controller/RecipeParser.py
index 3960c97..12b1214 100644
--- a/lnst/Controller/RecipeParser.py
+++ b/lnst/Controller/RecipeParser.py
@@ -141,6 +141,11 @@ class RecipeParser(XmlParser):
opts = self._proces_options(opts_tag)
if len(opts) > 0:
iface["options"] = opts
+ elif iface["type"] in ["vti"]:
+ # interface options
+ opts_tag = iface_tag.find("options")
+ opts = self._proces_options(opts_tag)
+ iface["options"] = opts
elif iface["type"] in ["vlan"]:
# real_dev of the VLAN interface
slaves_tag = iface_tag.find("slaves")
diff --git a/lnst/Slave/InterfaceManager.py b/lnst/Slave/InterfaceManager.py
index e30b52a..f83dd33 100644
--- a/lnst/Slave/InterfaceManager.py
+++ b/lnst/Slave/InterfaceManager.py
@@ -223,6 +223,8 @@ class InterfaceManager(object):
return self._assign_name_generic(prefix)
elif dev_type == "veth":
return self._assign_name_pair("veth")
+ elif dev_type == "vti":
+ return self._assign_name_generic("vti")
else:
return self._assign_name_generic("dev")
diff --git a/lnst/Slave/NetConfigDevice.py b/lnst/Slave/NetConfigDevice.py
index 2a15a82..0d88ce8 100644
--- a/lnst/Slave/NetConfigDevice.py
+++ b/lnst/Slave/NetConfigDevice.py
@@ -414,6 +414,42 @@ class NetConfigDeviceVEth(NetConfigDeviceGeneric):
def deconfigure(self):
return True
+class NetConfigDeviceVti(NetConfigDeviceGeneric):
+ _modulename = ""
+ _moduleload = False
+
+ def create(self):
+ conf = self._dev_config
+ local = ''
+ remote = ''
+ key = None
+ for opt, val in conf['options']:
+ if opt == 'local':
+ local = 'local ' + val
+ elif opt == 'remote':
+ remote = 'remote ' + val
+ elif opt == 'key':
+ key = val
+ else:
+ pass
+
+ if key == None:
+ raise Exception("Option 'key' not set for a vti device")
+
+ exec_cmd("ip link add %s type vti %s %s key %s" %
+ (conf["name"], local, remote, key))
+
+ def destroy(self):
+ conf = self._dev_config
+ exec_cmd("ip link del %s" % conf["name"])
+
+ def configure(self):
+ #no configuration options supported at the moment
+ return True
+
+ def deconfigure(self):
+ return True
+
type_class_mapping = {
"eth": NetConfigDeviceEth,
"bond": NetConfigDeviceBond,
@@ -422,7 +458,8 @@ type_class_mapping = {
"vlan": NetConfigDeviceVlan,
"team": NetConfigDeviceTeam,
"ovs_bridge": NetConfigDeviceOvsBridge,
- "veth": NetConfigDeviceVEth
+ "veth": NetConfigDeviceVEth,
+ "vti": NetConfigDeviceVti
}
def NetConfigDevice(dev_config, if_manager):
diff --git a/lnst/Slave/NmConfigDevice.py b/lnst/Slave/NmConfigDevice.py
index 37251e9..4e4f9bf 100644
--- a/lnst/Slave/NmConfigDevice.py
+++ b/lnst/Slave/NmConfigDevice.py
@@ -811,6 +811,12 @@ class NmConfigDeviceVEth(NmConfigDeviceGeneric):
def is_nm_managed(cls, dev_config, if_manager):
return False
+class NmConfigDeviceVti(NmConfigDeviceGeneric):
+ #Not supported by NetworkManager
+ @classmethod
+ def is_nm_managed(cls, dev_config, if_manager):
+ return False
+
type_class_mapping = {
"eth": NmConfigDeviceEth,
"bond": NmConfigDeviceBond,
@@ -819,7 +825,8 @@ type_class_mapping = {
"vlan": NmConfigDeviceVlan,
"team": NmConfigDeviceTeam,
"ovs_bridge": NmConfigDeviceOvsBridge,
- "veth": NmConfigDeviceVEth
+ "veth": NmConfigDeviceVEth,
+ "vti": NmConfigDeviceVti
}
def is_nm_managed(dev_config, if_manager):
diff --git a/schema-recipe.rng b/schema-recipe.rng
index f13f36a..594ec5b 100644
--- a/schema-recipe.rng
+++ b/schema-recipe.rng
@@ -136,6 +136,7 @@
<ref name="team"/>
<ref name="ovs_bridge"/>
<ref name="veth_pair"/>
+ <ref name="vti"/>
</choice>
</zeroOrMore>
</element>
@@ -364,6 +365,24 @@
</element>
</define>
+ <define name="vti">
+ <element name="vti">
+ <attribute name="id"/>
+ <optional>
+ <attribute name="netns"/>
+ </optional>
+ <interleave>
+ <optional>
+ <ref name="define"/>
+ </optional>
+
+ <zeroOrMore>
+ <ref name="options"/>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
<define name="options">
<element name="options">
<interleave>
9 years, 7 months
[lnst] logs: add netns information to logs
by Jiří Pírko
commit 6ec37f0cd673964101a430dbb8b3da5d4a18b6ee
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Tue Sep 9 15:59:22 2014 +0200
logs: add netns information to logs
All log messages now contain information about what network namespace
they've originated in. Since xml result files are generated
automatically, the information about the network namespace is already
present in them.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Common/LoggingHandler.py | 6 ++++++
lnst/Common/Logs.py | 28 ++++++++++++++++++++++------
lnst/Common/NetTestCommand.py | 22 +++++++++++++++++++---
lnst/Slave/NetTestSlave.py | 1 +
4 files changed, 48 insertions(+), 9 deletions(-)
---
diff --git a/lnst/Common/LoggingHandler.py b/lnst/Common/LoggingHandler.py
index 3fd8919..22d58f5 100644
--- a/lnst/Common/LoggingHandler.py
+++ b/lnst/Common/LoggingHandler.py
@@ -66,12 +66,18 @@ class TransmitHandler(logging.Handler):
def __init__(self, target):
logging.Handler.__init__(self)
self.target = target
+ self._origin_name = None
+
+ def set_origin_name(self, name):
+ self._origin_name = name
def emit(self, record):
r = dict(record.__dict__)
r['msg'] = record.getMessage()
r['args'] = None
r['exc_info'] = None
+ if self._origin_name != None:
+ r['origin_name'] = self._origin_name
data = {"type": "log", "record": r}
diff --git a/lnst/Common/Logs.py b/lnst/Common/Logs.py
index b891439..89118c1 100644
--- a/lnst/Common/Logs.py
+++ b/lnst/Common/Logs.py
@@ -24,11 +24,12 @@ def log_exc_traceback():
class MultilineFormatter(Formatter): # addr:17 level:7
_ADDR_WIDTH = 17
+ _NETNS_WIDTH = 8
_LEVEL_WIDTH = 7
_coloured = False
def __init__(self, coloured=False):
- fmt = "%(asctime)s %(address)s %(levelname)s: %(message)s"
+ fmt = "%(asctime)s %(address)s %(netns)s %(levelname)s: %(message)s"
datefmt = "%Y-%m-%d %H:%M:%S"
self.linefmt = " "
self._coloured = coloured
@@ -44,12 +45,12 @@ class MultilineFormatter(Formatter): # addr:17 level:7
def _format_addr(self, record):
if not "address" in record.__dict__:
- addr = "(localhost)".rjust(17)
+ addr = "(localhost)"
else:
- addr = record.address.rjust(17)
+ addr = "(" + record.address + ")"
- just = " " * (self._ADDR_WIDTH - len(addr))
- return just + self._decorate_value(addr, "log_header")
+ addr = addr.rjust(self._ADDR_WIDTH)
+ return self._decorate_value(addr, "log_header")
def _format_level(self, record):
level = record.levelname
@@ -66,6 +67,12 @@ class MultilineFormatter(Formatter): # addr:17 level:7
values["address"] = self._format_addr(record)
values["levelname"] = self._format_level(record)
+ try:
+ values["netns"] = record.__dict__["origin_name"]
+ except:
+ values["netns"] = "-"
+ values["netns"] = values["netns"].rjust(self._NETNS_WIDTH)
+
msg = ""
level = record.levelname
lines = record.getMessage().split("\n")
@@ -95,6 +102,8 @@ class LoggingCtl:
transmit_handler = None
def __init__(self, debug=False, log_dir=None, log_subdir="", colours=True):
+ self._origin_name = None
+
if log_dir != None:
self.log_folder = os.path.abspath(os.path.join(log_dir, log_subdir))
else:
@@ -171,7 +180,7 @@ class LoggingCtl:
def add_client_log(self, slave_id, log_record):
logger = logging.getLogger(slave_id)
- log_record['address'] = '(' + slave_id + ')'
+ log_record['address'] = slave_id
record = logging.makeLogRecord(log_record)
logger.handle(record)
@@ -180,6 +189,8 @@ class LoggingCtl:
self.cancel_connection()
self.transmit_handler = TransmitHandler(target)
+ self.transmit_handler.set_origin_name(self._origin_name)
+
logger = logging.getLogger()
logger.addHandler(self.transmit_handler)
@@ -224,3 +235,8 @@ class LoggingCtl:
def get_recipe_log_path(self):
return self.recipe_log_path
+
+ def set_origin_name(self, name):
+ self._origin_name = name
+ if self.transmit_handler != None:
+ self.transmit_handler.set_origin_name(name)
diff --git a/lnst/Common/NetTestCommand.py b/lnst/Common/NetTestCommand.py
index 6b6db0b..c1b39d9 100644
--- a/lnst/Common/NetTestCommand.py
+++ b/lnst/Common/NetTestCommand.py
@@ -349,7 +349,12 @@ class NetTestCommandGeneric:
raise CommandException(msg)
def _format_cmd_res_header(self):
- return "%-9s" % self._command["type"]
+ if "netns" in self._command and self._command["netns"] != None:
+ netns = "(%s) " % self._command["netns"]
+ else:
+ netns = ""
+
+ return "%-9s" % (self._command["type"] + netns)
def set_handle_intr(self):
pass
@@ -392,7 +397,12 @@ class NetTestCommandExec(NetTestCommandGeneric):
else:
bg_id = ""
- cmd = "%-9s%scmd: \"%s\"" %(cmd_type, bg_id, cmd_val)
+ if "netns" in self._command and self._command["netns"] != None:
+ netns = "(%s) " % self._command["netns"]
+ else:
+ netns = ""
+
+ cmd = "%-9s%scmd: \"%s\"" %(cmd_type + netns, bg_id, cmd_val)
return cmd
class NetTestCommandConfig(NetTestCommandGeneric):
@@ -459,7 +469,13 @@ class NetTestCommandControl(NetTestCommandGeneric):
def _format_cmd_res_header(self):
cmd_type = self._command["type"]
cmd_val = self._command["proc_id"]
- cmd = "%-9sid: %s" % (cmd_type, cmd_val)
+
+ if "netns" in self._command and self._command["netns"] != None:
+ netns = "(%s) " % self._command["netns"]
+ else:
+ netns = ""
+
+ cmd = "%-9s id: %s" % (cmd_type + netns, cmd_val)
return cmd
class NetTestCommandWait(NetTestCommandControl):
diff --git a/lnst/Slave/NetTestSlave.py b/lnst/Slave/NetTestSlave.py
index 0fbbcff..74ffba0 100644
--- a/lnst/Slave/NetTestSlave.py
+++ b/lnst/Slave/NetTestSlave.py
@@ -542,6 +542,7 @@ class SlaveMethods:
self._server_handler.set_ctl_sock((write_pipe, "root_netns"))
self._log_ctl.disable_logging()
+ self._log_ctl.set_origin_name(netns)
self._log_ctl.set_connection(write_pipe)
self._if_manager.rescan_devices()
9 years, 7 months