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
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
29 def __init__(self, driver):
32 def get_nodes(self, options={}):
33 filter = {'peer_id': None}
34 geni_available = options.get('geni_available')
35 if geni_available == True:
36 filter['boot_state'] = 'boot'
37 nodes = self.driver.shell.GetNodes(filter)
41 def get_sites(self, filter={}):
43 for site in self.driver.shell.GetSites(filter):
44 sites[site['site_id']] = site
47 def get_interfaces(self, filter={}):
49 for interface in self.driver.shell.GetInterfaces(filter):
51 if interface['bwlimit']:
52 interface['bwlimit'] = str(int(interface['bwlimit'])/1000)
53 interfaces[interface['interface_id']] = interface
56 def get_links(self, sites, nodes, interfaces):
60 for (site_id1, site_id2) in topology:
61 site_id1 = int(site_id1)
62 site_id2 = int(site_id2)
64 if not site_id1 in sites or site_id2 not in sites:
66 site1 = sites[site_id1]
67 site2 = sites[site_id2]
69 site1_hrn = self.driver.hrn + '.' + site1['login_base']
70 site2_hrn = self.driver.hrn + '.' + site2['login_base']
72 for s1_node_id in site1['node_ids']:
73 for s2_node_id in site2['node_ids']:
74 if s1_node_id not in nodes or s2_node_id not in nodes:
76 node1 = nodes[s1_node_id]
77 node2 = nodes[s2_node_id]
79 # just get first interface of the first node
80 if1_xrn = PlXrn(auth=self.driver.hrn, interface='node%s:eth0' % (node1['node_id']))
81 if1_ipv4 = interfaces[node1['interface_ids'][0]]['ip']
82 if2_xrn = PlXrn(auth=self.driver.hrn, interface='node%s:eth0' % (node2['node_id']))
83 if2_ipv4 = interfaces[node2['interface_ids'][0]]['ip']
85 if1 = Interface({'component_id': if1_xrn.urn, 'ipv4': if1_ipv4} )
86 if2 = Interface({'component_id': if2_xrn.urn, 'ipv4': if2_ipv4} )
89 link = Link({'capacity': '1000000', 'latency': '0', 'packet_loss': '0', 'type': 'ipv4'})
90 link['interface1'] = if1
91 link['interface2'] = if2
92 link['component_name'] = "%s:%s" % (site1['login_base'], site2['login_base'])
93 link['component_id'] = PlXrn(auth=self.driver.hrn, interface=link['component_name']).get_urn()
94 link['component_manager_id'] = hrn_to_urn(self.driver.hrn, 'authority+am')
99 def get_node_tags(self, filter={}):
101 for node_tag in self.driver.shell.GetNodeTags(filter):
102 node_tags[node_tag['node_tag_id']] = node_tag
105 def get_pl_initscripts(self, filter={}):
107 filter.update({'enabled': True})
108 for initscript in self.driver.shell.GetInitScripts(filter):
109 pl_initscripts[initscript['initscript_id']] = initscript
110 return pl_initscripts
112 def get_slivers(self, urns, options):
118 if xrn.type == 'sliver':
119 # id: slice_id-node_id
120 id_parts = xrn.leaf.split('-')
121 slice_ids.add(id_parts[0])
122 node_ids.append(id_parts[1])
124 names.add(xrn.pl_slicename())
130 filter['name'] = list(names)
132 filter['slice_id'] = list(slice_ids)
133 slices = self.driver.shell.GetSlices(filter)
136 slice['node_ids'] = node_ids
137 tags_dict = self.get_slice_tags(slice)
138 nodes_dict = self.get_slice_nodes(slice, options)
140 for node in nodes_dict.values():
141 node.update(slices[0])
142 node['tags'] = tags_dict[node['node_id']]
143 sliver_hrn = '%s.%s-%s' % (self.driver.hrn, slice['slice_id'], node['node_id'])
144 node['urn'] = PlXrn(xrn=sliver_hrn, type='sliver').get_urn()
148 def node_to_rspec_node(self, node, sites, interfaces, node_tags, pl_initscripts=[], grain=None, options={}):
150 # xxx how to retrieve site['login_base']
151 site=sites[node['site_id']]
152 rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], node['hostname'])
153 rspec_node['component_name'] = node['hostname']
154 rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
155 rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
156 # do not include boot state (<available> element) in the manifest rspec
157 rspec_node['boot_state'] = node['boot_state']
158 rspec_node['exclusive'] = 'false'
159 rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
160 HardwareType({'name': 'pc'})]
161 # only doing this because protogeni rspec needs
162 # to advertise available initscripts
163 rspec_node['pl_initscripts'] = pl_initscripts.values()
164 # add site/interface info to nodes.
165 # assumes that sites, interfaces and tags have already been prepared.
166 if site['longitude'] and site['latitude']:
167 location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
168 rspec_node['location'] = location
170 granularity = Granularity({'grain': grain})
171 rspec_node['granularity'] = granularity
172 rspec_node['interfaces'] = []
174 for if_id in node['interface_ids']:
175 interface = Interface(interfaces[if_id])
176 interface['ipv4'] = interface['ip']
177 interface['component_id'] = PlXrn(auth=self.driver.hrn,
178 interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
179 # interfaces in the manifest need a client id
181 interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
182 rspec_node['interfaces'].append(interface)
184 tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
185 rspec_node['tags'] = tags
188 def sliver_to_rspec_node(self, sliver, sites, interfaces, node_tags, pl_initscripts):
189 # get the granularity in second for the reservation system
190 grain = self.driver.shell.GetLeaseGranularity()
191 rspec_node = self.node_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts, grain)
192 # xxx how to retrieve site['login_base']
193 rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
194 # remove interfaces from manifest
195 rspec_node['interfaces'] = []
197 rspec_sliver = Sliver({'sliver_id': sliver['urn'],
198 'name': sliver['name'],
199 'type': 'plab-vserver',
201 rspec_node['sliver_id'] = rspec_sliver['sliver_id']
202 rspec_node['client_id'] = sliver['hostname']
203 rspec_node['slivers'] = [rspec_sliver]
205 # slivers always provide the ssh service
206 login = Login({'authentication': 'ssh-keys', 'hostname': sliver['hostname'], 'port':'22', 'username': sliver['name']})
207 service = Services({'login': login})
208 rspec_node['services'] = [service]
211 def get_slice_tags(self, slice):
213 slice_tag_ids.extend(slice['slice_tag_ids'])
214 tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice_tag_ids})
216 tags_dict = defaultdict(list)
218 tags_dict[tag['node_id']] = tag
221 def get_slice_nodes(self, slice, options={}):
223 filter = {'peer_id': None}
225 if slice and slice.get('node_ids'):
226 filter['node_id'] = slice['node_ids']
228 # there are no nodes to look up
230 tags_filter=filter.copy()
231 geni_available = options.get('geni_available')
232 if geni_available == True:
233 filter['boot_state'] = 'boot'
234 nodes = self.driver.shell.GetNodes(filter)
236 nodes_dict[node['node_id']] = node
239 def rspec_node_to_geni_sliver(self, rspec_node):
240 op_status = "geni_unknown"
241 state = rspec_node['boot_state'].lower()
243 op_status = 'geni_ready'
245 op_status =' geni_failed'
248 geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
249 'geni_expires': rspec_node['expires'],
250 'geni_allocation_status': 'geni_provisioned',
251 'geni_operational_status': op_status,
256 def get_leases(self, slice=None, options={}):
258 now = int(time.time())
260 filter.update({'clip':now})
262 filter.update({'name':slice['name']})
263 return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
264 leases = self.driver.shell.GetLeases(filter)
265 grain = self.driver.shell.GetLeaseGranularity()
269 site_ids.append(lease['site_id'])
272 sites_dict = self.get_sites({'site_id': site_ids})
277 rspec_lease = Lease()
279 # xxx how to retrieve site['login_base']
280 site_id=lease['site_id']
281 site=sites_dict[site_id]
283 rspec_lease['lease_id'] = lease['lease_id']
284 rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], lease['hostname'])
285 slice_hrn = slicename_to_hrn(self.driver.hrn, lease['name'])
286 slice_urn = hrn_to_urn(slice_hrn, 'slice')
287 rspec_lease['slice_id'] = slice_urn
288 rspec_lease['start_time'] = lease['t_from']
289 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) / grain
290 rspec_leases.append(rspec_lease)
294 def list_resources(self, version = None, options={}):
296 version_manager = VersionManager()
297 version = version_manager.get_version(version)
298 rspec_version = version_manager._get_version(version.type, version.version, 'ad')
299 rspec = RSpec(version=rspec_version, user_options=options)
301 if not options.get('list_leases') or options['list_leases'] != 'leases':
303 nodes = self.get_nodes(options)
309 site_ids.append(node['site_id'])
310 interface_ids.extend(node['interface_ids'])
311 tag_ids.extend(node['node_tag_ids'])
312 nodes_dict[node['node_id']] = node
313 sites = self.get_sites({'site_id': site_ids})
314 interfaces = self.get_interfaces({'interface_id':interface_ids})
315 node_tags = self.get_node_tags({'node_tag_id': tag_ids})
316 pl_initscripts = self.get_pl_initscripts()
317 # convert nodes to rspec nodes
320 rspec_node = self.node_to_rspec_node(node, sites, interfaces, node_tags, pl_initscripts)
321 rspec_nodes.append(rspec_node)
322 rspec.version.add_nodes(rspec_nodes)
325 links = self.get_links(sites, nodes_dict, interfaces)
326 rspec.version.add_links(links)
329 def describe(self, urns, version=None, options={}):
330 version_manager = VersionManager()
331 version = version_manager.get_version(version)
332 rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
333 rspec = RSpec(version=version, user_options=options)
337 slivers = self.get_slivers(urns, options)
338 if len(slivers) == 0:
339 raise SliverDoesNotExist("You have not allocated any slivers here")
340 rspec.xml.set('expires', datetime_to_string(utcparse(slivers[0]['expires'])))
342 if not options.get('list_leases') or options['list_leases'] != 'leases':
348 for sliver in slivers:
349 site_ids.append(sliver['site_id'])
350 interface_ids.extend(sliver['interface_ids'])
351 tag_ids.extend(sliver['node_tag_ids'])
352 nodes_dict[sliver['node_id']] = sliver
353 sites = self.get_sites({'site_id': site_ids})
354 interfaces = self.get_interfaces({'interface_id':interface_ids})
355 node_tags = self.get_node_tags({'node_tag_id': tag_ids})
356 pl_initscripts = self.get_pl_initscripts()
358 for sliver in slivers:
359 if sliver['slice_ids_whitelist'] and sliver['slice_id'] not in sliver['slice_ids_whitelist']:
361 rspec_node = self.sliver_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts)
362 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node)
363 rspec_nodes.append(rspec_node)
364 geni_slivers.append(geni_sliver)
365 rspec.version.add_nodes(rspec_nodes)
367 # add sliver defaults
368 #default_sliver = slivers.get(None, [])
370 # default_sliver_attribs = default_sliver.get('tags', [])
371 # for attrib in default_sliver_attribs:
372 # rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
375 links = self.get_links(sites, nodes_dict, interfaces)
376 rspec.version.add_links(links)
378 if not options.get('list_leases') or options['list_leases'] != 'resources':
379 leases = self.get_leases(slivers[0])
380 rspec.version.add_leases(leases)
383 return {'geni_urn': urns[0],
384 'geni_rspec': rspec.toxml(),
385 'geni_slivers': geni_slivers}