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):
117 names.add(xrn.get_slice_name())
121 slices = self.driver.shell.GetSlices(names)
124 slices = [slice for slice in slices if slice['slice_id'] in ids]
126 tags_dict = self.get_slice_tags(slices)
127 nodes_dict = self.get_slice_nodes(slices, options)
129 for node in nodes_dict.values():
130 sliver = node.update(slices[0])
131 sliver['tags'] = tags_dict[node['node_id']]
134 def node_to_rspec_node(self, sites, interfaces, tags, pl_initscripts=[], grain=None, options={}):
136 # xxx how to retrieve site['login_base']
137 site=sites_dict[node['site_id']]
138 rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], node['hostname'])
139 rspec_node['component_name'] = node['hostname']
140 rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
141 rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
142 # do not include boot state (<available> element) in the manifest rspec
143 rspec_node['boot_state'] = node['boot_state']
144 rspec_node['exclusive'] = 'false'
145 rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
146 HardwareType({'name': 'pc'})]
147 # only doing this because protogeni rspec needs
148 # to advertise available initscripts
149 rspec_node['pl_initscripts'] = pl_initscripts.values()
150 # add site/interface info to nodes.
151 # assumes that sites, interfaces and tags have already been prepared.
152 if site['longitude'] and site['latitude']:
153 location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
154 rspec_node['location'] = location
156 granularity = Granularity({'grain': grain})
157 rspec_node['granularity'] = granularity
158 rspec_node['interfaces'] = []
160 for if_id in node['interface_ids']:
161 interface = Interface(interfaces[if_id])
162 interface['ipv4'] = interface['ip']
163 interface['component_id'] = PlXrn(auth=self.driver.hrn,
164 interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
165 # interfaces in the manifest need a client id
167 interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
168 rspec_node['interfaces'].append(interface)
171 tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
172 rspec_node['tags'] = tags
175 def sliver_to_rspec_node(self, sliver):
176 # get the granularity in second for the reservation system
177 grain = self.driver.shell.GetLeaseGranularity()
178 if sliver['slice_ids_whitelist'] and sliver['slice_id'] not in sliver['slice_ids_whitelist']:
180 rspec_node = self.get_rspec_node(node, sites_dict, interfaces, node_tags, pl_initscripts, grain)
181 # xxx how to retrieve site['login_base']
182 rspec_node['expires'] = datetime_to_string(utcparse(slice[0]['expires']))
183 # remove interfaces from manifest
184 rspec_node['interfaces'] = []
186 id = ":".join(map(str, [slices[0]['slice_id'], node['node_id']]))
187 sliver_xrn = Xrn(slice_urn, id=id).get_urn()
188 sliver_xrn.set_authority(self.driver.hrn)
189 sliver = Sliver({'sliver_id': sliver_xrn.get_urn(),
190 'name': slice[0]['name'],
191 'type': 'plab-vserver',
193 rspec_node['sliver_id'] = sliver['sliver_id']
194 rspec_node['client_id'] = node['hostname']
195 rspec_node['slivers'] = [sliver]
197 # slivers always provide the ssh service
198 login = Login({'authentication': 'ssh-keys', 'hostname': node['hostname'], 'port':'22', 'username': sliver['name']})
199 service = Services({'login': login})
200 rspec_node['services'] = [service]
201 rspec_nodes.append(rspec_node)
204 def get_slice_tags(self, slices):
207 slice_tag_ids.extend(slice['slice_tag_ids'])
208 tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice_tag_ids})
210 tags_dict = defaultdict([])
212 tags_dict[tag['node_id']] = tag
215 def get_slice_nodes(self, slices, options={}):
216 filter = {'peer_id': None}
218 if slice and 'node_ids' in slice and slice['node_ids']:
219 filter['node_id'] = slice['node_ids']
220 tags_filter=filter.copy()
222 geni_available = options.get('geni_available')
223 if geni_available == True:
224 filter['boot_state'] = 'boot'
225 nodes = self.driver.shell.GetNodes(filter)
228 nodes_dict[node['node_id']] = node
231 def rspec_node_to_geni_sliver(self, rspec_node):
232 op_status = "geni_unknown"
233 state = sliver['boot_stat'].lower()
235 op_status = 'geni_ready'
237 op_status =' geni_failed'
240 geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
241 'geni_expires': rspec_node['expires'],
242 'geni_allocation_status': 'geni_provisioned',
243 'geni_operational_status': op_status,
248 def get_leases(self, slice=None, options={}):
250 now = int(time.time())
252 filter.update({'clip':now})
254 filter.update({'name':slice['name']})
255 return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
256 leases = self.driver.shell.GetLeases(filter)
257 grain = self.driver.shell.GetLeaseGranularity()
261 site_ids.append(lease['site_id'])
264 sites_dict = self.get_sites({'site_id': site_ids})
269 rspec_lease = Lease()
271 # xxx how to retrieve site['login_base']
272 site_id=lease['site_id']
273 site=sites_dict[site_id]
275 rspec_lease['lease_id'] = lease['lease_id']
276 rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], lease['hostname'])
277 slice_hrn = slicename_to_hrn(self.driver.hrn, lease['name'])
278 slice_urn = hrn_to_urn(slice_hrn, 'slice')
279 rspec_lease['slice_id'] = slice_urn
280 rspec_lease['start_time'] = lease['t_from']
281 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) / grain
282 rspec_leases.append(rspec_lease)
286 def list_resources(self, version = None, options={}):
288 version_manager = VersionManager()
289 version = version_manager.get_version(version)
290 rspec_version = version_manager._get_version(version.type, version.version, 'ad')
291 rspec = RSpec(version=rspec_version, user_options=options)
293 if not options.get('list_leases') or options['list_leases'] != 'leases':
295 nodes = self.get_nodes(options)
300 for sliver in slivers:
301 site_ids.append(sliver['site_id'])
302 interface_ids.extend(sliver['interface_ids'])
303 tag_ids.extend(sliver['node_tag_ids'])
304 nodes_dict[sliver['node_id']] = sliver
305 sites = self.get_sites({'site_id': site_ids})
306 interfaces = self.get_interfaces({'interface_id':interface_ids})
307 node_tags = self.get_node_tags(tags_filter)
308 pl_initscripts = self.get_pl_initscripts()
309 # convert nodes to rspec nodes
312 rspec_node = self.node_to_rspec_node(node, sites, interfaces, node_tags, pl_initscripts)
313 rspec_nodes.append(rspec_node)
314 rspec.version.add_nodes(rspec_nodes)
317 links = self.get_links(sites_dict, nodes_dict, interfaces)
318 rspec.version.add_links(links)
321 def describe(self, urns, version=None, options={}):
322 # update nova connection
323 tenant_name = OSXrn(xrn=urns[0], type='slice').get_tenant_name()
324 self.driver.shell.nova_manager.connect(tenant=tenant_name)
326 version_manager = VersionManager()
327 version = version_manager.get_version(version)
328 rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
329 rspec = RSpec(version=version, user_options=options)
333 slivers = self.get_slivers(urns, options)
334 if len(slivers) == 0:
335 raise SliverDoesNotExist("You have not allocated any slivers here")
336 rspec.xml.set('expires', datetime_to_string(utcparse(slivers[0]['expires'])))
338 if not options.get('list_leases') or options['list_leases'] != 'leases':
344 for sliver in slivers:
345 site_ids.append(sliver['site_id'])
346 interface_ids.extend(sliver['interface_ids'])
347 tag_ids.extend(sliver['node_tag_ids'])
348 nodes_dict[sliver['node_id']] = sliver
349 sites = self.get_sites({'site_id': site_ids})
350 interfaces = self.get_interfaces({'interface_id':interface_ids})
351 node_tags = self.get_node_tags(tags_filter)
352 pl_initscripts = self.get_pl_initscripts()
354 for sliver in slivers:
355 if sliver['slice_ids_whitelist'] and sliver['slice_id'] not in sliver['slice_ids_whitelist']:
357 rspec_node = self.sliver_to_rspec_node(sites, interfaces, node_tags)
358 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node)
359 rspec_nodes.append(rspec_node)
360 geni_slivers.append(geni_sliver)
361 rspec.version.add_nodes(rspec_nodes)
363 # add sliver defaults
364 default_sliver = slivers.get(None, [])
366 default_sliver_attribs = default_sliver.get('tags', [])
367 for attrib in default_sliver_attribs:
368 rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
371 links = self.get_links(sites_dict, nodes_dict, interfaces)
372 rspec.version.add_links(links)
374 if not options.get('list_leases') or options['list_leases'] != 'resources':
375 leases = self.get_leases(slivers[0])
376 rspec.version.add_leases(leases)
379 return {'geni_urn': urns[0],
380 'geni_rspec': rspec.toxml(),
381 'geni_slivers': geni_slivers}