# # NEPI, a framework to manage network experiments # Copyright (C) 2013 INRIA # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation; # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # from nepi.util.logger import Logger try: from sfa.rspecs.rspec import RSpec from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn, urn_to_hrn except ImportError: log = Logger("SFA RSpec Processing") log.debug("Package sfa-common not installed.\ Could not import sfa.rspecs.rspec and sfa.util.xrn") from types import StringTypes, ListType class SfaRSpecProcessing(object): """ Class to process SFA RSpecs, parse the RSpec replies such as Advertisement RSpecs, and build in the case of Request RSpecs. """ def __init__(self, config=None): self._log = Logger("SFA RSpec Processing") self.config = config def make_dict_rec(self, obj): if not obj or isinstance(obj, (StringTypes, bool)): return obj if isinstance(obj, list): objcopy = [] for x in obj: objcopy.append(self.make_dict_rec(x)) return objcopy # We thus suppose we have a child of dict objcopy = {} for k, v in obj.items(): objcopy[k] = self.make_dict_rec(v) return objcopy def parse_sfa_rspec(self, rspec_string): """ Parse the RSpec XML as a string. """ # rspec_type and rspec_version should be set in the config of the platform, # we use GENIv3 as default one if not if self.config: if 'rspec_type' and 'rspec_version' in self.config: rspec_version = self.config['rspec_type'] + ' ' + self.config['rspec_version'] else: rspec_version = 'GENI 3' self._log.debug(rspec_version) rspec = RSpec(rspec_string, version=rspec_version) try: nodes = rspec.version.get_nodes() except Exception as e: self._log.warn("Could not retrieve nodes in RSpec: %s" % e) try: leases = rspec.version.get_leases() except Exception as e: self._log.warn("Could not retrieve leases in RSpec: %s" % e) try: links = rspec.version.get_links() except Exception as e: self._log.warn("Could not retrieve links in RSpec: %s" % e) try: channels = rspec.version.get_channels() except Exception as e: self._log.warn("Could not retrieve channels in RSpec: %s" % e) resources = [] # Extend object and Format object field's name for node in nodes: node['type'] = 'node' node['network_hrn'] = Xrn(node['component_id']).authority[0] # network ? XXX node['hrn'] = urn_to_hrn(node['component_id'])[0] node['urn'] = node['component_id'] node['hostname'] = node['component_name'] node['initscripts'] = node.pop('pl_initscripts') if 'exclusive' in node and node['exclusive']: node['exclusive'] = node['exclusive'].lower() == 'true' # XXX This should use a MAP as before if 'position' in node: # iotlab node['x'] = node['position']['posx'] node['y'] = node['position']['posy'] node['z'] = node['position']['posz'] del node['position'] if 'location' in node: if node['location']: node['latitude'] = node['location']['latitude'] node['longitude'] = node['location']['longitude'] del node['location'] # Flatten tags if 'tags' in node: if node['tags']: for tag in node['tags']: node[tag['tagname']] = tag['value'] del node['tags'] # We suppose we have children of dict that cannot be serialized # with xmlrpc, let's make dict resources.append(self.make_dict_rec(node)) # NOTE a channel is a resource and should not be treated independently # resource # | # +----+------+-------+ # | | | | # node link channel etc. #resources.extend(nodes) #resources.extend(channels) return {'resource': resources, 'lease': leases } # 'channel': channels \ # } def build_sfa_rspec(self, slice_id, resources, properties, leases): """ Build the XML RSpec from list of resources' urns. eg. resources = ["urn:publicid:IDN+ple:modenaple+node+planetlab-1.ing.unimo.it"] """ #if isinstance(resources, str): # resources = eval(resources) # rspec_type and rspec_version should be set in the config of the platform, # we use GENIv3 as default one if not if self.config: if 'rspec_type' and 'rspec_version' in self.config: rspec_version = self.config['rspec_type'] + ' ' + self.config['rspec_version'] else: rspec_version = 'GENI 3' # extend rspec version with "content_type" rspec_version += ' request' rspec = RSpec(version=rspec_version) nodes = [] channels = [] links = [] self._log.debug("Building RSpec for resources %s" % resources) cardinal = 0 wilab = False for urn in resources: # XXX TO BE CORRECTED, this handles None values if not urn: continue self._log.debug(urn) resource = dict() # TODO: take into account the case where we send a dict of URNs without keys #resource['component_id'] = resource.pop('urn') resource['component_id'] = urn resource_hrn, resource_type = urn_to_hrn(resource['component_id']) # build component_manager_id top_auth = resource_hrn.split('.')[0] cm = urn.split("+") resource['component_manager_id'] = "%s+%s+authority+cm" % (cm[0],top_auth) if resource_type == 'node': # XXX dirty hack WiLab !!! # Commented Lucia, doesn't work for wilabt # if self.config: # if 'wilab2' in self.config['sm']: # resource['client_id'] = "PC" # resource['sliver_type'] = "raw-pc" if 'wilab2' in urn: wilab = True resource['client_id'] = "node%s" % cardinal resource['sliver_type'] = "raw-pc" resource['disk_image'] = "hola" top_auth = resource_hrn.replace("\\", "").split('.') top_auth.pop() top_auth = '.'.join(top_auth) cm = urn.split("+") resource['component_manager_id'] = "%s+%s+authority+cm" % (cm[0],top_auth) cardinal += 1 nodes.append(resource) elif resource_type == 'link': links.append(resource) elif resource_type == 'channel': channels.append(resource) else: raise Exception("Not supported type of resource") rspec.version.add_nodes(nodes, rspec_content_type="request") #rspec.version.add_leases(leases) #rspec.version.add_links(links) #rspec.version.add_channels(channels) #self._log.debug("request rspec: %s"%rspec.toxml()) string = rspec.toxml() if wilab and properties is not None: ## dirty hack for the f4f demo b = string.split('\n') for i, n in enumerate(b): if 'sliver_type name="raw-pc"' in n: b[i] = '' b.insert(i+1, '' % properties['disk_image']) #b.insert(i+1, '' % properties['disk_image']) b.insert(i+2, '') string = ''.join(b) self._log.debug("request rspec : %s" % string) return string