1 from sfa.util.faults import *
2 from sfa.util.misc import *
3 from sfa.util.rspec import Rspec
4 from sfa.server.registry import Registries
5 from sfa.plc.nodes import *
9 SFA_VINI_DEFAULT_RSPEC = '/etc/sfa/vini.rspec'
12 def __init__(self, node):
13 self.id = node['node_id']
14 self.hostname = node['hostname']
15 self.shortname = self.hostname.replace('.vini-veritas.net', '')
16 self.site_id = node['site_id']
17 self.ipaddr = socket.gethostbyname(self.hostname)
20 def get_link_id(self, remote):
21 if self.id < remote.id:
22 link = (self.id<<7) + remote.id
24 link = (remote.id<<7) + self.id
27 def get_iface_id(self, remote):
28 if self.id < remote.id:
34 def get_virt_ip(self, remote):
35 link = self.get_link_id(remote)
36 iface = self.get_iface_id(remote)
38 second = ((link & 0x3f)<<2) + iface
39 return "192.168.%d.%d" % (first, second)
41 def get_virt_net(self, remote):
42 link = self.get_link_id(remote)
44 second = (link & 0x3f)<<2
45 return "192.168.%d.%d/30" % (first, second)
47 def get_site(self, sites):
48 return sites[self.site_id]
50 def adjacent_nodes(self, sites, nodes, node_ids):
51 mysite = self.get_site(sites)
52 adj_ids = mysite.adj_node_ids.intersection(node_ids)
55 adj_nodes.append(nodes[id])
61 def add_link(self, remote, bw):
62 my_ip = self.get_virt_ip(remote)
63 remote_ip = remote.get_virt_ip(self)
64 net = self.get_virt_net(remote)
65 link = remote.id, remote.ipaddr, bw, my_ip, remote_ip, net
66 self.links.append(link)
70 def __init__(self, site):
71 self.id = site['site_id']
72 self.node_ids = site['node_ids']
73 self.adj_site_ids = set()
74 self.adj_node_ids = set()
76 def get_sitenodes(self, nodes):
78 for i in self.node_ids:
82 def add_adjacency(self, site):
83 self.adj_site_ids.add(site.id)
84 for n in site.node_ids:
85 self.adj_node_ids.add(n)
89 def __init__(self, slice):
90 self.id = slice['slice_id']
91 self.name = slice['name']
92 self.node_ids = set(slice['node_ids'])
93 self.slice_tag_ids = slice['slice_tag_ids']
95 def get_tag(self, tagname, slicetags, node = None):
96 for i in self.slice_tag_ids:
98 if tag.tagname == tagname:
99 if (not node) or (node.id == tag.node_id):
104 def get_nodes(self, nodes):
106 for id in self.node_ids:
111 # Add a new slice tag
112 def add_tag(self, tagname, value, slicetags, node = None):
113 record = {'slice_tag_id':None, 'slice_id':self.id, 'tagname':tagname, 'value':value}
115 record['node_id'] = node.id
117 record['node_id'] = None
118 tag = Slicetag(record)
119 slicetags[tag.id] = tag
120 self.slice_tag_ids.append(tag.id)
125 # Update a slice tag if it exists, else add it
126 def update_tag(self, tagname, value, slicetags, node = None):
127 tag = self.get_tag(tagname, slicetags, node)
128 if tag and tag.value == value:
134 tag = self.add_tag(tagname, value, slicetags, node)
137 def assign_egre_key(self, slicetags):
138 if not self.get_tag('egre_key', slicetags):
140 key = free_egre_key(slicetags)
141 self.update_tag('egre_key', key, slicetags)
143 # Should handle this case...
147 def turn_on_netns(self, slicetags):
148 tag = self.get_tag('netns', slicetags)
149 if (not tag) or (tag.value != '1'):
150 self.update_tag('netns', '1', slicetags)
153 def turn_off_netns(self, slicetags):
154 tag = self.get_tag('netns', slicetags)
155 if tag and (tag.value != '0'):
159 def add_cap_net_admin(self, slicetags):
160 tag = self.get_tag('capabilities', slicetags)
162 caps = tag.value.split(',')
164 if cap == "CAP_NET_ADMIN":
167 newcaps = "CAP_NET_ADMIN," + tag.value
168 self.update_tag('capabilities', newcaps, slicetags)
170 self.add_tag('capabilities', 'CAP_NET_ADMIN', slicetags)
173 def remove_cap_net_admin(self, slicetags):
174 tag = self.get_tag('capabilities', slicetags)
176 caps = tag.value.split(',')
179 if cap != "CAP_NET_ADMIN":
182 value = ','.join(newcaps)
183 self.update_tag('capabilities', value, slicetags)
188 # Update the vsys/setup-link and vsys/setup-nat slice tags.
189 def add_vsys_tags(self, slicetags):
191 for i in self.slice_tag_ids:
193 if tag.tagname == 'vsys':
194 if tag.value == 'setup-link':
196 elif tag.value == 'setup-nat':
199 self.add_tag('vsys', 'setup-link', slicetags)
201 self.add_tag('vsys', 'setup-nat', slicetags)
207 def __init__(self, tag):
208 self.id = tag['slice_tag_id']
210 # Make one up for the time being...
211 self.id = Slicetag.newid
213 self.slice_id = tag['slice_id']
214 self.tagname = tag['tagname']
215 self.value = tag['value']
216 self.node_id = tag['node_id']
221 # Mark a tag as deleted
226 def write(self, api):
229 api.plshell.UpdateSliceTag(api.plauth, self.id, self.value)
231 api.plshell.AddSliceTag(api.plauth, self.slice_id,
232 self.tagname, self.value, self.node_id)
233 elif self.deleted and int(self.id) > 0:
234 api.plshell.DeleteSliceTag(api.plauth, self.id)
238 Create a dictionary of site objects keyed by site ID
242 for site in GetSites():
243 t = site['site_id'], Site(site)
249 Create a dictionary of node objects keyed by node ID
253 for node in api.plshell.GetNodes(api.plauth):
254 t = node['node_id'], Node(node)
259 Create a dictionary of slice objects keyed by slice ID
261 def get_slice(api, slicename):
262 slice = api.plshell.GetSlices(api.plauth, [slicename])
264 return Slice(slice[0])
269 Create a dictionary of slicetag objects keyed by slice tag ID
271 def get_slice_tags(api):
273 for tag in api.plshell.GetSliceTags(api.plauth):
274 t = tag['slice_tag_id'], Slicetag(tag)
281 def free_egre_key(slicetags):
285 if tag.tagname == 'egre_key':
286 used.add(int(tag.value))
288 for i in range(1, 256):
293 raise KeyError("No more EGRE keys available")
299 Copied from create_slice_aggregate() in sfa.plc.slices
301 def create_slice_vini_aggregate(api, hrn, nodes):
302 # Get the slice record from geni
304 registries = Registries(api)
305 registry = registries[api.hrn]
306 credential = api.getCredential()
307 records = registry.resolve(credential, hrn)
308 for record in records:
309 if record.get_type() in ['slice']:
310 slice = record.as_dict()
312 raise RecordNotFound(hrn)
314 # Make sure slice exists at plc, if it doesnt add it
315 slicename = hrn_to_pl_slicename(hrn)
316 slices = api.plshell.GetSlices(api.plauth, [slicename], ['node_ids'])
318 parts = slicename.split("_")
319 login_base = parts[0]
320 # if site doesnt exist add it
321 sites = api.plshell.GetSites(api.plauth, [login_base])
323 authority = get_authority(hrn)
324 site_records = registry.resolve(credential, authority)
327 raise RecordNotFound(authority)
328 site_record = site_records[0]
329 site = site_record.as_dict()
333 site_id = api.plshell.AddSite(api.plauth, site)
338 slice_keys = ['name', 'url', 'description']
339 for key in slice_keys:
340 if key in slice and slice[key]:
341 slice_fields[key] = slice[key]
342 api.plshell.AddSlice(api.plauth, slice_fields)
344 slice['node_ids'] = 0
348 # get the list of valid slice users from the registry and make
349 # they are added to the slice
350 researchers = record.get('researcher', [])
351 for researcher in researchers:
353 person_records = registry.resolve(credential, researcher)
354 for record in person_records:
355 if record.get_type() in ['user']:
356 person_record = record
357 if not person_record:
359 person_dict = person_record.as_dict()
360 persons = api.plshell.GetPersons(api.plauth, [person_dict['email']],
361 ['person_id', 'key_ids'])
363 # Create the person record
365 person_id=api.plshell.AddPerson(api.plauth, person_dict)
367 # The line below enables the user account on the remote aggregate
368 # soon after it is created.
369 # without this the user key is not transfered to the slice
370 # (as GetSlivers returns key of only enabled users),
371 # which prevents the user from login to the slice.
372 # We may do additional checks before enabling the user.
374 api.plshell.UpdatePerson(api.plauth, person_id, {'enabled' : True})
377 key_ids = persons[0]['key_ids']
379 api.plshell.AddPersonToSlice(api.plauth, person_dict['email'],
382 # Get this users local keys
383 keylist = api.plshell.GetKeys(api.plauth, key_ids, ['key'])
384 keys = [key['key'] for key in keylist]
386 # add keys that arent already there
387 for personkey in person_dict['keys']:
388 if personkey not in keys:
389 key = {'key_type': 'ssh', 'key': personkey}
390 api.plshell.AddPersonKey(api.plauth, person_dict['email'], key)
392 # find out where this slice is currently running
393 nodelist = api.plshell.GetNodes(api.plauth, slice['node_ids'],
395 hostnames = [node['hostname'] for node in nodelist]
397 # remove nodes not in rspec
398 deleted_nodes = list(set(hostnames).difference(nodes))
399 # add nodes from rspec
400 added_nodes = list(set(nodes).difference(hostnames))
403 print >> sys.stderr, "Slice on nodes:"
405 print >> sys.stderr, n
406 print >> sys.stderr, "Wants nodes:"
408 print >> sys.stderr, n
409 print >> sys.stderr, "Deleting nodes:"
410 for n in deleted_nodes:
411 print >> sys.stderr, n
412 print >> sys.stderr, "Adding nodes:"
413 for n in added_nodes:
414 print >> sys.stderr, n
417 api.plshell.AddSliceToNodes(api.plauth, slicename, added_nodes)
418 api.plshell.DeleteSliceFromNodes(api.plauth, slicename, deleted_nodes)
422 def get_rspec(api, hrn):
425 default.parseFile(SFA_VINI_DEFAULT_RSPEC)
428 slicename = hrn_to_pl_slicename(hrn)
429 defaultrspec = default.toDict()
430 nodedict = get_nodedict(defaultrspec)
432 # call the default sfa.plc.nodes.get_rspec() method
434 rspec = nodes.get_rspec(hrn)
436 # Grab all the PLC info we'll need at once
437 slice = get_slice(api, slicename)
439 nodes = get_nodes(api)
440 tags = get_slice_tags(api)
442 # Add the node tags from the Capacity statement to Node objects
443 for (k, v) in nodedict.iteritems():
445 if v == nodes[id].hostname:
449 for node in slice.get_nodes(nodes):
450 linktag = slice.get_tag('topo_rspec', tags, node)
452 l = eval(linktag.value)
453 for (id, realip, bw, lvip, rvip, vnet) in l:
454 endpoints.append((node.id, id, bw))
458 for (l, r, bw) in endpoints:
459 if (r, l, bw) in endpoints:
462 edict['endpoint'] = [nodes[l].tag, nodes[r].tag]
464 linkspecs.append(edict)
467 d['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec'] = linkspecs
468 d['Rspec']['Request'][0]['NetSpec'][0]['name'] = hrn
473 # Return canned response for now...
474 rspec = default.toxml()
479 def create_slice(api, hrn, xml):
483 # Check request against current allocations
486 nodes = rspec_to_nodeset(rspec)
487 create_slice_vini_aggregate(api, hrn, nodes)
489 # Add VINI-specific topology attributes to slice here
491 linkspecs = rspec['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec']
493 slicename = hrn_to_pl_slicename(hrn)
495 # Grab all the PLC info we'll need at once
496 slice = get_slice(api, slicename)
498 nodes = get_nodes(api)
499 tags = get_slice_tags(api)
501 slice.update_tag('vini_topo', 'manual', tags)
502 slice.assign_egre_key(tags)
503 slice.turn_on_netns(tags)
504 slice.add_cap_net_admin(tags)
507 for (k, v) in get_nodedict(rspec).iteritems():
509 if v == nodes[id].hostname:
510 nodedict[k] = nodes[id]
513 n1 = nodedict[l['endpoint'][0]]
514 n2 = nodedict[l['endpoint'][1]]
519 for node in slice.get_nodes(nodes):
521 topo_str = "%s" % node.links
522 slice.update_tag('topo_rspec', topo_str, tags, node)
524 # Update slice tags in database
527 if tag.slice_id == slice.id:
528 if tag.tagname == 'topo_rspec' and not tag.updated:
538 def get_nodedict(rspec):
541 sitespecs = rspec['Rspec']['Capacity'][0]['NetSpec'][0]['SiteSpec']
543 for node in s['NodeSpec']:
544 nodedict[node['name']] = node['hostname'][0]
551 def rspec_to_nodeset(rspec):
554 nodedict = get_nodedict(rspec)
555 linkspecs = rspec['Rspec']['Request'][0]['NetSpec'][0]['LinkSpec']
557 for e in l['endpoint']:
558 nodes.add(nodedict[e])
567 r.parseFile(sys.argv[1])
569 create_slice(None,'plc',rspec)
571 if __name__ == "__main__":