5 Scan the VINI Central database and create topology "rspec" tags for
6 slices that have an EGRE key. This script to be run from a cron job.
11 from topology import links, bwlimits
14 def __init__(self, node):
15 self.id = node['node_id']
16 self.hostname = node['hostname']
17 self.shortname = self.hostname.replace('.vini-veritas.net', '')
18 self.site_id = node['site_id']
19 self.ipaddr = socket.gethostbyname(self.hostname)
21 def get_link_id(self, remote):
22 if self.id < remote.id:
23 link = (self.id<<7) + remote.id
25 link = (remote.id<<7) + self.id
28 def get_iface_id(self, remote):
29 if self.id < remote.id:
35 def get_virt_ip(self, remote):
36 link = self.get_link_id(remote)
37 iface = self.get_iface_id(remote)
39 second = ((link & 0x3f)<<2) + iface
40 return "192.168.%d.%d" % (first, second)
42 def get_virt_net(self, remote):
43 link = self.get_link_id(remote)
45 second = (link & 0x3f)<<2
46 return "192.168.%d.%d/30" % (first, second)
48 def get_site(self, sites):
49 return sites[self.site_id]
52 # What nodes in the set of node_ids are adjacent to this one?
53 def adjacent_nodes(self, sites, nodes, node_ids):
54 mysite = self.get_site(sites)
55 adj_ids = mysite.adj_node_ids.intersection(node_ids)
58 adj_nodes.append(nodes[id])
61 def init_rspecs(self):
64 def add_rspec(self, remote, bw):
65 my_ip = self.get_virt_ip(remote)
66 remote_ip = remote.get_virt_ip(self)
67 net = self.get_virt_net(remote)
68 rspec = remote.id, remote.ipaddr, bw, my_ip, remote_ip, net
69 self.rspecs.append(rspec)
73 def __init__(self, site):
74 self.id = site['site_id']
75 self.node_ids = site['node_ids']
76 self.adj_site_ids = set()
77 self.adj_node_ids = set()
79 def get_sitenodes(self, nodes):
81 for i in self.node_ids:
85 def add_adjacency(self, site):
86 self.adj_site_ids.add(site.id)
87 for n in site.node_ids:
88 self.adj_node_ids.add(n)
92 def __init__(self, slice):
93 self.id = slice['slice_id']
94 self.name = slice['name']
95 self.node_ids = set(slice['node_ids'])
96 self.slice_tag_ids = slice['slice_tag_ids']
98 def get_tag(self, tagname, slicetags, node = None):
99 for i in self.slice_tag_ids:
101 if tag.tagname == tagname:
102 if (not node) or (node.id == tag.node_id):
107 def get_nodes(self, nodes):
109 for id in self.node_ids:
114 # Add a new slice tag
115 def add_tag(self, tagname, value, slicetags, node = None):
116 record = {'slice_tag_id':None, 'slice_id':self.id, 'tagname':tagname, 'value':value}
118 record['node_id'] = node.id
120 record['node_id'] = None
121 tag = Slicetag(record)
122 slicetags[tag.id] = tag
123 self.slice_tag_ids.append(tag.id)
128 # Update a slice tag if it exists, else add it
129 def update_tag(self, tagname, value, slicetags, node = None):
130 tag = self.get_tag(tagname, slicetags, node)
131 if tag and tag.value == value:
137 tag = self.add_tag(tagname, value, slicetags, node)
140 def assign_egre_key(self, slicetags):
141 if not self.get_tag('egre_key', slicetags):
143 key = free_egre_key(slicetags)
144 self.update_tag('egre_key', key, slicetags)
146 # Should handle this case...
150 def turn_on_netns(self, slicetags):
151 tag = self.get_tag('netns', slicetags)
152 if (not tag) or (tag.value != '1'):
153 self.update_tag('netns', '1', slicetags)
156 def turn_off_netns(self, slicetags):
157 tag = self.get_tag('netns', slicetags)
158 if tag and (tag.value != '0'):
162 def add_cap_net_admin(self, slicetags):
163 tag = self.get_tag('capabilities', slicetags)
165 caps = tag.value.split(',')
167 if cap == "CAP_NET_ADMIN":
170 newcaps = "CAP_NET_ADMIN," + tag.value
171 self.update_tag('capabilities', newcaps, slicetags)
173 self.add_tag('capabilities', 'CAP_NET_ADMIN', slicetags)
176 def remove_cap_net_admin(self, slicetags):
177 tag = self.get_tag('capabilities', slicetags)
179 caps = tag.value.split(',')
182 if cap != "CAP_NET_ADMIN":
185 value = ','.join(newcaps)
186 self.update_tag('capabilities', value, slicetags)
191 # Update the vsys/setup-link and vsys/setup-nat slice tags.
192 def add_vsys_tags(self, slicetags):
194 for i in self.slice_tag_ids:
196 if tag.tagname == 'vsys':
197 if tag.value == 'setup-link':
199 elif tag.value == 'setup-nat':
202 self.add_tag('vsys', 'setup-link', slicetags)
204 self.add_tag('vsys', 'setup-nat', slicetags)
210 def __init__(self, tag):
211 self.id = tag['slice_tag_id']
213 # Make one up for the time being...
214 self.id = Slicetag.newid
216 self.slice_id = tag['slice_id']
217 self.tagname = tag['tagname']
218 self.value = tag['value']
219 self.node_id = tag['node_id']
224 # Mark a tag as deleted
229 def write(self, slices, nodes, dryrun):
233 UpdateSliceTag(self.id, self.value)
235 AddSliceTag(self.slice_id, self.tagname, self.value, self.node_id)
236 elif self.deleted and int(self.id) > 0:
238 DeleteSliceTag(self.id)
240 print "[%s] %s: could not delete" % (self.id, self.tagname)
243 slice = slices[self.slice_id].name
247 node = nodes[tag.node_id].hostname
250 self.value = "deleted"
251 elif not self.changed:
252 self.value = "no change"
256 print "[%s] %s: %s (%s, %s)" % (self.id, self.tagname, self.value, slice, node)
258 print "[%s] %s: %s (%s)" % (self.id, self.tagname, self.value, slice)
262 Create a dictionary of site objects keyed by site ID
266 for site in GetSites():
267 t = site['site_id'], Site(site)
273 Create a dictionary of node objects keyed by node ID
277 for node in GetNodes():
278 t = node['node_id'], Node(node)
283 Create a dictionary of slice objects keyed by slice ID
287 for slice in GetSlices():
288 t = slice['slice_id'], Slice(slice)
293 Create a dictionary of slicetag objects keyed by slice tag ID
295 def get_slice_tags():
297 for tag in GetSliceTags():
298 t = tag['slice_tag_id'], Slicetag(tag)
305 def free_egre_key(slicetags):
309 if tag.tagname == 'egre_key':
310 used.add(int(tag.value))
312 for i in range(1, 256):
317 raise KeyError("No more EGRE keys available")
326 slices = get_slices()
327 slicetags = get_slice_tags()
331 sites[a].add_adjacency(sites[b])
332 sites[b].add_adjacency(sites[a])
336 tag = slice.get_tag('vini_topo', slicetags)
338 topo_type = tag.value
343 Valid values of topo_type:
344 'vsys': Use vsys topology scripts to set up virtual links
345 'iias': Automatically create a virtual topology mirroring the physical one
346 'manual': Don't modify the topo_rspec tags if present
347 None: No virtual topology
349 if topo_type in ['vsys', 'iias', 'manual']:
350 slice.assign_egre_key(slicetags)
351 slice.turn_on_netns(slicetags)
352 slice.add_cap_net_admin(slicetags)
354 # Let them keep EGRE key for now...
355 slice.turn_off_netns(slicetags)
356 slice.remove_cap_net_admin(slicetags)
358 # Add vsys/setup-link and vsys/setup-nat
359 if topo_type == 'vsys' and slice.get_tag('egre_key', slicetags):
360 slice.add_vsys_tags(slicetags)
362 if topo_type == 'iias' and slice.get_tag('egre_key', slicetags):
364 print "Building virtual topology for %s" % slice.name
366 if slice.name in bwlimits:
367 bw = bwlimits[slice.name]
371 hosts = "127.0.0.1\t\tlocalhost\n"
373 For each node in the slice, check whether the slice is running on any
374 adjacent nodes. For each pair of adjacent nodes, add to nodes' rspecs.
376 for node in slice.get_nodes(nodes):
378 adj_nodes = node.adjacent_nodes(sites, nodes, slice.node_ids)
379 for adj in adj_nodes:
380 node.add_rspec(adj, bw)
381 hosts += "%s\t\t%s\n" % (node.get_virt_ip(adj), node.shortname)
383 topo_str = "%s" % node.rspecs
384 slice.update_tag('topo_rspec', topo_str, slicetags, node)
386 slice.update_tag('hosts', hosts, slicetags)
389 print "Slice %s not using IIAS" % slice.name
391 if topo_type == 'manual' and slice.get_tag('egre_key', slicetags):
392 for node in slice.get_nodes(nodes):
393 topo_tag = slice.get_tag('topo_rspec', slicetags, node)
395 topo_tag.updated = True
397 # Update the tag values in the database
400 if (tag.tagname == 'topo_rspec' or tag.tagname == 'hosts') and not tag.updated:
402 tag.write(slices, nodes, dryrun)