add exception info to statistics section
[sfa.git] / sfa / managers / slice_manager.py
index 55bbe03..cba7295 100644 (file)
@@ -1,31 +1,23 @@
 import sys
-import time,datetime
+import traceback
+import time
 from StringIO import StringIO
-from types import StringTypes
-from copy import deepcopy
 from copy import copy
 from lxml import etree
 
-from sfa.util.sfalogging import logger
-from sfa.util.rspecHelper import merge_rspecs
-from sfa.util.xrn import Xrn, urn_to_hrn, hrn_to_urn
-from sfa.util.plxrn import hrn_to_pl_slicename
-from sfa.util.faults import *
-from sfa.util.record import SfaRecord
-from sfa.rspecs.rspec_converter import RSpecConverter
-from sfa.client.client_helper import sfa_to_pg_users_arg
-from sfa.rspecs.version_manager import VersionManager
-from sfa.rspecs.rspec import RSpec 
-from sfa.util.policy import Policy
-from sfa.util.prefixTree import prefixTree
 from sfa.trust.sfaticket import SfaTicket
 from sfa.trust.credential import Credential
+
+from sfa.util.sfalogging import logger
+from sfa.util.xrn import Xrn, urn_to_hrn
 from sfa.util.threadmanager import ThreadManager
-import sfa.util.xmlrpcprotocol as xmlrpcprotocol     
-import sfa.plc.peers as peers
 from sfa.util.version import version_core
 from sfa.util.callids import Callids
 
