# $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'] self.attrs = {} def get_tag(self, tagname, slicetags): if tagname not in self.attrs: for i in self.slice_tag_ids: if slicetags[i].tagname == tagname: self.attrs[tagname] = slicetags[i] break else: self.attrs[tagname] = None return self.attrs[tagname] def get_nodes(self, nodes): n = [] for id in self.node_ids: n.append(nodes[id]) return n def get_rspec(self, slicetags, node): for i in self.slice_tag_ids: tag = slicetags[i] if tag.tagname == 'topo_rspec' and node.id == tag.node_id: return tag else: return None 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) # 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 slice.get_tag('egre_key', slicetags) and topo_type == 'iias': if dryrun: print "Virtual topology for %s:" % slice.name 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) old_rspec = slice.get_rspec(slicetags, node) if node.rspecs: topo_str = "%s" % node.rspecs if old_rspec: old_rspec.updated = 1 id = old_rspec.id if old_rspec and old_rspec.value == topo_str: topo_str = "no change" elif not dryrun: if old_rspec: UpdateSliceTag(old_rspec.id, topo_str) else: AddSliceTag(slice.id, 'topo_rspec', topo_str, node.id) if dryrun: if not id: id = 'new' print "[%s] rspec for %s: %s" % (id, node.shortname, topo_str) hosttag = slice.get_tag('hosts', slicetags) if hosttag: hosttag.updated = 1 if hosttag and hosts == hosttag.value: hosts = "/etc/hosts: no change" elif not dryrun: if hosttag: UpdateSliceTag(hosttag.id, hosts) else: AddSliceTag(slice.id, 'hosts', hosts) if dryrun: print hosts 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 node = nodes[tag.node_id].hostname print "Deleting topo_rspec tag %s (%s, %s)" % (tag.id, slice, node) else: DeleteSliceTag(tag.id)