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 sliver_id_parts = xrn.get_sliver_id_parts()
124 slice_ids.add(sliver_id_parts[0])
125 node_ids.append(sliver_id_parts[1])
127 names.add(xrn.pl_slicename())
131 filter['name'] = list(names)
133 filter['slice_id'] = list(slice_ids)
134 slices = self.driver.shell.GetSlices(filter)
139 slice['node_ids'] = node_ids
140 tags_dict = self.get_slice_tags(slice)
141 nodes_dict = self.get_slice_nodes(slice, options)
143 for node in nodes_dict.values():
144 node.update(slices[0])
145 node['tags'] = tags_dict[node['node_id']]
146 sliver_hrn = '%s.%s-%s' % (self.driver.hrn, slice['slice_id'], node['node_id'])
147 node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
148 node['urn'] = node['sliver_id']
152 def node_to_rspec_node(self, node, sites, interfaces, node_tags, pl_initscripts=[], grain=None, options={}):
154 # xxx how to retrieve site['login_base']
155 site=sites[node['site_id']]
156 rspec_node['component_id'] = PlXrn(self.driver.hrn, hostname=node['hostname']).get_urn()
157 rspec_node['component_name'] = node['hostname']
158 rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
159 rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
160 # do not include boot state (<available> element) in the manifest rspec
161 rspec_node['boot_state'] = node['boot_state']
162 if node['boot_state'] == 'boot':
163 rspec_node['available'] = 'true'
165 rspec_node['available'] = 'false'
166 rspec_node['exclusive'] = 'false'
167 rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
168 HardwareType({'name': 'pc'})]
169 # only doing this because protogeni rspec needs
170 # to advertise available initscripts
171 rspec_node['pl_initscripts'] = pl_initscripts.values()
172 # add site/interface info to nodes.
173 # assumes that sites, interfaces and tags have already been prepared.
174 if site['longitude'] and site['latitude']:
175 location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
176 rspec_node['location'] = location
178 granularity = Granularity({'grain': grain})
179 rspec_node['granularity'] = granularity
180 rspec_node['interfaces'] = []
182 for if_id in node['interface_ids']:
183 interface = Interface(interfaces[if_id])
184 interface['ipv4'] = interface['ip']
185 interface['component_id'] = PlXrn(auth=self.driver.hrn,
186 interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
187 # interfaces in the manifest need a client id
189 interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
190 rspec_node['interfaces'].append(interface)
192 tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids'] if tag_id in node_tags]
193 rspec_node['tags'] = tags
196 def sliver_to_rspec_node(self, sliver, sites, interfaces, node_tags, \
197 pl_initscripts, sliver_allocations):
198 # get the granularity in second for the reservation system
199 grain = self.driver.shell.GetLeaseGranularity()
200 rspec_node = self.node_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts, grain)
201 # xxx how to retrieve site['login_base']
202 rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
203 # remove interfaces from manifest
204 rspec_node['interfaces'] = []
206 rspec_sliver = Sliver({'sliver_id': sliver['urn'],
207 'name': sliver['name'],
208 'type': 'plab-vserver',
210 rspec_node['sliver_id'] = rspec_sliver['sliver_id']
211 rspec_node['client_id'] = sliver_allocations[sliver['urn']].client_id
212 if sliver_allocations[sliver['urn']].component_id:
213 rspec_node['component_id'] = sliver_allocations[sliver['urn']].component_id
214 rspec_node['slivers'] = [rspec_sliver]
216 # slivers always provide the ssh service
217 login = Login({'authentication': 'ssh-keys', 'hostname': sliver['hostname'], 'port':'22', 'username': sliver['name']})
218 service = Services({'login': login})
219 rspec_node['services'] = [service]
222 def get_slice_tags(self, slice):
224 slice_tag_ids.extend(slice['slice_tag_ids'])
225 tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice_tag_ids})
227 tags_dict = defaultdict(list)
229 tags_dict[tag['node_id']] = tag
232 def get_slice_nodes(self, slice, options={}):
234 filter = {'peer_id': None}
236 if slice and slice.get('node_ids'):
237 filter['node_id'] = slice['node_ids']
239 # there are no nodes to look up
241 tags_filter=filter.copy()
242 geni_available = options.get('geni_available')
243 if geni_available == True:
244 filter['boot_state'] = 'boot'
245 nodes = self.driver.shell.GetNodes(filter)
247 nodes_dict[node['node_id']] = node
250 def rspec_node_to_geni_sliver(self, rspec_node, sliver_allocations = {}):
251 if rspec_node['sliver_id'] in sliver_allocations:
252 # set sliver allocation and operational status
253 sliver_allocation = sliver_allocations[rspec_node['sliver_id']]
254 if sliver_allocation:
255 allocation_status = sliver_allocation.allocation_state
256 if allocation_status == 'geni_allocated':
257 op_status = 'geni_pending_allocation'
258 elif allocation_status == 'geni_provisioned':
259 if rspec_node['boot_state'] == 'boot':
260 op_status = 'geni_ready'
262 op_status = 'geni_failed'
264 op_status = 'geni_unknown'
266 allocation_status = 'geni_unallocated'
268 geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
269 'geni_expires': rspec_node['expires'],
270 'geni_allocation_status' : allocation_status,
271 'geni_operational_status': op_status,
276 def get_leases(self, slice=None, options={}):
278 now = int(time.time())
280 filter.update({'clip':now})
282 filter.update({'name':slice['name']})
283 return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
284 leases = self.driver.shell.GetLeases(filter)
285 grain = self.driver.shell.GetLeaseGranularity()
289 site_ids.append(lease['site_id'])
292 sites_dict = self.get_sites({'site_id': site_ids})
297 rspec_lease = Lease()
299 # xxx how to retrieve site['login_base']
300 site_id=lease['site_id']
301 site=sites_dict[site_id]
303 rspec_lease['lease_id'] = lease['lease_id']
304 rspec_lease['component_id'] = PlXrn(self.driver.hrn, hostname=lease['hostname']).urn
305 slice_hrn = slicename_to_hrn(self.driver.hrn, lease['name'])
306 slice_urn = hrn_to_urn(slice_hrn, 'slice')
307 rspec_lease['slice_id'] = slice_urn
308 rspec_lease['start_time'] = lease['t_from']
309 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) / grain
310 rspec_leases.append(rspec_lease)
314 def list_resources(self, version = None, options={}):
316 version_manager = VersionManager()
317 version = version_manager.get_version(version)
318 rspec_version = version_manager._get_version(version.type, version.version, 'ad')
319 rspec = RSpec(version=rspec_version, user_options=options)
321 if not options.get('list_leases') or options['list_leases'] != 'leases':
323 nodes = self.get_nodes(options)
329 site_ids.append(node['site_id'])
330 interface_ids.extend(node['interface_ids'])
331 tag_ids.extend(node['node_tag_ids'])
332 nodes_dict[node['node_id']] = node
333 sites = self.get_sites({'site_id': site_ids})
334 interfaces = self.get_interfaces({'interface_id':interface_ids})
335 node_tags = self.get_node_tags({'node_tag_id': tag_ids})
336 pl_initscripts = self.get_pl_initscripts()
337 # convert nodes to rspec nodes
340 rspec_node = self.node_to_rspec_node(node, sites, interfaces, node_tags, pl_initscripts)
341 rspec_nodes.append(rspec_node)
342 rspec.version.add_nodes(rspec_nodes)
345 links = self.get_links(sites, nodes_dict, interfaces)
346 rspec.version.add_links(links)
349 def describe(self, urns, version=None, options={}):
350 version_manager = VersionManager()
351 version = version_manager.get_version(version)
352 rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
353 rspec = RSpec(version=rspec_version, user_options=options)
357 slivers = self.get_slivers(urns, options)
359 rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
361 rspec_expires = datetime_to_string(utcparse(time.time()))
362 rspec.xml.set('expires', rspec_expires)
364 # lookup the sliver allocations
365 sliver_ids = [sliver['sliver_id'] for sliver in slivers]
366 constraint = SliverAllocation.sliver_id.in_(sliver_ids)
367 sliver_allocations = dbsession.query(SliverAllocation).filter(constraint)
368 sliver_allocation_dict = {}
369 for sliver_allocation in sliver_allocations:
370 sliver_allocation_dict[sliver_allocation.sliver_id] = sliver_allocation
372 if not options.get('list_leases') or options['list_leases'] != 'leases':
378 for sliver in slivers:
379 site_ids.append(sliver['site_id'])
380 interface_ids.extend(sliver['interface_ids'])
381 tag_ids.extend(sliver['node_tag_ids'])
382 nodes_dict[sliver['node_id']] = sliver
383 sites = self.get_sites({'site_id': site_ids})
384 interfaces = self.get_interfaces({'interface_id':interface_ids})
385 node_tags = self.get_node_tags({'node_tag_id': tag_ids})
386 pl_initscripts = self.get_pl_initscripts()
388 for sliver in slivers:
389 if sliver['slice_ids_whitelist'] and sliver['slice_id'] not in sliver['slice_ids_whitelist']:
391 rspec_node = self.sliver_to_rspec_node(sliver, sites, interfaces, node_tags,
392 pl_initscripts, sliver_allocation_dict)
393 # manifest node element shouldn't contain available attribute
394 rspec_node.pop('available')
395 rspec_nodes.append(rspec_node)
396 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node, sliver_allocation_dict)
397 geni_slivers.append(geni_sliver)
398 rspec.version.add_nodes(rspec_nodes)
400 # add sliver defaults
401 #default_sliver = slivers.get(None, [])
403 # default_sliver_attribs = default_sliver.get('tags', [])
404 # for attrib in default_sliver_attribs:
405 # rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
408 links = self.get_links(sites, nodes_dict, interfaces)
409 rspec.version.add_links(links)
411 if not options.get('list_leases') or options['list_leases'] != 'resources':
413 leases = self.get_leases(slivers[0])
414 rspec.version.add_leases(leases)
417 return {'geni_urn': urns[0],
418 'geni_rspec': rspec.toxml(),
419 'geni_slivers': geni_slivers}