+from sfa.rspecs.rspec_converter import RSpecConverter
+from sfa.rspecs.version_manager import VersionManager
+from sfa.rspecs.rspec import RSpec 
+from sfa.client.client_helper import sfa_to_pg_users_arg
 
 def _call_id_supported(api, server):
     """
@@ -89,9 +81,9 @@ def drop_slicemgr_stats(rspec):
         for node in stats_elements:
             node.getparent().remove(node)
     except Exception, e:
-        api.logger.warn("drop_slicemgr_stats failed: %s " % (str(e)))
+        logger.warn("drop_slicemgr_stats failed: %s " % (str(e)))
 
-def add_slicemgr_stat(rspec, callname, aggname, elapsed, status):
+def add_slicemgr_stat(rspec, callname, aggname, elapsed, status, exc_info=None):
     try:
         stats_tags = rspec.xml.xpath('//statistics[@call="%s"]' % callname)
         if stats_tags:
@@ -99,9 +91,21 @@ def add_slicemgr_stat(rspec, callname, aggname, elapsed, status):
         else:
             stats_tag = etree.SubElement(rspec.xml.root, "statistics", call=callname)
 
-        etree.SubElement(stats_tag, "aggregate", name=str(aggname), elapsed=str(elapsed), status=str(status))
+        stat_tag = etree.SubElement(stats_tag, "aggregate", name=str(aggname), elapsed=str(elapsed), status=str(status))
+
+        if exc_info:
+            exc_tag = etree.SubElement(stat_tag, "exc_info", name=str(exc_info[1]))
+
+            # this would encode it as a text block
+            #exc_tag.text = "\n".join(traceback.format_exception(exc_info[0], exc_info[1], exc_info[2]))
+
+            # this encodes the traceback as a set of xml tags
+            tb = traceback.extract_tb(exc_info[2])
+            for item in tb:
+                exc_frame = etree.SubElement(exc_tag, "tb_frame", filename=str(item[0]), line=str(item[1]), func=str(item[2]), code=str(item[3]))
+
     except Exception, e:
-        api.logger.warn("add_slicemgr_stat failed on  %s: %s" %(aggname, str(e)))
+        logger.warn("add_slicemgr_stat failed on  %s: %s" %(aggname, str(e)))
 
 def ListResources(api, creds, options, call_id):
     version_manager = VersionManager()
@@ -121,7 +125,7 @@ def ListResources(api, creds, options, call_id):
             return {"aggregate": aggregate, "rspec": rspec, "elapsed": time.time()-tStart, "status": "success"}
         except Exception, e:
             api.logger.log_exc("ListResources failed at %s" %(server.url))
-            return {"aggregate": aggregate, "elapsed": time.time()-tStart, "status": "exception"}
+            return {"aggregate": aggregate, "elapsed": time.time()-tStart, "status": "exception", "exc_info": sys.exc_info()}
 
     if Callids().already_handled(call_id): return ""
 
@@ -166,11 +170,11 @@ def ListResources(api, creds, options, call_id):
     rspec_version = version_manager.get_version(options.get('rspec_version'))
     if xrn:    
         result_version = version_manager._get_version(rspec_version.type, rspec_version.version, 'manifest')
-    else: 
+    else:
         result_version = version_manager._get_version(rspec_version.type, rspec_version.version, 'ad')
     rspec = RSpec(version=result_version)
     for result in results:
-        add_slicemgr_stat(rspec, "ListResources", result["aggregate"], result["elapsed"], result["status"])
+        add_slicemgr_stat(rspec, "ListResources", result["aggregate"], result["elapsed"], result["status"], result.get("exc_info",None))
         if result["status"]=="success":
             try:
                 rspec.version.merge(result["rspec"])
@@ -209,16 +213,16 @@ def CreateSliver(api, xrn, creds, rspec_str, users, call_id):
             return {"aggregate": aggregate, "rspec": rspec, "elapsed": time.time()-tStart, "status": "success"}
         except: 
             logger.log_exc('Something wrong in _CreateSliver with URL %s'%server.url)
-            return {"aggregate": aggregate, "elapsed": time.time()-tStart, "status": "exception"}
+            return {"aggregate": aggregate, "elapsed": time.time()-tStart, "status": "exception", "exc_info": sys.exc_info()}
 
     if Callids().already_handled(call_id): return ""
     # Validate the RSpec against PlanetLab's schema --disabled for now
     # The schema used here needs to aggregate the PL and VINI schemas
     # schema = "/var/www/html/schemas/pl.rng"
     rspec = RSpec(rspec_str)
-    schema = None
-    if schema:
-        rspec.validate(schema)
+#    schema = None
+#    if schema:
+#        rspec.validate(schema)
 
     # if there is a <statistics> section, the aggregates don't care about it,
     # so delete it.
@@ -248,7 +252,7 @@ def CreateSliver(api, xrn, creds, rspec_str, users, call_id):
     manifest_version = version_manager._get_version(rspec.version.type, rspec.version.version, 'manifest')
     result_rspec = RSpec(version=manifest_version)
     for result in results:
-        add_slicemgr_stat(result_rspec, "CreateSliver", result["aggregate"], result["elapsed"], result["status"])
+        add_slicemgr_stat(result_rspec, "CreateSliver", result["aggregate"], result["elapsed"], result["status"], result.get("exc_info",None))
         if result["status"]=="success":
             try:
                 result_rspec.version.merge(result["rspec"])
@@ -442,7 +446,7 @@ def get_ticket(api, xrn, creds, rspec, users):
     results = threads.get_results()
     
     # gather information from each ticket 
-    rspecs = []
+    rspec = None
     initscripts = []
     slivers = [] 
     object_gid = None  
@@ -451,15 +455,17 @@ def get_ticket(api, xrn, creds, rspec, users):
         attrs = agg_ticket.get_attributes()
         if not object_gid:
             object_gid = agg_ticket.get_gid_object()
-        rspecs.append(agg_ticket.get_rspec())
+        if not rspec:
+            rspec = RSpec(agg_ticket.get_rspec())
+        else:
+            rspec.version.merge(agg_ticket.get_rspec())
         initscripts.extend(attrs.get('initscripts', [])) 
         slivers.extend(attrs.get('slivers', [])) 
     
     # merge info
     attributes = {'initscripts': initscripts,
                  'slivers': slivers}
-    merged_rspec = merge_rspecs(rspecs) 
-
+    
     # create a new ticket
     ticket = SfaTicket(subject = slice_hrn)
     ticket.set_gid_caller(api.auth.client_gid)
@@ -468,7 +474,7 @@ def get_ticket(api, xrn, creds, rspec, users):
     ticket.set_pubkey(object_gid.get_pubkey())
     #new_ticket.set_parent(api.auth.hierarchy.get_auth_ticket(auth_hrn))
     ticket.set_attributes(attributes)
-    ticket.set_rspec(merged_rspec)
+    ticket.set_rspec(rspec.toxml())
     ticket.encode()
     ticket.sign()          
     return ticket.save_to_string(save_parents=True)
@@ -537,11 +543,12 @@ def status(api, xrn, creds):
     """
     return 1
 
-def main():
-    r = RSpec()
-    r.parseFile(sys.argv[1])
-    rspec = r.toDict()
-    CreateSliver(None,'plc.princeton.tmacktestslice',rspec,'create-slice-tmacktestslice')
+# this is plain broken
+#def main():
+#    r = RSpec()
+#    r.parseFile(sys.argv[1])
+#    rspec = r.toDict()
+#    CreateSliver(None,'plc.princeton.tmacktestslice',rspec,'create-slice-tmacktestslice')
 
 if __name__ == "__main__":
     main()