From 3b80293fb4f3091b17ed9d124ae3fc9decd94d2a Mon Sep 17 00:00:00 2001 From: Andy Bavier Date: Mon, 25 Jan 2010 17:47:32 +0000 Subject: [PATCH] New RSpec format --- sfa/managers/aggregate_manager_vini.py | 31 +-- sfa/rspecs/aggregates/vini/utils.py | 297 +++++++++++++------------ 2 files changed, 161 insertions(+), 167 deletions(-) diff --git a/sfa/managers/aggregate_manager_vini.py b/sfa/managers/aggregate_manager_vini.py index b4d0984a..faeaebb2 100644 --- a/sfa/managers/aggregate_manager_vini.py +++ b/sfa/managers/aggregate_manager_vini.py @@ -3,12 +3,11 @@ from sfa.util.namespace import * from sfa.util.rspec import RSpec from sfa.server.registry import Registries from sfa.plc.nodes import * +from sfa.plc.api import * from sfa.rspecs.aggregates.vini.utils import * from sfa.rspecs.aggregates.vini.rspec import * import sys -SFA_VINI_WHITELIST = '/etc/sfa/vini.whitelist' - """ Copied from create_slice_aggregate() in sfa.plc.slices """ @@ -154,26 +153,13 @@ Hook called via 'sfi.py create' """ def create_slice(api, xrn, xml): hrn = urn_to_hrn(xrn)[0] - ### Check the whitelist - ### It consists of lines of the form: - whitelist = {} - f = open(SFA_VINI_WHITELIST) - for line in f.readlines(): - (slice, maxbw) = line.split() - whitelist[slice] = maxbw - - if hrn in whitelist: - maxbw = whitelist[hrn] - else: - raise PermissionError("%s not in VINI whitelist" % hrn) - rspec = RSpec(xml) topo = Topology(api) topo.nodeTopoFromRSpec(rspec) # Check request against current allocations - topo.verifyNodeTopo(hrn, topo, maxbw) + topo.verifyNodeTopo(hrn, topo) nodes = topo.nodesInTopo() hostnames = [] @@ -186,6 +172,8 @@ def create_slice(api, xrn, xml): if slice: topo.updateSliceTags(slice) + # print topo.toxml(hrn) + return True """ @@ -199,10 +187,13 @@ def fetch_context(slice_hrn, user_hrn, contexts): return base_context def main(): - r = RSpec() - r.parseFile(sys.argv[1]) - rspec = r.toDict() - create_slice(None,'plc',rspec) + api = GeniAPI() + #rspec = get_rspec(api, "plc.princeton.iias", None) + #print rspec + f = open(sys.argv[1]) + xml = f.read() + f.close() + create_slice(api, "plc.princeton.iias", xml) if __name__ == "__main__": main() diff --git a/sfa/rspecs/aggregates/vini/utils.py b/sfa/rspecs/aggregates/vini/utils.py index ea36aadd..34f23e4a 100644 --- a/sfa/rspecs/aggregates/vini/utils.py +++ b/sfa/rspecs/aggregates/vini/utils.py @@ -1,70 +1,11 @@ +from __future__ import with_statement import re import socket from sfa.util.faults import * from sfa.rspecs.aggregates.vini.topology import * +from xmlbuilder import XMLBuilder +import sys -default_topo_xml = """ - - i2atla1 - i2chic1 - 1000 - - - i2atla1 - i2hous1 - 1000 - - - i2atla1 - i2wash1 - 1000 - - - i2chic1 - i2kans1 - 1000 - - - i2chic1 - i2wash1 - 1000 - - - i2hous1 - i2kans1 - 1000 - - - i2hous1 - i2losa1 - 1000 - - - i2kans1 - i2salt1 - 1000 - - - i2losa1 - i2salt1 - 1000 - - - i2losa1 - i2seat1 - 1000 - - - i2newy1 - i2wash1 - 1000 - - - i2salt1 - i2seat1 - 1000 - """ - # Taken from bwlimit.py # # See tc_util.c and http://physics.nist.gov/cuu/Units/binary.html. Be @@ -129,12 +70,14 @@ def format_tc_rate(rate): class Node: def __init__(self, node, bps = 1000 * 1000000): self.id = node['node_id'] + self.idtag = "n%s" % self.id self.hostname = node['hostname'] - self.shortname = self.hostname.replace('.vini-veritas.net', '') + self.name = self.shortname = self.hostname.replace('.vini-veritas.net', '') self.site_id = node['site_id'] self.ipaddr = socket.gethostbyname(self.hostname) self.bps = bps self.links = set() + self.sliver = False def get_link_id(self, remote): if self.id < remote.id: @@ -200,21 +143,58 @@ class Node: if len(sl): return sl.pop() return None + + def add_sliver(self): + self.sliver = True + + def toxml(self, xml, hrn): + if not self.tag: + return + with xml.node(id = self.idtag): + with xml.hostname: + xml << self.hostname + with xml.kbps: + xml << str(int(self.bps/1000)) + if self.sliver: + with xml.sliver: + pass class Link: - def __init__(self, end1, end2, bps = 1000 * 1000000): + def __init__(self, end1, end2, bps = 1000 * 1000000, parent = None): self.end1 = end1 self.end2 = end2 self.bps = bps - + self.parent = parent + self.children = [] + end1.add_link(self) end2.add_link(self) + if self.parent: + self.parent.children.append(self) + + def toxml(self, xml): + end_ids = "%s %s" % (self.end1.idtag, self.end2.idtag) + + if self.parent: + element = xml.vlink(endpoints=end_ids) + else: + element = xml.link(endpoints=end_ids) + + with element: + with xml.description: + xml << "%s -- %s" % (self.end1.name, self.end2.name) + with xml.kbps: + xml << str(int(self.bps/1000)) + for child in self.children: + child.toxml(xml) + class Site: def __init__(self, site): self.id = site['site_id'] + self.idtag = "s%s" % self.id self.node_ids = site['node_ids'] self.name = site['abbreviated_name'].replace(" ", "_") self.tag = site['login_base'] @@ -230,7 +210,17 @@ class Site: def add_link(self, link): self.links.add(link) - + + def toxml(self, xml, hrn, nodes): + if not (self.public and self.enabled and self.node_ids): + return + with xml.site(id = self.idtag): + with xml.name: + xml << self.name + + for node in self.get_sitenodes(nodes): + node.toxml(xml, hrn) + class Slice: def __init__(self, slice): @@ -422,8 +412,11 @@ class Topology: pass + """ Lookup site based on id or idtag value """ def lookupSite(self, id): val = None + if isinstance(id, basestring): + id = int(id.lstrip('s')) try: val = self.sites[id] except: @@ -436,8 +429,11 @@ class Topology: sites.append(self.sites[s]) return sites + """ Lookup node based on id or idtag value """ def lookupNode(self, id): val = None + if isinstance(id, basestring): + id = int(id.lstrip('n')) try: val = self.nodes[id] except: @@ -453,8 +449,9 @@ class Topology: def nodesInTopo(self): nodes = [] for n in self.nodes: - if self.nodes[n].links: - nodes.append(self.nodes[n]) + node = self.nodes[n] + if node.sliver: + nodes.append(node) return nodes def lookupSliceTag(self, id): @@ -481,6 +478,48 @@ class Topology: return link return None + + def __add_vlink(self, vlink, slicenodes, parent = None): + n1 = n2 = None + if 'endpoints' in vlink: + end = vlink['endpoints'].split() + n1 = self.lookupNode(end[0]) + n2 = self.lookupNode(end[1]) + elif parent: + """ Try to infer the endpoints """ + (n1, n2) = self.__infer_endpoints(parent['endpoints'],slicenodes) + else: + raise Error("no endpoints given") + + #print "Added virtual link: %s -- %s" % (n1.tag, n2.tag) + bps = int(vlink['kbps'][0]) * 1000 + sitelink = self.lookupSiteLink(n1, n2) + if not sitelink: + raise PermissionError("nodes %s and %s not adjacent" % + (n1.idtag, n2.idtag)) + self.nodelinks.append(Link(n1, n2, bps, sitelink)) + return + + """ + Infer the endpoints of the virtual link. If the slice exists on + only a single node at each end of the physical link, we'll assume that + the user wants the virtual link to terminate at these nodes. + """ + def __infer_endpoints(self, endpoints, slicenodes): + n = [] + ends = endpoints.split() + for end in ends: + found = 0 + site = self.lookupSite(end) + for id in site.node_ids: + if id in slicenodes: + n.append(slicenodes[id]) + found += 1 + if found != 1: + raise Error("could not infer endpoint for site %s" % site.id) + #print "Inferred endpoints: %s %s" % (n[0].idtag, n[1].idtag) + return n + def nodeTopoFromRSpec(self, rspec): if self.nodelinks: raise Error("virtual topology already present") @@ -488,20 +527,39 @@ class Topology: rspecdict = rspec.toDict() nodedict = {} for node in self.getNodes(): - nodedict[node.tag] = node + nodedict[node.idtag] = node - linkspecs = rspecdict['RSpec']['Request'][0]['NetSpec'][0]['LinkSpec'] - for l in linkspecs: - n1 = nodedict[l['endpoint'][0]] - n2 = nodedict[l['endpoint'][1]] - bps = int(l['kbps'][0]) * 1000 - self.nodelinks.append(Link(n1, n2, bps)) - + slicenodes = {} + + top = rspecdict['rspec'] + if ('network' in top): + sites = top['network'][0]['site'] + for site in sites: + for node in site['node']: + if 'sliver' in node: + n = nodedict[node['id']] + slicenodes[n.id] = n + n.add_sliver() + links = top['network'][0]['link'] + for link in links: + if 'vlink' in link: + for vlink in link['vlink']: + self.__add_vlink(vlink, slicenodes, link) + elif ('request' in top): + for sliver in top['request'][0]['sliver']: + n = nodedict[sliver['nodeid']] + slicenodes[n.id] = n + n.add_sliver() + for vlink in top['request'][0]['vlink']: + self.__add_vlink(vlink, slicenodes) + return + def nodeTopoFromSliceTags(self, slice): if self.nodelinks: raise Error("virtual topology already present") for node in slice.get_nodes(self.nodes): + node.sliver = True linktag = slice.get_tag('topo_rspec', self.tags, node) if linktag: l = eval(linktag.value) @@ -509,7 +567,8 @@ class Topology: if node.id < id: bps = get_tc_rate(bw) remote = self.lookupNode(id) - self.nodelinks.append(Link(node, remote, bps)) + sitelink = self.lookupSiteLink(node, remote) + self.nodelinks.append(Link(node,remote,bps,sitelink)) def updateSliceTags(self, slice): if not self.nodelinks: @@ -538,14 +597,10 @@ class Topology: """ Check the requested topology against the available topology and capacity """ - def verifyNodeTopo(self, hrn, topo, maxbw): - maxbps = get_tc_rate(maxbw) + def verifyNodeTopo(self, hrn, topo): for link in self.nodelinks: if link.bps <= 0: - raise SfaInvalidArgument(bw, "BW") - if link.bps > maxbps: - raise PermissionError(" %s requested %s but max BW is %s" % - (hrn, format_tc_rate(link.bps), maxbw)) + raise GeniInvalidArgument(bw, "BW") n1 = link.end1 n2 = link.end2 @@ -559,72 +614,20 @@ class Topology: Produce XML directly from the topology specification. """ def toxml(self, hrn = None): - xml = """ - - - """ - - for site in self.getSites(): - if not (site.public and site.enabled and site.node_ids): - continue - - xml += """ - """ % site.name - - for node in site.get_sitenodes(self.nodes): - if not node.tag: - continue + xml = XMLBuilder() + with xml.rspec(type="VINI"): + if hrn: + element = xml.network(name="Public VINI", slice=hrn) + else: + element = xml.network(name="Public VINI") - xml += """ - - %s - %s - """ % (node.tag, node.hostname, int(node.bps/1000)) - xml += """ - """ - - for link in self.sitelinks: - xml += """ - - %s - %s - %s - """ % (link.end1.name, link.end2.name, int(link.bps/1000)) - - - if hrn: - name = hrn - else: - name = 'default_topology' - xml += """ - - - - """ % name - - if hrn: - for link in self.nodelinks: - xml += """ - - %s - %s - %s - """ % (link.end1.tag, link.end2.tag, int(link.bps/1000)) - else: - xml += default_topo_xml - - xml += """ - - -""" - - # Remove all leading whitespace and newlines - lines = xml.split("\n") - noblanks = "" - for line in lines: - noblanks += line.strip() - return noblanks + with element: + for site in self.getSites(): + site.toxml(xml, hrn, self.nodes) + for link in self.sitelinks: + link.toxml(xml) + return str(xml) """ Create a dictionary of site objects keyed by site ID -- 2.43.0