Convert Rspecs and SliceTags to data structure with Node objects connected by Link...
[sfa.git] / sfa / rspecs / aggregates / rspec_manager_vini.py
index d2d5e60..ab82c13 100644 (file)
@@ -3,10 +3,10 @@ from sfa.util.misc import *
 from sfa.util.rspec import Rspec
 from sfa.server.registry import Registries
 from sfa.plc.nodes import *
-from sfa.rspecs.aggregates.vini_utils import *
+from sfa.rspecs.aggregates.vini.utils import *
+from sfa.rspecs.aggregates.vini.rspec import *
 import sys
 
-SFA_VINI_DEFAULT_RSPEC = '/etc/sfa/vini.rspec'
 SFA_VINI_WHITELIST = '/etc/sfa/vini.whitelist'
 
 """
@@ -134,66 +134,56 @@ def create_slice_vini_aggregate(api, hrn, nodes):
     return 1
 
 def get_rspec(api, hrn):
-    # Get default rspec
-    default = Rspec()
-    default.parseFile(SFA_VINI_DEFAULT_RSPEC)
+    rspec = ViniRspec()  
+    topo = Topology(api)  
+
+    rspec.updateCapacity(topo)
     
     if (hrn):
         slicename = hrn_to_pl_slicename(hrn)
-        defaultrspec = default.toDict()
-        nodedict = get_nodedict(defaultrspec)
-
-        # call the default sfa.plc.nodes.get_rspec() method
-        nodes = Nodes(api)     
-        rspec = nodes.get_rspec(hrn)     
-
-        # Grab all the PLC info we'll need at once
         slice = get_slice(api, slicename)
         if slice:
-            nodes = get_nodes(api)
-            tags = get_slice_tags(api)
-
-            # Add the node tags from the Capacity statement to Node objects
-            for (k, v) in nodedict.iteritems():
-                for id in nodes:
-                    if v == nodes[id].hostname:
-                        nodes[id].tag = k
+            slice.hrn = hrn
+            topo.nodeTopoFromSliceTags(slice)
+            rspec.updateRequest(slice, topo)
+        else:
+            # call the default sfa.plc.nodes.get_rspec() method
+            return Nodes(api).get_rspec(hrn)     
 
-            endpoints = []
-            for node in slice.get_nodes(nodes):
-                linktag = slice.get_tag('topo_rspec', tags, node)
-                if linktag:
-                    l = eval(linktag.value)
-                    for (id, realip, bw, lvip, rvip, vnet) in l:
-                        endpoints.append((node.id, id, bw))
-            
-            if endpoints:
-                linkspecs = []
-                for (l, r, bw) in endpoints:
-                    if (r, l, bw) in endpoints:
-                        if l < r:
-                            edict = {}
-                            edict['endpoint'] = [nodes[l].tag, nodes[r].tag]
-                            edict['bw'] = [bw]
-                            linkspecs.append(edict)
+    return rspec.toxml()
 
-                d = default.toDict()
-                d['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec'] = linkspecs
-                d['Rspec']['Request'][0]['NetSpec'][0]['name'] = hrn
-                new = Rspec()
-                new.parseDict(d)
-                rspec = new.toxml()
-    else:
-        # Return canned response for now...
-        rspec = default.toxml()
 
-    return rspec
+"""
+Check the requested topology against the available topology and capacity
+"""
+def check_request(hrn, rspec, nodes, sites, sitelinks, maxbw):
+    linkspecs = rspec['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec']
+    if linkspecs:
+        for l in linkspecs:
+            n1 = Node.lookup(l['endpoint'][0])
+            n2 = Node.lookup(l['endpoint'][1])
+            bw = l['bw'][0]
+            reqbps = get_tc_rate(bw)
+            maxbps = get_tc_rate(maxbw)
 
+            if reqbps <= 0:
+                raise GeniInvalidArgument(bw, "BW")
+            if reqbps > maxbps:
+                raise PermissionError(" %s requested %s but max BW is %s" % 
+                                      (hrn, bw, maxbw))
+
+            if adjacent_nodes(n1, n2, sites, sitelinks):
+                availbps = get_avail_bps(n1, n2, sites, sitelinks)
+                if availbps < reqbps:
+                    raise PermissionError("%s: capacity exceeded" % hrn)
+            else:
+                raise PermissionError("%s: nodes %s and %s not adjacent" 
+                                      % (hrn, n1.tag, n2.tag))
 
+"""
+Hook called via 'sfi.py create'
+"""
 def create_slice(api, hrn, xml):
-    r = Rspec(xml)
-    rspec = r.toDict()
-
     ### Check the whitelist
     ### It consists of lines of the form: <slice hrn> <bw>
     whitelist = {}
@@ -203,103 +193,31 @@ def create_slice(api, hrn, xml):
         whitelist[slice] = maxbw
         
     if hrn in whitelist:
-        maxbps = get_tc_rate(whitelist[hrn])
+        maxbw = whitelist[hrn]
     else:
         raise PermissionError("%s not in VINI whitelist" % hrn)
         
-    ### Check to make sure that the slice isn't requesting more
-    ### than its maximum bandwidth.
-    linkspecs = rspec['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec']
-    if linkspecs:
-        for l in linkspecs:
-            bw = l['bw'][0]
-            bps = get_tc_rate(bw)
-            if bps <= 0:
-                raise GeniInvalidArgument(bw, "BW")
-            if bps > maxbps:
-                raise PermissionError(" %s requested %s but max BW is %s" % (hrn, bw, whitelist[hrn]))
+    rspec = ViniRspec(xml)
+    topo = Topology(api)
+    
+    topo.nodeTopoFromRspec(rspec)
 
     # Check request against current allocations
-    # Request OK
-
-    nodes = rspec_to_nodeset(rspec)
-    create_slice_vini_aggregate(api, hrn, nodes)
-
-    # Add VINI-specific topology attributes to slice here
-    try:
-        linkspecs = rspec['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec']
-        if linkspecs:
-            slicename = hrn_to_pl_slicename(hrn)
-
-            # Grab all the PLC info we'll need at once
-            slice = get_slice(api, slicename)
-            if slice:
-                nodes = get_nodes(api)
-                tags = get_slice_tags(api)
-
-                slice.update_tag('vini_topo', 'manual', tags)
-                slice.assign_egre_key(tags)
-                slice.turn_on_netns(tags)
-                slice.add_cap_net_admin(tags)
-
-                nodedict = {}
-                for (k, v) in get_nodedict(rspec).iteritems():
-                    for id in nodes:
-                        if v == nodes[id].hostname:
-                            nodedict[k] = nodes[id]
-
-                for l in linkspecs:
-                    n1 = nodedict[l['endpoint'][0]]
-                    n2 = nodedict[l['endpoint'][1]]
-                    bw = l['bw'][0]
-                    n1.add_link(n2, bw)
-                    n2.add_link(n1, bw)
-
-                for node in slice.get_nodes(nodes):
-                    if node.links:
-                        topo_str = "%s" % node.links
-                        slice.update_tag('topo_rspec', topo_str, tags, node)
-
-                # Update slice tags in database
-                for i in tags:
-                    tag = tags[i]
-                    if tag.slice_id == slice.id:
-                        if tag.tagname == 'topo_rspec' and not tag.updated:
-                            tag.delete()
-                        tag.write(api)
-    except KeyError:
-        # Bad Rspec
-        pass
+    #check_request(hrn, rspec, nodes, sites, sitelinks, maxbw)
     
+    nodes = topo.nodesInTopo()
+    hostnames = []
+    for node in nodes:
+        hostnames.append(node.hostname)
+    create_slice_vini_aggregate(api, hrn, hostnames)
 
-    return True
-
-def get_nodedict(rspec):
-    nodedict = {}
-    try:    
-        sitespecs = rspec['Rspec']['Capacity'][0]['NetSpec'][0]['SiteSpec']
-        for s in sitespecs:
-            for node in s['NodeSpec']:
-                nodedict[node['name']] = node['hostname'][0]
-    except KeyError:
-        pass
+    slicename = hrn_to_pl_slicename(hrn)
+    slice = get_slice(api, slicename)
+    if slice:
+        topo.updateSliceTags(slice)    
 
-    return nodedict
+    return True
 
-       
-def rspec_to_nodeset(rspec):
-    nodes = set()
-    try:
-        nodedict = get_nodedict(rspec)
-        linkspecs = rspec['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec']
-        for l in linkspecs:
-            for e in l['endpoint']:
-                nodes.add(nodedict[e])
-    except KeyError:
-        # Bad Rspec
-        pass
-    
-    return nodes
 
 def main():
     r = Rspec()