fixed
[sfa.git] / sfa / managers / aggregate_manager_max.py
index 7f0a253..90c94a6 100644 (file)
@@ -1,5 +1,3 @@
-#!/usr/bin/python
-
 from sfa.util.rspec import RSpec
 import sys
 import pdb
@@ -11,7 +9,12 @@ from sfa.util.storage import *
 from sfa.util.policy import Policy
 from sfa.util.debug import log
 from sfa.server.aggregate import Aggregates
+from sfa.util.xrn import urn_to_hrn, hrn_to_urn, get_authority
+from sfa.util.plxrn import hrn_to_pl_slicename
+from sfa.util.plxrn import hrn_to_pl_slicename
 from sfa.server.registry import Registries
+from sfa.util.rspec import RSpec
+from sfa.util.sfalogging import sfa_logger
 from sfa.util.faults import *
 
 import xml.dom.minidom
@@ -22,15 +25,15 @@ SFA_MAX_CANNED_RSPEC = '/etc/sfa/max_physical_canned.xml'
 
 topology = {}
 
-class GeniOutOfResource(GeniFault):
+class SfaOutOfResource(SfaFault):
     def __init__(self, interface):
         faultString = "Interface " + interface + " not available"
-        GeniFault.__init__(self, 100, faultString, '')
+        SfaFault.__init__(self, 100, faultString, '')
 
-class GeniNoPairRSpec(GeniFault):
+class SfaNoPairRSpec(SfaFault):
     def __init__(self, interface, interface2):
         faultString = "Interface " + interface + " should be paired with " + interface2
-        GeniFault.__init__(self, 100, faultString, '')
+        SfaFault.__init__(self, 100, faultString, '')
 
 # Returns a mapping from interfaces to the nodes they lie on and their peer interfaces
 # i -> node,i_peer
@@ -118,6 +121,41 @@ def collapse_alloc_dict(d):
     ret = []
     for k in d.keys():
         ret.extend(d[k])
+from sfa.util.config import Config
+from sfa.managers.aggregate_manager_pl import GetVersion
+import os
+import time
+
+RSPEC_TMP_FILE_PREFIX = "/tmp/max_rspec"
+
+# execute shell command and return both exit code and text output
+def shell_execute(cmd, timeout):
+    pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r')
+    pipe = os.popen(cmd + ' 2>&1', 'r')
+    text = ''
+    while timeout:
+        line = pipe.read()
+        text += line
+        time.sleep(1)
+        timeout = timeout-1
+    code = pipe.close()
+    if code is None: code = 0
+    if text[-1:] == '\n': text = text[:-1]
+    return code, text
+
+"""
+ call AM API client with command like in the following example:
+ cd aggregate_client; java -classpath AggregateWS-client-api.jar:lib/* \
+      net.geni.aggregate.client.examples.CreateSliceNetworkClient \
+      ./repo https://geni:8443/axis2/services/AggregateGENI \
+      ... params ...
+"""
+
+def call_am_apiclient(client_app, params, timeout):
+    (client_path, am_url) = Config().get_max_aggrMgr_info()
+    sys_cmd = "cd " + client_path + "; java -classpath AggregateWS-client-api.jar:lib/* net.geni.aggregate.client.examples." + client_app + " ./repo " + am_url + " " + ' '.join(params)
+    ret = shell_execute(sys_cmd, timeout)
+    sfa_logger().debug("shell_execute cmd: %s returns %s" % (sys_cmd, ret))
     return ret
 
 
@@ -131,6 +169,44 @@ def alloc_links(api, hrn, links_to_add, links_to_drop):
         except Exception: 
             # Probably a duplicate tag. XXX July 21
             pass
+# save request RSpec xml content to a tmp file
+def save_rspec_to_file(rspec):
+    path = RSPEC_TMP_FILE_PREFIX + "_" + time.strftime('%Y%m%dT%H:%M:%S', time.gmtime(time.time())) +".xml"
+    file = open(path, "w")
+    file.write(rspec)
+    file.close()
+    return path
+
+# get stripped down slice id/name plc:maxpl:xi_slice1 --> xi_slice1
+def get_short_slice_id(cred, hrn):
+    if hrn == None:
+        return None
+    slice_id = hrn[hrn.rfind('+')+1:]
+    if slice_id == None:
+        slice_id = hrn[hrn.rfind(':')+1:]
+    if slice_id == None:
+       return hrn
+       pass
+    return str(slice_id)
+
+# extract xml 
+def get_xml_by_tag(text, tag):
+    indx1 = text.find('<'+tag)
+    indx2 = text.find('/'+tag+'>')
+    xml = None
+    if indx1!=-1 and indx2>indx1:
+        xml = text[indx1:indx2+len(tag)+2]
+    return xml
+
+def create_slice(api, xrn, cred, rspec, users):
+    indx1 = rspec.find("<RSpec")
+    indx2 = rspec.find("</RSpec>")
+    if indx1 > -1 and indx2 > indx1:
+        rspec = rspec[indx1+len("<RSpec type=\"SFA\">"):indx2-1]
+    rspec_path = save_rspec_to_file(rspec)
+    (ret, output) = call_am_apiclient("CreateSliceNetworkClient", [rspec_path,], 3)
+    # parse output ?
+    rspec = "<RSpec type=\"SFA\"> Done! </RSpec>"
     return True
 
 def alloc_nodes(api,hrn, requested_ifs):
