applied the except and raise fixers to the master branch to close the gap with py3
[nepi.git] / src / nepi / util / sfarspec_proc.py
1 #
2 #    NEPI, a framework to manage network experiments
3 #    Copyright (C) 2013 INRIA
4 #
5 #    This program is free software: you can redistribute it and/or modify
6 #    it under the terms of the GNU General Public License version 2 as
7 #    published by the Free Software Foundation;
8 #
9 #    This program is distributed in the hope that it will be useful,
10 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #    GNU General Public License for more details.
13 #
14 #    You should have received a copy of the GNU General Public License
15 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 #
17
18 from nepi.util.logger import Logger
19 try:
20     from sfa.rspecs.rspec import RSpec
21     from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn, urn_to_hrn
22 except ImportError:
23     log = Logger("SFA RSpec Processing")
24     log.debug("Package sfa-common not installed.\
25          Could not import sfa.rspecs.rspec and sfa.util.xrn")
26
27 from types import StringTypes, ListType
28
29
30 class SfaRSpecProcessing(object):
31     """
32     Class to process SFA RSpecs, parse the RSpec replies such as Advertisement RSpecs,
33     and build in the case of Request RSpecs.
34     """
35     def __init__(self, config=None):
36         self._log = Logger("SFA RSpec Processing")
37         self.config = config 
38
39     def make_dict_rec(self, obj):
40         if not obj or isinstance(obj, (StringTypes, bool)):
41             return obj
42         if isinstance(obj, list):
43             objcopy = []
44             for x in obj:
45                 objcopy.append(self.make_dict_rec(x))
46             return objcopy
47         # We thus suppose we have a child of dict
48         objcopy = {}
49         for k, v in obj.items():
50             objcopy[k] = self.make_dict_rec(v)
51         return objcopy
52
53     def parse_sfa_rspec(self, rspec_string):
54         """
55         Parse the RSpec XML as a string.
56         """
57         # rspec_type and rspec_version should be set in the config of the platform,
58         # we use GENIv3 as default one if not
59         if self.config:
60             if 'rspec_type' and 'rspec_version' in self.config:
61                 rspec_version = self.config['rspec_type'] + ' ' + self.config['rspec_version']
62         else:
63             rspec_version = 'GENI 3'
64         self._log.debug(rspec_version)
65         rspec = RSpec(rspec_string, version=rspec_version)
66         
67         try:
68             nodes = rspec.version.get_nodes()
69         except Exception as e:
70             self._log.warn("Could not retrieve nodes in RSpec: %s" % e)
71         try:
72             leases = rspec.version.get_leases()
73         except Exception as e:
74             self._log.warn("Could not retrieve leases in RSpec: %s" % e)
75         try:
76             links = rspec.version.get_links()
77         except Exception as e:
78             self._log.warn("Could not retrieve links in RSpec: %s" % e)
79         try:
80             channels = rspec.version.get_channels()
81         except Exception as e:
82             self._log.warn("Could not retrieve channels in RSpec: %s" % e)
83   
84         resources = [] 
85         # Extend object and Format object field's name
86         for node in nodes:
87             node['type'] = 'node'
88             node['network_hrn'] = Xrn(node['component_id']).authority[0] # network ? XXX
89             node['hrn'] = urn_to_hrn(node['component_id'])[0]
90             node['urn'] = node['component_id']
91             node['hostname'] = node['component_name']
92             node['initscripts'] = node.pop('pl_initscripts')
93             if 'exclusive' in node and node['exclusive']:
94                 node['exclusive'] = node['exclusive'].lower() == 'true'
95  
96             # XXX This should use a MAP as before
97             if 'position' in node: # iotlab
98                 node['x'] = node['position']['posx']
99                 node['y'] = node['position']['posy']
100                 node['z'] = node['position']['posz']
101                 del node['position']
102  
103             if 'location' in node:
104                 if node['location']:
105                     node['latitude'] = node['location']['latitude']
106                     node['longitude'] = node['location']['longitude']
107                 del node['location']
108  
109             # Flatten tags
110             if 'tags' in node:
111                 if node['tags']:
112                     for tag in node['tags']:
113                         node[tag['tagname']] = tag['value']
114                 del node['tags']
115  
116             
117             # We suppose we have children of dict that cannot be serialized
118             # with xmlrpc, let's make dict
119             resources.append(self.make_dict_rec(node))
120  
121         # NOTE a channel is a resource and should not be treated independently
122         #     resource
123         #        |
124         #   +----+------+-------+
125         #   |    |      |       |
126         # node  link  channel  etc.
127         #resources.extend(nodes)
128         #resources.extend(channels)
129  
130         return {'resource': resources, 'lease': leases } 
131 #               'channel': channels \
132 #               }
133
134  
135     def build_sfa_rspec(self, slice_id, resources, properties, leases):
136         """
137         Build the XML RSpec from list of resources' urns.
138         eg. resources = ["urn:publicid:IDN+ple:modenaple+node+planetlab-1.ing.unimo.it"]
139         """
140         #if isinstance(resources, str):
141         #    resources = eval(resources)
142         # rspec_type and rspec_version should be set in the config of the platform,
143         # we use GENIv3 as default one if not
144         if self.config:
145             if 'rspec_type' and 'rspec_version' in self.config:
146                 rspec_version = self.config['rspec_type'] + ' ' + self.config['rspec_version']
147         else:
148             rspec_version = 'GENI 3'
149
150         # extend rspec version with "content_type"
151         rspec_version += ' request'
152         
153         rspec = RSpec(version=rspec_version)
154
155         nodes = []
156         channels = []
157         links = []
158         self._log.debug("Building RSpec for resources %s" % resources)
159         cardinal = 0
160         wilab = False
161         for urn in resources:
162             # XXX TO BE CORRECTED, this handles None values
163             if not urn:
164                 continue
165             self._log.debug(urn)
166             resource = dict()
167             # TODO: take into account the case where we send a dict of URNs without keys
168             #resource['component_id'] = resource.pop('urn')
169             resource['component_id'] = urn
170             resource_hrn, resource_type = urn_to_hrn(resource['component_id'])
171             # build component_manager_id
172             top_auth = resource_hrn.split('.')[0]
173             cm = urn.split("+")
174             resource['component_manager_id'] = "%s+%s+authority+cm" % (cm[0],top_auth)
175
176             if resource_type == 'node':
177                 # XXX dirty hack WiLab !!!
178 #                Commented Lucia, doesn't work for wilabt  
179 #                if self.config:
180 #                    if 'wilab2' in self.config['sm']:
181 #                        resource['client_id'] = "PC"
182 #                        resource['sliver_type'] = "raw-pc"
183                 if 'wilab2' in urn:
184                     wilab = True
185                     resource['client_id'] = "node%s" % cardinal
186                     resource['sliver_type'] = "raw-pc"
187                     resource['disk_image'] = "hola"
188                     top_auth = resource_hrn.replace("\\", "").split('.')
189                     top_auth.pop()
190                     top_auth = '.'.join(top_auth)
191                     cm = urn.split("+")
192                     resource['component_manager_id'] = "%s+%s+authority+cm" % (cm[0],top_auth)
193                     cardinal += 1
194                 nodes.append(resource)
195             elif resource_type == 'link':
196                 links.append(resource)
197             elif resource_type == 'channel':
198                 channels.append(resource)
199             else:
200                 raise Exception("Not supported type of resource") 
201         
202         rspec.version.add_nodes(nodes, rspec_content_type="request")
203         #rspec.version.add_leases(leases)
204         #rspec.version.add_links(links)
205         #rspec.version.add_channels(channels)
206
207         #self._log.debug("request rspec: %s"%rspec.toxml())
208         string = rspec.toxml()
209         if wilab and properties is not None:
210             ## dirty hack for the f4f demo
211             b = string.split('\n')
212             for i, n in enumerate(b):
213                 if 'sliver_type name="raw-pc"' in n:
214                     b[i] = '<sliver_type name="raw-pc">'
215                     b.insert(i+1, '<disk_image name="urn:publicid:IDN+wall2.ilabt.iminds.be+image+emulab-ops//%s"/>' % properties['disk_image'])
216                     #b.insert(i+1, '<disk_image name="urn:publicid:IDN+wilab2.ilabt.iminds.be+image+nepi:%s"/>' % properties['disk_image'])
217                     b.insert(i+2, '</sliver_type>')
218             string = ''.join(b)
219         self._log.debug("request rspec : %s" % string)
220         return string
221
222