sfiapi.py complete. needs testing
authorAlina Quereilhac <alina.quereilhac@inria.fr>
Fri, 13 Jan 2012 17:26:34 +0000 (18:26 +0100)
committerAlina Quereilhac <alina.quereilhac@inria.fr>
Fri, 13 Jan 2012 17:26:34 +0000 (18:26 +0100)
src/nepi/testbeds/planetlab/execute.py
src/nepi/testbeds/planetlab/node.py
src/nepi/testbeds/planetlab/plcapi.py
src/nepi/testbeds/planetlab/sfiapi.py [deleted file]
src/nepi/util/parser/sfa.py
src/nepi/util/sfiapi.py [new file with mode: 0644]

index cd9e06c..698e865 100644 (file)
@@ -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
index 0785769..e6bbebb 100644 (file)
@@ -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])
index 507dcdb..00a06a8 100644 (file)
@@ -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 (file)
index 1082a38..0000000
+++ /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()
-
index 4ccb69a..5194493 100644 (file)
@@ -16,18 +16,32 @@ def xmlencode(s):
 def xmldecode(s):
     return s.replace(u'&#0000',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 (file)
index 0000000..90affff
--- /dev/null
@@ -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
+