[lnst] Machine: Fixing a number of issues in the virt support
by Jiří Pírko
commit 10062b638e0c231af8dfc9ba574764d617c6612e
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Fri Apr 26 10:11:16 2013 +0200
Machine: Fixing a number of issues in the virt support
This code hasn't really been tested during the refactoring (because
the virtualization wasn't supported at that time). This patch fixes
a number of issues that accumulated in the code as the rest of the
codebase changed since the last time it was used.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
lnst/Controller/Machine.py | 46 +++++++++++++++++++++------------
lnst/Controller/NetTestController.py | 1 +
2 files changed, 30 insertions(+), 17 deletions(-)
---
diff --git a/lnst/Controller/Machine.py b/lnst/Controller/Machine.py
index 7abb484..78f4c70 100644
--- a/lnst/Controller/Machine.py
+++ b/lnst/Controller/Machine.py
@@ -22,7 +22,7 @@ from xmlrpclib import Binary
from pprint import pprint, pformat
from lnst.Common.Logs import log_exc_traceback
from lnst.Common.XmlRpc import ServerProxy, ServerException
-from lnst.Common.NetUtils import MacPool
+from lnst.Common.NetUtils import MacPool, normalize_hwaddr
from lnst.Common.VirtUtils import VirtNetCtl, VirtDomainCtl, BridgeCtl
from lnst.Common.Utils import wait_for, md5sum, dir_md5sum, create_tar_archive
from lnst.Common.ConnectionHandler import send_data, recv_data
@@ -47,6 +47,7 @@ class Machine(object):
self._system_config = {}
self._domain_ctl = None
+ self._network_bridges = None
self._libvirt_domain = libvirt_domain
if libvirt_domain:
self._domain_ctl = VirtDomainCtl(libvirt_domain)
@@ -207,12 +208,18 @@ class Machine(object):
def set_network_bridges(self, bridges):
self._network_bridges = bridges
- def get_network_bridges(self, bridges):
- if self._network_bridges:
+ def get_network_bridges(self):
+ if self._network_bridges != None:
return self._network_bridges
else:
raise MachineError("Network bridges not available.")
+ def get_domain_ctl(self):
+ if not self._domain_ctl:
+ raise MachineError("Machine '%s' is not virtual." % self.get_id())
+
+ return self._domain_ctl
+
def start_packet_capture(self):
return self._rpc_call("start_packet_capture", "")
@@ -309,7 +316,7 @@ class Interface(object):
return self._id
def set_hwaddr(self, hwaddr):
- self._hwaddr = hwaddr
+ self._hwaddr = normalize_hwaddr(hwaddr)
def get_hwaddr(self):
if not self._hwaddr:
@@ -396,8 +403,10 @@ class Interface(object):
if_info = self._machine._rpc_call("get_interface_info", self.get_id())
if "name" in if_info:
- self._devname = if_info["name"]
- self._hwaddr = if_info["hwaddr"]
+ self.set_devname(if_info["name"])
+
+ if "hwaddr" in if_info:
+ self.set_hwaddr(if_info["hwaddr"])
def deconfigure(self):
if not self._configured:
@@ -431,10 +440,7 @@ class VirtualInterface(Interface):
super(VirtualInterface, self).__init__(machine, if_id, if_type)
def initialize(self):
- if not self._domain_ctl:
- msg = "Cannot create an interface. " \
- "Machine '%s' is not virtual." % machine_id
- raise MachineError(msg)
+ domain_ctl = self._machine.get_domain_ctl()
if self._hwaddr:
query = self._machine._rpc_call('get_devices_by_hwaddr',
@@ -447,14 +453,14 @@ class VirtualInterface(Interface):
self._hwaddr = self._machine.get_mac_pool().get_addr()
query = self._machine._rpc_call('get_devices_by_hwaddr',
self._hwaddr)
- if not len(query_result):
+ if not len(query):
break
bridges = self._machine.get_network_bridges()
if self._network in bridges:
- brctl = bridges[network]
+ brctl = bridges[self._network]
else:
- bridges["network"] = brctl = BridgeCtl()
+ bridges[self._network] = brctl = BridgeCtl()
br_name = brctl.get_name()
brctl.init()
@@ -462,14 +468,20 @@ class VirtualInterface(Interface):
logging.info("Creating interface %s (%s) on machine %s",
self.get_id(), self._hwaddr, self._machine.get_id())
- domain_ctl = self._machine.get_domain_ctl()
domain_ctl.attach_interface(self._hwaddr, br_name)
- ready = wait_for(self._ready, timeout=10)
+
+ # The sleep here is necessary, because udev sometimes renames the
+ # newly created device and if the query for name comes too early,
+ # the controller will then try to configure an nonexistent device
+ sleep(1)
+
+ ready = wait_for(self.is_ready, timeout=10)
+
if not ready:
msg = "Netdevice initialization failed." \
"Unable to create device %s (%s) on machine %s" \
- % (self._get_id, self._hwaddr, self._machine.get_id())
+ % (self.get_id(), self._hwaddr, self._machine.get_id())
raise MachineError(msg)
super(VirtualInterface, self).initialize()
@@ -479,7 +491,7 @@ class VirtualInterface(Interface):
domain_ctl.detach_interface(self._hwaddr)
def is_ready(self):
- ifaces = self._rpc_call('get_devices_by_hwaddr', self._hwaddr)
+ ifaces = self._machine._rpc_call('get_devices_by_hwaddr', self._hwaddr)
return len(ifaces) > 0
class SoftInterface(Interface):
diff --git a/lnst/Controller/NetTestController.py b/lnst/Controller/NetTestController.py
index b5722c3..078746d 100644
--- a/lnst/Controller/NetTestController.py
+++ b/lnst/Controller/NetTestController.py
@@ -128,6 +128,7 @@ class NetTestController:
port = self._config.get_option('environment', 'rpcport')
machine.set_rpc(self._msg_dispatcher, port)
machine.set_mac_pool(self._mac_pool)
+ machine.set_network_bridges(self._network_bridges)
recipe_name = os.path.basename(self._recipe_path)
machine.configure(recipe_name, self._docleanup)
10 years, 11 months
[lnst] NetTestController: Fixing a bug in bridges cleanup
by Jiří Pírko
commit 4ede91df83f9b5899a37f9ae84d77e621f875521
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Fri Apr 26 10:11:15 2013 +0200
NetTestController: Fixing a bug in bridges cleanup
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
lnst/Controller/NetTestController.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
---
diff --git a/lnst/Controller/NetTestController.py b/lnst/Controller/NetTestController.py
index 8adde13..b5722c3 100644
--- a/lnst/Controller/NetTestController.py
+++ b/lnst/Controller/NetTestController.py
@@ -169,7 +169,7 @@ class NetTestController:
self._log_ctl.remove_slave(machine_id)
# remove dynamically created bridges
- for bridge in self._network_bridges:
+ for bridge in self._network_bridges.itervalues():
bridge.cleanup()
def _prepare(self):
10 years, 11 months
[lnst] NetTestSlave: Making the get_iface_info more precise
by Jiří Pírko
commit bc7c2cde326b6ff3cd45431f94864ed3e2e8e9d2
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Fri Apr 26 10:11:14 2013 +0200
NetTestSlave: Making the get_iface_info more precise
This patch changes the rpc method so it always returns both the devname
and the hw address. If one of them is missing, it will do a query and
add it to the results.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
lnst/Slave/NetTestSlave.py | 23 ++++++++++++++++++++---
1 files changed, 20 insertions(+), 3 deletions(-)
---
diff --git a/lnst/Slave/NetTestSlave.py b/lnst/Slave/NetTestSlave.py
index f4549f6..2b0def5 100644
--- a/lnst/Slave/NetTestSlave.py
+++ b/lnst/Slave/NetTestSlave.py
@@ -24,6 +24,7 @@ from lnst.Common.Logs import log_exc_traceback
from lnst.Common.PacketCapture import PacketCapture
from lnst.Common.Utils import die_when_parent_die
from lnst.Common.NetUtils import scan_netdevs, test_tcp_connection
+from lnst.Common.NetUtils import normalize_hwaddr
from lnst.Common.ExecCmd import exec_cmd
from lnst.Common.ResourceCache import ResourceCache
from lnst.Common.NetTestCommand import NetTestCommandContext
@@ -93,7 +94,17 @@ class SlaveMethods:
netdevs = []
for entry in name_scan:
- if entry["hwaddr"] == hwaddr:
+ if entry["hwaddr"] == normalize_hwaddr(hwaddr):
+ netdevs.append(entry)
+
+ return netdevs
+
+ def get_devices_by_devname(self, devname):
+ name_scan = scan_netdevs()
+ netdevs = []
+
+ for entry in name_scan:
+ if entry["name"] == devname:
netdevs.append(entry)
return netdevs
@@ -110,11 +121,17 @@ class SlaveMethods:
if_config = self._netconfig.get_interface_config(if_id)
info = {}
- if "name" in if_config:
+ if "name" in if_config and if_config["name"] != None:
info["name"] = if_config["name"]
+ else:
+ devs = self.get_devices_by_hwaddr(if_config["hwaddr"])
+ info["name"] = devs[0]["name"]
- if "hwaddr" in if_config:
+ if "hwaddr" in if_config and if_config["hwaddr"] != None:
info["hwaddr"] = if_config["hwaddr"]
+ else:
+ devs = self.get_devices_by_devname(if_config["name"])
+ info["hwaddr"] = devs[0]["hwaddr"]
return info
10 years, 11 months
[lnst] SlavePool: Support matching virtualized schemes
by Jiří Pírko
commit 71ba5cb7eb608c42c5d4ae0ac80c98ca30bed780
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Fri Apr 26 10:11:13 2013 +0200
SlavePool: Support matching virtualized schemes
This commit adds native support for virtual machines with the
matching algorithm. Up to now, virtual machines could be only used
as if they were physical.
Now if the matching for physical machines fails, the controller
will try to find suitable set of virtual machines using which it could
create the required network.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
lnst/Controller/SlavePool.py | 70 ++++++++++++++++++++++++++++++++++++++++--
1 files changed, 67 insertions(+), 3 deletions(-)
---
diff --git a/lnst/Controller/SlavePool.py b/lnst/Controller/SlavePool.py
index dc13f23..d602027 100644
--- a/lnst/Controller/SlavePool.py
+++ b/lnst/Controller/SlavePool.py
@@ -106,8 +106,12 @@ class SlavePool:
return None
machines = {}
- for m_id in self._map["machines"]:
- machines[m_id] = self._get_mapped_slave(m_id)
+ if self._map["virtual"]:
+ for m_id in self._map["machines"]:
+ machines[m_id] = self._prepare_virtual_slave(m_id, mreqs[m_id])
+ else:
+ for m_id in self._map["machines"]:
+ machines[m_id] = self._get_mapped_slave(m_id)
return machines
@@ -167,6 +171,30 @@ class SlavePool:
return machine
+ def _prepare_virtual_slave(self, tm_id, tm):
+ pm_id = self._get_machine_mapping(tm_id)
+ pm = self._pool[pm_id]
+
+ hostname = pm["params"]["hostname"]
+ libvirt_domain = pm["params"]["libvirt_domain"]
+
+ machine = Machine(tm_id, hostname, libvirt_domain)
+
+ # make all the existing unused
+ for if_id, if_data in pm["interfaces"].iteritems():
+ iface = machine.new_unused_interface("eth")
+ iface.set_hwaddr(if_data["hwaddr"])
+ iface.set_network(if_data["network"])
+
+ # add all the other devices
+ for if_id, if_data in tm["interfaces"].iteritems():
+ iface = machine.new_virtual_interface(if_id, "eth")
+ iface.set_network(if_data["network"])
+ if "hwaddr" in if_data["params"]:
+ iface.set_hwaddr(if_data["params"]["hwaddr"])
+
+ return machine
+
class SetupMapper:
"""
This class can be used for matching machine setups against
@@ -503,7 +531,14 @@ class SetupMapper:
machine_map = [(tm, pm, self._iface_map[tm]) \
for tm, pm in self._machine_map]
network_map = list(self._network_map)
- return self._format_map_dict(machine_map, network_map)
+ mmap = self._format_map_dict(machine_map, network_map)
+ mmap["virtual"] = False
+ return mmap
+ elif self._map_setup_virt(template_machines, pool_machines):
+ machine_map = [(tm, pm, []) for tm, pm in self._machine_map]
+ mmap = self._format_map_dict(machine_map, [])
+ mmap["virtual"] = True
+ return mmap
else:
return None
@@ -552,3 +587,32 @@ class SetupMapper:
mmap.discard((machine, possible_match))
return False
+
+ def _machine_matches(self, tm, pm):
+ for prop_name, prop_value in tm["params"].iteritems():
+ if pm["params"][prop_name] != prop_value:
+ return False
+
+ return True
+
+ def _map_setup_virt(self, template_machines, pool_machines):
+ available = set()
+ matches = set()
+ for m_id in pool_machines.iterkeys():
+ available.add(m_id)
+
+ for tm_id, tm in template_machines.iteritems():
+ match = None
+ for am_id in available:
+ if self._machine_matches(tm, pool_machines[am_id]):
+ match = (tm_id, am_id)
+ available.remove(am_id)
+ break
+
+ if match:
+ matches.add(match)
+ else:
+ return False
+
+ self._machine_map = list(matches)
+ return True
10 years, 11 months
[lnst] TestPacketAssert: fix line processing bug
by Jiří Pírko
commit 547e493a484d16df72a929c99332663ad5b6e1fb
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Thu Apr 25 16:09:16 2013 +0200
TestPacketAssert: fix line processing bug
The last two lines from tcpdump were not being processed due to a bug in
the handling loop. This commit fixes that.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
test_modules/TestPacketAssert.py | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
---
diff --git a/test_modules/TestPacketAssert.py b/test_modules/TestPacketAssert.py
index 32884a4..0466c20 100644
--- a/test_modules/TestPacketAssert.py
+++ b/test_modules/TestPacketAssert.py
@@ -58,6 +58,8 @@ class TestPacketAssert(TestGeneric):
self.line = next_line
else:
self.line += next_line
+ if self.line != "":
+ self._process_captured_line(self.line)
def _prepare_grep_filters(self):
@@ -152,6 +154,9 @@ class TestPacketAssert(TestGeneric):
else:
self.line += next_line
+ if self.line != "":
+ self._process_captured_line(self.line)
+
logging.info("Capturing finished. Received %d packets", self._num_recv)
res = {"received": self._num_recv,
"min": self._min_cond,
10 years, 11 months
[PATCH] NetTestController: handling of error messages
by Ondrej Lichtner
From: Ondrej Lichtner <olichtne(a)redhat.com>
The communication protocol that was implemented can also send error
messages, however the Controller wasn't handling them and instead raised
an Unknown message exception. This patch fixes that by raising an
exception with the correct message.
I also modified the message that Slave sends when an unsupported method
call is recieved.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
lnst/Controller/NetTestController.py | 4 ++++
lnst/Slave/NetTestSlave.py | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/lnst/Controller/NetTestController.py b/lnst/Controller/NetTestController.py
index 62600ca..169f0af 100644
--- a/lnst/Controller/NetTestController.py
+++ b/lnst/Controller/NetTestController.py
@@ -394,6 +394,10 @@ class MessageDispatcher(ConnectionHandler):
elif message[1]["type"] == "exception":
msg = "Recieved an exception from slave: %s" % message[0]
raise CommandException(msg)
+ elif message[1]["type"] == "error":
+ msg = "Recieved an error message from slave %s: %s" %\
+ (message[0], message[1]["err"])
+ raise CommandException(msg)
else:
msg = "Unknown message type: %s" % message[1]["type"]
raise NetTestError(msg)
diff --git a/lnst/Slave/NetTestSlave.py b/lnst/Slave/NetTestSlave.py
index 2b0def5..9b39c0a 100644
--- a/lnst/Slave/NetTestSlave.py
+++ b/lnst/Slave/NetTestSlave.py
@@ -437,7 +437,7 @@ class NetTestSlave:
self._cmd_context.cleanup()
self._log_ctl.cancel_connection()
else:
- err = "Method not found: %s" % msg["method_name"]
+ err = "Method '%s' not supported." % msg["method_name"]
response = {"type": "error", "err": err}
if not self._server_handler.send_data_to_ctl(response):
self._cmd_context.cleanup()
--
1.7.11.7
10 years, 11 months
[PATCH 0/7] Virt support for the matching algorithm
by Radek Pazdera
This series finishes what have been started during the refactoring of
the NetTestController in the previous one. LNST now supports automatic
configuration of virtual machines based on the description of the in
the recipe file.
It is done during the macthing phase. LNST first tries to match the
network against the pool normaly and in case it fails, it will try
to find a set of suitable virtual machines (those with libvirt_domain
specified) to configure.
Then the configuration of the network connections between the virtual
guests is done automatically using libvirt. It will add interfaces to
the machines and connect them together through bridges on the controller.
There are a few limitations however. The machines must be virtualized
directly on the controller. And in case you want to use this feature,
you need to run lnst-ctl with root priviledges, so it can use brctl and
virsh.
Radek Pazdera (7):
SlavePool: Support matching virtualized schemes
NetTestSlave: Making the get_iface_info more precise
NetTestController: Fixing a bug in bridges cleanup
Machine: Fixing a number of issues in the virt support
SlavePool: Adding a is_setup_virtual() predicate
VirtUtils: Don't log virsh output
NetTestController: Adding check for root priviledges
lnst/Common/VirtUtils.py | 2 +-
lnst/Controller/Machine.py | 46 +++++++++++++-------
lnst/Controller/NetTestController.py | 9 ++++-
lnst/Controller/SlavePool.py | 77 +++++++++++++++++++++++++++++++--
lnst/Slave/NetTestSlave.py | 23 +++++++++-
5 files changed, 130 insertions(+), 27 deletions(-)
--
1.7.7.6
10 years, 11 months
[PATCH] TestPacketAssert: fix line processing bug
by Ondrej Lichtner
From: Ondrej Lichtner <olichtne(a)redhat.com>
The last two lines from tcpdump were not being processed due to a bug in
the handling loop. This commit fixes that.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
test_modules/TestPacketAssert.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/test_modules/TestPacketAssert.py b/test_modules/TestPacketAssert.py
index 32884a4..0466c20 100644
--- a/test_modules/TestPacketAssert.py
+++ b/test_modules/TestPacketAssert.py
@@ -58,6 +58,8 @@ class TestPacketAssert(TestGeneric):
self.line = next_line
else:
self.line += next_line
+ if self.line != "":
+ self._process_captured_line(self.line)
def _prepare_grep_filters(self):
@@ -152,6 +154,9 @@ class TestPacketAssert(TestGeneric):
else:
self.line += next_line
+ if self.line != "":
+ self._process_captured_line(self.line)
+
logging.info("Capturing finished. Received %d packets", self._num_recv)
res = {"received": self._num_recv,
"min": self._min_cond,
--
1.7.11.7
10 years, 11 months