Merge Master in geni-v3 conflict resolution
[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
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                  
168             # retreive slicename
169             for slc in slices:
170                  if slc['slice_id'] == channel['slice_id']:
171                      slicename = slc['slice_name']
172                      break
173
174             if slice_xrn:
175                 slice_urn = slice_xrn
176                 slice_hrn = urn_to_hrn(slice_urn)
177             else:
178                 slice_hrn = slicename_to_hrn(self.driver.hrn, self.driver.testbedInfo['name'], slicename)
179                 slice_urn = hrn_to_urn(slice_hrn, 'slice')
180
181             rspec_channel['slice_id'] = slice_urn
182             rspec_channels.append(rspec_channel)
183
184  
185         rspec_leases = []
186         for lease in leases:
187
188             rspec_lease = Lease()
189             
190             rspec_lease['lease_id'] = lease['reservation_id']
191             # retreive node name
192             for node in nodes:
193                  if node['node_id'] == lease['node_id']:
194                      nodename = node['hostname']
195                      break
196            
197             rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, self.driver.testbedInfo['name'], nodename)
198             # retreive slicename
199             for slc in slices:
200                  if slc['slice_id'] == lease['slice_id']:
201                      slicename = slc['slice_name']
202                      break
203             
204             if slice_xrn:
205                 slice_urn = slice_xrn
206                 slice_hrn = urn_to_hrn(slice_urn)
207             else:
208                 slice_hrn = slicename_to_hrn(self.driver.hrn, self.driver.testbedInfo['name'], slicename)
209                 slice_urn = hrn_to_urn(slice_hrn, 'slice')
210
211             rspec_lease['slice_id'] = slice_urn
212             rspec_lease['start_time'] = lease['start_time']
213             rspec_lease['duration'] = (int(lease['end_time']) - int(lease['start_time'])) / int(grain)
214             rspec_leases.append(rspec_lease)
215
216         return (rspec_leases, rspec_channels)
217
218
219     def get_channels(self, slice=None, options={}):
220  
221         all_channels = self.driver.shell.getChannels({}, [])
222         channels = []
223         if slice:
224             reserved_channels = self.driver.shell.getReservedChannels()
225             reserved_channel_ids = []
226             for channel in reserved_channels:
227                  if channel['slice_id'] == slice['slice_id']:
228                      reserved_channel_ids.append(channel['channel_id'])
229
230             for channel in all_channels:
231                  if channel['channel_id'] in reserved_channel_ids:
232                      channels.append(channel)
233         else:
234             channels = all_channels
235
236         rspec_channels = []
237         for channel in channels:
238             rspec_channel = Channel()
239             rspec_channel['channel_num'] = channel['channel']
240             rspec_channel['frequency'] = channel['frequency']
241             rspec_channel['standard'] = channel['modulation']
242             rspec_channels.append(rspec_channel)
243         return rspec_channels
244
245
246     
247     def get_rspec(self, slice_xrn=None, version = None, options={}):
248
249         version_manager = VersionManager()
250         version = version_manager.get_version(version)
251
252         if not slice_xrn:
253             rspec_version = version_manager._get_version(version.type, version.version, 'ad')
254         else:
255             rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
256
257         slice, slivers = self.get_slice_and_slivers(slice_xrn)
258
259         rspec = RSpec(version=rspec_version, user_options=options)
260
261         if slice and 'expires' in slice:
262             rspec.xml.set('expires',  datetime_to_string(utcparse(slice['expires'])))
263
264         if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'leases':
265            nodes = self.get_nodes(slice_xrn, slice, slivers, options)
266            rspec.version.add_nodes(nodes)
267            # add sliver defaults
268            default_sliver = slivers.get(None, [])
269            if default_sliver:
270               default_sliver_attribs = default_sliver.get('tags', [])
271               for attrib in default_sliver_attribs:
272                   logger.info(attrib)
273                   rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
274            # add wifi channels
275            channels = self.get_channels(slice, options)
276            rspec.version.add_channels(channels)
277
278         if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'resources':
279            leases, channels = self.get_leases_and_channels(slice, slice_xrn)
280            rspec.version.add_leases(leases, channels)
281
282         return rspec.toxml()
283
284