commit 1a27b014e5328e3028070cfb8f8b4f704de1c8dd
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu Mar 7 17:33:40 2013 +0100
ctl: Recent XML format changes
This patch implements the XML format changes we discussed recently.
What used to be <machineconfig> is now called <slavemachine>:
<slavemachine>
<params>
<param name="hostname" value="192.168.122.10"/>
<param name="libvirt_domain" value="Fedora16"/>
<param name="os" value="fedora16"/>
<param name="type" value="virtual"/>
</params>
<netdevices>
<netdevice network="test-net" phys_id="1">
<params>
<param name="type" value="eth"/>
<param name="hwaddr"
value="52:54:00:e4:75:16"/>
<param name="driver" value="virtio"/>
</params>
</netdevice>
</netdevices>
</slavemachine>
<machinerequires> tag in the recipe changed to <requirements>:
<requirements>
<params>
<param name="os" value="rhel6.2"/>
</params>
<netdevices>
<netdevice network="ttnet" phys_id="t1"/>
<netdevice network="ttnet" phys_id="t2"/>
</netdevices>
</requirements>
Both machines and netdevices now have variable tag called <params>
that can be used to specify different parameters and also to match
accordingly to these parameters.
WARNING:
Changes in this patch are not yet done. Although the code is functional,
these changes will require larger refactoring of the code, especially
in the NetTestController class.
We expect some changes to the controller from Ondra in the following
days, so I decided to postpone the refactoring and do it afterwards.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
lnst/Controller/NetTestController.py | 19 ++--
lnst/Controller/NetTestParse.py | 219 ++++++++++++++++-----------------
lnst/Controller/SlavePool.py | 60 +++------
3 files changed, 137 insertions(+), 161 deletions(-)
---
diff --git a/lnst/Controller/NetTestController.py b/lnst/Controller/NetTestController.py
index d915420..d686475 100644
--- a/lnst/Controller/NetTestController.py
+++ b/lnst/Controller/NetTestController.py
@@ -64,16 +64,13 @@ class NetTestController:
ntparse.set_recipe(self._recipe)
ntparse.set_definitions(definitions)
- ntparse.register_event_handler("netdevice_ready",
- self._prepare_device)
- ntparse.register_event_handler("machine_info_ready",
+ ntparse.register_event_handler("provisioning_requirements_ready",
+ self._prepare_provisioning)
+ ntparse.register_event_handler("machine_ready",
self._prepare_slave)
ntparse.register_event_handler("interface_config_ready",
self._prepare_interface)
- ntparse.register_event_handler("provisioning_requirements_ready",
- self._prepare_provisioning)
-
modules_dirs = config.get_option('environment', 'module_dirs')
tools_dirs = config.get_option('environment', 'tool_dirs')
@@ -85,9 +82,9 @@ class NetTestController:
def _get_machineinfo(self, machine_id):
try:
- info = self._recipe["machines"][machine_id]["info"]
+ info = self._recipe["machines"][machine_id]["params"]
except KeyError:
- msg = "Machine info is required, but not yet available"
+ msg = "Machine parameters requested, but not yet available"
raise NetTestError(msg)
return info
@@ -127,6 +124,8 @@ class NetTestController:
provisioning["map"][m_id] = provisioner
logging.info(" machine %s uses %s" % (m_id, provisioner))
+ machines[m_id]["params"]["system_config"] = {}
+
def _prepare_device(self, machine_id, dev_id):
info = self._get_machineinfo(machine_id)
dev =
self._recipe["machines"][machine_id]["netdevices"][dev_id]
@@ -297,6 +296,10 @@ class NetTestController:
for device in provisioner["netdevices"].itervalues():
self._rpc_call(machine_id, 'set_device_down',
device["hwaddr"])
+ machine = self._recipe["machines"][machine_id]
+ for dev_id in machine["netdevices"].iterkeys():
+ self._prepare_device(machine_id, dev_id)
+
def _init_slave_rpc(self, machine_id):
info = self._get_machineinfo(machine_id)
hostname = info["hostname"]
diff --git a/lnst/Controller/NetTestParse.py b/lnst/Controller/NetTestParse.py
index 28fe9ed..39d23bd 100644
--- a/lnst/Controller/NetTestParse.py
+++ b/lnst/Controller/NetTestParse.py
@@ -44,23 +44,6 @@ class NetTestParse(RecipeParser):
except Exception as exc:
raise XmlProcessingError(str(exc), xml_dom)
- # process machine requirements if used in the recipe before
- # proceeding to the second pass
- provisioning = self._recipe["provisioning"]
-
- dom_init = XmlDomTreeInit()
- for name, req in provisioning["setup_requirements"].iteritems():
- xml = provisioning["allocated_machines"][name]
- dom = dom_init.parse_string(xml, "pool_machine_config")
-
- # replace the original machinerequires with
- # the config recived from MachinePool
- original_node = req["dom_node_ref"]
- parent = original_node.parentNode
- replacement_node = dom.getElementsByTagName("machineconfig")[0]
-
- parent.replaceChild(replacement_node, original_node)
-
second_pass = SecondPass(self)
second_pass.parse(xml_dom)
@@ -74,9 +57,6 @@ class FirstPass(RecipeParser):
detect provisioning at the moment.
"""
- _has_machineconfigs = False
- _provisioned_setup = False
-
def parse(self, node):
self._recipe["provisioning"] = {}
self._recipe["provisioning"]["setup_requirements"] = {}
@@ -102,33 +82,18 @@ class FirstPass(RecipeParser):
params = {}
params["id"] = self._get_attribute(node, "id")
- scheme = {"machineconfig": self._machineconfig,
- "machinerequires": self._machinerequires}
+ scheme = {"requirements": self._requirements}
self._process_child_nodes(node, scheme, params,
default_handler=self._ignore_tag)
- def _machineconfig(self, node, params):
- if self._provisioned_setup:
- msg = "Cannot mix provisioned and non-provisioned machines"
- raise XmlProcessingError(msg, node)
-
- self._has_machineconfigs = True
-
- def _machinerequires(self, node, params):
- if self._has_machineconfigs:
- msg = "Cannot mix provisioned and non-provisioned machines"
- raise XmlProcessingError(msg, node)
-
- self._provisioned_setup = True
-
+ def _requirements(self, node, params):
machine_req =
self._recipe["provisioning"]["setup_requirements"]
m_id = params["id"]
template = {}
- template["info"] = {}
template["netdevices"] = {}
machine_req[m_id] = template
- subparser = MachineRequiresParse(self)
+ subparser = RequirementsParse(self)
subparser.set_template(template)
subparser.parse(node)
@@ -158,7 +123,6 @@ class SecondPass(RecipeParser):
self._process_child_nodes(node, scheme)
def _machines(self, node, params):
- self._recipe["machines"] = {}
scheme = {"machine": self._machine}
self._process_child_nodes(node, scheme)
@@ -198,71 +162,91 @@ class MachineParse(RecipeParser):
def parse(self, node):
self._id = self._get_attribute(node, "id")
- self._machine = {}
- self._recipe[self._target][self._id] = self._machine
- self._machine["info"] = {}
- self._machine["netdevices"] = {}
+ recipe = self._recipe
+ self._machine = recipe["machines"][self._id]
self._machine["netconfig"] = {}
- scheme = {"machineconfig": self._machineconfig,
+ scheme = {"requirements": self._requirements,
"netconfig": self._netconfig }
self._process_child_nodes(node, scheme)
- def _machineconfig(self, node, params):
- subparser = MachineConfigParse(self)
- subparser.set_machine(self._id, self._machine)
- subparser.parse(node)
-
def _netconfig(self, node, params):
subparser = NetConfigParse(self)
subparser.set_machine(self._id, self._machine)
subparser.parse(node)
-class MachineRequiresParse(RecipeParser):
+ def _requirements(self, node, params):
+ try:
+ self._trigger_event("machine_ready", {"machine_id":
self._id})
+ except Exception as exc:
+ raise XmlProcessingError(str(exc), node)
+
+class ParamsParse(RecipeParser):
+ _params = None
+
+ def set_params_dict(self, target):
+ self._params = target
+
+ def parse(self, node):
+ scheme = {"param": self._param}
+ self._process_child_nodes(node, scheme)
+
+ def _param(self, node, params):
+ name = self._get_attribute(node, "name")
+
+ if self._has_attribute(node, "value"):
+ value = self._get_attribute(node, "value")
+ else:
+ value = self._get_text_content(node)
+
+ self._params[name] = value
+
+class RequirementsParse(RecipeParser):
_requirements = None
def set_template(self, tmp_dict):
self._requirements = tmp_dict
def parse(self, node):
- self._requirements["dom_node_ref"] = node
+ self._requirements["params"] = {}
+ self._requirements["netdevices"] = {}
- scheme = {"info": self._info,
+ scheme = {"params": self._params,
"netdevices": self._netdevices}
- self._process_child_nodes(node, scheme)
-
- def _info(self, node, params):
- template = self._requirements
- info = template["info"]
-
- if self._has_attribute(node, "hostname"):
- info["hostname"] = self._get_attribute(node, "hostname")
+ params = {"target": self._requirements["params"]}
+ self._process_child_nodes(node, scheme, params)
- if self._has_attribute(node, "libvirt_domain"):
- info["libvirt_domain"] = self._get_attribute(node,
- "libvirt_domain")
+ def _params(self, node, params):
+ subparser = ParamsParse(self)
+ subparser.set_params_dict(params["target"])
+ subparser.parse(node)
def _netdevices(self, node, params):
scheme = {"netdevice": self._netdevice}
self._process_child_nodes(node, scheme)
def _netdevice(self, node, params):
- template = self._requirements
+ reqs = self._requirements
phys_id = self._get_attribute(node, "phys_id")
- dev = template["netdevices"][phys_id] = {}
+ dev = reqs["netdevices"][phys_id] = {}
dev["network"] = self._get_attribute(node, "network")
- if self._has_attribute(node, "type"):
+ dev["params"] = {}
+
+ scheme = {"params": self._params}
+ params = {"target": dev["params"]}
+ self._process_child_nodes(node, scheme)
+
+ if "type" in dev["params"]:
dev["type"] = self._get_attribute(node, "type")
- if self._has_attribute(node, "hwaddr"):
- hwaddr = self._get_attribute(node, "hwaddr")
- dev["hwaddr"] = normalize_hwaddr(hwaddr)
+ if "hwaddr" in dev["params"]:
+ dev["hwaddr"] =
normalize_hwaddr(dev["params"]["hwaddr"])
-class MachineConfigParse(RecipeParser):
+class SlaveMachineParse(RecipeParser):
_machine_id = None
_machine = None
@@ -271,36 +255,22 @@ class MachineConfigParse(RecipeParser):
self._machine = machine
def parse(self, node):
- scheme = {"info": self._info,
+ scheme = {"params": self._params,
"netdevices": self._netdevices}
- self._process_child_nodes(node, scheme)
-
- def _info(self, node, params):
- machine = self._machine
- info = machine["info"]
-
- info["hostname"] = self._get_attribute(node, "hostname")
-
- if self._has_attribute(node, "libvirt_domain"):
- info["libvirt_domain"] = self._get_attribute(node,
- "libvirt_domain")
-
- if self._has_attribute(node, "rpcport"):
- info["rpcport"] = self._get_attribute(node, "rpcport",
int)
-
- if self._has_attribute(node, "skip_cleanup"):
- info["skip_cleanup"] = self._get_attribute(node,
- "skip_cleanup", bool_it)
- else:
- info["skip_cleanup"] = False
+ params = {"target": self._machine["params"]}
+ self._process_child_nodes(node, scheme, params)
- info["system_config"] = {}
+ self._machine["params"]["skip_cleanup"] = False
+ mandatory_params = ["hostname"]
+ for mandatory in mandatory_params:
+ if mandatory not in self._machine["params"]:
+ msg = "Missing required parameter '%s'" % mandatory
+ raise XmlProcessingError(msg, node)
- try:
- self._trigger_event("machine_info_ready",
- {"machine_id": self._machine_id})
- except Exception as exc:
- raise XmlProcessingError(str(exc), node)
+ def _params(self, node, params):
+ subparser = ParamsParse(self)
+ subparser.set_params_dict(params["target"])
+ subparser.parse(node)
def _netdevices(self, node, params):
scheme = {"netdevice": self._netdevice,
@@ -321,23 +291,47 @@ class MachineConfigParse(RecipeParser):
dev = machine["netdevices"][phys_id] = {}
dev["create"] = params["create"]
- dev["type"] = self._get_attribute(node, "type")
dev["network"] = self._get_attribute(node, "network")
+ dev["params"] = {}
+
+ # parse device parameters
+ scheme = {"params": self._params}
+ params = {"target": dev["params"]}
+ self._process_child_nodes(node, scheme, params)
+
+ if "type" in dev["params"]:
+ dev["type"] = dev["params"]["type"]
+ else:
+ msg = "Missing required parameter 'type'"
+ raise XmlProcessingError(msg, node)
- # hwaddr attribute is optional for dynamic devices,
+ # hwaddr parameter is optional for dynamic devices,
# but it is required by non-dynamic devices
- if dev["create"] == None or self._has_attribute(node,
"hwaddr"):
- hwaddr = self._get_attribute(node, "hwaddr")
- dev["hwaddr"] = normalize_hwaddr(hwaddr)
+ if dev["create"] and "hwaddr" in dev["params"]:
+ dev["hwaddr"] =
normalize_hwaddr(dev["params"]["hwaddr"])
+ else:
+ if "hwaddr" in dev["params"]:
+ dev["hwaddr"] =
normalize_hwaddr(dev["params"]["hwaddr"])
+ else:
+ msg = "Missing required parameter 'hwaddr'"
+ raise XmlProcessingError(msg, node)
- # name attribute is only valid when the device is not dynamic
- if dev["create"] == None and self._has_attribute(node,
"name"):
- dev["name"] = self._get_attribute(node, "name")
+ # name parameter is only valid when the device is not dynamic
+ if "name" in dev["params"]:
+ if dev["create"]:
+ msg = "'name' parameter is not valid with dynamic
devices"
+ raise XmlProcessingError(msg, node)
+ else:
+ dev["name"] = dev["params"]["name"]
- # bridge attribute is valid only when the device is dynamic
- if dev["create"] == "libvirt" and \
- self._has_attribute(node, "libvirt_bridge"):
- dev["libvirt_bridge"] = self._get_attribute(node,
"libvirt_bridge")
+ # bridge parameter is valid only when the device is dynamic
+ if "libvirt_bridge" in dev["params"]:
+ if dev["create"] == "libvirt":
+ dev["libvirt_bridge"] =
dev["params"]["libvirt_bridge"]
+ else:
+ msg = "'libvirt_bridge' parameter is not valid with" \
+ "dynamic devices"
+ raise XmlProcessingError(msg, node)
try:
self._trigger_event("netdevice_ready",
@@ -345,7 +339,6 @@ class MachineConfigParse(RecipeParser):
except Exception as exc:
raise XmlProcessingError(str(exc), node)
-
class NetConfigParse(RecipeParser):
_machine_id = None
_machine = None
diff --git a/lnst/Controller/SlavePool.py b/lnst/Controller/SlavePool.py
index 15b0de2..e430bbe 100644
--- a/lnst/Controller/SlavePool.py
+++ b/lnst/Controller/SlavePool.py
@@ -19,7 +19,7 @@ import re
import copy
from xml.dom import minidom
from lnst.Common.XmlProcessing import XmlDomTreeInit
-from lnst.Controller.NetTestParse import MachineConfigParse
+from lnst.Controller.NetTestParse import SlaveMachineParse
class SlavePool:
"""
@@ -53,19 +53,19 @@ class SlavePool:
dirname, basename = os.path.split(filepath)
- parser = MachineConfigParse()
+ parser = SlaveMachineParse()
parser.set_include_root(dirname)
parser.disable_events()
- machine = {"info": {}, "netdevices": {}}
+ machine = {"params": {}, "netdevices": {}}
machine_id = re.sub("\.xml$", "", basename, flags=re.I)
parser.set_machine(machine_id, machine)
- machineconfig = dom.getElementsByTagName("machineconfig")[0]
- machine["dom_node_ref"] = machineconfig
+ slavemachine = dom.getElementsByTagName("slavemachine")[0]
- parser.parse(machineconfig)
- if 'libvirt_domain' not in machine['info'] or
self._allow_virtual:
+ parser.parse(slavemachine)
+ if 'libvirt_domain' not in machine['params'] \
+ or self._allow_virtual:
self._pool[machine_id] = machine
else:
logging.warning("libvirtd not found- Machine Pool skipping "\
@@ -87,12 +87,13 @@ class SlavePool:
mapper = SetupMapper()
self._map = mapper.map_setup(setup_requirements, self._pool)
+
if self._map == None:
return None
configs = {}
for m_id in self._map["machines"]:
- configs[m_id] = self._get_mapped_machineconfig_xml(m_id)
+ configs[m_id] = self._get_mapped_slave(m_id)
return configs
@@ -118,42 +119,23 @@ class SlavePool:
def _get_network_mapping(self, net_id):
return self._map["networks"][net_id]
- def _get_mapped_machineconfig_xml(self, tm_id):
+ def _get_mapped_slave(self, tm_id):
pm_id = self._get_machine_mapping(tm_id)
- dom = minidom.Document()
-
- mcfg = dom.createElement("machineconfig")
-
- info = dom.createElement("info")
- supported = ["hostname", "libvirt_domain",
"rpcport"]
- for attr_name, attr_val in self._pool[pm_id]["info"].iteritems():
- if attr_name in supported:
- info.setAttribute(attr_name, str(attr_val))
- mcfg.appendChild(info)
-
- netdevices = dom.createElement("netdevices")
- mcfg.appendChild(netdevices)
+ machine = copy.deepcopy(self._pool[pm_id])
+ new_netdevices = {}
if_map = self._map["machines"][tm_id]["interfaces"]
for t_if, p_if in if_map.iteritems():
- dev_info = self._pool[pm_id]["netdevices"][p_if]
-
- dev_node = dom.createElement("netdevice")
-
- dev_node.setAttribute("phys_id", t_if)
- dev_node.setAttribute("type", dev_info["type"])
- dev_node.setAttribute("hwaddr", dev_info["hwaddr"])
+ new_netdevices[t_if] = machine["netdevices"][p_if]
for t_net, p_net in self._map["networks"].iteritems():
- if dev_info["network"] == p_net:
- dev_node.setAttribute("network", t_net)
+ if new_netdevices[t_if]["network"] == p_net:
+ new_netdevices[t_if]["network"] = t_net
break
- netdevices.appendChild(dev_node)
-
- return mcfg.toxml()
-
+ machine["netdevices"] = new_netdevices
+ return machine
class SetupMapper:
"""
@@ -265,11 +247,9 @@ class SetupMapper:
pool_machine = self._pool_machines[pool_id]
# check machine properties
- properties = ["hostname", "libvirt_domain"]
- for prop_name, prop_value in template_machine["info"].iteritems():
- if prop_name in properties:
- if pool_machine["info"][prop_name] != prop_value:
- return False
+ for prop_name, prop_value in template_machine["params"].iteritems():
+ if pool_machine["params"][prop_name] != prop_value:
+ return False
# check number of devices
tm_ndevs = len(template_machine["netdevices"])