#!/usr/bin/python
-from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn, urn_to_sliver_id
+from collections import defaultdict
+from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn
from sfa.util.sfatime import utcparse, datetime_to_string
from sfa.util.sfalogging import logger
-
+from sfa.util.faults import SliverDoesNotExist
from sfa.rspecs.rspec import RSpec
from sfa.rspecs.elements.hardware_type import HardwareType
from sfa.rspecs.elements.node import Node
from sfa.planetlab.plxrn import PlXrn, hostname_to_urn, hrn_to_pl_slicename, slicename_to_hrn
from sfa.planetlab.vlink import get_tc_rate
from sfa.planetlab.topology import Topology
+from sfa.storage.alchemy import dbsession
+from sfa.storage.model import SliverAllocation
+
import time
def __init__(self, driver):
self.driver = driver
+
+ def get_nodes(self, options={}):
+ filter = {'peer_id': None}
+ geni_available = options.get('geni_available')
+ if geni_available == True:
+ filter['boot_state'] = 'boot'
+ nodes = self.driver.shell.GetNodes(filter)
+
+ return nodes
def get_sites(self, filter={}):
sites = {}
pl_initscripts[initscript['initscript_id']] = initscript
return pl_initscripts
+ def get_slivers(self, urns, options={}):
+ names = set()
+ slice_ids = set()
+ node_ids = []
+ for urn in urns:
+ xrn = PlXrn(xrn=urn)
+ if xrn.type == 'sliver':
+ # id: slice_id-node_id
+ id_parts = xrn.leaf.split('-')
+ slice_ids.add(id_parts[0])
+ node_ids.append(id_parts[1])
+ else:
+ names.add(xrn.pl_slicename())
+ if xrn.id:
+ ids.add(xrn.id)
- def get_slice_and_slivers(self, slice_xrn):
- """
- Returns a dict of slivers keyed on the sliver's node_id
- """
- slivers = {}
- slice = None
- if not slice_xrn:
- return (slice, slivers)
- slice_urn = hrn_to_urn(slice_xrn, 'slice')
- slice_hrn, _ = urn_to_hrn(slice_xrn)
- slice_name = hrn_to_pl_slicename(slice_hrn)
- slices = self.driver.shell.GetSlices(slice_name)
+ filter = {}
+ if names:
+ filter['name'] = list(names)
+ if slice_ids:
+ filter['slice_id'] = list(slice_ids)
+ slices = self.driver.shell.GetSlices(filter)
if not slices:
- return (slice, slivers)
+ return []
slice = slices[0]
-
- # sort slivers by node id
- for node_id in slice['node_ids']:
- sliver = Sliver({'sliver_id': urn_to_sliver_id(slice_urn, slice['slice_id'], node_id, authority=self.driver.hrn),
- 'name': slice['name'],
- 'type': 'plab-vserver',
- 'tags': []})
- slivers[node_id]= sliver
-
- # sort sliver attributes by node id
- tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice['slice_tag_ids']})
+ if node_ids:
+ slice['node_ids'] = node_ids
+ tags_dict = self.get_slice_tags(slice)
+ nodes_dict = self.get_slice_nodes(slice, options)
+ slivers = []
+ for node in nodes_dict.values():
+ node.update(slices[0])
+ node['tags'] = tags_dict[node['node_id']]
+ sliver_hrn = '%s.%s-%s' % (self.driver.hrn, slice['slice_id'], node['node_id'])
+ node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
+ node['urn'] = node['sliver_id']
+ slivers.append(node)
+ return slivers
+
+ def node_to_rspec_node(self, node, sites, interfaces, node_tags, pl_initscripts=[], grain=None, options={}):
+ rspec_node = Node()
+ # xxx how to retrieve site['login_base']
+ site=sites[node['site_id']]
+ rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], node['hostname'])
+ rspec_node['component_name'] = node['hostname']
+ rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
+ rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
+ # do not include boot state (<available> element) in the manifest rspec
+ rspec_node['boot_state'] = node['boot_state']
+ rspec_node['exclusive'] = 'false'
+ rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
+ HardwareType({'name': 'pc'})]
+ # only doing this because protogeni rspec needs
+ # to advertise available initscripts
+ rspec_node['pl_initscripts'] = pl_initscripts.values()
+ # add site/interface info to nodes.
+ # assumes that sites, interfaces and tags have already been prepared.
+ if site['longitude'] and site['latitude']:
+ location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
+ rspec_node['location'] = location
+ # Granularity
+ granularity = Granularity({'grain': grain})
+ rspec_node['granularity'] = granularity
+ rspec_node['interfaces'] = []
+ if_count=0
+ for if_id in node['interface_ids']:
+ interface = Interface(interfaces[if_id])
+ interface['ipv4'] = interface['ip']
+ interface['component_id'] = PlXrn(auth=self.driver.hrn,
+ interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
+ # interfaces in the manifest need a client id
+ if slice:
+ interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
+ rspec_node['interfaces'].append(interface)
+ if_count+=1
+ tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
+ rspec_node['tags'] = tags
+ return rspec_node
+
+ def sliver_to_rspec_node(self, sliver, sites, interfaces, node_tags, pl_initscripts):
+ # get the granularity in second for the reservation system
+ grain = self.driver.shell.GetLeaseGranularity()
+ rspec_node = self.node_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts, grain)
+ # xxx how to retrieve site['login_base']
+ rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
+ # remove interfaces from manifest
+ rspec_node['interfaces'] = []
+ # add sliver info
+ rspec_sliver = Sliver({'sliver_id': sliver['urn'],
+ 'name': sliver['name'],
+ 'type': 'plab-vserver',
+ 'tags': []})
+ rspec_node['sliver_id'] = rspec_sliver['sliver_id']
+ rspec_node['client_id'] = sliver['hostname']
+ rspec_node['slivers'] = [rspec_sliver]
+
+ # slivers always provide the ssh service
+ login = Login({'authentication': 'ssh-keys', 'hostname': sliver['hostname'], 'port':'22', 'username': sliver['name']})
+ service = Services({'login': login})
+ rspec_node['services'] = [service]
+ return rspec_node
+
+ def get_slice_tags(self, slice):
+ slice_tag_ids = []
+ slice_tag_ids.extend(slice['slice_tag_ids'])
+ tags = self.driver.shell.GetSliceTags({'slice_tag_id': slice_tag_ids})
+ # sorted by node_id
+ tags_dict = defaultdict(list)
for tag in tags:
- # most likely a default/global sliver attribute (node_id == None)
- if tag['node_id'] not in slivers:
- sliver = Sliver({'sliver_id': urn_to_sliver_id(slice_urn, slice['slice_id'], ""),
- 'name': slice['name'],
- 'type': 'plab-vserver',
- 'tags': []})
- slivers[tag['node_id']] = sliver
- slivers[tag['node_id']]['tags'].append(tag)
-
- return (slice, slivers)
+ tags_dict[tag['node_id']] = tag
+ return tags_dict
- def get_nodes_and_links(self, slice_xrn, slice=None,slivers=[], options={}):
- # if we are dealing with a slice that has no node just return
- # and empty list
- if slice_xrn:
- if not slice or not slice['node_ids']:
- return ([],[])
-
- filter = {}
+ def get_slice_nodes(self, slice, options={}):
+ nodes_dict = {}
+ filter = {'peer_id': None}
tags_filter = {}
- if slice and 'node_ids' in slice and slice['node_ids']:
+ if slice and slice.get('node_ids'):
filter['node_id'] = slice['node_ids']
- tags_filter=filter.copy()
-
- geni_available = options.get('geni_available')
- if geni_available:
- filter['boot_state'] = 'boot'
-
- filter.update({'peer_id': None})
+ else:
+ # there are no nodes to look up
+ return nodes_dict
+ tags_filter=filter.copy()
+ geni_available = options.get('geni_available')
+ if geni_available == True:
+ filter['boot_state'] = 'boot'
nodes = self.driver.shell.GetNodes(filter)
-
- # get the granularity in second for the reservation system
- grain = self.driver.shell.GetLeaseGranularity()
-
- site_ids = []
- interface_ids = []
- tag_ids = []
- nodes_dict = {}
for node in nodes:
- site_ids.append(node['site_id'])
- interface_ids.extend(node['interface_ids'])
- tag_ids.extend(node['node_tag_ids'])
nodes_dict[node['node_id']] = node
-
- # get sites
- sites_dict = self.get_sites({'site_id': site_ids})
- # get interfaces
- interfaces = self.get_interfaces({'interface_id':interface_ids})
- # get tags
- node_tags = self.get_node_tags(tags_filter)
- # get initscripts
- pl_initscripts = self.get_pl_initscripts()
-
- links = self.get_links(sites_dict, nodes_dict, interfaces)
+ return nodes_dict
- rspec_nodes = []
- for node in nodes:
- # skip whitelisted nodes
- if node['slice_ids_whitelist']:
- if not slice or slice['slice_id'] not in node['slice_ids_whitelist']:
- continue
- rspec_node = Node()
- # xxx how to retrieve site['login_base']
- site_id=node['site_id']
- site=sites_dict[site_id]
- rspec_node['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], node['hostname'])
- rspec_node['component_name'] = node['hostname']
- rspec_node['component_manager_id'] = Xrn(self.driver.hrn, 'authority+cm').get_urn()
- rspec_node['authority_id'] = hrn_to_urn(PlXrn.site_hrn(self.driver.hrn, site['login_base']), 'authority+sa')
- # do not include boot state (<available> element) in the manifest rspec
- if not slice:
- rspec_node['boot_state'] = node['boot_state']
- rspec_node['exclusive'] = 'false'
- rspec_node['hardware_types'] = [HardwareType({'name': 'plab-pc'}),
- HardwareType({'name': 'pc'})]
- # only doing this because protogeni rspec needs
- # to advertise available initscripts
- rspec_node['pl_initscripts'] = pl_initscripts.values()
- # add site/interface info to nodes.
- # assumes that sites, interfaces and tags have already been prepared.
- site = sites_dict[node['site_id']]
- if site['longitude'] and site['latitude']:
- location = Location({'longitude': site['longitude'], 'latitude': site['latitude'], 'country': 'unknown'})
- rspec_node['location'] = location
- # Granularity
- granularity = Granularity({'grain': grain})
- rspec_node['granularity'] = granularity
-
- rspec_node['interfaces'] = []
- if_count=0
- for if_id in node['interface_ids']:
- interface = Interface(interfaces[if_id])
- interface['ipv4'] = interface['ip']
- interface['component_id'] = PlXrn(auth=self.driver.hrn,
- interface='node%s:eth%s' % (node['node_id'], if_count)).get_urn()
- # interfaces in the manifest need a client id
- if slice:
- interface['client_id'] = "%s:%s" % (node['node_id'], if_id)
- rspec_node['interfaces'].append(interface)
- if_count+=1
-
- tags = [PLTag(node_tags[tag_id]) for tag_id in node['node_tag_ids']]
- rspec_node['tags'] = tags
- if node['node_id'] in slivers:
- # add sliver info
- sliver = slivers[node['node_id']]
- rspec_node['sliver_id'] = sliver['sliver_id']
- rspec_node['client_id'] = node['hostname']
- rspec_node['slivers'] = [sliver]
-
- # slivers always provide the ssh service
- login = Login({'authentication': 'ssh-keys', 'hostname': node['hostname'], 'port':'22', 'username': sliver['name']})
- service = Services({'login': login})
- rspec_node['services'] = [service]
- rspec_nodes.append(rspec_node)
- return (rspec_nodes, links)
-
+ def rspec_node_to_geni_sliver(self, rspec_node):
+ op_status = "geni_unknown"
+ state = rspec_node['boot_state'].lower()
+ if state == 'boot':
+ op_status = 'geni_ready'
+ else:
+ op_status =' geni_failed'
+
+
+ # required fields
+ geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
+ 'geni_expires': rspec_node['expires'],
+ 'geni_operational_status': op_status,
+ 'geni_error': None,
+ }
+ return geni_sliver
def get_leases(self, slice=None, options={}):
return rspec_leases
- def get_rspec(self, slice_xrn=None, version = None, options={}):
+ def list_resources(self, version = None, options={}):
version_manager = VersionManager()
version = version_manager.get_version(version)
- if not slice_xrn:
- rspec_version = version_manager._get_version(version.type, version.version, 'ad')
- else:
- rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
-
- slice, slivers = self.get_slice_and_slivers(slice_xrn)
+ rspec_version = version_manager._get_version(version.type, version.version, 'ad')
rspec = RSpec(version=rspec_version, user_options=options)
- if slice and 'expires' in slice:
- rspec.xml.set('expires', datetime_to_string(utcparse(slice['expires'])))
-
- if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'leases':
- nodes, links = self.get_nodes_and_links(slice_xrn, slice, slivers)
- rspec.version.add_nodes(nodes)
- rspec.version.add_links(links)
- # add sliver defaults
- default_sliver = slivers.get(None, [])
- if default_sliver:
- default_sliver_attribs = default_sliver.get('tags', [])
- for attrib in default_sliver_attribs:
- logger.info(attrib)
- rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
-
- if not options.get('list_leases') or options.get('list_leases') and options['list_leases'] != 'resources':
- leases = self.get_leases(slice)
- rspec.version.add_leases(leases)
-
+
+ if not options.get('list_leases') or options['list_leases'] != 'leases':
+ # get nodes
+ nodes = self.get_nodes(options)
+ site_ids = []
+ interface_ids = []
+ tag_ids = []
+ nodes_dict = {}
+ for node in nodes:
+ site_ids.append(node['site_id'])
+ interface_ids.extend(node['interface_ids'])
+ tag_ids.extend(node['node_tag_ids'])
+ nodes_dict[node['node_id']] = node
+ sites = self.get_sites({'site_id': site_ids})
+ interfaces = self.get_interfaces({'interface_id':interface_ids})
+ node_tags = self.get_node_tags({'node_tag_id': tag_ids})
+ pl_initscripts = self.get_pl_initscripts()
+ # convert nodes to rspec nodes
+ rspec_nodes = []
+ for node in nodes:
+ rspec_node = self.node_to_rspec_node(node, sites, interfaces, node_tags, pl_initscripts)
+ rspec_nodes.append(rspec_node)
+ rspec.version.add_nodes(rspec_nodes)
+
+ # add links
+ links = self.get_links(sites, nodes_dict, interfaces)
+ rspec.version.add_links(links)
return rspec.toxml()
-
+ def describe(self, urns, version=None, options={}):
+ version_manager = VersionManager()
+ version = version_manager.get_version(version)
+ rspec_version = version_manager._get_version(version.type, version.version, 'manifest')
+ rspec = RSpec(version=version, user_options=options)
+
+ # get slivers
+ geni_slivers = []
+ slivers = self.get_slivers(urns, options)
+ if len(slivers) == 0:
+ raise SliverDoesNotExist("You have not allocated any slivers here for %s" % str(urns))
+ rspec.xml.set('expires', datetime_to_string(utcparse(slivers[0]['expires'])))
+
+ # lookup the sliver allocations
+ sliver_ids = [sliver['sliver_id'] for sliver in slivers]
+ constraint = SliverAllocation.sliver_id.in_(sliver_ids)
+ sliver_allocations = dbsession.query(SliverAllocation).filter(constraint)
+ sliver_allocation_dict = {}
+ for sliver_allocation in sliver_allocations:
+ sliver_allocation_dict[sliver_allocation.sliver_id] = sliver_allocation
+
+ if not options.get('list_leases') or options['list_leases'] != 'leases':
+ # add slivers
+ site_ids = []
+ interface_ids = []
+ tag_ids = []
+ nodes_dict = {}
+ for sliver in slivers:
+ site_ids.append(sliver['site_id'])
+ interface_ids.extend(sliver['interface_ids'])
+ tag_ids.extend(sliver['node_tag_ids'])
+ nodes_dict[sliver['node_id']] = sliver
+ sites = self.get_sites({'site_id': site_ids})
+ interfaces = self.get_interfaces({'interface_id':interface_ids})
+ node_tags = self.get_node_tags({'node_tag_id': tag_ids})
+ pl_initscripts = self.get_pl_initscripts()
+ rspec_nodes = []
+ for sliver in slivers:
+ if sliver['slice_ids_whitelist'] and sliver['slice_id'] not in sliver['slice_ids_whitelist']:
+ continue
+ rspec_node = self.sliver_to_rspec_node(sliver, sites, interfaces, node_tags, pl_initscripts)
+ geni_sliver = self.rspec_node_to_geni_sliver(rspec_node)
+ sliver_allocation_record = sliver_allocation_dict.get(sliver['sliver_id'])
+ if sliver_allocation_record:
+ sliver_allocation = sliver_allocation.allocation_state
+ else:
+ sliver_allocation = 'geni_unallocated'
+ geni_sliver['geni_allocation_status'] = sliver_allocation
+ rspec_nodes.append(rspec_node)
+ geni_slivers.append(geni_sliver)
+ rspec.version.add_nodes(rspec_nodes)
+
+ # add sliver defaults
+ #default_sliver = slivers.get(None, [])
+ #if default_sliver:
+ # default_sliver_attribs = default_sliver.get('tags', [])
+ # for attrib in default_sliver_attribs:
+ # rspec.version.add_default_sliver_attribute(attrib['tagname'], attrib['value'])
+
+ # add links
+ links = self.get_links(sites, nodes_dict, interfaces)
+ rspec.version.add_links(links)
+
+ if not options.get('list_leases') or options['list_leases'] != 'resources':
+ leases = self.get_leases(slivers[0])
+ rspec.version.add_leases(leases)
+
+
+ return {'geni_urn': urns[0],
+ 'geni_rspec': rspec.toxml(),
+ 'geni_slivers': geni_slivers}