Assign EGRE keys and vsys attributes
[nodemanager-topo.git] / create-topo-attributes.py
1 # $Id$
2 # $URL$
3
4 """
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.
7 """
8
9 import string
10 import socket
11 from topology import links
12
13 class Node:
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)
20
21     def get_link_id(self, remote):
22         if self.id < remote.id:
23             link = (self.id<<7) + remote.id
24         else:
25             link = (remote.id<<7) + self.id
26         return link
27         
28     def get_iface_id(self, remote):
29         if self.id < remote.id:
30             iface = 1
31         else:
32             iface = 2
33         return iface
34     
35     def get_virt_ip(self, remote):
36         link = self.get_link_id(remote)
37         iface = self.get_iface_id(remote)
38         first = link >> 6
39         second = ((link & 0x3f)<<2) + iface
40         return "192.168.%d.%d" % (first, second)
41
42     def get_virt_net(self, remote):
43         link = self.get_link_id(remote)
44         first = link >> 6
45         second = (link & 0x3f)<<2
46         return "192.168.%d.%d/30" % (first, second)
47         
48     def get_site(self, sites):
49         return sites[self.site_id]
50             
51     
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)
56         adj_nodes = []
57         for id in adj_ids:
58             adj_nodes.append(nodes[id])
59         return adj_nodes
60     
61     def init_rspecs(self):
62         self.rspecs = []
63         
64     def add_rspec(self, remote):
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, "1Mbit", my_ip, remote_ip, net
69         self.rspecs.append(rspec)
70
71         
72 class Site:
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()
78
79     def get_sitenodes(self, nodes):
80         n = []
81         for i in self.node_ids:
82             n.append(nodes[i])
83         return n
84     
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)
89         
90     
91 class Slice:
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']
97     
98     def get_tag(self, tagname, slicetags, node = None):
99         for i in self.slice_tag_ids:
100             tag = slicetags[i]
101             if tag.tagname == tagname:
102                 if (not node) or (node.id == tag.node_id):
103                     return tag
104         else:
105             return None
106         
107     def get_nodes(self, nodes):
108         n = []
109         for id in self.node_ids:
110             n.append(nodes[id])
111         return n
112              
113              
114     def add_tag(self, tagname, value, slicetags, dryrun, node = None):
115         if node:
116             id = AddSliceTag(self.id, tagname, value, node.id)
117         else:
118             id = AddSliceTag(self.id, tagname, value)
119             
120         record = GetSliceTags([id])[0]
121         tag = Slicetag(record)
122         slicetags[id] = tag
123         self.slice_tag_ids.append(id)
124         
125         return tag
126                 
127     def update_tag(self, tagname, value, slicetags, dryrun, node = None):
128         tag = self.get_tag(tagname, slicetags, node)
129         
130         if tag and tag.value == value:
131             value = "no change"
132         elif not dryrun:
133             if tag:
134                 UpdateSliceTag(tag.id, value)
135             else:
136                 tag = self.add_tag(tagname, value, slicetags, dryrun, node)
137             
138         if tag: 
139             tag.updated = 1
140             id = tag.id
141         else:
142             id = 'new'
143             
144         if dryrun:
145             if node:
146                 print "[%s] %s: %s (%s)" % (id, tagname, value, node.shortname)
147             else:
148                 print "[%s] %s: %s" % (id, tagname, value)
149
150     """
151     Update the vsys/setup-link and vsys/setup-nat slice tags.
152     """
153     def add_vsys_tags(self, slicetags, dryrun):
154         link = nat = False
155         for i in self.slice_tag_ids:
156             tag = slicetags[i]
157             if tag.tagname == 'vsys':
158                 if tag.value == 'setup-link':
159                     link = True
160                 elif tag.value == 'setup-nat':
161                     nat = True
162         if not link:
163             self.add_tag('vsys', 'setup-link', slicetags, dryrun)
164         if not nat:
165             self.add_tag('vsys', 'setup-nat', slicetags, dryrun)
166
167 class Slicetag:
168     def __init__(self, tag):
169         self.id = tag['slice_tag_id']
170         self.slice_id = tag['slice_id']
171         self.tagname = tag['tagname']
172         self.value = tag['value']
173         self.node_id = tag['node_id']
174         self.updated = 0
175       
176         
177                  
178
179 """
180 Create a dictionary of site objects keyed by site ID
181 """
182 def get_sites():
183     tmp = []
184     for site in GetSites():
185         t = site['site_id'], Site(site)
186         tmp.append(t)
187     return dict(tmp)
188
189
190 """
191 Create a dictionary of node objects keyed by node ID
192 """
193 def get_nodes():
194     tmp = []
195     for node in GetNodes():
196         t = node['node_id'], Node(node)
197         tmp.append(t)
198     return dict(tmp)
199
200 """
201 Create a dictionary of slice objects keyed by slice ID
202 """
203 def get_slices():
204     tmp = []
205     for slice in GetSlices():
206         t = slice['slice_id'], Slice(slice)
207         tmp.append(t)
208     return dict(tmp)
209
210 """
211 Create a dictionary of slicetag objects keyed by slice tag ID
212 """
213 def get_slice_tags():
214     tmp = []
215     for tag in GetSliceTags():
216         t = tag['slice_tag_id'], Slicetag(tag)
217         tmp.append(t)
218     return dict(tmp)
219     
220 """
221 Find a free EGRE key
222 """
223 def free_egre_key(slicetags):
224     for i in slicetags:
225         used = set()
226         tag = slicetags[i]
227         if tag.tagname == 'egre_key':
228             used.add(int(tag.value))
229                 
230     for i in range(1, 256):
231         if i not in used:
232             key = i
233             break
234     else:
235         raise KeyError("No more EGRE keys available")
236         
237     return "%s" % key
238    
239 # For debugging
240 dryrun = 0
241
242 sites = get_sites()
243 nodes = get_nodes()
244 slices = get_slices()
245 slicetags = get_slice_tags()
246
247 # Add adjacencies
248 for (a, b) in links:
249     sites[a].add_adjacency(sites[b])
250     sites[b].add_adjacency(sites[a])  
251
252 for i in slices:
253     slice = slices[i]
254     tag = slice.get_tag('vini_topo', slicetags)
255     if tag:
256         topo_type = tag.value
257     else:
258         topo_type = None
259     
260     if topo_type == 'vsys' or topo_type == 'iias':
261         """ 
262         Assign EGRE key to the slice if needed
263         If no 'netns' attribute, add netns/1
264         For 'vsys', add vsys/setup-link and vsys/setup-nat
265         """
266         if not slice.get_tag('egre_key', slicetags):
267             key = free_egre_key(slicetags)
268             slice.update_tag('egre_key', key, slicetags, dryrun)
269             
270     if topo_type == 'vsys' and slice.get_tag('egre_key', slicetags):
271         slice.add_vsys_tags(slicetags, dryrun)
272         
273     if topo_type == 'iias' and slice.get_tag('egre_key', slicetags):
274         if dryrun:
275             print "Virtual topology for %s:" % slice.name
276             
277         if not slice.get_tag('netns', slicetags):
278             slice.update_tag('netns', '1', slicetags, dryrun)
279             
280         hosts = "127.0.0.1\t\tlocalhost\n"
281         """
282         For each node in the slice, check whether the slice is running on any
283         adjacent nodes.  For each pair of adjacent nodes, add to nodes' rspecs.
284         """
285         for node in slice.get_nodes(nodes):
286             node.init_rspecs()
287             adj_nodes = node.adjacent_nodes(sites, nodes, slice.node_ids)
288             for adj in adj_nodes:
289                 node.add_rspec(adj)
290                 hosts += "%s\t\t%s\n" % (node.get_virt_ip(adj), node.shortname)
291             if node.rspecs:
292                 topo_str = "%s" % node.rspecs
293                 slice.update_tag('topo_rspec', topo_str, slicetags, dryrun, node)
294                     
295         slice.update_tag('hosts', hosts, slicetags, dryrun)
296     else:
297         if dryrun:
298             print "Slice %s not using IIAS" % slice.name
299
300 # Remove old topo_rspec entries
301 for i in slicetags:
302     tag = slicetags[i]
303     if (tag.tagname == 'topo_rspec' or tag.tagname == 'hosts') and not tag.updated:
304         if dryrun:
305             slice = slices[tag.slice_id].name
306             if tag.node_id:
307                 node = nodes[tag.node_id].hostname
308                 print "Deleting tag %s (%s, %s)" % (tag.id, slice, node)
309             else:
310                 print "Deleting tag %s (%s)" % (tag.id, slice)
311
312         else:
313             DeleteSliceTag(tag.id)
314
315