@@ -140,7 +216,7 @@ def alloc_nodes(api,hrn, requested_ifs):
 # Taken from slices.py
 
 def create_slice_max_aggregate(api, hrn, nodes):
-    # Get the slice record from geni
+    # Get the slice record 
     global topology
     topology = get_interface_map()
     slice = {}
@@ -245,24 +321,38 @@ def create_slice_max_aggregate(api, hrn, nodes):
     api.plshell.AddSliceToNodes(api.plauth, slicename, added_nodes) 
     api.plshell.DeleteSliceFromNodes(api.plauth, slicename, deleted_nodes)
 
+def delete_slice(api, xrn, cred):
+    slice_id = get_short_slice_id(cred, xrn)
+    (ret, output) = call_am_apiclient("DeleteSliceNetworkClient", [slice_id,], 3)
+    # parse output ?
     return 1
 
 
-def get_rspec(api, hrn):
+def get_rspec(api, creds, options):
+    # get slice's hrn from options
+    xrn = options.get('geni_slice_urn', None)
+    hrn, type = urn_to_hrn(xrn)
     # Eg. config line:
     # plc.princeton.sapan vlan23,vlan45
 
     allocations = read_alloc_dict()
     if (hrn and allocations.has_key(hrn)):
             ret_rspec = allocations_to_rspec(allocations[hrn])
+def get_rspec(api, cred, options):
+    #geni_slice_urn: urn:publicid:IDN+plc:maxpl+slice+xi_rspec_test1
+    urn = options.get('geni_slice_urn')
+    slice_id = get_short_slice_id(cred, urn)
+    if slice_id == None:
+        (ret, output) = call_am_apiclient("GetResourceTopology", ['all', '\"\"'], 5)
     else:
         ret_rspec = open(SFA_MAX_CANNED_RSPEC).read()
 
     return (ret_rspec)
 
 
-def create_slice(api, hrn, rspec_xml):
+def create_slice(api, xrn, creds, rspec_xml, users):
     global topology
+    hrn = urn_to_hrn(xrn)[0]
     topology = get_interface_map()
 
     # Check if everything in rspec is either allocated by hrn
@@ -288,9 +378,9 @@ def create_slice(api, hrn, rspec_xml):
 
     for a in requested_interfaces:
         if (a not in current_hrn_interfaces and a in current_interfaces):
-            raise GeniOutOfResource(a)
+            raise SfaOutOfResource(a)
         if (topology[a][1] not in requested_interfaces):
-            raise GeniNoPairRSpec(a,topology[a][1])
+            raise SfaNoPairRSpec(a,topology[a][1])
     # Request OK
 
     # Allocations to delete
@@ -319,13 +409,54 @@ def rspec_to_allocations(rspec):
         # Bad RSpec
         pass
     return ifs
+        (ret, output) = call_am_apiclient("GetResourceTopology", ['all', slice_id,], 5)
+    # parse output into rspec XML
+    if output.find("No resouce found") > 0:
+        rspec = "<RSpec type=\"SFA\"> <Fault>No resource found</Fault> </RSpec>"
+    else:
+        comp_rspec = get_xml_by_tag(output, 'computeResource')
+        sfa_logger().debug("#### computeResource %s" % comp_rspec)
+        topo_rspec = get_xml_by_tag(output, 'topology')
+        sfa_logger().debug("#### topology %s" % topo_rspec)
+        rspec = "<RSpec type=\"SFA\"> <network name=\"" + Config().get_interface_hrn() + "\">";
+        if comp_rspec != None:
+            rspec = rspec + get_xml_by_tag(output, 'computeResource')
+        if topo_rspec != None:
+            rspec = rspec + get_xml_by_tag(output, 'topology')
+        rspec = rspec + "</network> </RSpec>"
+
+    return (rspec)
+
+def start_slice(api, xrn, cred):
+    # service not supported
+    return None
+
+def stop_slice(api, xrn, cred):
+    # service not supported
+    return None
+
+def reset_slices(api, xrn):
+    # service not supported
+    return None
+
+"""
+Returns the request context required by sfatables. At some point, this mechanism should be changed
+to refer to "contexts", which is the information that sfatables is requesting. But for now, we just
+return the basic information needed in a dict.
+"""
+def fetch_context(slice_hrn, user_hrn, contexts):
+    base_context = {'sfa':{'user':{'hrn':user_hrn}}}
+    return base_context
 
 def main():
     t = get_interface_map()
+    api = SfaAPI()
     r = RSpec()
     rspec_xml = open(sys.argv[1]).read()
     #get_rspec(None,'foo')
     create_slice(None, "plc.princeton.sap0", rspec_xml)
     
+    create_slice(api, "plc.maxpl.test000", None, rspec_xml, None)
+
 if __name__ == "__main__":
     main()