First draft of the Nitos federation with SFA
[sfa.git] / sfa / nitos / nitosaggregate.py
1 #!/usr/bin/python
2 from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn, urn_to_sliver_id
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     def get_sites(self, filter={}):
34         sites = {}
35         for site in self.driver.shell.GetSites(filter):
36             sites[site['site_id']] = site
37         return sites
38
39     def get_interfaces(self, filter={}):
40         interfaces = {}
41         for interface in self.driver.shell.GetInterfaces(filter):
42             iface = Interface()
43             if interface['bwlimit']:
44                 interface['bwlimit'] = str(int(interface['bwlimit'])/1000)
45             interfaces[interface['interface_id']] = interface
46         return interfaces
47
48     def get_links(self, sites, nodes, interfaces):
49         
50         topology = Topology() 
51         links = []
52         for (site_id1, site_id2) in topology:
53             site_id1 = int(site_id1)
54             site_id2 = int(site_id2)
55             link = Link()
56             if not site_id1 in sites or site_id2 not in sites:
57                 continue
58             site1 = sites[site_id1]
59             site2 = sites[site_id2]
60             # get hrns
61             site1_hrn = self.driver.hrn + '.' + site1['login_base']
62             site2_hrn = self.driver.hrn + '.' + site2['login_base']
63
64             for s1_node_id in site1['node_ids']:
65                 for s2_node_id in site2['node_ids']:
66                     if s1_node_id not in nodes or s2_node_id not in nodes:
67                         continue
68                     node1 = nodes[s1_node_id]
69                     node2 = nodes[s2_node_id]
70                     # set interfaces
71                     # just get first interface of the first node
72                     if1_xrn = PlXrn(auth=self.driver.hrn, interface='node%s:eth0' % (node1['node_id']))
73                     if1_ipv4 = interfaces[node1['interface_ids'][0]]['ip']
74                     if2_xrn = PlXrn(auth=self.driver.hrn, interface='node%s:eth0' % (node2['node_id']))
75                     if2_ipv4 = interfaces[node2['interface_ids'][0]]['ip']
76
77                     if1 = Interface({'component_id': if1_xrn.urn, 'ipv4': if1_ipv4} )
78                     if2 = Interface({'component_id': if2_xrn.urn, 'ipv4': if2_ipv4} )
79
80                     # set link
81                     link = Link({'capacity': '1000000', 'latency': '0', 'packet_loss': '0', 'type': 'ipv4'})
82                     link['interface1'] = if1
83                     link['interface2'] = if2
84                     link['component_name'] = "%s:%s" % (site1['login_base'], site2['login_base'])
85                     link['component_id'] = PlXrn(auth=self.driver.hrn, interface=link['component_name']).get_urn()
86                     link['component_manager_id'] =  hrn_to_urn(self.driver.hrn, 'authority+am')
87                     links.append(link)
88
89         return links
90
91     def get_node_tags(self, filter={}):
92         node_tags = {}
93         for node_tag in self.driver.shell.GetNodeTags(filter):
94             node_tags[node_tag['node_tag_id']] = node_tag
95         return node_tags
96
97     def get_pl_initscripts(self, filter={}):
98         pl_initscripts = {}
99         filter.update({'enabled': True})
100         for initscript in self.driver.shell.GetInitScripts(filter):
101             pl_initscripts[initscript['initscript_id']] = initscript
102         return pl_initscripts
103
104
105     def get_slice_and_slivers(self, slice_xrn):
106         """
107         Returns a dict of slivers keyed on the sliver's node_id
108         """
109         slivers = {}
110         slice = None
111         if not slice_xrn:
112             return (slice, slivers)
113         slice_urn = hrn_to_urn(slice_xrn, 'slice')
114         slice_hrn, _ = urn_to_hrn(slice_xrn)
115         slice_name = hrn_to_nitos_slicename(slice_hrn)
116         slices = self.driver.shell.getSlices()
117         # filter results
118         for slc in slices:
119              if slc['slice_name'] == slice_name:
120                  slice = slc
121                  break
122
123         if not slice:
124             return (slice, slivers)
125       
126         reserved_nodes = self.driver.shell.getReservedNodes()
127         # filter results
128         for node in reserved_nodes:
129              if node['slice_id'] == slice['slice_id']:
130                  slivers[node[node_id]] = node
131
132         return (slice, slivers)
133        
134
135
136     def get_nodes_and_links(self, slice_xrn, slice=None,slivers={}, options={}):
137         # if we are dealing with a slice that has no node just return 
138         # and empty list    
139         if slice_xrn:
140             if not slice or not slivers:
141                 return ([],[])
142             else:
143                 nodes = [slivers[sliver] for sliver in slivers]
144         else:
145             nodes = self.driver.shell.getNodes()
146         
147         # get the granularity in second for the reservation system
148         grain = self.driver.testbedInfo['grain']
149         #grain = 1800
150        
151  
152
153         rspec_nodes = []
154         for node in nodes:
155             rspec_node = Node()
156             site_name = self.driver.testbedInfo['name']
157             rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site_name, node['name'])
158             rspec_node['component_name'] = node['name']
159             rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
160             rspec_node['authority_id'] = hrn_to_urn(NitosXrn.site_hrn(self.driver.hrn, site_name), 'authority+sa')
161             # do not include boot state (<available> element) in the manifest rspec
162             #if not slice:     
163             #    rspec_node['boot_state'] = node['boot_state']
164             rspec_node['exclusive'] = 'true'
165             # site location
166             longitude = self.driver.testbedInfo['longitude']
167             latitude = self.driver.testbedInfo['latitude']  
168             if longitude and latitude:  
169                 location = Location({'longitude': longitude, 'latitude': latitude, 'country': 'unknown'})
170                 rspec_node['location'] = location
171             # 3D position
172             position_3d = Position3D({'x': node['position']['X'], 'y': node['position']['Y'], 'z': node['position']['Z']})
173             #position_3d = Position3D({'x': 1, 'y': 2, 'z': 3})
174             rspec_node['position_3d'] = position_3d 
175             # Granularity
176             granularity = Granularity({'grain': grain})
177             rspec_node['granularity'] = granularity
178
179             # HardwareType
180             rspec_node['hardware_type'] = node['node_type']
181             #rspec_node['hardware_type'] = "orbit"
182
183                 
184             rspec_nodes.append(rspec_node)
185         return (rspec_nodes, []) 
186
187     def get_leases_and_channels(self, slice=None, options={}):
188         
189         slices = self.driver.shell.getSlices()
190         nodes = self.driver.shell.getNodes()
191         leases = self.driver.shell.getReservedNodes()
192         channels = self.driver.shell.getChannels()
193         reserved_channels = self.driver.shell.getReservedChannels()
194         grain = self.driver.testbedInfo['grain']
195
196         if slice:
197             for lease in leases:
198                  if lease['slice_id'] != slice['slice_id']:
199                      leases.remove(lease)
200             for channel in reserved_channels:
201                  if channel['slice_id'] != slice['slice_id']:
202                      reserved_channels.remove(channel)
203
204         rspec_channels = []
205         for channel in reserved_channels:
206              
207             rspec_channel = {}
208             #retrieve channel number  
209             for chl in channels:
210                  if chl['channel_id'] == channel['channel_id']:
211                      channel_number = chl['channel']
212                      break
213
214             rspec_channel['channel_num'] = channel_number
215             rspec_channel['start_time'] = channel['start_time']
216             rspec_channel['duration'] = (int(channel['end_time']) - int(channel['start_time'])) / int(grain)
217                  
218             # retreive slicename
219             for slc in slices:
220                  if slc['slice_id'] == channel['slice_id']:
221                      slicename = slc['slice_name']
222                      break
223
224             slice_hrn = slicename_to_hrn(self.driver.hrn, self.driver.testbedInfo['name'], slicename)
225             slice_urn = hrn_to_urn(slice_hrn, 'slice')
226             rspec_channel['slice_id'] = slice_urn
227             rspec_channels.append(rspec_channel)
228
229  
230         rspec_leases = []
231         for lease in leases:
232
233             rspec_lease = Lease()
234             
235             rspec_lease['lease_id'] = lease['reservation_id']
236             # retreive node name
237             for node in nodes:
238                  if node['node_id'] == lease['node_id']:
239                      nodename = node['name']
240                      break
241            
242             rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, self.driver.testbedInfo['name'], nodename)
243             # retreive slicename
244             for slc in slices:
245                  if slc['slice_id'] == lease['slice_id']:
246                      slicename = slc['slice_name']
247                      break
248             
249             slice_hrn = slicename_to_hrn(self.driver.hrn, self.driver.testbedInfo['name'], slicename)
250             slice_urn = hrn_to_urn(slice_hrn, 'slice')
251             rspec_lease['slice_id'] = slice_urn
252             rspec_lease['start_time'] = lease['start_time']
253             rspec_lease['duration'] = (int(lease['end_time']) - int(lease['start_time'])) / int(grain)
254             rspec_leases.append(rspec_lease)
255
256         return (rspec_leases, rspec_channels)
257
258
259     def get_channels(self, options={}):
260         
261         filter = {}
262         channels = self.driver.shell.getChannels()
263         rspec_channels = []
264         for channel in channels:
265             rspec_channel = Channel()
266             rspec_channel['channel_num'] = channel['channel']
267             rspec_channel['frequency'] = channel['frequency']
268             rspec_channel['standard'] = channel['modulation']
269             rspec_channels.append(rspec_channel)
270         return rspec_channels
271
272
273     
274     def get_rspec(self, slice_xrn=None, version = None, options={}):
275
276         version_manager = VersionManager()
277         version = version_manager.get_version(version)
278
279         if not slice_xrn:
280             rspec_version = version_manager._get_version(version.type, version.version, 'ad')
281         else:
282             rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
283
284         slice, slivers = self.get_slice_and_slivers(slice_xrn)
285
286         rspec = RSpec(version=rspec_version, user_options=options)
287
288         if slice and 'expires' in slice:
289             rspec.xml.set('expires',  datetime_to_string(utcparse(slice['expires'])))
290
291         if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'leases':
292            nodes, links = self.get_nodes_and_links(slice_xrn, slice, slivers, options)
293            rspec.version.add_nodes(nodes)
294            rspec.version.add_links(links)
295            # add sliver defaults
296            default_sliver = slivers.get(None, [])
297            if default_sliver:
298               default_sliver_attribs = default_sliver.get('tags', [])
299               for attrib in default_sliver_attribs:
300                   logger.info(attrib)
301                   rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
302            # add wifi channels
303            channels = self.get_channels()
304            rspec.version.add_channels(channels)
305
306         if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'resources':
307            leases, channels = self.get_leases_and_channels(slice)
308            rspec.version.add_leases(leases, channels)
309
310         return rspec.toxml()
311
312