From: Alina Quereilhac Date: Fri, 13 Jan 2012 17:26:34 +0000 (+0100) Subject: sfiapi.py complete. needs testing X-Git-Tag: nepi-3.0.0~163^2~42 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=871d990d6d9448041b848dc35ec31bfcfa63e2f0;p=nepi.git sfiapi.py complete. needs testing --- diff --git a/src/nepi/testbeds/planetlab/execute.py b/src/nepi/testbeds/planetlab/execute.py index cd9e06ca..698e865b 100644 --- a/src/nepi/testbeds/planetlab/execute.py +++ b/src/nepi/testbeds/planetlab/execute.py @@ -80,14 +80,14 @@ class TestbedController(testbed_impl.TestbedController): if not self.sfa: self._sliceapi = self.plcapi else: - import sfiapi - self._sliceapi = sfiapi.sfiapi() + from nepi.util import sfiapi + self._sliceapi = sfiapi.sfiapi(self.slice_id) return self._sliceapi @property def slice_id(self): if not self._slice_id: - self._slice_id = self.plcapi.GetSliceId(self.slicename) + self._slice_id = self.sliceapi.GetSliceId(self.slicename) return self._slice_id @property diff --git a/src/nepi/testbeds/planetlab/node.py b/src/nepi/testbeds/planetlab/node.py index 0785769a..e6bbebb7 100644 --- a/src/nepi/testbeds/planetlab/node.py +++ b/src/nepi/testbeds/planetlab/node.py @@ -214,7 +214,7 @@ class Node(object): candidates &= set(map(operator.itemgetter('node_id'), self._sliceapi.GetNodeTags(filters=tagfilter, fields=fields))) - + # filter by vsys tags - special case since it doesn't follow # the usual semantics if self.required_vsys: @@ -269,6 +269,7 @@ class Node(object): hostnames = dict(map(operator.itemgetter('node_id','hostname'), self._api.GetNodes(list(candidates), ['node_id','hostname']) )) + def resolvable(node_id): try: addr = socket.gethostbyname(hostnames[node_id]) diff --git a/src/nepi/testbeds/planetlab/plcapi.py b/src/nepi/testbeds/planetlab/plcapi.py index 507dcdb3..00a06a84 100644 --- a/src/nepi/testbeds/planetlab/plcapi.py +++ b/src/nepi/testbeds/planetlab/plcapi.py @@ -262,7 +262,6 @@ class PLCAPI(object): filters = kw.pop('filters',{}) filters.update(kw) return _retry(self.mcapi.GetSliceTags)(self.auth, filters, *fieldstuple) - def GetInterfaces(self, interfaceIdOrIp=None, fields=None, **kw): if fields is not None: @@ -290,7 +289,6 @@ class PLCAPI(object): def UpdateSlice(self, sliceIdOrName, **kw): return _retry(self.mcapi.UpdateSlice)(self.auth, sliceIdOrName, kw) - def StartMulticall(self): self.threadlocal.mc = xmlrpclib.MultiCall(self.mcapi) @@ -317,7 +315,7 @@ class PLCAPI(object): slice_id = None slices = self.GetSlices(slicename, fields=('slice_id',)) if slices: - slice_id = slices[0]['slice_id'] + slice_id = slices[0]['slice_id'] # If it wasn't found, don't remember this failure, keep trying return slice_id diff --git a/src/nepi/testbeds/planetlab/sfiapi.py b/src/nepi/testbeds/planetlab/sfiapi.py deleted file mode 100644 index 1082a38e..00000000 --- a/src/nepi/testbeds/planetlab/sfiapi.py +++ /dev/null @@ -1,19 +0,0 @@ -class SFIAPI(object): - def __init__(self): - self._slice_nodes = dict() - self._all_nodes = dict() - - def GetSliceNodes(self, slicename): - return None - - def AddSliceNodes(self, slicename, nodes=None): - pass - - def GetNodeTags(self, nodeTagId=None, fields=None, **kw): - pass - - def GetNodes(self, filters=basefilters, fields=('node_id','interface_ids')) )) - -def sfiapi(): - return SFIAPI() - diff --git a/src/nepi/util/parser/sfa.py b/src/nepi/util/parser/sfa.py index 4ccb69a1..51944934 100644 --- a/src/nepi/util/parser/sfa.py +++ b/src/nepi/util/parser/sfa.py @@ -16,18 +16,32 @@ def xmlencode(s): def xmldecode(s): return s.replace(u'�',u'\x00').encode("utf8") -def get_text(p_tag, name): - tags = p_tag.getElementsByTagName(name) +def get_child_text(tag, name): + tags = tag.getElementsByTagName(name) if not tags: return "" - return xmldecode(tags[0].childNodes[0].nodeValue) + return get_text(tags[0]) + +def get_name(tag): + return xmldecode(tag.tagName) + +def get_text(tag): + text = ''.join(t.nodeValue for t in tag.childNodes if t.nodeType == t.TEXT_NODE) + return xmldecode(text) + +def set_text(doc, tag, text): + ttag = doc.createTextNode(text) + tag.appendChild(ttag) def get_attribute(p_tag, name): return xmldecode(p_tag.getAttribute(name)) +def has_sliver(node_tag): + sliver_tag = node_tag.getElementsByTagName("sliver") + return len(sliver_tag) > 0 class SFAResourcesParser(object): - def from_xml(self, xml): + def resources_from_xml(self, xml): data = dict() doc = minidom.parseString(xml) rspec_tag = doc.getElementsByTagName("RSpec")[0] @@ -38,12 +52,27 @@ class SFAResourcesParser(object): data.update(node_data) return data - def nodes_from_xml(self, doc, network_tag): + def slice_info_from_xml(self, xml): + nodes_data = dict() + doc = minidom.parseString(xml) + rspec_tag = doc.getElementsByTagName("RSpec")[0] + network_tags = rspec_tag.getElementsByTagName("network") + for network_tag in network_tags: + if network_tag.nodeType == doc.ELEMENT_NODE: + node_data = self.nodes_from_xml(doc, network_tag, in_sliver = True) + nodes_data.update(node_data) + nodes_data = set(nodes_data.keys()) + tags_data = self.slice_tags_from_xml(doc, rspec_tag) + return tags_data, nodes_data + + def nodes_from_xml(self, doc, network_tag, in_sliver = False): nodes_data = dict() - network_name = get_attribute(network_tag, "name") + network_name = get_attribute(network_tag, 'name') node_tags = network_tag.getElementsByTagName('node') for node_tag in node_tags: if node_tag.nodeType == doc.ELEMENT_NODE: + if in_sliver and not has_sliver(node_tag): + continue node_data = dict() node_data['network_name'] = network_name node_name = get_attribute(node_tag, 'component_name') @@ -63,16 +92,70 @@ class SFAResourcesParser(object): 'response', 'loadw', 'country', 'load', 'mem', 'slices', 'region', 'asnumber', 'bw', 'hrn', 'city', 'responsew', 'bwy', 'cpu']: - node_data[name] = get_text(node_tag, name) + node_data[name] = get_child_text(node_tag, name) iface_tags = node_tag.getElementsByTagName('interface') ifaces_data = dict() for iface_tag in iface_tags: if iface_tag.nodeType == doc.ELEMENT_NODE: for name in ['component_id', 'ipv4']: ifaces_data[name] = get_attribute(iface_tag, name) - node_data['interfaces'] = ifaces_data + node_data['interfaces'] = ifaces_data return nodes_data + def slice_tags_from_xml(self, doc, rspec_tag): + tags_data = dict() + sliver_tag = rspec_tag.getElementsByTagName('sliver_defaults') + if len(sliver_tag) == 0: + return tags_data + for child_tag in sliver_tag[0].childNodes: + if child_tag.nodeType == doc.ELEMENT_NODE: + name = get_name(child_tag) + value = get_text(child_tag) + tags_data[name] = value + return tags_data + + def create_slice_xml(self, node_data, slice_tags): + doc = minidom.Document() + rspec_tag = doc.createElement("RSpec") + doc.appendChild(rspec_tag) + rspec_tag.setAttribute("type", "SFA") + slice_defaults_tag = self.slice_defaults_xml(doc, slice_tags) + + networks = dict() + for k, data in node_data.iteritems(): + network_name = data["network_name"] + if network_name not in networks: + networks[network_name] = dict() + networks[network_name][k] = data + + for n, netdata in networks.iteritems(): + network_tag = doc.createElement("testbeds") + network_tag.setAttribute("name", n) + rspec_tag.appendChild(network_tag) + for k, data in netdata.iteritems(): + node_tag = doc.createElement("node") + node_tag.setAttribute("component_manager_id", data["component_manager_id"]) + node_tag.setAttribute("component_id", data["component_id"]) + node_tag.setAttribute("component_name", data["component_name"]) + node_tag.setAttribute("boot_state", data["boot_state"]) + node_tag.setAttribute("site_id", data["site_id"]) + hostname_tag = doc.createElement("hostname") + set_text(doc, hostname_tag, data["hostname"]) + node_tag.appendChild(hostname_tag) + sliver_tag = doc.createElement("sliver") + node_tag.appendChild(sliver_tag) + network_tag.appendChild(node_tag) + network_tag.appendChild(slice_defaults_tag) + return doc.toxml() + + def slice_defaults_xml(self, doc, slice_tags): + slice_defaults_tag = doc.createElement("sliver_defaults") + for name, value in slice_tags.iteritems(): + tag = doc.createElement(name) + set_text(doc, tag, value) + slice_defaults_tag.appendChild(tag) + return slice_defaults_tag + """ if __name__ == "__main__": path = sys.argv[1] @@ -80,6 +163,6 @@ if __name__ == "__main__": xml = fd.read() fd.close() p = SFAResourcesParser() - data = p.from_xml(xml) - print data.keys() + tags, nodes = p.slice_info_from_xml(xml) + print tags, nodes """ diff --git a/src/nepi/util/sfiapi.py b/src/nepi/util/sfiapi.py new file mode 100644 index 00000000..90affffc --- /dev/null +++ b/src/nepi/util/sfiapi.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- + +from nepi.util.parser import sfa + +class SFIAPI(object): + def __init__(self): + self._slice_tags = dict() + self._slice_nodes = set() + self._all_nodes = dict() + self._slice_id = None + + def FetchSliceInfo(self, slice_id): + self._slice_id = slice_id + p = sfa.SFAResourcesParser() + import commands + xml = commands.getoutput("sfi.py resources") + self._all_nodes = p.resources_from_xml(xml) + xml = commands.getoutput("sfi.py resources %s" % slice_id) + self._slice_tags, self._slice_nodes = p.slice_info_from_xml(xml) + + def GetSliceNodes(self, slicename): + return list(self._slice_nodes) + + def GetNodeInfo(self, node_id): + info = self.GetNodes(node_id) + tags = self.GetNodeTags(node_id=node_id, fields=('tagname','value')) + return info, tags + + def GetSliceId(self, slicename): + return self._slice_id + + def GetSliceVnetSysTag(self, slicename): + return self._slice_tags.get('vsys_net') + + def GetNodeTags(self, node_id=None, fields=None, **kw): + nodes = self._all_nodes + if node_id is not None: + node_ids = node_id + if not isinstance(node_id, list): + node_ids = [node_ids] + nodes = self._FilterByNodeId(nodes, node_ids) + else: + filters = kw.pop('filters',{}) + if '|slice_ids' in filters: + nodes = self._FilterByNodeId(nodes, self._slice_nodes) + del filters['|slice_ids'] + nodes = self._FilterByFilters(nodes, filters) + tagnames = kw.pop('tagname',[]) + return self._GetTagInfo(nodes, tagnames, fields) + + def GetNodes(self, nodeIdOrName=None, fields=[], **kw): + #TODO: filter - peer + # field - interface_ids + nodes = self._all_nodes + if nodeIdOrName is not None: + node_ids = nodeIdOrName + if not isinstance(nodeIdOrName, list): + node_ids = [node_ids] + nodes = self._FilterByNodeId(nodes, node_ids) + else: + filters = kw.pop('filters',{}) + if '|slice_ids' in filters: + nodes = self._FilterByNodeId(nodes, self._slice_nodes) + del filters['|slice_ids'] + nodes = self._FilterByFilters(nodes, filters) + return self._GetNodeInfo(nodes, fields) + + def _FilterByNodeId(self, nodes, node_ids): + return dict((k, nodes[k]) for k in node_ids if k in nodes) + + def _FilterByFilters(self, nodes, filters): + def has_all_tags(node_id): + data = nodes[node_id] + for name, value in filters.iteritems(): + #if (name == '>last_contact' and data['lastcontact'] > value) or \ + if (not name in data or data[tag] != value): + return False + return True + return dict((k, value) for k, value in nodes.iteritems() if has_all_tags(k)) + + def _GetNodeInfo(self, nodes, fields): + result = list() + for k, data in nodes.iteritems(): + r_data = dict() + result.append(r_data) + for f in fields: + if f == "node_id": + value = k + else: + value = data[f] + r_data[f] = value + return result + + def _GetTagInfo(self, nodes, tagnames, fields): + result = list() + for k, data in nodes.iteritems(): + for name, value in data.iteritems(): + r_data = dict() + if tagnames and name not in tagnames: + continue + for f in fields: + if f == "node_id": + val = k + if f == "tagname": + val = name + if f == "value": + val = value + r_data[f] = val + result.append(r_data) + return result + + def AddSliceNodes(self, slicename, nodes=None): + import os, commands, tempfile + nodes = set(nodes) + nodes.update(self._slice_nodes) + nodes_data = dict((k, self._all_nodes[k]) for k in nodes) + p = sfa.SFAResourcesParser() + xml = p.create_slice_xml(nodes_data, self._slice_tags) + fh, fname = tempfile.mkstemp() + os.write(fh, xml) + os.close(fh) + out = commands.getoutput("sfi.py create %s %s" % (self._slice_id, fname)) + os.remove(fname) + #print out + +def sfiapi(slice_id): + api = SFIAPI() + api.FetchSliceInfo(slice_id) + return api +