merging rspecs avoid duplicated networks
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Wed, 15 Dec 2010 15:55:29 +0000 (16:55 +0100)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Wed, 15 Dec 2010 15:55:29 +0000 (16:55 +0100)
slice manager to use the helper function for merging for get_rspecs as well

sfa/managers/slice_manager_pl.py
sfa/util/rspecHelper.py

index 756800c..a58bc80 100644 (file)
@@ -363,7 +363,6 @@ def get_rspec(api, creds, options):
             return rspec
 
     hrn, type = urn_to_hrn(xrn)
-    rspec = None
 
     # get the callers hrn
     valid_cred = api.auth.checkCredentials(creds, 'listnodes', hrn)[0]
@@ -387,31 +386,13 @@ def get_rspec(api, creds, options):
         #threads.run(server.get_resources, cred, xrn, origin_hrn)
                     
     results = threads.get_results()
-    # combine the rspecs into a single rspec 
-    for agg_rspec in results:
-        try:
-            tree = etree.parse(StringIO(agg_rspec))
-        except etree.XMLSyntaxError:
-            message = str(agg_rspec) + ": " + str(sys.exc_info()[1])
-            raise InvalidRSpec(message)
+    merged_rspec = merge_rspecs(results)
 
-        root = tree.getroot()
-        if root.get("type") in ["SFA"]:
-            if rspec == None:
-                rspec = root
-            else:
-                for network in root.iterfind("./network"):
-                    rspec.append(deepcopy(network))
-                for request in root.iterfind("./request"):
-                    rspec.append(deepcopy(request))
-    
-    sfa_logger().debug('get_rspec: rspec=%r'%rspec)
-    rspec =  etree.tostring(rspec, xml_declaration=True, pretty_print=True)
     # cache the result
     if api.cache and not xrn:
-        api.cache.add('nodes', rspec)
+        api.cache.add('nodes', merged_rspec)
  
-    return rspec
+    return merged_rspec
 
 def main():
     r = RSpec()
index a943190..8174e6b 100755 (executable)
@@ -1,11 +1,14 @@
 #! /usr/bin/env python
 
 import sys
+
 from copy import deepcopy
 from lxml import etree
 from StringIO import StringIO
 from optparse import OptionParser
 
+from sfa.util.faults import *
+from sfa.util.sfalogging import sfa_logger
 
 def merge_rspecs(rspecs):
     """
@@ -15,24 +18,53 @@ def merge_rspecs(rspecs):
     if not rspecs or not isinstance(rspecs, list):
         return rspecs
 
+    # ugly hack to avoid sending the same info twice, when the call graph has dags
+    known_networks={}
+    def register_network (network):
+        try:
+            known_networks[network.get('name')]=True
+        except:
+            sfa_logger().error("merge_rspecs: cannot register network with no name in rspec")
+            pass
+    def is_registered_network (network):
+        try:
+            return network.get('name') in known_networks
+        except:
+            sfa_logger().error("merge_rspecs: cannot retrieve network with no name in rspec")
+            return False
+
+    # the resulting tree
     rspec = None
-    for tmp_rspec in rspecs:
+    for input_rspec in rspecs:
         try:
-            tree = etree.parse(StringIO(tmp_rspec))
+            tree = etree.parse(StringIO(input_rspec))
         except etree.XMLSyntaxError:
             # consider failing silently here
-            message = str(agg_rspec) + ": " + str(sys.exc_info()[1])
+            sfa_logger().log_exc("merge_rspecs, parse error")
+            message = str(sys.exc_info()[1]) + ' with ' + input_rspec
             raise InvalidRSpec(message)
 
         root = tree.getroot()
-        if root.get("type") in ["SFA"]:
-            if rspec == None:
-                rspec = root
-            else:
-                for network in root.iterfind("./network"):
+        if not root.get("type") in ["SFA"]:
+            sfa_logger().error("merge_rspecs: unexpected type for rspec root, %s"%root.get('type'))
+            continue
+        if rspec == None:
+            # we scan the first input, register all networks
+            # in addition we remove duplicates - needed until everyone runs 1.0-10
+            rspec = root
+            for network in root.iterfind("./network"):
+                if not is_registered_network(network):
+                    register_network(network)
+                else:
+                    # duplicate in the first input - trash it
+                    root.remove(network)
+        else:
+            for network in root.iterfind("./network"):
+                if not is_registered_network(network):
                     rspec.append(deepcopy(network))
-                for request in root.iterfind("./request"):
-                    rspec.append(deepcopy(request))
+                    register_network(network)
+            for request in root.iterfind("./request"):
+                rspec.append(deepcopy(request))
     return etree.tostring(rspec, xml_declaration=True, pretty_print=True)
 
 class RSpec: