# $Id$ # $URL$ """ Scan the VINI Central database and create topology "rspec" tags for slices that have an EGRE key. This script to be run from a cron job. """ import string import socket from topology import links 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) 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] # What nodes in the set of node_ids are adjacent to this one? 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_rspecs(self): self.rspecs = [] def add_rspec(self, remote): my_ip = self.get_virt_ip(remote) remote_ip = remote.get_virt_ip(self) net = self.get_virt_net(remote) rspec = remote.id, remote.ipaddr, "1Mbit", my_ip, remote_ip, net self.rspecs.append(rspec) 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 def add_tag(self, tagname, value, slicetags, dryrun, node = None): if node: id = AddSliceTag(self.id, tagname, value, node.id) else: id = AddSliceTag(self.id, tagname, value) record = GetSliceTags([id])[0] tag = Slicetag(record) slicetags[id] = tag self.slice_tag_ids.append(id) return tag def update_tag(self, tagname, value, slicetags, dryrun, node = None): tag = self.get_tag(tagname, slicetags, node) if tag and tag.value == value: value = "no change" elif not dryrun: if tag: UpdateSliceTag(tag.id, value) else: tag = self.add_tag(tagname, value, slicetags, dryrun, node) if tag: tag.updated = 1 id = tag.id else: id = 'new' if dryrun: if node: print "[%s] %s: %s (%s)" % (id, tagname, value, node.shortname) else: print "[%s] %s: %s" % (id, tagname, value) """ Update the vsys/setup-link and vsys/setup-nat slice tags. """ def add_vsys_tags(self, slicetags, dryrun): 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, dryrun) if not nat: self.add_tag('vsys', 'setup-nat', slicetags, dryrun) class Slicetag: def __init__(self, tag): self.id = tag['slice_tag_id'] self.slice_id = tag['slice_id'] self.tagname = tag['tagname'] self.value = tag['value'] self.node_id = tag['node_id'] self.updated = 0 """ 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(): tmp = [] for node in GetNodes(): t = node['node_id'], Node(node) tmp.append(t) return dict(tmp) """ Create a dictionary of slice objects keyed by slice ID """ def get_slices(): tmp = [] for slice in GetSlices(): t = slice['slice_id'], Slice(slice) tmp.append(t) return dict(tmp) """ Create a dictionary of slicetag objects keyed by slice tag ID """ def get_slice_tags(): tmp = [] for tag in GetSliceTags(): t = tag['slice_tag_id'], Slicetag(tag) tmp.append(t) return dict(tmp) """ Find a free EGRE key """ def free_egre_key(slicetags): for i in slicetags: used = set() 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 # For debugging dryrun = 0 sites = get_sites() nodes = get_nodes() slices = get_slices() slicetags = get_slice_tags() # Add adjacencies for (a, b) in links: sites[a].add_adjacency(sites[b]) sites[b].add_adjacency(sites[a]) for i in slices: slice = slices[i] tag = slice.get_tag('vini_topo', slicetags) if tag: topo_type = tag.value else: topo_type = None if topo_type == 'vsys' or topo_type == 'iias': """ Assign EGRE key to the slice if needed If no 'netns' attribute, add netns/1 For 'vsys', add vsys/setup-link and vsys/setup-nat """ if not slice.get_tag('egre_key', slicetags): key = free_egre_key(slicetags) slice.update_tag('egre_key', key, slicetags, dryrun) if topo_type == 'vsys' and slice.get_tag('egre_key', slicetags): slice.add_vsys_tags(slicetags, dryrun) if topo_type == 'iias' and slice.get_tag('egre_key', slicetags): if dryrun: print "Virtual topology for %s:" % slice.name if not slice.get_tag('netns', slicetags): slice.update_tag('netns', '1', slicetags, dryrun) hosts = "127.0.0.1\t\tlocalhost\n" """ For each node in the slice, check whether the slice is running on any adjacent nodes. For each pair of adjacent nodes, add to nodes' rspecs. """ for node in slice.get_nodes(nodes): node.init_rspecs() adj_nodes = node.adjacent_nodes(sites, nodes, slice.node_ids) for adj in adj_nodes: node.add_rspec(adj) hosts += "%s\t\t%s\n" % (node.get_virt_ip(adj), node.shortname) if node.rspecs: topo_str = "%s" % node.rspecs slice.update_tag('topo_rspec', topo_str, slicetags, dryrun, node) slice.update_tag('hosts', hosts, slicetags, dryrun) else: if dryrun: print "Slice %s not using IIAS" % slice.name # Remove old topo_rspec entries for i in slicetags: tag = slicetags[i] if (tag.tagname == 'topo_rspec' or tag.tagname == 'hosts') and not tag.updated: if dryrun: slice = slices[tag.slice_id].name if tag.node_id: node = nodes[tag.node_id].hostname print "Deleting tag %s (%s, %s)" % (tag.id, slice, node) else: print "Deleting tag %s (%s)" % (tag.id, slice) else: DeleteSliceTag(tag.id)