1 -from sfa.util.rspec import RSpec
4 -from sfa.util.namespace import *
5 -from sfa.util.rspec import *
6 -from sfa.util.specdict import *
7 -from sfa.util.faults import *
8 -from sfa.util.storage import *
9 -from sfa.util.policy import Policy
10 -from sfa.util.debug import log
11 -from sfa.server.aggregate import Aggregates
12 +from sfa.util.xrn import urn_to_hrn, hrn_to_urn, get_authority
13 +from sfa.util.plxrn import hrn_to_pl_slicename
14 +from sfa.util.plxrn import hrn_to_pl_slicename
15 from sfa.server.registry import Registries
16 +from sfa.util.rspec import RSpec
17 +from sfa.util.sfalogging import sfa_logger
18 from sfa.util.faults import *
20 -import xml.dom.minidom
22 -SFA_MAX_CONF_FILE = '/etc/sfa/max_allocations'
23 -SFA_MAX_DEFAULT_RSPEC = '/etc/sfa/max_physical.xml'
24 -SFA_MAX_CANNED_RSPEC = '/etc/sfa/max_physical_canned.xml'
28 -class SfaOutOfResource(SfaFault):
29 - def __init__(self, interface):
30 - faultString = "Interface " + interface + " not available"
31 - SfaFault.__init__(self, 100, faultString, '')
33 -class SfaNoPairRSpec(SfaFault):
34 - def __init__(self, interface, interface2):
35 - faultString = "Interface " + interface + " should be paired with " + interface2
36 - SfaFault.__init__(self, 100, faultString, '')
38 -# Returns a mapping from interfaces to the nodes they lie on and their peer interfaces
41 -def get_interface_map():
43 - r.parseFile(SFA_MAX_DEFAULT_RSPEC)
45 - capacity = rspec['rspec']['capacity']
46 - netspec = capacity[0]['netspec'][0]
48 - for n in netspec['nodespec']:
49 - ifspecs = n['ifspec']
50 - nodename = n['node']
53 - linkid = i['linkid']
55 - if (linkdefs.has_key(linkid)):
56 - linkdefs[linkid].extend([(nodename,ifname)])
58 - linkdefs[linkid]=[(nodename,ifname)]
60 - # topology maps interface x interface -> link,node1,node2
63 - for k in linkdefs.keys():
64 - (n1,i1) = linkdefs[k][0]
65 - (n2,i2) = linkdefs[k][1]
67 - topology[i1] = (n1, i2)
68 - topology[i2] = (n2, i1)
74 -def allocations_to_rspec(allocations):
75 - rspec = xml.dom.minidom.parse(SFA_MAX_DEFAULT_RSPEC)
76 - req = rspec.firstChild.appendChild(rspec.createElement("request"))
77 - for (iname,ip) in allocations:
78 - ifspec = req.appendChild(rspec.createElement("ifspec"))
79 - ifspec.setAttribute("name","tns:"+iname)
80 - ifspec.setAttribute("ip",ip)
82 - return rspec.toxml()
85 -def if_endpoints(ifs):
88 - nodes.extend(topology[l][0])
91 -def lock_state_file():
95 -def unlock_state_file():
99 -def read_alloc_dict():
101 - rows = open(SFA_MAX_CONF_FILE).read().split('\n')
103 - columns = r.split(' ')
104 - if (len(columns)==2):
106 - allocs = columns[1].split(',')
107 - ipallocs = map(lambda alloc:alloc.split('/'), allocs)
108 - alloc_dict[hrn]=ipallocs
111 -def commit_alloc_dict(d):
112 - f = open(SFA_MAX_CONF_FILE, 'w')
113 - for hrn in d.keys():
115 - ipcolumns = map(lambda x:"/".join(x), columns)
116 - row = hrn+' '+','.join(ipcolumns)+'\n'
120 -def collapse_alloc_dict(d):
124 +from sfa.util.config import Config
125 +from sfa.managers.aggregate_manager_pl import GetVersion
129 +RSPEC_TMP_FILE_PREFIX = "/tmp/max_rspec"
131 +# execute shell command and return both exit code and text output
132 +def shell_execute(cmd, timeout):
133 + pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r')
134 + pipe = os.popen(cmd + ' 2>&1', 'r')
140 + timeout = timeout-1
141 + code = pipe.close()
142 + if code is None: code = 0
143 + if text[-1:] == '\n': text = text[:-1]
147 + call AM API client with command like in the following example:
148 + cd aggregate_client; java -classpath AggregateWS-client-api.jar:lib/* \
149 + net.geni.aggregate.client.examples.CreateSliceNetworkClient \
150 + ./repo https://geni:8443/axis2/services/AggregateGENI \
154 +def call_am_apiclient(client_app, params, timeout):
155 + (client_path, am_url) = Config().get_max_aggrMgr_info()
156 + sys_cmd = "cd " + client_path + "; java -classpath AggregateWS-client-api.jar:lib/* net.geni.aggregate.client.examples." + client_app + " ./repo " + am_url + " " + ' '.join(params)
157 + ret = shell_execute(sys_cmd, timeout)
158 + sfa_logger().debug("shell_execute cmd: %s returns %s" % (sys_cmd, ret))
162 -def alloc_links(api, hrn, links_to_add, links_to_drop):
163 - slicename=hrn_to_pl_slicename(hrn)
164 - for (iface,ip) in links_to_add:
165 - node = topology[iface][0][0]
167 - api.plshell.AddSliceTag(api.plauth, slicename, "ip_addresses", ip, node)
168 - api.plshell.AddSliceTag(api.plauth, slicename, "vsys", "getvlan", node)
170 - # Probably a duplicate tag. XXX July 21
172 +# save request RSpec xml content to a tmp file
173 +def save_rspec_to_file(rspec):
174 + path = RSPEC_TMP_FILE_PREFIX + "_" + time.strftime('%Y%m%dT%H:%M:%S', time.gmtime(time.time())) +".xml"
175 + file = open(path, "w")
180 +# get stripped down slice id/name plc:maxpl:xi_slice1 --> xi_slice1
181 +def get_short_slice_id(cred, hrn):
184 + slice_id = hrn[hrn.rfind('+')+1:]
185 + if slice_id == None:
186 + slice_id = hrn[hrn.rfind(':')+1:]
187 + if slice_id == None:
190 + return str(slice_id)
193 +def get_xml_by_tag(text, tag):
194 + indx1 = text.find('<'+tag)
195 + indx2 = text.find('/'+tag+'>')
197 + if indx1!=-1 and indx2>indx1:
198 + xml = text[indx1:indx2+len(tag)+2]
201 +def create_slice(api, xrn, cred, rspec, users):
202 + indx1 = rspec.find("<RSpec")
203 + indx2 = rspec.find("</RSpec>")
204 + if indx1 > -1 and indx2 > indx1:
205 + rspec = rspec[indx1+len("<RSpec type=\"SFA\">"):indx2-1]
206 + rspec_path = save_rspec_to_file(rspec)
207 + (ret, output) = call_am_apiclient("CreateSliceNetworkClient", [rspec_path,], 3)
209 + rspec = "<RSpec type=\"SFA\"> Done! </RSpec>"
212 -def alloc_nodes(api,hrn, requested_ifs):
213 - requested_nodes = if_endpoints(requested_ifs)
214 - create_slice_max_aggregate(api, hrn, requested_nodes)
216 -# Taken from slices.py
218 -def create_slice_max_aggregate(api, hrn, nodes):
219 - # Get the slice record
221 - topology = get_interface_map()
223 - registries = Registries(api)
224 - registry = registries[api.hrn]
225 - credential = api.getCredential()
226 - records = registry.resolve(credential, hrn)
227 - for record in records:
228 - if record.get_type() in ['slice']:
229 - slice = record.as_dict()
231 - raise RecordNotFound(hrn)
233 - # Make sure slice exists at plc, if it doesnt add it
234 - slicename = hrn_to_pl_slicename(hrn)
235 - slices = api.plshell.GetSlices(api.plauth, [slicename], ['node_ids'])
237 - parts = slicename.split("_")
238 - login_base = parts[0]
239 - # if site doesnt exist add it
240 - sites = api.plshell.GetSites(api.plauth, [login_base])
242 - authority = get_authority(hrn)
243 - site_records = registry.resolve(credential, authority)
245 - if not site_records:
246 - raise RecordNotFound(authority)
247 - site_record = site_records[0]
248 - site = site_record.as_dict()
251 - site.pop('site_id')
252 - site_id = api.plshell.AddSite(api.plauth, site)
257 - slice_keys = ['name', 'url', 'description']
258 - for key in slice_keys:
259 - if key in slice and slice[key]:
260 - slice_fields[key] = slice[key]
261 - api.plshell.AddSlice(api.plauth, slice_fields)
262 - slice = slice_fields
263 - slice['node_ids'] = 0
267 - # get the list of valid slice users from the registry and make
268 - # they are added to the slice
269 - researchers = record.get('researcher', [])
270 - for researcher in researchers:
272 - person_records = registry.resolve(credential, researcher)
273 - for record in person_records:
274 - if record.get_type() in ['user']:
275 - person_record = record
276 - if not person_record:
278 - person_dict = person_record.as_dict()
279 - persons = api.plshell.GetPersons(api.plauth, [person_dict['email']],
280 - ['person_id', 'key_ids'])
282 - # Create the person record
284 - person_id=api.plshell.AddPerson(api.plauth, person_dict)
286 - # The line below enables the user account on the remote aggregate
287 - # soon after it is created.
288 - # without this the user key is not transfered to the slice
289 - # (as GetSlivers returns key of only enabled users),
290 - # which prevents the user from login to the slice.
291 - # We may do additional checks before enabling the user.
293 - api.plshell.UpdatePerson(api.plauth, person_id, {'enabled' : True})
296 - key_ids = persons[0]['key_ids']
298 - api.plshell.AddPersonToSlice(api.plauth, person_dict['email'],
301 - # Get this users local keys
302 - keylist = api.plshell.GetKeys(api.plauth, key_ids, ['key'])
303 - keys = [key['key'] for key in keylist]
305 - # add keys that arent already there
306 - for personkey in person_dict['keys']:
307 - if personkey not in keys:
308 - key = {'key_type': 'ssh', 'key': personkey}
309 - api.plshell.AddPersonKey(api.plauth, person_dict['email'], key)
311 - # find out where this slice is currently running
312 - nodelist = api.plshell.GetNodes(api.plauth, slice['node_ids'],
314 - hostnames = [node['hostname'] for node in nodelist]
316 - # remove nodes not in rspec
317 - deleted_nodes = list(set(hostnames).difference(nodes))
318 - # add nodes from rspec
319 - added_nodes = list(set(nodes).difference(hostnames))
321 - api.plshell.AddSliceToNodes(api.plauth, slicename, added_nodes)
322 - api.plshell.DeleteSliceFromNodes(api.plauth, slicename, deleted_nodes)
324 +def delete_slice(api, xrn, cred):
325 + slice_id = get_short_slice_id(cred, xrn)
326 + (ret, output) = call_am_apiclient("DeleteSliceNetworkClient", [slice_id,], 3)
331 -def get_rspec(api, creds, options):
332 - # get slice's hrn from options
333 - xrn = options.get('geni_slice_urn', None)
334 - hrn, type = urn_to_hrn(xrn)
336 - # plc.princeton.sapan vlan23,vlan45
338 - allocations = read_alloc_dict()
339 - if (hrn and allocations.has_key(hrn)):
340 - ret_rspec = allocations_to_rspec(allocations[hrn])
341 +def get_rspec(api, cred, options):
342 + #geni_slice_urn: urn:publicid:IDN+plc:maxpl+slice+xi_rspec_test1
343 + urn = options.get('geni_slice_urn')
344 + slice_id = get_short_slice_id(cred, urn)
345 + if slice_id == None:
346 + (ret, output) = call_am_apiclient("GetResourceTopology", ['all', '\"\"'], 5)
348 - ret_rspec = open(SFA_MAX_CANNED_RSPEC).read()
353 -def create_slice(api, xrn, creds, rspec_xml, users):
355 - hrn = urn_to_hrn(xrn)[0]
356 - topology = get_interface_map()
358 - # Check if everything in rspec is either allocated by hrn
359 - # or not allocated at all.
361 - r.parseString(rspec_xml)
366 - allocations = read_alloc_dict()
367 - requested_allocations = rspec_to_allocations (rspec)
368 - current_allocations = collapse_alloc_dict(allocations)
370 - current_hrn_allocations=allocations[hrn]
372 - current_hrn_allocations=[]
374 - # Check request against current allocations
375 - requested_interfaces = map(lambda(elt):elt[0], requested_allocations)
376 - current_interfaces = map(lambda(elt):elt[0], current_allocations)
377 - current_hrn_interfaces = map(lambda(elt):elt[0], current_hrn_allocations)
379 - for a in requested_interfaces:
380 - if (a not in current_hrn_interfaces and a in current_interfaces):
381 - raise SfaOutOfResource(a)
382 - if (topology[a][1] not in requested_interfaces):
383 - raise SfaNoPairRSpec(a,topology[a][1])
386 - # Allocations to delete
387 - allocations_to_delete = []
388 - for a in current_hrn_allocations:
389 - if (a not in requested_allocations):
390 - allocations_to_delete.extend([a])
392 - # Ok, let's do our thing
393 - alloc_nodes(api, hrn, requested_interfaces)
394 - alloc_links(api, hrn, requested_allocations, allocations_to_delete)
395 - allocations[hrn] = requested_allocations
396 - commit_alloc_dict(allocations)
398 - unlock_state_file()
402 -def rspec_to_allocations(rspec):
405 - ifspecs = rspec['rspec']['request'][0]['ifspec']
407 - ifs.extend([(l['name'].replace('tns:',''),l['ip'])])
412 + (ret, output) = call_am_apiclient("GetResourceTopology", ['all', slice_id,], 5)
413 + # parse output into rspec XML
414 + if output.find("No resouce found") > 0:
415 + rspec = "<RSpec type=\"SFA\"> <Fault>No resource found</Fault> </RSpec>"
417 + comp_rspec = get_xml_by_tag(output, 'computeResource')
418 + sfa_logger().debug("#### computeResource %s" % comp_rspec)
419 + topo_rspec = get_xml_by_tag(output, 'topology')
420 + sfa_logger().debug("#### topology %s" % topo_rspec)
421 + rspec = "<RSpec type=\"SFA\"> <network name=\"" + Config().get_interface_hrn() + "\">";
422 + if comp_rspec != None:
423 + rspec = rspec + get_xml_by_tag(output, 'computeResource')
424 + if topo_rspec != None:
425 + rspec = rspec + get_xml_by_tag(output, 'topology')
426 + rspec = rspec + "</network> </RSpec>"
430 +def start_slice(api, xrn, cred):
431 + # service not supported
434 +def stop_slice(api, xrn, cred):
435 + # service not supported
438 +def reset_slices(api, xrn):
439 + # service not supported
443 +Returns the request context required by sfatables. At some point, this mechanism should be changed
444 +to refer to "contexts", which is the information that sfatables is requesting. But for now, we just
445 +return the basic information needed in a dict.
447 +def fetch_context(slice_hrn, user_hrn, contexts):
448 + base_context = {'sfa':{'user':{'hrn':user_hrn}}}
449 + return base_context
452 - t = get_interface_map()
455 rspec_xml = open(sys.argv[1]).read()
456 - #get_rspec(None,'foo')
457 - create_slice(None, "plc.princeton.sap0", rspec_xml)
459 + create_slice(api, "plc.maxpl.test000", None, rspec_xml, None)
461 if __name__ == "__main__":