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'] = PlXrn(self.driver.hrn, hostname=node['hostname']).get_urn()
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 if node['boot_state'] == 'boot':
165 rspec_node['available'] = 'true'
167 rspec_node['available'] = 'false'
168 rspec_node['exclusive'] = 'false'
169 rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
170 HardwareType({'name': 'pc'})]
171 # only doing this because protogeni rspec needs
172 # to advertise available initscripts
173 rspec_node['pl_initscripts'] = pl_initscripts.values()
174 # add site/interface info to nodes.
175 # assumes that sites, interfaces and tags have already been prepared.
176 if site['longitude'] and site['latitude']:
177 location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
178 rspec_node['location'] = location
180 granularity = Granularity({'grain': grain})
181 rspec_node['granularity'] = granularity
182 rspec_node['interfaces'] = []
184 for if_id in node['interface_ids']:
185 interface = Interface(interfaces[if_id])
186 interface['ipv4'] = interface['ip']
187 interface['component_id'] = PlXrn(auth=self.driver.hrn,
188 interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
189 # interfaces in the manifest need a client id
191 interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
192 rspec_node['interfaces'].append(interface)
194 tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids'] if tag_id in node_tags]
195 rspec_node['tags'] = tags
198 def sliver_to_rspec_node(self, sliver, sites, interfaces, node_tags, \
199 pl_initscripts, sliver_allocations):
200 # get the granularity in second for the reservation system
201 grain = self.driver.shell.GetLeaseGranularity()
202 rspec_node = self.node_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts, grain)
203 # xxx how to retrieve site['login_base']
204 rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
205 # remove interfaces from manifest
206 rspec_node['interfaces'] = []
208 rspec_sliver = Sliver({'sliver_id': sliver['urn'],
209 'name': sliver['name'],
210 'type': 'plab-vserver',
212 rspec_node['sliver_id'] = rspec_sliver['sliver_id']
213 rspec_node['client_id'] = sliver_allocations[sliver['urn']].client_id
214 if sliver_allocations[sliver['urn']].component_id:
215 rspec_node['component_id'] = sliver_allocations[sliver['urn']].component_id
216 rspec_node['slivers'] = [rspec_sliver]
218 # slivers always provide the ssh service
219 login = Login({'authentication': 'ssh-keys', 'hostname': sliver['hostname'], 'port':'22', 'username': sliver['name']})
220 service = Services({'login': login})
221 rspec_node['services'] = [service]
224 def get_slice_tags(self, slice):
226 slice_tag_ids.extend(slice['slice_tag_ids'])
227 tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice_tag_ids})
229 tags_dict = defaultdict(list)
231 tags_dict[tag['node_id']] = tag
234 def get_slice_nodes(self, slice, options={}):
236 filter = {'peer_id': None}
238 if slice and slice.get('node_ids'):
239 filter['node_id'] = slice['node_ids']
241 # there are no nodes to look up
243 tags_filter=filter.copy()
244 geni_available = options.get('geni_available')
245 if geni_available == True:
246 filter['boot_state'] = 'boot'
247 nodes = self.driver.shell.GetNodes(filter)
249 nodes_dict[node['node_id']] = node
252 def rspec_node_to_geni_sliver(self, rspec_node, sliver_allocations = {}):
253 if rspec_node['sliver_id'] in sliver_allocations:
254 # set sliver allocation and operational status
255 sliver_allocation = sliver_allocations[rspec_node['sliver_id']]
256 if sliver_allocation:
257 allocation_status = sliver_allocation.allocation_state
258 if allocation_status == 'geni_allocated':
259 op_status = 'geni_pending_allocation'
260 elif allocation_status == 'geni_provisioned':
261 if rspec_node['boot_state'] == 'boot':
262 op_status = 'geni_ready'
264 op_status = 'geni_failed'
266 op_status = 'geni_unknown'
268 allocation_status = 'geni_unallocated'
270 geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
271 'geni_expires': rspec_node['expires'],
272 'geni_allocation_status' : allocation_status,
273 'geni_operational_status': op_status,
278 def get_leases(self, slice=None, options={}):
280 now = int(time.time())
282 filter.update({'clip':now})
284 filter.update({'name':slice['name']})
285 return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
286 leases = self.driver.shell.GetLeases(filter)
287 grain = self.driver.shell.GetLeaseGranularity()
291 site_ids.append(lease['site_id'])
294 sites_dict = self.get_sites({'site_id': site_ids})
299 rspec_lease = Lease()
301 # xxx how to retrieve site['login_base']
302 site_id=lease['site_id']
303 site=sites_dict[site_id]
305 rspec_lease['lease_id'] = lease['lease_id']
306 rspec_lease['component_id'] = PlXrn(self.driver.hrn, hostname=lease['hostname']).urn
307 slice_hrn = slicename_to_hrn(self.driver.hrn, lease['name'])
308 slice_urn = hrn_to_urn(slice_hrn, 'slice')
309 rspec_lease['slice_id'] = slice_urn
310 rspec_lease['start_time'] = lease['t_from']
311 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) / grain
312 rspec_leases.append(rspec_lease)
316 def list_resources(self, version = None, options={}):
318 version_manager = VersionManager()
319 version = version_manager.get_version(version)
320 rspec_version = version_manager._get_version(version.type, version.version, 'ad')
321 rspec = RSpec(version=rspec_version, user_options=options)
323 if not options.get('list_leases') or options['list_leases'] != 'leases':
325 nodes = self.get_nodes(options)
331 site_ids.append(node['site_id'])
332 interface_ids.extend(node['interface_ids'])
333 tag_ids.extend(node['node_tag_ids'])
334 nodes_dict[node['node_id']] = node
335 sites = self.get_sites({'site_id': site_ids})
336 interfaces = self.get_interfaces({'interface_id':interface_ids})
337 node_tags = self.get_node_tags({'node_tag_id': tag_ids})
338 pl_initscripts = self.get_pl_initscripts()
339 # convert nodes to rspec nodes
342 rspec_node = self.node_to_rspec_node(node, sites, interfaces, node_tags, pl_initscripts)
343 rspec_nodes.append(rspec_node)
344 rspec.version.add_nodes(rspec_nodes)
347 links = self.get_links(sites, nodes_dict, interfaces)
348 rspec.version.add_links(links)
351 def describe(self, urns, version=None, options={}):
352 version_manager = VersionManager()
353 version = version_manager.get_version(version)
354 rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
355 rspec = RSpec(version=rspec_version, user_options=options)
359 slivers = self.get_slivers(urns, options)
361 rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
363 rspec_expires = datetime_to_string(utcparse(time.time()))
364 rspec.xml.set('expires', rspec_expires)
366 # lookup the sliver allocations
367 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
368 constraint = SliverAllocation.sliver_id.in_(sliver_ids)
369 sliver_allocations = dbsession.query(SliverAllocation).filter(constraint)
370 sliver_allocation_dict = {}
371 for sliver_allocation in sliver_allocations:
372 sliver_allocation_dict[sliver_allocation.sliver_id] = sliver_allocation
374 if not options.get('list_leases') or options['list_leases'] != 'leases':
380 for sliver in slivers:
381 site_ids.append(sliver['site_id'])
382 interface_ids.extend(sliver['interface_ids'])
383 tag_ids.extend(sliver['node_tag_ids'])
384 nodes_dict[sliver['node_id']] = sliver
385 sites = self.get_sites({'site_id': site_ids})
386 interfaces = self.get_interfaces({'interface_id':interface_ids})
387 node_tags = self.get_node_tags({'node_tag_id': tag_ids})
388 pl_initscripts = self.get_pl_initscripts()
390 for sliver in slivers:
391 if sliver['slice_ids_whitelist'] and sliver['slice_id'] not in sliver['slice_ids_whitelist']:
393 rspec_node = self.sliver_to_rspec_node(sliver, sites, interfaces, node_tags,
394 pl_initscripts, sliver_allocation_dict)
395 # manifest node element shouldn't contain available attribute
396 rspec_node.pop('available')
397 rspec_nodes.append(rspec_node)
398 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node, sliver_allocation_dict)
399 geni_slivers.append(geni_sliver)
400 rspec.version.add_nodes(rspec_nodes)
402 # add sliver defaults
403 #default_sliver = slivers.get(None, [])
405 # default_sliver_attribs = default_sliver.get('tags', [])
406 # for attrib in default_sliver_attribs:
407 # rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
410 links = self.get_links(sites, nodes_dict, interfaces)
411 rspec.version.add_links(links)
413 if not options.get('list_leases') or options['list_leases'] != 'resources':
415 leases = self.get_leases(slivers[0])
416 rspec.version.add_leases(leases)
419 return {'geni_urn': urns[0],
420 'geni_rspec': rspec.toxml(),
421 'geni_slivers': geni_slivers}