2 from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn
3 from sfa.util.sfatime import utcparse, datetime_to_string
4 from sfa.util.sfalogging import logger
6 from sfa.rspecs.rspec import RSpec
7 from sfa.rspecs.elements.hardware_type import HardwareType
8 from sfa.rspecs.elements.node import Node
9 from sfa.rspecs.elements.link import Link
10 from sfa.rspecs.elements.sliver import Sliver
11 from sfa.rspecs.elements.login import Login
12 from sfa.rspecs.elements.location import Location
13 from sfa.rspecs.elements.interface import Interface
14 from sfa.rspecs.elements.services import Services
15 from sfa.rspecs.elements.pltag import PLTag
16 from sfa.rspecs.elements.lease import Lease
17 from sfa.rspecs.elements.granularity import Granularity
18 from sfa.rspecs.version_manager import VersionManager
20 from sfa.planetlab.plxrn import PlXrn, hostname_to_urn, hrn_to_pl_slicename, slicename_to_hrn
21 from sfa.planetlab.vlink import get_tc_rate
22 from sfa.planetlab.topology import Topology
28 def __init__(self, driver):
31 def get_sites(self, filter={}):
33 for site in self.driver.shell.GetSites(filter):
34 sites[site['site_id']] = site
37 def get_interfaces(self, filter={}):
39 for interface in self.driver.shell.GetInterfaces(filter):
41 if interface['bwlimit']:
42 interface['bwlimit'] = str(int(interface['bwlimit'])/1000)
43 interfaces[interface['interface_id']] = interface
46 def get_links(self, sites, nodes, interfaces):
50 for (site_id1, site_id2) in topology:
51 site_id1 = int(site_id1)
52 site_id2 = int(site_id2)
54 if not site_id1 in sites or site_id2 not in sites:
56 site1 = sites[site_id1]
57 site2 = sites[site_id2]
59 site1_hrn = self.driver.hrn + '.' + site1['login_base']
60 site2_hrn = self.driver.hrn + '.' + site2['login_base']
62 for s1_node_id in site1['node_ids']:
63 for s2_node_id in site2['node_ids']:
64 if s1_node_id not in nodes or s2_node_id not in nodes:
66 node1 = nodes[s1_node_id]
67 node2 = nodes[s2_node_id]
69 # just get first interface of the first node
70 if1_xrn = PlXrn(auth=self.driver.hrn, interface='node%s:eth0' % (node1['node_id']))
71 if1_ipv4 = interfaces[node1['interface_ids'][0]]['ip']
72 if2_xrn = PlXrn(auth=self.driver.hrn, interface='node%s:eth0' % (node2['node_id']))
73 if2_ipv4 = interfaces[node2['interface_ids'][0]]['ip']
75 if1 = Interface({'component_id': if1_xrn.urn, 'ipv4': if1_ipv4} )
76 if2 = Interface({'component_id': if2_xrn.urn, 'ipv4': if2_ipv4} )
79 link = Link({'capacity': '1000000', 'latency': '0', 'packet_loss': '0', 'type': 'ipv4'})
80 link['interface1'] = if1
81 link['interface2'] = if2
82 link['component_name'] = "%s:%s" % (site1['login_base'], site2['login_base'])
83 link['component_id'] = PlXrn(auth=self.driver.hrn, interface=link['component_name']).get_urn()
84 link['component_manager_id'] = hrn_to_urn(self.driver.hrn, 'authority+am')
89 def get_node_tags(self, filter={}):
91 for node_tag in self.driver.shell.GetNodeTags(filter):
92 node_tags[node_tag['node_tag_id']] = node_tag
95 def get_pl_initscripts(self, filter={}):
97 filter.update({'enabled': True})
98 for initscript in self.driver.shell.GetInitScripts(filter):
99 pl_initscripts[initscript['initscript_id']] = initscript
100 return pl_initscripts
103 def get_slice_and_slivers(self, slice_xrn):
105 Returns a dict of slivers keyed on the sliver's node_id
110 return (slice, slivers)
111 slice_urn = hrn_to_urn(slice_xrn, 'slice')
112 slice_hrn, _ = urn_to_hrn(slice_xrn)
113 slice_name = hrn_to_pl_slicename(slice_hrn)
114 slices = self.driver.shell.GetSlices(slice_name)
116 return (slice, slivers)
119 # sort slivers by node id
120 for node_id in slice['node_ids']:
122 id = ":".join(map(str, [slice['slice_id'], node_id]))
123 xrn = Xrn(slice_urn, id=id).get_urn()
124 xrn.set_authority(self.driver.hrn)
125 sliver_urn = xrn.get_urn()
126 sliver = Sliver({'sliver_id': sliver_urn,
127 'name': slice['name'],
128 'type': 'plab-vserver',
130 slivers[node_id]= sliver
132 # sort sliver attributes by node id
133 tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice['slice_tag_ids']})
135 # most likely a default/global sliver attribute (node_id == None)
136 if tag['node_id'] not in slivers:
137 sliver_urn = Xrn(slice_urn, id = slice['slice_id']).get_urn()
138 sliver = Sliver({'sliver_id': sliver_urn,
139 'name': slice['name'],
140 'type': 'plab-vserver',
142 slivers[tag['node_id']] = sliver
143 slivers[tag['node_id']]['tags'].append(tag)
145 return (slice, slivers)
147 def get_nodes_and_links(self, slice_xrn, slice=None,slivers=[], options={}):
148 # if we are dealing with a slice that has no node just return
151 if not slice or not slice['node_ids']:
156 if slice and 'node_ids' in slice and slice['node_ids']:
157 filter['node_id'] = slice['node_ids']
158 tags_filter=filter.copy()
160 geni_available = options.get('geni_available')
161 if geni_available == True:
162 filter['boot_state'] = 'boot'
164 filter.update({'peer_id': None})
165 nodes = self.driver.shell.GetNodes(filter)
167 # get the granularity in second for the reservation system
168 grain = self.driver.shell.GetLeaseGranularity()
175 site_ids.append(node['site_id'])
176 interface_ids.extend(node['interface_ids'])
177 tag_ids.extend(node['node_tag_ids'])
178 nodes_dict[node['node_id']] = node
181 sites_dict = self.get_sites({'site_id': site_ids})
183 interfaces = self.get_interfaces({'interface_id':interface_ids})
185 node_tags = self.get_node_tags(tags_filter)
187 pl_initscripts = self.get_pl_initscripts()
189 links = self.get_links(sites_dict, nodes_dict, interfaces)
193 # skip whitelisted nodes
194 if node['slice_ids_whitelist']:
195 if not slice or slice['slice_id'] not in node['slice_ids_whitelist']:
198 # xxx how to retrieve site['login_base']
199 site_id=node['site_id']
200 site=sites_dict[site_id]
201 rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], node['hostname'])
202 rspec_node['component_name'] = node['hostname']
203 rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
204 rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
205 # do not include boot state (<available> element) in the manifest rspec
207 rspec_node['boot_state'] = node['boot_state']
208 rspec_node['exclusive'] = 'false'
209 rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
210 HardwareType({'name': 'pc'})]
211 # only doing this because protogeni rspec needs
212 # to advertise available initscripts
213 rspec_node['pl_initscripts'] = pl_initscripts.values()
214 # add site/interface info to nodes.
215 # assumes that sites, interfaces and tags have already been prepared.
216 site = sites_dict[node['site_id']]
217 if site['longitude'] and site['latitude']:
218 location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
219 rspec_node['location'] = location
221 granularity = Granularity({'grain': grain})
222 rspec_node['granularity'] = granularity
224 rspec_node['interfaces'] = []
226 for if_id in node['interface_ids']:
227 interface = Interface(interfaces[if_id])
228 interface['ipv4'] = interface['ip']
229 interface['component_id'] = PlXrn(auth=self.driver.hrn,
230 interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
231 # interfaces in the manifest need a client id
233 interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
234 rspec_node['interfaces'].append(interface)
237 tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
238 rspec_node['tags'] = tags
239 if node['node_id'] in slivers:
241 sliver = slivers[node['node_id']]
242 rspec_node['sliver_id'] = sliver['sliver_id']
243 rspec_node['client_id'] = node['hostname']
244 rspec_node['slivers'] = [sliver]
246 # slivers always provide the ssh service
247 login = Login({'authentication': 'ssh-keys', 'hostname': node['hostname'], 'port':'22', 'username': sliver['name']})
248 service = Services({'login': login})
249 rspec_node['services'] = [service]
250 rspec_nodes.append(rspec_node)
251 return (rspec_nodes, links)
254 def get_leases(self, slice=None, options={}):
256 now = int(time.time())
258 filter.update({'clip':now})
260 filter.update({'name':slice['name']})
261 return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
262 leases = self.driver.shell.GetLeases(filter)
263 grain = self.driver.shell.GetLeaseGranularity()
267 site_ids.append(lease['site_id'])
270 sites_dict = self.get_sites({'site_id': site_ids})
275 rspec_lease = Lease()
277 # xxx how to retrieve site['login_base']
278 site_id=lease['site_id']
279 site=sites_dict[site_id]
281 rspec_lease['lease_id'] = lease['lease_id']
282 rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], lease['hostname'])
283 slice_hrn = slicename_to_hrn(self.driver.hrn, lease['name'])
284 slice_urn = hrn_to_urn(slice_hrn, 'slice')
285 rspec_lease['slice_id'] = slice_urn
286 rspec_lease['start_time'] = lease['t_from']
287 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) / grain
288 rspec_leases.append(rspec_lease)
292 def list_resources(self, version = None, options={}):
294 version_manager = VersionManager()
295 version = version_manager.get_version(version)
296 rspec_version = version_manager._get_version(version.type, version.version, 'ad')
297 rspec = RSpec(version=rspec_version, user_options=options)
299 if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'leases':
300 nodes, links = self.get_nodes_and_links(options=options)
301 rspec.version.add_nodes(nodes)
302 rspec.version.add_links(links)
305 def describe(self, urns, version=None, options={}):
306 version_manager = VersionManager()
307 version = version_manager.get_version(version)
308 rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
309 rspec = RSpec(version=version, user_options=options)
310 slice, slivers = self.get_slice_and_slivers(urns)
311 if slice and 'expires' in slice:
312 rspec.xml.set('expires', datetime_to_string(utcparse(slice['expires'])))
314 if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'leases':
315 nodes, links = self.get_nodes_and_links(urns, slice, slivers, options)
316 rspec.version.add_nodes(nodes)
317 rspec.version.add_links(links)
318 # add sliver defaults
319 default_sliver = slivers.get(None, [])
321 default_sliver_attribs = default_sliver.get('tags', [])
322 for attrib in default_sliver_attribs:
323 rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
326 if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'resources':
327 leases = self.get_leases(slice)
328 rspec.version.add_leases(leases)
330 result = {'geni_urn': '',
331 'geni_rspec': rspec.toxml(),