#
# 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 as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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, e:
self._log.warn("Could not retrieve nodes in RSpec: %s" % e)
try:
leases = rspec.version.get_leases()
except Exception, e:
self._log.warn("Could not retrieve leases in RSpec: %s" % e)
try:
links = rspec.version.get_links()
except Exception, e:
self._log.warn("Could not retrieve links in RSpec: %s" % e)
try:
channels = rspec.version.get_channels()
except Exception, 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