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_xrn = Xrn(slice_urn, type='sliver', id=node_id)
122 sliver_xrn.set_authority(self.driver.hrn)
123 sliver = Sliver({'sliver_id': sliver_xrn.urn,
124 'name': slice['name'],
125 'type': 'plab-vserver',
127 slivers[node_id]= sliver
129 # sort sliver attributes by node id
130 tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice['slice_tag_ids']})
132 # most likely a default/global sliver attribute (node_id == None)
133 if tag['node_id'] not in slivers:
134 sliver_xrn = Xrn(slice_urn, type='sliver', id=tag['node_id'])
135 sliver_xrn.set_authority(self.driver.hrn)
136 sliver = Sliver({'sliver_id': sliver_xrn.urn,
137 'name': slice['name'],
138 'type': 'plab-vserver',
140 slivers[tag['node_id']] = sliver
141 slivers[tag['node_id']]['tags'].append(tag)
143 return (slice, slivers)
145 def get_nodes_and_links(self, slice_xrn, slice=None,slivers=[], options={}):
146 # if we are dealing with a slice that has no node just return
149 if not slice or not slice['node_ids']:
154 if slice and 'node_ids' in slice and slice['node_ids']:
155 filter['node_id'] = slice['node_ids']
156 tags_filter=filter.copy()
158 geni_available = options.get('geni_available')
159 if geni_available == True:
160 filter['boot_state'] = 'boot'
162 filter.update({'peer_id': None})
163 nodes = self.driver.shell.GetNodes(filter)
165 # get the granularity in second for the reservation system
166 grain = self.driver.shell.GetLeaseGranularity()
173 site_ids.append(node['site_id'])
174 interface_ids.extend(node['interface_ids'])
175 tag_ids.extend(node['node_tag_ids'])
176 nodes_dict[node['node_id']] = node
179 sites_dict = self.get_sites({'site_id': site_ids})
181 interfaces = self.get_interfaces({'interface_id':interface_ids})
183 node_tags = self.get_node_tags(tags_filter)
185 pl_initscripts = self.get_pl_initscripts()
187 links = self.get_links(sites_dict, nodes_dict, interfaces)
191 # skip whitelisted nodes
192 if node['slice_ids_whitelist']:
193 if not slice or slice['slice_id'] not in node['slice_ids_whitelist']:
196 # xxx how to retrieve site['login_base']
197 site_id=node['site_id']
198 site=sites_dict[site_id]
199 rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], node['hostname'])
200 rspec_node['component_name'] = node['hostname']
201 rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
202 rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
203 # do not include boot state (<available> element) in the manifest rspec
205 rspec_node['boot_state'] = node['boot_state']
207 #add the exclusive tag to distinguish between Shared and Reservable nodes
208 if node['node_type'] == 'reservable':
209 rspec_node['exclusive'] = 'true'
211 rspec_node['exclusive'] = 'false'
213 rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
214 HardwareType({'name': 'pc'})]
215 # only doing this because protogeni rspec needs
216 # to advertise available initscripts
217 rspec_node['pl_initscripts'] = pl_initscripts.values()
218 # add site/interface info to nodes.
219 # assumes that sites, interfaces and tags have already been prepared.
220 site = sites_dict[node['site_id']]
221 if site['longitude'] and site['latitude']:
222 location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
223 rspec_node['location'] = location
225 granularity = Granularity({'grain': grain})
226 rspec_node['granularity'] = granularity
228 rspec_node['interfaces'] = []
230 for if_id in node['interface_ids']:
231 interface = Interface(interfaces[if_id])
232 interface['ipv4'] = interface['ip']
233 interface['component_id'] = PlXrn(auth=self.driver.hrn,
234 interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
235 # interfaces in the manifest need a client id
237 interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
238 rspec_node['interfaces'].append(interface)
241 tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']\
242 if tag_id in node_tags]
243 rspec_node['tags'] = tags
244 if node['node_id'] in slivers:
246 sliver = slivers[node['node_id']]
247 rspec_node['sliver_id'] = sliver['sliver_id']
248 rspec_node['slivers'] = [sliver]
249 for tag in sliver['tags']:
250 if tag['tagname'] == 'client_id':
251 rspec_node['client_id'] = tag['value']
253 # slivers always provide the ssh service
254 login = Login({'authentication': 'ssh-keys', 'hostname': node['hostname'], 'port':'22', 'username': sliver['name']})
255 service = Services({'login': login})
256 rspec_node['services'] = [service]
257 rspec_nodes.append(rspec_node)
258 return (rspec_nodes, links)
261 def get_leases(self, slice_xrn=None, slice=None, options={}):
263 if slice_xrn and not slice:
266 now = int(time.time())
268 filter.update({'clip':now})
270 filter.update({'name':slice['name']})
271 return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
272 leases = self.driver.shell.GetLeases(filter)
273 grain = self.driver.shell.GetLeaseGranularity()
277 site_ids.append(lease['site_id'])
280 sites_dict = self.get_sites({'site_id': site_ids})
285 rspec_lease = Lease()
287 # xxx how to retrieve site['login_base']
288 site_id=lease['site_id']
289 site=sites_dict[site_id]
291 #rspec_lease['lease_id'] = lease['lease_id']
292 rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], lease['hostname'])
294 slice_urn = slice_xrn
295 slice_hrn = urn_to_hrn(slice_urn)
297 slice_hrn = slicename_to_hrn(self.driver.hrn, lease['name'])
298 slice_urn = hrn_to_urn(slice_hrn, 'slice')
299 rspec_lease['slice_id'] = slice_urn
300 rspec_lease['start_time'] = lease['t_from']
301 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) / grain
302 rspec_leases.append(rspec_lease)
306 def get_rspec(self, slice_xrn=None, version = None, options={}):
308 version_manager = VersionManager()
309 version = version_manager.get_version(version)
311 rspec_version = version_manager._get_version(version.type, version.version, 'ad')
313 rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
315 slice, slivers = self.get_slice_and_slivers(slice_xrn)
316 rspec = RSpec(version=rspec_version, user_options=options)
317 if slice and 'expires' in slice:
318 rspec.xml.set('expires', datetime_to_string(utcparse(slice['expires'])))
320 if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'leases':
321 if slice_xrn and not slivers:
322 nodes, links = [], []
324 nodes, links = self.get_nodes_and_links(slice_xrn, slice, slivers, options)
325 rspec.version.add_nodes(nodes)
326 rspec.version.add_links(links)
327 # add sliver defaults
328 default_sliver = slivers.get(None, [])
330 default_sliver_attribs = default_sliver.get('tags', [])
331 for attrib in default_sliver_attribs:
333 rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
335 if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'resources':
336 leases = self.get_leases(slice_xrn, slice)
337 rspec.version.add_leases(leases)