2 from collections import defaultdict
3 from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn
4 from sfa.util.sfatime import utcparse, datetime_to_string
5 from sfa.util.sfalogging import logger
6 from sfa.util.faults import SliverDoesNotExist
7 from sfa.rspecs.rspec import RSpec
8 from sfa.rspecs.elements.hardware_type import HardwareType
9 from sfa.rspecs.elements.node import Node
10 from sfa.rspecs.elements.link import Link
11 from sfa.rspecs.elements.sliver import Sliver
12 from sfa.rspecs.elements.login import Login
13 from sfa.rspecs.elements.location import Location
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.version_manager import VersionManager
21 from sfa.planetlab.plxrn import PlXrn, hostname_to_urn, hrn_to_pl_slicename, slicename_to_hrn
22 from sfa.planetlab.vlink import get_tc_rate
23 from sfa.planetlab.topology import Topology
24 from sfa.storage.alchemy import dbsession
25 from sfa.storage.model import SliverAllocation
32 def __init__(self, driver):
35 def get_nodes(self, options={}):
36 filter = {'peer_id': None}
37 geni_available = options.get('geni_available')
38 if geni_available == True:
39 filter['boot_state'] = 'boot'
40 nodes = self.driver.shell.GetNodes(filter)
44 def get_sites(self, filter={}):
46 for site in self.driver.shell.GetSites(filter):
47 sites[site['site_id']] = site
50 def get_interfaces(self, filter={}):
52 for interface in self.driver.shell.GetInterfaces(filter):
54 if interface['bwlimit']:
55 interface['bwlimit'] = str(int(interface['bwlimit'])/1000)
56 interfaces[interface['interface_id']] = interface
59 def get_links(self, sites, nodes, interfaces):
63 for (site_id1, site_id2) in topology:
64 site_id1 = int(site_id1)
65 site_id2 = int(site_id2)
67 if not site_id1 in sites or site_id2 not in sites:
69 site1 = sites[site_id1]
70 site2 = sites[site_id2]
72 site1_hrn = self.driver.hrn + '.' + site1['login_base']
73 site2_hrn = self.driver.hrn + '.' + site2['login_base']
75 for s1_node_id in site1['node_ids']:
76 for s2_node_id in site2['node_ids']:
77 if s1_node_id not in nodes or s2_node_id not in nodes:
79 node1 = nodes[s1_node_id]
80 node2 = nodes[s2_node_id]
82 # just get first interface of the first node
83 if1_xrn = PlXrn(auth=self.driver.hrn, interface='node%s:eth0' % (node1['node_id']))
84 if1_ipv4 = interfaces[node1['interface_ids'][0]]['ip']
85 if2_xrn = PlXrn(auth=self.driver.hrn, interface='node%s:eth0' % (node2['node_id']))
86 if2_ipv4 = interfaces[node2['interface_ids'][0]]['ip']
88 if1 = Interface({'component_id': if1_xrn.urn, 'ipv4': if1_ipv4} )
89 if2 = Interface({'component_id': if2_xrn.urn, 'ipv4': if2_ipv4} )
92 link = Link({'capacity': '1000000', 'latency': '0', 'packet_loss': '0', 'type': 'ipv4'})
93 link['interface1'] = if1
94 link['interface2'] = if2
95 link['component_name'] = "%s:%s" % (site1['login_base'], site2['login_base'])
96 link['component_id'] = PlXrn(auth=self.driver.hrn, interface=link['component_name']).get_urn()
97 link['component_manager_id'] = hrn_to_urn(self.driver.hrn, 'authority+am')
102 def get_node_tags(self, filter={}):
104 for node_tag in self.driver.shell.GetNodeTags(filter):
105 node_tags[node_tag['node_tag_id']] = node_tag
108 def get_pl_initscripts(self, filter={}):
110 filter.update({'enabled': True})
111 for initscript in self.driver.shell.GetInitScripts(filter):
112 pl_initscripts[initscript['initscript_id']] = initscript
113 return pl_initscripts
115 def get_slivers(self, urns, options={}):
121 if xrn.type == 'sliver':
122 # id: slice_id-node_id
123 id_parts = xrn.leaf.split('-')
124 slice_ids.add(id_parts[0])
125 node_ids.append(id_parts[1])
127 names.add(xrn.pl_slicename())
133 filter['name'] = list(names)
135 filter['slice_id'] = list(slice_ids)
136 slices = self.driver.shell.GetSlices(filter)
141 slice['node_ids'] = node_ids
142 tags_dict = self.get_slice_tags(slice)
143 nodes_dict = self.get_slice_nodes(slice, options)
145 for node in nodes_dict.values():
146 node.update(slices[0])
147 node['tags'] = tags_dict[node['node_id']]
148 sliver_hrn = '%s.%s-%s' % (self.driver.hrn, slice['slice_id'], node['node_id'])
149 node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
150 node['urn'] = node['sliver_id']
154 def node_to_rspec_node(self, node, sites, interfaces, node_tags, pl_initscripts=[], grain=None, options={}):
156 # xxx how to retrieve site['login_base']
157 site=sites[node['site_id']]
158 rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], node['hostname'])
159 rspec_node['component_name'] = node['hostname']
160 rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
161 rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
162 # do not include boot state (<available> element) in the manifest rspec
163 rspec_node['boot_state'] = node['boot_state']
164 rspec_node['exclusive'] = 'false'
165 rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
166 HardwareType({'name': 'pc'})]
167 # only doing this because protogeni rspec needs
168 # to advertise available initscripts
169 rspec_node['pl_initscripts'] = pl_initscripts.values()
170 # add site/interface info to nodes.
171 # assumes that sites, interfaces and tags have already been prepared.
172 if site['longitude'] and site['latitude']:
173 location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
174 rspec_node['location'] = location
176 granularity = Granularity({'grain': grain})
177 rspec_node['granularity'] = granularity
178 rspec_node['interfaces'] = []
180 for if_id in node['interface_ids']:
181 interface = Interface(interfaces[if_id])
182 interface['ipv4'] = interface['ip']
183 interface['component_id'] = PlXrn(auth=self.driver.hrn,
184 interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
185 # interfaces in the manifest need a client id
187 interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
188 rspec_node['interfaces'].append(interface)
190 tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
191 rspec_node['tags'] = tags
194 def sliver_to_rspec_node(self, sliver, sites, interfaces, node_tags, pl_initscripts):
195 # get the granularity in second for the reservation system
196 grain = self.driver.shell.GetLeaseGranularity()
197 rspec_node = self.node_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts, grain)
198 # xxx how to retrieve site['login_base']
199 rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
200 # remove interfaces from manifest
201 rspec_node['interfaces'] = []
203 rspec_sliver = Sliver({'sliver_id': sliver['urn'],
204 'name': sliver['name'],
205 'type': 'plab-vserver',
207 rspec_node['sliver_id'] = rspec_sliver['sliver_id']
208 rspec_node['client_id'] = sliver['hostname']
209 rspec_node['slivers'] = [rspec_sliver]
211 # slivers always provide the ssh service
212 login = Login({'authentication': 'ssh-keys', 'hostname': sliver['hostname'], 'port':'22', 'username': sliver['name']})
213 service = Services({'login': login})
214 rspec_node['services'] = [service]
217 def get_slice_tags(self, slice):
219 slice_tag_ids.extend(slice['slice_tag_ids'])
220 tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice_tag_ids})
222 tags_dict = defaultdict(list)
224 tags_dict[tag['node_id']] = tag
227 def get_slice_nodes(self, slice, options={}):
229 filter = {'peer_id': None}
231 if slice and slice.get('node_ids'):
232 filter['node_id'] = slice['node_ids']
234 # there are no nodes to look up
236 tags_filter=filter.copy()
237 geni_available = options.get('geni_available')
238 if geni_available == True:
239 filter['boot_state'] = 'boot'
240 nodes = self.driver.shell.GetNodes(filter)
242 nodes_dict[node['node_id']] = node
245 def rspec_node_to_geni_sliver(self, rspec_node):
246 op_status = "geni_unknown"
247 state = rspec_node['boot_state'].lower()
249 op_status = 'geni_ready'
251 op_status =' geni_failed'
255 geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
256 'geni_expires': rspec_node['expires'],
257 'geni_operational_status': op_status,
262 def get_leases(self, slice=None, options={}):
264 now = int(time.time())
266 filter.update({'clip':now})
268 filter.update({'name':slice['name']})
269 return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
270 leases = self.driver.shell.GetLeases(filter)
271 grain = self.driver.shell.GetLeaseGranularity()
275 site_ids.append(lease['site_id'])
278 sites_dict = self.get_sites({'site_id': site_ids})
283 rspec_lease = Lease()
285 # xxx how to retrieve site['login_base']
286 site_id=lease['site_id']
287 site=sites_dict[site_id]
289 rspec_lease['lease_id'] = lease['lease_id']
290 rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], lease['hostname'])
291 slice_hrn = slicename_to_hrn(self.driver.hrn, lease['name'])
292 slice_urn = hrn_to_urn(slice_hrn, 'slice')
293 rspec_lease['slice_id'] = slice_urn
294 rspec_lease['start_time'] = lease['t_from']
295 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) / grain
296 rspec_leases.append(rspec_lease)
300 def list_resources(self, version = None, options={}):
302 version_manager = VersionManager()
303 version = version_manager.get_version(version)
304 rspec_version = version_manager._get_version(version.type, version.version, 'ad')
305 rspec = RSpec(version=rspec_version, user_options=options)
307 if not options.get('list_leases') or options['list_leases'] != 'leases':
309 nodes = self.get_nodes(options)
315 site_ids.append(node['site_id'])
316 interface_ids.extend(node['interface_ids'])
317 tag_ids.extend(node['node_tag_ids'])
318 nodes_dict[node['node_id']] = node
319 sites = self.get_sites({'site_id': site_ids})
320 interfaces = self.get_interfaces({'interface_id':interface_ids})
321 node_tags = self.get_node_tags({'node_tag_id': tag_ids})
322 pl_initscripts = self.get_pl_initscripts()
323 # convert nodes to rspec nodes
326 rspec_node = self.node_to_rspec_node(node, sites, interfaces, node_tags, pl_initscripts)
327 rspec_nodes.append(rspec_node)
328 rspec.version.add_nodes(rspec_nodes)
331 links = self.get_links(sites, nodes_dict, interfaces)
332 rspec.version.add_links(links)
335 def describe(self, urns, version=None, options={}):
336 version_manager = VersionManager()
337 version = version_manager.get_version(version)
338 rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
339 rspec = RSpec(version=version, user_options=options)
343 slivers = self.get_slivers(urns, options)
344 if len(slivers) == 0:
345 raise SliverDoesNotExist("You have not allocated any slivers here for %s" % str(urns))
346 rspec.xml.set('expires', datetime_to_string(utcparse(slivers[0]['expires'])))
348 # lookup the sliver allocations
349 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
350 constraint = SliverAllocation.sliver_id.in_(sliver_ids)
351 sliver_allocations = dbsession.query(SliverAllocation).filter(constraint)
352 sliver_allocation_dict = {}
353 for sliver_allocation in sliver_allocations:
354 sliver_allocation_dict[sliver_allocation.sliver_id] = sliver_allocation
356 if not options.get('list_leases') or options['list_leases'] != 'leases':
362 for sliver in slivers:
363 site_ids.append(sliver['site_id'])
364 interface_ids.extend(sliver['interface_ids'])
365 tag_ids.extend(sliver['node_tag_ids'])
366 nodes_dict[sliver['node_id']] = sliver
367 sites = self.get_sites({'site_id': site_ids})
368 interfaces = self.get_interfaces({'interface_id':interface_ids})
369 node_tags = self.get_node_tags({'node_tag_id': tag_ids})
370 pl_initscripts = self.get_pl_initscripts()
372 for sliver in slivers:
373 if sliver['slice_ids_whitelist'] and sliver['slice_id'] not in sliver['slice_ids_whitelist']:
375 rspec_node = self.sliver_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts)
376 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node)
377 sliver_allocation = sliver_allocation_dict[sliver['sliver_id']]
378 geni_sliver['geni_allocation_status'] = sliver_allocation.allocation_state
379 rspec_nodes.append(rspec_node)
380 geni_slivers.append(geni_sliver)
381 rspec.version.add_nodes(rspec_nodes)
383 # add sliver defaults
384 #default_sliver = slivers.get(None, [])
386 # default_sliver_attribs = default_sliver.get('tags', [])
387 # for attrib in default_sliver_attribs:
388 # rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
391 links = self.get_links(sites, nodes_dict, interfaces)
392 rspec.version.add_links(links)
394 if not options.get('list_leases') or options['list_leases'] != 'resources':
395 leases = self.get_leases(slivers[0])
396 rspec.version.add_leases(leases)
399 return {'geni_urn': urns[0],
400 'geni_rspec': rspec.toxml(),
401 'geni_slivers': geni_slivers}