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']:
121 sliver = Sliver({'sliver_id': Xrn(slice_urn, type='slice', id=node_id, authority=self.driver.hrn).urn,
122 'name': slice['name'],
123 'type': 'plab-vserver',
125 slivers[node_id]= sliver
127 # sort sliver attributes by node id
128 tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice['slice_tag_ids']})
130 # most likely a default/global sliver attribute (node_id == None)
131 if tag['node_id'] not in slivers:
132 sliver = Sliver({'sliver_id': urn_to_sliver_id(slice_urn, slice['slice_id'], ""),
133 'name': slice['name'],
134 'type': 'plab-vserver',
136 slivers[tag['node_id']] = sliver
137 slivers[tag['node_id']]['tags'].append(tag)
139 return (slice, slivers)
141 def get_nodes_and_links(self, slice_xrn, slice=None,slivers=[], options={}):
142 # if we are dealing with a slice that has no node just return
145 if not slice or not slice['node_ids']:
150 if slice and 'node_ids' in slice and slice['node_ids']:
151 filter['node_id'] = slice['node_ids']
152 tags_filter=filter.copy()
154 geni_available = options.get('geni_available')
155 if geni_available == True:
156 filter['boot_state'] = 'boot'
158 filter.update({'peer_id': None})
159 nodes = self.driver.shell.GetNodes(filter)
161 # get the granularity in second for the reservation system
162 grain = self.driver.shell.GetLeaseGranularity()
169 site_ids.append(node['site_id'])
170 interface_ids.extend(node['interface_ids'])
171 tag_ids.extend(node['node_tag_ids'])
172 nodes_dict[node['node_id']] = node
175 sites_dict = self.get_sites({'site_id': site_ids})
177 interfaces = self.get_interfaces({'interface_id':interface_ids})
179 node_tags = self.get_node_tags(tags_filter)
181 pl_initscripts = self.get_pl_initscripts()
183 links = self.get_links(sites_dict, nodes_dict, interfaces)
187 # skip whitelisted nodes
188 if node['slice_ids_whitelist']:
189 if not slice or slice['slice_id'] not in node['slice_ids_whitelist']:
192 # xxx how to retrieve site['login_base']
193 site_id=node['site_id']
194 site=sites_dict[site_id]
195 rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], node['hostname'])
196 rspec_node['component_name'] = node['hostname']
197 rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
198 rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
199 # do not include boot state (<available> element) in the manifest rspec
201 rspec_node['boot_state'] = node['boot_state']
202 rspec_node['exclusive'] = 'false'
203 rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
204 HardwareType({'name': 'pc'})]
205 # only doing this because protogeni rspec needs
206 # to advertise available initscripts
207 rspec_node['pl_initscripts'] = pl_initscripts.values()
208 # add site/interface info to nodes.
209 # assumes that sites, interfaces and tags have already been prepared.
210 site = sites_dict[node['site_id']]
211 if site['longitude'] and site['latitude']:
212 location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
213 rspec_node['location'] = location
215 granularity = Granularity({'grain': grain})
216 rspec_node['granularity'] = granularity
218 rspec_node['interfaces'] = []
220 for if_id in node['interface_ids']:
221 interface = Interface(interfaces[if_id])
222 interface['ipv4'] = interface['ip']
223 interface['component_id'] = PlXrn(auth=self.driver.hrn,
224 interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
225 # interfaces in the manifest need a client id
227 interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
228 rspec_node['interfaces'].append(interface)
231 tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
232 rspec_node['tags'] = tags
233 if node['node_id'] in slivers:
235 sliver = slivers[node['node_id']]
236 rspec_node['sliver_id'] = sliver['sliver_id']
237 rspec_node['client_id'] = node['hostname']
238 rspec_node['slivers'] = [sliver]
240 # slivers always provide the ssh service
241 login = Login({'authentication': 'ssh-keys', 'hostname': node['hostname'], 'port':'22', 'username': sliver['name']})
242 service = Services({'login': login})
243 rspec_node['services'] = [service]
244 rspec_nodes.append(rspec_node)
245 return (rspec_nodes, links)
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 get_rspec(self, slice_xrn=None, version = None, options={}, requested_slivers={}):
288 version_manager = VersionManager()
289 version = version_manager.get_version(version)
291 rspec_version = version_manager._get_version(version.type, version.version, 'ad')
293 rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
295 slice, slivers = self.get_slice_and_slivers(slice_xrn)
296 rspec = RSpec(version=rspec_version, user_options=options)
297 if slice and 'expires' in slice:
298 rspec.xml.set('expires', datetime_to_string(utcparse(slice['expires'])))
300 if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'leases':
301 nodes, links = self.get_nodes_and_links(slice_xrn, slice, slivers, options)
302 # preserve client ids from request
303 if requested_slivers:
305 if node['component_name'] in requested_slivers:
306 node['client_id'] = requested_slivers[node['component_name']]
307 rspec.version.add_nodes(nodes)
308 rspec.version.add_links(links)
309 # add sliver defaults
310 default_sliver = slivers.get(None, [])
312 default_sliver_attribs = default_sliver.get('tags', [])
313 for attrib in default_sliver_attribs:
315 rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
317 if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'resources':
318 leases = self.get_leases(slice)
319 rspec.version.add_leases(leases)