2 from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn, get_authority, get_leaf
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, top_auth, hash_loginbase
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)
112 slice_urn = hrn_to_urn(slice_xrn, 'slice')
113 slice_hrn, _ = urn_to_hrn(slice_xrn)
115 top_auth_hrn = top_auth(slice_hrn)
116 site_hrn = '.'.join(slice_hrn.split('.')[:-1])
117 slice_part = slice_hrn.split('.')[-1]
118 if top_auth_hrn == self.driver.hrn:
119 login_base = slice_hrn.split('.')[-2][:12]
121 login_base = hash_loginbase(site_hrn)
123 slice_name = '_'.join([login_base, slice_part])
125 slices = self.driver.shell.GetSlices(slice_name)
127 return (slice, slivers)
130 # sort slivers by node id
131 for node_id in slice['node_ids']:
132 sliver_xrn = Xrn(slice_urn, type='sliver', id=node_id)
133 sliver_xrn.set_authority(self.driver.hrn)
134 sliver = Sliver({'sliver_id': sliver_xrn.urn,
135 'name': slice['name'],
136 'type': 'plab-vserver',
138 slivers[node_id]= sliver
140 # sort sliver attributes by node id
141 tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice['slice_tag_ids']})
143 # most likely a default/global sliver attribute (node_id == None)
144 if tag['node_id'] not in slivers:
145 sliver_xrn = Xrn(slice_urn, type='sliver', id=tag['node_id'])
146 sliver_xrn.set_authority(self.driver.hrn)
147 sliver = Sliver({'sliver_id': sliver_xrn.urn,
148 'name': slice['name'],
149 'type': 'plab-vserver',
151 slivers[tag['node_id']] = sliver
152 slivers[tag['node_id']]['tags'].append(tag)
154 return (slice, slivers)
156 def get_nodes_and_links(self, slice_xrn, slice=None,slivers=[], options={}):
157 # if we are dealing with a slice that has no node just return
160 if not slice or not slice['node_ids']:
165 if slice and 'node_ids' in slice and slice['node_ids']:
166 filter['node_id'] = slice['node_ids']
167 tags_filter=filter.copy()
169 geni_available = options.get('geni_available')
170 if geni_available == True:
171 filter['boot_state'] = 'boot'
173 filter.update({'peer_id': None})
174 nodes = self.driver.shell.GetNodes(filter)
176 # get the granularity in second for the reservation system
177 grain = self.driver.shell.GetLeaseGranularity()
184 site_ids.append(node['site_id'])
185 interface_ids.extend(node['interface_ids'])
186 tag_ids.extend(node['node_tag_ids'])
187 nodes_dict[node['node_id']] = node
190 sites_dict = self.get_sites({'site_id': site_ids})
192 interfaces = self.get_interfaces({'interface_id':interface_ids})
194 node_tags = self.get_node_tags(tags_filter)
196 pl_initscripts = self.get_pl_initscripts()
198 links = self.get_links(sites_dict, nodes_dict, interfaces)
202 # skip whitelisted nodes
203 if node['slice_ids_whitelist']:
204 if not slice or slice['slice_id'] not in node['slice_ids_whitelist']:
207 # xxx how to retrieve site['login_base']
208 site_id=node['site_id']
209 site=sites_dict[site_id]
210 rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], node['hostname'])
211 rspec_node['component_name'] = node['hostname']
212 rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
213 rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
214 # do not include boot state (<available> element) in the manifest rspec
216 rspec_node['boot_state'] = node['boot_state']
218 #add the exclusive tag to distinguish between Shared and Reservable nodes
219 if node['node_type'] == 'reservable':
220 rspec_node['exclusive'] = 'true'
222 rspec_node['exclusive'] = 'false'
224 rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
225 HardwareType({'name': 'pc'})]
226 # only doing this because protogeni rspec needs
227 # to advertise available initscripts
228 rspec_node['pl_initscripts'] = pl_initscripts.values()
229 # add site/interface info to nodes.
230 # assumes that sites, interfaces and tags have already been prepared.
231 site = sites_dict[node['site_id']]
232 if site['longitude'] and site['latitude']:
233 location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
234 rspec_node['location'] = location
236 granularity = Granularity({'grain': grain})
237 rspec_node['granularity'] = granularity
239 rspec_node['interfaces'] = []
241 for if_id in node['interface_ids']:
242 interface = Interface(interfaces[if_id])
243 interface['ipv4'] = interface['ip']
244 interface['component_id'] = PlXrn(auth=self.driver.hrn,
245 interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
246 # interfaces in the manifest need a client id
248 interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
249 rspec_node['interfaces'].append(interface)
252 tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']\
253 if tag_id in node_tags]
254 rspec_node['tags'] = tags
255 if node['node_id'] in slivers:
257 sliver = slivers[node['node_id']]
258 rspec_node['sliver_id'] = sliver['sliver_id']
259 rspec_node['slivers'] = [sliver]
260 for tag in sliver['tags']:
261 if tag['tagname'] == 'client_id':
262 rspec_node['client_id'] = tag['value']
264 # slivers always provide the ssh service
265 login = Login({'authentication': 'ssh-keys', 'hostname': node['hostname'], 'port':'22', 'username': sliver['name']})
266 service = Services({'login': login})
267 rspec_node['services'] = [service]
268 rspec_nodes.append(rspec_node)
269 return (rspec_nodes, links)
272 def get_leases(self, slice_xrn=None, slice=None, options={}):
274 if slice_xrn and not slice:
277 now = int(time.time())
279 filter.update({'clip':now})
281 filter.update({'name':slice['name']})
282 return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
283 leases = self.driver.shell.GetLeases(filter)
284 grain = self.driver.shell.GetLeaseGranularity()
288 site_ids.append(lease['site_id'])
291 sites_dict = self.get_sites({'site_id': site_ids})
296 rspec_lease = Lease()
298 # xxx how to retrieve site['login_base']
299 site_id=lease['site_id']
300 site=sites_dict[site_id]
302 #rspec_lease['lease_id'] = lease['lease_id']
303 rspec_lease['component_id'] = hrn_to_urn(self.driver.shell.GetNodeHrn(lease['hostname']), 'node')
304 #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], lease['hostname'])
306 slice_urn = slice_xrn
307 slice_hrn, _ = urn_to_hrn(slice_urn)
309 if slice_hrn != self.driver.shell.GetSliceHrn(lease['slice_id']):
310 self.driver.shell.SetSliceHrn(lease['slice_id'], slice_hrn)
312 slice_hrn = self.driver.shell.GetSliceHrn(lease['slice_id'])
313 slice_urn = hrn_to_urn(slice_hrn, 'slice')
314 rspec_lease['slice_id'] = slice_urn
315 rspec_lease['start_time'] = lease['t_from']
316 rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) / grain
317 rspec_leases.append(rspec_lease)
321 def get_rspec(self, slice_xrn=None, version = None, options={}):
323 version_manager = VersionManager()
324 version = version_manager.get_version(version)
326 rspec_version = version_manager._get_version(version.type, version.version, 'ad')
328 rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
330 slice, slivers = self.get_slice_and_slivers(slice_xrn)
331 rspec = RSpec(version=rspec_version, user_options=options)
332 if slice and 'expires' in slice:
333 rspec.xml.set('expires', datetime_to_string(utcparse(slice['expires'])))
335 if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'leases':
336 if slice_xrn and not slivers:
337 nodes, links = [], []
339 nodes, links = self.get_nodes_and_links(slice_xrn, slice, slivers, options)
340 rspec.version.add_nodes(nodes)
341 rspec.version.add_links(links)
342 # add sliver defaults
343 default_sliver = slivers.get(None, [])
345 default_sliver_attribs = default_sliver.get('tags', [])
346 for attrib in default_sliver_attribs:
347 logger.info("adding default sliver attribute xrn=%s attrib=%s"%(slice_xrn,attrib))
348 rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'], self.driver.hrn)
350 if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'resources':
351 leases = self.get_leases(slice_xrn, slice)
352 rspec.version.add_leases(leases)