X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sfa%2Frspecs%2Faggregates%2Frspec_manager_vini.py;h=20dc7fb566e57aa4dea4402e6e4286bd9a81f131;hb=3d7237fa0b5f2b4a60cb97c7fb3b6aecfd94558a;hp=dff71a84a48f47bd627894980a9dbda7269246b7;hpb=cba129da4df6ed490942dcc0625b884148a74a2e;p=sfa.git diff --git a/sfa/rspecs/aggregates/rspec_manager_vini.py b/sfa/rspecs/aggregates/rspec_manager_vini.py index dff71a84..20dc7fb5 100644 --- a/sfa/rspecs/aggregates/rspec_manager_vini.py +++ b/sfa/rspecs/aggregates/rspec_manager_vini.py @@ -1,313 +1,27 @@ from sfa.util.faults import * -from sfa.util.misc import * -from sfa.util.rspec import Rspec +from sfa.util.namespace 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.rspec import * import sys -import socket - -SFA_VINI_DEFAULT_RSPEC = '/etc/sfa/vini.rspec' - -class Node: - def __init__(self, node): - self.id = node['node_id'] - self.hostname = node['hostname'] - self.shortname = self.hostname.replace('.vini-veritas.net', '') - self.site_id = node['site_id'] - self.ipaddr = socket.gethostbyname(self.hostname) - self.links = [] - - def get_link_id(self, remote): - if self.id < remote.id: - link = (self.id<<7) + remote.id - else: - link = (remote.id<<7) + self.id - return link - - def get_iface_id(self, remote): - if self.id < remote.id: - iface = 1 - else: - iface = 2 - return iface - - def get_virt_ip(self, remote): - link = self.get_link_id(remote) - iface = self.get_iface_id(remote) - first = link >> 6 - second = ((link & 0x3f)<<2) + iface - return "192.168.%d.%d" % (first, second) - - def get_virt_net(self, remote): - link = self.get_link_id(remote) - first = link >> 6 - second = (link & 0x3f)<<2 - return "192.168.%d.%d/30" % (first, second) - - def get_site(self, sites): - return sites[self.site_id] - - def adjacent_nodes(self, sites, nodes, node_ids): - mysite = self.get_site(sites) - adj_ids = mysite.adj_node_ids.intersection(node_ids) - adj_nodes = [] - for id in adj_ids: - adj_nodes.append(nodes[id]) - return adj_nodes - - def init_links(self): - self.links = [] - - def add_link(self, remote, bw): - my_ip = self.get_virt_ip(remote) - remote_ip = remote.get_virt_ip(self) - net = self.get_virt_net(remote) - link = remote.id, remote.ipaddr, bw, my_ip, remote_ip, net - self.links.append(link) - - -class Site: - def __init__(self, site): - self.id = site['site_id'] - self.node_ids = site['node_ids'] - self.adj_site_ids = set() - self.adj_node_ids = set() - - def get_sitenodes(self, nodes): - n = [] - for i in self.node_ids: - n.append(nodes[i]) - return n - - def add_adjacency(self, site): - self.adj_site_ids.add(site.id) - for n in site.node_ids: - self.adj_node_ids.add(n) - - -class Slice: - def __init__(self, slice): - self.id = slice['slice_id'] - self.name = slice['name'] - self.node_ids = set(slice['node_ids']) - self.slice_tag_ids = slice['slice_tag_ids'] - - def get_tag(self, tagname, slicetags, node = None): - for i in self.slice_tag_ids: - tag = slicetags[i] - if tag.tagname == tagname: - if (not node) or (node.id == tag.node_id): - return tag - else: - return None - - def get_nodes(self, nodes): - n = [] - for id in self.node_ids: - n.append(nodes[id]) - return n - - - # Add a new slice tag - def add_tag(self, tagname, value, slicetags, node = None): - record = {'slice_tag_id':None, 'slice_id':self.id, 'tagname':tagname, 'value':value} - if node: - record['node_id'] = node.id - else: - record['node_id'] = None - tag = Slicetag(record) - slicetags[tag.id] = tag - self.slice_tag_ids.append(tag.id) - tag.changed = True - tag.updated = True - return tag - - # Update a slice tag if it exists, else add it - def update_tag(self, tagname, value, slicetags, node = None): - tag = self.get_tag(tagname, slicetags, node) - if tag and tag.value == value: - value = "no change" - elif tag: - tag.value = value - tag.changed = True - else: - tag = self.add_tag(tagname, value, slicetags, node) - tag.updated = True - - def assign_egre_key(self, slicetags): - if not self.get_tag('egre_key', slicetags): - try: - key = free_egre_key(slicetags) - self.update_tag('egre_key', key, slicetags) - except: - # Should handle this case... - pass - return - - def turn_on_netns(self, slicetags): - tag = self.get_tag('netns', slicetags) - if (not tag) or (tag.value != '1'): - self.update_tag('netns', '1', slicetags) - return - - def turn_off_netns(self, slicetags): - tag = self.get_tag('netns', slicetags) - if tag and (tag.value != '0'): - tag.delete() - return - - def add_cap_net_admin(self, slicetags): - tag = self.get_tag('capabilities', slicetags) - if tag: - caps = tag.value.split(',') - for cap in caps: - if cap == "CAP_NET_ADMIN": - return - else: - newcaps = "CAP_NET_ADMIN," + tag.value - self.update_tag('capabilities', newcaps, slicetags) - else: - self.add_tag('capabilities', 'CAP_NET_ADMIN', slicetags) - return - - def remove_cap_net_admin(self, slicetags): - tag = self.get_tag('capabilities', slicetags) - if tag: - caps = tag.value.split(',') - newcaps = [] - for cap in caps: - if cap != "CAP_NET_ADMIN": - newcaps.append(cap) - if newcaps: - value = ','.join(newcaps) - self.update_tag('capabilities', value, slicetags) - else: - tag.delete() - return - - # Update the vsys/setup-link and vsys/setup-nat slice tags. - def add_vsys_tags(self, slicetags): - link = nat = False - for i in self.slice_tag_ids: - tag = slicetags[i] - if tag.tagname == 'vsys': - if tag.value == 'setup-link': - link = True - elif tag.value == 'setup-nat': - nat = True - if not link: - self.add_tag('vsys', 'setup-link', slicetags) - if not nat: - self.add_tag('vsys', 'setup-nat', slicetags) - return - - -class Slicetag: - newid = -1 - def __init__(self, tag): - self.id = tag['slice_tag_id'] - if not self.id: - # Make one up for the time being... - self.id = Slicetag.newid - Slicetag.newid -= 1 - self.slice_id = tag['slice_id'] - self.tagname = tag['tagname'] - self.value = tag['value'] - self.node_id = tag['node_id'] - self.updated = False - self.changed = False - self.deleted = False - - # Mark a tag as deleted - def delete(self): - self.deleted = True - self.updated = True - - def write(self, api): - if self.changed: - if int(self.id) > 0: - api.plshell.UpdateSliceTag(api.plauth, self.id, self.value) - else: - api.plshell.AddSliceTag(api.plauth, self.slice_id, - self.tagname, self.value, self.node_id) - elif self.deleted and int(self.id) > 0: - api.plshell.DeleteSliceTag(api.plauth, self.id) - -""" -Create a dictionary of site objects keyed by site ID -""" -def get_sites(): - tmp = [] - for site in GetSites(): - t = site['site_id'], Site(site) - tmp.append(t) - return dict(tmp) - - -""" -Create a dictionary of node objects keyed by node ID -""" -def get_nodes(api): - tmp = [] - for node in api.plshell.GetNodes(api.plauth): - t = node['node_id'], Node(node) - tmp.append(t) - return dict(tmp) - -""" -Create a dictionary of slice objects keyed by slice ID -""" -def get_slice(api, slicename): - slice = api.plshell.GetSlices(api.plauth, [slicename]) - if slice: - return Slice(slice[0]) - else: - return None - -""" -Create a dictionary of slicetag objects keyed by slice tag ID -""" -def get_slice_tags(api): - tmp = [] - for tag in api.plshell.GetSliceTags(api.plauth): - t = tag['slice_tag_id'], Slicetag(tag) - tmp.append(t) - return dict(tmp) - -""" -Find a free EGRE key -""" -def free_egre_key(slicetags): - used = set() - for i in slicetags: - tag = slicetags[i] - if tag.tagname == 'egre_key': - used.add(int(tag.value)) - - for i in range(1, 256): - if i not in used: - key = i - break - else: - raise KeyError("No more EGRE keys available") - - return "%s" % key - +SFA_VINI_WHITELIST = '/etc/sfa/vini.whitelist' """ Copied from create_slice_aggregate() in sfa.plc.slices """ def create_slice_vini_aggregate(api, hrn, nodes): - # Get the slice record from geni + # Get the slice record from SFA slice = {} registries = Registries(api) registry = registries[api.hrn] credential = api.getCredential() records = registry.resolve(credential, hrn) for record in records: - if record.get_type() in ['slice']: - slice = record.as_dict() + if record['type'] in ['slice']: + slice = record if not slice: raise RecordNotFound(hrn) @@ -325,8 +39,7 @@ def create_slice_vini_aggregate(api, hrn, nodes): site_record = {} if not site_records: raise RecordNotFound(authority) - site_record = site_records[0] - site = site_record.as_dict() + site = site_records[0] # add the site site.pop('site_id') @@ -352,11 +65,11 @@ def create_slice_vini_aggregate(api, hrn, nodes): person_record = {} person_records = registry.resolve(credential, researcher) for record in person_records: - if record.get_type() in ['user']: + if record['type'] in ['user']: person_record = record if not person_record: pass - person_dict = person_record.as_dict() + person_dict = person_record persons = api.plshell.GetPersons(api.plauth, [person_dict['email']], ['person_id', 'key_ids']) @@ -399,7 +112,7 @@ def create_slice_vini_aggregate(api, hrn, nodes): # add nodes from rspec added_nodes = list(set(nodes).difference(hostnames)) -""" + """ print >> sys.stderr, "Slice on nodes:" for n in hostnames: print >> sys.stderr, n @@ -412,7 +125,7 @@ def create_slice_vini_aggregate(api, hrn, nodes): print >> sys.stderr, "Adding nodes:" for n in added_nodes: print >> sys.stderr, n -""" + """ api.plshell.AddSliceToNodes(api.plauth, slicename, added_nodes) api.plshell.DeleteSliceFromNodes(api.plauth, slicename, deleted_nodes) @@ -420,153 +133,74 @@ 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) - + topo = Topology(api) 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 - - 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) + slice.hrn = hrn + topo.nodeTopoFromSliceTags(slice) + else: + # call the default sfa.plc.nodes.get_rspec() method + return Nodes(api).get_rspec(hrn) - 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 topo.toxml(hrn) - return rspec +""" +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: + 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 - # 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 + topo.verifyNodeTopo(hrn, topo, 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 +""" +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}, + 'slice':{'hrn':slice_hrn}}} + return base_context def main(): - r = Rspec() + r = RSpec() r.parseFile(sys.argv[1]) rspec = r.toDict() create_slice(None,'plc',rspec) - + if __name__ == "__main__": main()