0f26bbde3e7d692c4ad4c5ea55d4428443eb084e
[nodemanager-topo.git] / create-topo-attributes.py
1 #!/usr/bin/python
2
3 # $Id$
4 # $URL$
5
6
7 import string
8 import socket
9 import sys
10 import optparse
11 from time import time
12
13 # Load shell with default configuration
14 sys.path.append('/usr/share/plc_api')
15 from PLC.Shell import Shell
16 plc = Shell(globals())
17
18 parser = optparse.OptionParser()
19 parser.add_option('-l', '--linkspec', action='store_true', dest='genlinkspec', default=False, help='Generate linkspec dict.')
20 (options, args) = parser.parse_args()
21
22 #
23 # Links in the physical topology, gleaned from looking at the Internet2
24 # and NLR topology maps.  Link (a, b) connects sites with IDs a and b.
25 #
26 links = [(2, 12),  # I2 Princeton - New York 
27          (4, 5),   # NLR Chicago - Houston
28          (4, 6),   # NLR Chicago - Atlanta
29          (4, 7),   # NLR Chicago - Seattle
30          (4, 9),   # NLR Chicago - New York
31          (4, 10),  # NLR Chicago - Wash DC
32          (5, 6),   # NLR Houston - Atlanta
33          (5, 8),   # NLR Houston - Los Angeles
34          (6, 10),  # NLR Atlanta - Wash DC
35          (7, 8),   # NLR Seattle - Los Angeles
36          (9, 10),  # NLR New York - Wash DC
37          (11, 13), # I2 Chicago - Wash DC
38          (11, 15), # I2 Chicago - Atlanta
39          (11, 16), # I2 Chicago - CESNET
40          (11, 17), # I2 Chicago - Kansas City
41          (12, 13), # I2 New York - Wash DC
42          (13, 15), # I2 Wash DC - Atlanta
43          (15, 19), # I2 Atlanta - Houston
44          (17, 19), # I2 Kansas City - Houston
45          (17, 22), # I2 Kansas City - Salt Lake City
46          (19, 20), # I2 Houston - Los Angeles
47          (20, 21), # I2 Los Angeles - Seattle
48          (20, 22), # I2 Los Angeles - Salt Lake City
49          (21, 22)] # I2 Seattle - Salt Lake City
50
51
52 def gen_adjacencies(links):
53     """
54     Generate site adjacency map from list of links
55     """
56     adj = {}
57     for (a, b) in links:
58         if a in adj:
59             adj[a].append(b)
60         else:
61             adj[a] = [a, b]
62         if b in adj:
63             adj[b].append(a)
64         else:
65             adj[b] = [b, a]
66     return adj
67
68
69 def is_adjacent(adjacencies, s1, s2):
70     """
71     Test whether two sites are adjacent to each other in the adjacency graph.
72     """
73     set1 = set(adjacencies[s1])
74     set2 = set(adjacencies[s2])
75
76     if s1 in set2 and s2 in set1:
77         return True
78     elif not s1 in set2 and not s2 in set1:
79         return False
80     else:
81         raise Exception("Adjacency mismatch, sites %d and %d." % (s1, s2))
82
83
84 def check_adjacencies(adjacencies):
85     """
86     Check the adjacency graph for discrepancies.
87     """
88     for site in adjacencies:
89         for adj in adjacencies[site]:
90             try:
91                 test = is_adjacent(adjacencies, site, adj)
92             except Exception, e:
93                 print "Error: ", e, " Fix adjacencies!"
94     return
95
96
97 def get_site(nodeid):
98     if nodes[nodeid]:
99         return nodes[nodeid]['site_id']
100     raise Exception("Nodeid %s not found." % nodeid)
101
102
103 def get_ipaddr(nodeid):
104     if nodes[nodeid]:
105         return socket.gethostbyname(nodes[nodeid]['hostname'])
106     raise Exception("Nodeid %s not found." % nodeid)
107
108
109 def get_sitenodes(siteid):
110     if sites[siteid]:
111         return sites[siteid]['node_ids']
112     raise Exception("Siteid %s not found." % siteid)
113
114
115 def get_virt_ip(myid, nodeid):
116     """
117     Find the IP address assigned to a virtual interface in the topology
118     (for creating /etc/hosts)
119     """
120     if myid < nodeid:
121         virtip = "10.%d.%d.2" % (myid, nodeid)
122     else:
123         virtip = "10.%d.%d.3" % (nodeid, myid)
124     return virtip
125
126
127 def get_sites():
128     """
129     Create a dictionary of site records keyed by site ID
130     """
131     tmp = {}
132     for site in GetSites():
133         tmp[site['site_id']] = site
134     return tmp
135
136
137 def get_nodes():
138     """
139     Create a dictionary of node records keyed by node ID
140     """
141     tmp = {}
142     for node in GetNodes():
143         tmp[node['node_id']] = node
144     return tmp
145
146
147 def ifSpecDict(nodedict):
148     """
149     Generate ifspec dict for given node dict.
150     """
151     # ifspecattrs = ['name',
152     #            'addr',
153     #            'type', 
154     #            'init_params', 
155     #            'bw', 
156     #            'min_alloc', 
157     #            'max_alloc', 
158     #            'ip_spoof']
159     # Assume only 1 node network per node.
160     nodenetwork = GetNodeNetworks(nodedict['nodenetwork_ids'])[0]
161     ifspecs = {'name': nodenetwork['hostname'],
162                'addr': nodenetwork['ip'],
163                'type': nodenetwork['type'],
164                'init_params': None,
165                'bw': '1Gps',
166                'min_alloc': 0,
167                'max_alloc': '1Gbps',
168                'ip_spoof': False}
169     return ifspecs
170
171
172 def linkSpecDict():
173     """
174     Create dict for physical topology.
175     """
176     # list of attributes in the LinkSpec 
177     # (https://svn.planet-lab.org/svn/geniwrapper/trunk/rspec/model/planetlab.{ecore,xsd})
178     # linkspecattrs = ['type', 
179     #            'init_params', 
180     #            'bw', 
181     #            'min_alloc', 
182     #            'max_alloc', 
183     #            'endpoint', # <-- ifspec(S)?
184     #            'start_time', 
185     #            'duration']
186     # list of linkspecs.  1 per adjacency 
187     linkspecs = []
188     # links maps sites.  Get nodes in site, make linkspecs for each.
189     for (i, j) in links:
190         print "sites = (%s, %s) nodes = %s" %(i,j, GetNodes({'site_id':[i,j]}, ['node_id']))
191         nodeset = GetNodes({'site_id':[i,j]})
192         ifspecs = []
193         for node in nodeset: 
194             ifspecs.append(ifSpecDict(node))
195         linkspecs.append({\
196                 'type': 'ipv4',
197                 'init_params': None,
198                 'bw': '1Gbps',
199                 'min_alloc': '0',
200                 'bw': '1Gbps',
201                 'endpoints': ifspecs,
202                 'start_time': int(time()),
203                 'duration': '-1'})
204     return linkspecs
205
206
207 adjacencies = gen_adjacencies(links)    
208 check_adjacencies(adjacencies)
209     
210 """ Need global topology information """
211 sites = get_sites()
212 nodes = get_nodes()
213         
214
215 def main():
216     """
217     Scan the VINI Central database and create topology "rspec" attributes for
218     slices that have an EGRE key.  This script to be run from a cron job.
219     """
220   
221     for slice in GetSlices():
222         """ Create dictionary of the slice's attributes """
223         attrs ={}
224         topo_attr = {}
225         for attribute in GetSliceAttributes(slice['slice_attribute_ids']):
226             attrs[attribute['name']] = attribute['slice_attribute_id']
227             if attribute['name'] == 'topo_rspec' and attribute['node_id']:
228                 topo_attr[attribute['node_id']] = attribute['slice_attribute_id']
229                 
230         if 'egre_key' in attrs:
231             #print "Virtual topology for %s:" % slice['name']
232             slicenodes = set(slice['node_ids'])
233             hosts = "127.0.0.1\t\tlocalhost\n"
234             """
235             For each node in the slice, check whether nodes at adjacent sites
236             are also in the slice's node set.  If so, add a virtual link to 
237             the rspec.  
238             """
239             for node in slicenodes:
240                 topo = []
241                 for adj in adjacencies[get_site(node)]:
242                     for adj_node in get_sitenodes(adj):
243                         if node != adj_node and adj_node in slicenodes:
244                             link = adj_node, get_ipaddr(adj_node), "1Mbit"
245                             topo.append(link)
246                             shortname = nodes[node]['hostname'].replace('.vini-veritas.net', '')
247                             hosts += "%s\t\t%s\n" % (get_virt_ip(node, adj_node),
248                                                       shortname)
249                 topo_str = "%s" % topo
250                 #print node, topo_str
251                 if node in topo_attr:
252                     UpdateSliceAttribute(topo_attr[node], topo_str)
253                     del topo_attr[node]
254                 else:
255                     id = slice['slice_id']
256                     AddSliceAttribute(id, 'topo_rspec', topo_str, node)
257     
258             #print hosts
259             if 'hosts' in attrs:
260                 UpdateSliceAttribute(attrs['hosts'], hosts)
261             else:
262                 id = slice['slice_id']
263                 AddSliceAttribute(id, 'hosts', hosts)
264         #else:
265             #print "No EGRE key for %s" % slice['name']
266     
267         """ Remove old topo_rspec entries """
268         for node in topo_attr:
269             DeleteSliceAttribute(topo_attr[node])
270     
271    
272
273 if __name__ == '__main__':
274     if options.genlinkspec: 
275         import pprint
276         pp = pprint
277         print "LinkSpecs ="
278         pp.pprint(linkSpecDict())
279     else:
280         print "Main" 
281         main()