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, node, sites, interfaces, node_tags, pl_initscripts=[], grain=None, options={}):
136 # xxx how to retrieve site['login_base']
137 site=sites[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)
170 tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
171 rspec_node['tags'] = tags
174 def sliver_to_rspec_node(self, sliver, sites, interfaces, node_tags, pl_initscripts):
175 # get the granularity in second for the reservation system
176 grain = self.driver.shell.GetLeaseGranularity()
177 rspec_node = self.get_rspec_node(node, sites, interfaces, node_tags, pl_initscripts, grain)
178 # xxx how to retrieve site['login_base']
179 rspec_node['expires'] = datetime_to_string(utcparse(slice[0]['expires']))
180 # remove interfaces from manifest
181 rspec_node['interfaces'] = []
183 id = ":".join(map(str, [slices[0]['slice_id'], node['node_id']]))
184 sliver_xrn = Xrn(slice_urn, id=id).get_urn()
185 sliver_xrn.set_authority(self.driver.hrn)
186 sliver = Sliver({'sliver_id': sliver_xrn.get_urn(),
187 'name': slice[0]['name'],
188 'type': 'plab-vserver',
190 rspec_node['sliver_id'] = sliver['sliver_id']
191 rspec_node['client_id'] = node['hostname']
192 rspec_node['slivers'] = [sliver]
194 # slivers always provide the ssh service
195 login = Login({'authentication': 'ssh-keys', 'hostname': node['hostname'], 'port':'22', 'username': sliver['name']})
196 service = Services({'login': login})
197 rspec_node['services'] = [service]
200 def get_slice_tags(self, slices):
203 slice_tag_ids.extend(slice['slice_tag_ids'])
204 tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice_tag_ids})
206 tags_dict = defaultdict([])
208 tags_dict[tag['node_id']] = tag
211 def get_slice_nodes(self, slices, options={}):
212 filter = {'peer_id': None}
214 if slice and 'node_ids' in slice and slice['node_ids']:
215 filter['node_id'] = slice['node_ids']
216 tags_filter=filter.copy()
218 geni_available = options.get('geni_available')
219 if geni_available == True:
220 filter['boot_state'] = 'boot'
221 nodes = self.driver.shell.GetNodes(filter)
224 nodes_dict[node['node_id']] = node
227 def rspec_node_to_geni_sliver(self, rspec_node):
228 op_status = "geni_unknown"
229 state = sliver['boot_stat'].lower()
231 op_status = 'geni_ready'
233 op_status =' geni_failed'
236 geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
237 'geni_expires': rspec_node['expires'],
238 'geni_allocation_status': 'geni_provisioned',
239 'geni_operational_status': op_status,
244 def get_leases(self, slice=None, options={}):
246 now = int(time.time())
248 filter.update({'clip':now})
250 filter.update({'name':slice['name']})
251 return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
252 leases = self.driver.shell.GetLeases(filter)
253 grain = self.driver.shell.GetLeaseGranularity()
257 site_ids.append(lease['site_id'])
260 sites_dict = self.get_sites({'site_id': site_ids})
265 rspec_lease = Lease()
267 # xxx how to retrieve site['login_base']
268 site_id=lease['site_id']
269 site=sites_dict[site_id]
271 rspec_lease['lease_id'] = lease['lease_id']
272 rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], lease['hostname'])
273 slice_hrn = slicename_to_hrn(self.driver.hrn, lease['name'])
274 slice_urn = hrn_to_urn(slice_hrn, 'slice')
275 rspec_lease['slice_id'] = slice_urn
276 rspec_lease['start_time'] = lease['t_from']
277 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) / grain
278 rspec_leases.append(rspec_lease)
282 def list_resources(self, version = None, options={}):
284 version_manager = VersionManager()
285 version = version_manager.get_version(version)
286 rspec_version = version_manager._get_version(version.type, version.version, 'ad')
287 rspec = RSpec(version=rspec_version, user_options=options)
289 if not options.get('list_leases') or options['list_leases'] != 'leases':
291 nodes = self.get_nodes(options)
297 site_ids.append(node['site_id'])
298 interface_ids.extend(node['interface_ids'])
299 tag_ids.extend(node['node_tag_ids'])
300 nodes_dict[node['node_id']] = node
301 sites = self.get_sites({'site_id': site_ids})
302 interfaces = self.get_interfaces({'interface_id':interface_ids})
303 node_tags = self.get_node_tags({'node_tag_id': tag_ids})
304 pl_initscripts = self.get_pl_initscripts()
305 # convert nodes to rspec nodes
308 rspec_node = self.node_to_rspec_node(node, sites, interfaces, node_tags, pl_initscripts)
309 rspec_nodes.append(rspec_node)
310 rspec.version.add_nodes(rspec_nodes)
313 links = self.get_links(sites, nodes_dict, interfaces)
314 rspec.version.add_links(links)
317 def describe(self, urns, version=None, options={}):
318 # update nova connection
319 tenant_name = OSXrn(xrn=urns[0], type='slice').get_tenant_name()
320 self.driver.shell.nova_manager.connect(tenant=tenant_name)
322 version_manager = VersionManager()
323 version = version_manager.get_version(version)
324 rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
325 rspec = RSpec(version=version, user_options=options)
329 slivers = self.get_slivers(urns, options)
330 if len(slivers) == 0:
331 raise SliverDoesNotExist("You have not allocated any slivers here")
332 rspec.xml.set('expires', datetime_to_string(utcparse(slivers[0]['expires'])))
334 if not options.get('list_leases') or options['list_leases'] != 'leases':
340 for sliver in slivers:
341 site_ids.append(sliver['site_id'])
342 interface_ids.extend(sliver['interface_ids'])
343 tag_ids.extend(sliver['node_tag_ids'])
344 nodes_dict[sliver['node_id']] = sliver
345 sites = self.get_sites({'site_id': site_ids})
346 interfaces = self.get_interfaces({'interface_id':interface_ids})
347 node_tags = self.get_node_tags(tags_filter)
348 pl_initscripts = self.get_pl_initscripts()
350 for sliver in slivers:
351 if sliver['slice_ids_whitelist'] and sliver['slice_id'] not in sliver['slice_ids_whitelist']:
353 rspec_node = self.sliver_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts)
354 geni_sliver = self.rspec_node_to_geni_sliver(rspec_node)
355 rspec_nodes.append(rspec_node)
356 geni_slivers.append(geni_sliver)
357 rspec.version.add_nodes(rspec_nodes)
359 # add sliver defaults
360 default_sliver = slivers.get(None, [])
362 default_sliver_attribs = default_sliver.get('tags', [])
363 for attrib in default_sliver_attribs:
364 rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
367 links = self.get_links(sites_dict, nodes_dict, interfaces)
368 rspec.version.add_links(links)
370 if not options.get('list_leases') or options['list_leases'] != 'resources':
371 leases = self.get_leases(slivers[0])
372 rspec.version.add_leases(leases)
375 return {'geni_urn': urns[0],
376 'geni_rspec': rspec.toxml(),
377 'geni_slivers': geni_slivers}