make uniform Lease management methods in nitos
[sfa.git] / sfa / nitos / nitosaggregate.py
1 #!/usr/bin/python
2 from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn
3 from sfa.util.sfatime import utcparse, datetime_to_string
4 from sfa.util.sfalogging import logger
5
6 from sfa.rspecs.rspec import RSpec
7 from sfa.rspecs.elements.hardware_type import HardwareType
8 from sfa.rspecs.elements.node import Node
9 from sfa.rspecs.elements.link import Link
10 from sfa.rspecs.elements.sliver import Sliver
11 from sfa.rspecs.elements.login import Login
12 from sfa.rspecs.elements.location import Location
13 from sfa.rspecs.elements.position_3d import Position3D
14 from sfa.rspecs.elements.interface import Interface
15 from sfa.rspecs.elements.services import Services
16 from sfa.rspecs.elements.pltag import PLTag
17 from sfa.rspecs.elements.lease import Lease
18 from sfa.rspecs.elements.granularity import Granularity
19 from sfa.rspecs.elements.channel import Channel
20 from sfa.rspecs.version_manager import VersionManager
21
22 from sfa.nitos.nitosxrn import NitosXrn, hostname_to_urn, hrn_to_nitos_slicename, slicename_to_hrn, channel_to_urn
23 from sfa.planetlab.vlink import get_tc_rate
24 from sfa.planetlab.topology import Topology
25
26 import time
27
28 class NitosAggregate:
29
30     def __init__(self, driver):
31         self.driver = driver
32
33
34     def get_slice_and_slivers(self, slice_xrn):
35         """
36         Returns a dict of slivers keyed on the sliver's node_id
37         """
38         slivers = {}
39         slice = None
40         if not slice_xrn:
41             return (slice, slivers)
42         slice_urn = hrn_to_urn(slice_xrn, 'slice')
43         slice_hrn, _ = urn_to_hrn(slice_xrn)
44         slice_name = hrn_to_nitos_slicename(slice_hrn)
45         slices = self.driver.shell.getSlices({'slice_name': slice_name}, [])
46         #filter results
47         for slc in slices:
48              if slc['slice_name'] == slice_name:
49                  slice = slc
50                  break
51
52         if not slice:
53             return (slice, slivers)
54       
55         reserved_nodes = self.driver.shell.getReservedNodes({'slice_id': slice['slice_id']}, [])
56         reserved_node_ids = []
57         # filter on the slice
58         for node in reserved_nodes:
59              if node['slice_id'] == slice['slice_id']:
60                  reserved_node_ids.append(node['node_id'])
61         #get all the nodes
62         all_nodes = self.driver.shell.getNodes({}, [])
63        
64         for node in all_nodes:
65              if node['node_id'] in reserved_node_ids:
66                  slivers[node['node_id']] = node
67         
68         return (slice, slivers)
69        
70
71
72     def get_nodes(self, slice_xrn, slice=None,slivers={}, options={}):
73         # if we are dealing with a slice that has no node just return 
74         # and empty list    
75         if slice_xrn:
76             if not slice or not slivers:
77                 return []
78             else:
79                 nodes = [slivers[sliver] for sliver in slivers]
80         else:
81             nodes = self.driver.shell.getNodes({}, [])
82         
83         # get the granularity in second for the reservation system
84         grain = self.driver.testbedInfo['grain']
85         #grain = 1800
86        
87
88         rspec_nodes = []
89         for node in nodes:
90             rspec_node = Node()
91             site_name = self.driver.testbedInfo['name']
92             rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site_name, node['hostname'])
93             rspec_node['component_name'] = node['hostname']
94             rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
95             rspec_node['authority_id'] = hrn_to_urn(NitosXrn.site_hrn(self.driver.hrn, site_name), 'authority+sa')
96             # do not include boot state (<available> element) in the manifest rspec
97             #if not slice:     
98             #    rspec_node['boot_state'] = node['boot_state']
99             rspec_node['exclusive'] = 'true'
100             # site location
101             longitude = self.driver.testbedInfo['longitude']
102             latitude = self.driver.testbedInfo['latitude']  
103             if longitude and latitude:  
104                 location = Location({'longitude': longitude, 'latitude': latitude, 'country': 'unknown'})
105                 rspec_node['location'] = location
106             # 3D position
107             position_3d = Position3D({'x': node['position']['X'], 'y': node['position']['Y'], 'z': node['position']['Z']})
108             #position_3d = Position3D({'x': 1, 'y': 2, 'z': 3})
109             rspec_node['position_3d'] = position_3d 
110             # Granularity
111             granularity = Granularity({'grain': grain})
112             rspec_node['granularity'] = granularity
113
114             # HardwareType
115             rspec_node['hardware_type'] = node['node_type']
116             #rspec_node['hardware_type'] = "orbit"
117             
118             #slivers
119             if node['node_id'] in slivers:
120                 # add sliver info
121                 sliver = slivers[node['node_id']]
122                 rspec_node['sliver_id'] = sliver['node_id']
123                 rspec_node['client_id'] = node['hostname']
124                 rspec_node['slivers'] = [sliver]
125
126                 
127             rspec_nodes.append(rspec_node)
128         return rspec_nodes 
129
130     def get_leases_and_channels(self, slice=None, slice_xrn=None,  options={}):
131         
132         slices = self.driver.shell.getSlices({}, [])
133         nodes = self.driver.shell.getNodes({}, [])
134         leases = self.driver.shell.getReservedNodes({}, [])
135         channels = self.driver.shell.getChannels({}, [])
136         reserved_channels = self.driver.shell.getReservedChannels()
137         grain = self.driver.testbedInfo['grain']
138
139         if slice_xrn and not slice:
140             return ([], [])
141
142         if slice:
143             all_leases = []
144             all_leases.extend(leases)
145             all_reserved_channels = []
146             all_reserved_channels.extend(reserved_channels)
147             for lease in all_leases:
148                  if lease['slice_id'] != slice['slice_id']:
149                      leases.remove(lease)
150             for channel in all_reserved_channels:
151                  if channel['slice_id'] != slice['slice_id']:
152                      reserved_channels.remove(channel)
153
154         rspec_channels = []
155         for channel in reserved_channels:
156              
157             rspec_channel = {}
158             #retrieve channel number  
159             for chl in channels:
160                  if chl['channel_id'] == channel['channel_id']:
161                      channel_number = chl['channel']
162                      break
163
164             rspec_channel['channel_num'] = channel_number
165             rspec_channel['start_time'] = channel['start_time']
166             rspec_channel['duration'] = (int(channel['end_time']) - int(channel['start_time'])) / int(grain)
167             rspec_channel['component_id'] = channel_to_urn(self.driver.hrn, self.driver.testbedInfo['name'], channel_number)
168                  
169             # retreive slicename
170             for slc in slices:
171                  if slc['slice_id'] == channel['slice_id']:
172                      slicename = slc['slice_name']
173                      break
174
175             if slice_xrn:
176                 slice_urn = slice_xrn
177                 slice_hrn = urn_to_hrn(slice_urn)
178             else:
179                 slice_hrn = slicename_to_hrn(self.driver.hrn, self.driver.testbedInfo['name'], slicename)
180                 slice_urn = hrn_to_urn(slice_hrn, 'slice')
181
182             rspec_channel['slice_id'] = slice_urn
183             rspec_channels.append(rspec_channel)
184
185  
186         rspec_leases = []
187         for lease in leases:
188
189             rspec_lease = Lease()
190             
191             rspec_lease['lease_id'] = lease['reservation_id']
192             # retreive node name
193             for node in nodes:
194                  if node['node_id'] == lease['node_id']:
195                      nodename = node['hostname']
196                      break
197            
198             rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, self.driver.testbedInfo['name'], nodename)
199             # retreive slicename
200             for slc in slices:
201                  if slc['slice_id'] == lease['slice_id']:
202                      slicename = slc['slice_name']
203                      break
204             
205             if slice_xrn:
206                 slice_urn = slice_xrn
207                 slice_hrn = urn_to_hrn(slice_urn)
208             else:
209                 slice_hrn = slicename_to_hrn(self.driver.hrn, self.driver.testbedInfo['name'], slicename)
210                 slice_urn = hrn_to_urn(slice_hrn, 'slice')
211
212             rspec_lease['slice_id'] = slice_urn
213             rspec_lease['start_time'] = lease['start_time']
214             rspec_lease['duration'] = (int(lease['end_time']) - int(lease['start_time'])) / int(grain)
215             rspec_leases.append(rspec_lease)
216
217         return (rspec_leases, rspec_channels)
218
219
220     def get_channels(self, slice=None, options={}):
221  
222         all_channels = self.driver.shell.getChannels({}, [])
223         channels = []
224         if slice:
225             reserved_channels = self.driver.shell.getReservedChannels()
226             reserved_channel_ids = []
227             for channel in reserved_channels:
228                  if channel['slice_id'] == slice['slice_id']:
229                      reserved_channel_ids.append(channel['channel_id'])
230
231             for channel in all_channels:
232                  if channel['channel_id'] in reserved_channel_ids:
233                      channels.append(channel)
234         else:
235             channels = all_channels
236
237         rspec_channels = []
238         for channel in channels:
239             rspec_channel = Channel()
240             rspec_channel['channel_num'] = channel['channel']
241             rspec_channel['frequency'] = channel['frequency']
242             rspec_channel['standard'] = channel['modulation']
243             rspec_channel['component_id'] = channel_to_urn(self.driver.hrn, self.driver.testbedInfo['name'], channel['channel'])
244             rspec_channels.append(rspec_channel)
245         return rspec_channels
246
247
248     
249     def get_rspec(self, slice_xrn=None, version = None, options={}):
250
251         version_manager = VersionManager()
252         version = version_manager.get_version(version)
253
254         if not slice_xrn:
255             rspec_version = version_manager._get_version(version.type, version.version, 'ad')
256         else:
257             rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
258
259         slice, slivers = self.get_slice_and_slivers(slice_xrn)
260
261         rspec = RSpec(version=rspec_version, user_options=options)
262
263         if slice and 'expires' in slice:
264             rspec.xml.set('expires',  datetime_to_string(utcparse(slice['expires'])))
265
266         if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'leases':
267            nodes = self.get_nodes(slice_xrn, slice, slivers, options)
268            rspec.version.add_nodes(nodes)
269            # add sliver defaults
270            default_sliver = slivers.get(None, [])
271            if default_sliver:
272               default_sliver_attribs = default_sliver.get('tags', [])
273               for attrib in default_sliver_attribs:
274                   logger.info(attrib)
275                   rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
276            # add wifi channels
277            channels = self.get_channels(slice, options)
278            rspec.version.add_channels(channels)
279
280         if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'resources':
281            leases_channels = self.get_leases_and_channels(slice, slice_xrn)
282            rspec.version.add_leases(leases_channels)
283
284         return rspec.toxml()
285
286