From: Mohamed Larabi Date: Mon, 4 Jun 2012 18:14:21 +0000 (+0200) Subject: Reservation-oriented Rspec with planetlab X-Git-Tag: sfa-2.1-10~10 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=e3877c867d5e9120a21b585782460842539abadb;p=sfa.git Reservation-oriented Rspec with planetlab --- diff --git a/sfa/client/sfi.py b/sfa/client/sfi.py index 4387dbaa..26a7f544 100644 --- a/sfa/client/sfi.py +++ b/sfa/client/sfi.py @@ -372,6 +372,9 @@ class Sfi: #panos: a new option to define the type of information about resources a user is interested in parser.add_option("-i", "--info", dest="info", help="optional component information", default=None) + # a new option to retreive or not reservation-oriented RSpecs (leases) + parser.add_option("-l", "--list_leases", dest="list_leases", type="choice", + help="Retreive or not reservation-oriented RSpecs ([resources]|leases|all )", # 'create' does return the new rspec, makes sense to save that too @@ -955,6 +958,8 @@ or with an slice hrn, shows currently provisioned resources api_options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice') if options.info: api_options['info'] = options.info + if options.list_leases: + api_options['list_leases'] = options.list_leases if options.current: if options.current == True: api_options['cached'] = False diff --git a/sfa/planetlab/plaggregate.py b/sfa/planetlab/plaggregate.py index ccf68527..e2ff3f9e 100644 --- a/sfa/planetlab/plaggregate.py +++ b/sfa/planetlab/plaggregate.py @@ -13,12 +13,15 @@ from sfa.rspecs.elements.location import Location from sfa.rspecs.elements.interface import Interface from sfa.rspecs.elements.services import Services from sfa.rspecs.elements.pltag import PLTag +from sfa.rspecs.elements.lease import Lease +from sfa.rspecs.elements.granularity import Granularity from sfa.rspecs.version_manager import VersionManager -from sfa.planetlab.plxrn import PlXrn, hostname_to_urn, hrn_to_pl_slicename +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 +import time class PlAggregate: @@ -154,6 +157,9 @@ class PlAggregate: filter.update({'peer_id': None}) nodes = self.driver.shell.GetNodes(filter) + + # get the granularity in second for the reservation system + grain = self.driver.shell.GetLeaseGranularity() site_ids = [] interface_ids = [] @@ -205,6 +211,10 @@ class PlAggregate: 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']: @@ -234,7 +244,44 @@ class PlAggregate: rspec_nodes.append(rspec_node) return (rspec_nodes, links) + + def get_leases(self, slice=None, options={}): + now = int(time.time()) + filter={} + filter.update({'clip':now}) + if slice: + filter.update({'name':slice['name']}) + return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until'] + leases = self.driver.shell.GetLeases(filter) + + site_ids = [] + for lease in leases: + site_ids.append(lease['site_id']) + + # get sites + sites_dict = self.get_sites({'site_id': site_ids}) + + rspec_leases = [] + for lease in leases: + + rspec_lease = Lease() + + # xxx how to retrieve site['login_base'] + site_id=lease['site_id'] + site=sites_dict[site_id] + + rspec_lease['lease_id'] = lease['lease_id'] + rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn, site['login_base'], lease['hostname']) + slice_hrn = slicename_to_hrn(self.driver.hrn, lease['name']) + slice_urn = hrn_to_urn(slice_hrn, 'slice') + rspec_lease['slice_id'] = slice_urn + rspec_lease['t_from'] = lease['t_from'] + rspec_lease['t_until'] = lease['t_until'] + rspec_leases.append(rspec_lease) + return rspec_leases + + def get_rspec(self, slice_xrn=None, version = None, options={}): version_manager = VersionManager() @@ -249,17 +296,22 @@ class PlAggregate: if slice and 'expires' in slice: rspec.xml.set('expires', datetime_to_string(utcparse(slice['expires']))) - nodes, links = self.get_nodes_and_links(slice_xrn, slice, slivers) - rspec.version.add_nodes(nodes) - rspec.version.add_links(links) + 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']) - # 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) + return rspec.toxml() diff --git a/sfa/planetlab/pldriver.py b/sfa/planetlab/pldriver.py index e4330e82..12d5410b 100644 --- a/sfa/planetlab/pldriver.py +++ b/sfa/planetlab/pldriver.py @@ -27,7 +27,7 @@ from sfa.planetlab.plshell import PlShell import sfa.planetlab.peers as peers from sfa.planetlab.plaggregate import PlAggregate from sfa.planetlab.plslices import PlSlices -from sfa.planetlab.plxrn import PlXrn, slicename_to_hrn, hostname_to_hrn, hrn_to_pl_slicename +from sfa.planetlab.plxrn import PlXrn, slicename_to_hrn, hostname_to_hrn, hrn_to_pl_slicename, hrn_to_pl_login_base, xrn_to_hostname def list_to_dict(recs, key): @@ -611,6 +611,10 @@ class PlDriver (Driver): #panos adding the info option to the caching key (can be improved) if options.get('info'): version_string = version_string + "_"+options.get('info', 'default') + + # Adding the list_leases option to the caching key + if options.get('list_leases'): + version_string = version_string + "_"+options.get('list_leases', 'default') # look in cache first if cached_requested and self.cache and not slice_hrn: @@ -737,6 +741,22 @@ class PlDriver (Driver): # add/remove links links slices.verify_slice_links(slice, rspec.version.get_link_requests(), nodes) + + # add/remove leases + requested_leases = [] + kept_leases = [] + for lease in rspec.version.get_leases(): + requested_lease = {} + if not lease.get('lease_id'): + requested_lease['hostname'] = xrn_to_hostname(lease.get('component_id').strip()) + requested_lease['t_from'] = lease.get('t_from') + requested_lease['t_until'] = lease.get('t_until') + else: + kept_leases.append(int(lease['lease_id'])) + if requested_lease.get('hostname'): + requested_leases.append(requested_lease) + + leases = slices.verify_slice_leases(slice, requested_leases, kept_leases, peer) # handle MyPLC peer association. # only used by plc and ple. diff --git a/sfa/planetlab/plshell.py b/sfa/planetlab/plshell.py index d2cd9cd3..f42af880 100644 --- a/sfa/planetlab/plshell.py +++ b/sfa/planetlab/plshell.py @@ -23,6 +23,9 @@ class PlShell: 'UpdateSlice', 'UpdateSliceTag', # also used as-is in importer 'GetSites','GetNodes', + # Lease management methods + 'GetLeases', 'GetLeaseGranularity', 'DeleteLeases','UpdateLeases', + 'AddLeases' ] # support for other names - this is experimental alias_calls = { 'get_authorities':'GetSites', @@ -84,3 +87,4 @@ class PlShell: logger.debug('PlShell %s (%s) returned ... '%(name,actual_name)) return result return func + diff --git a/sfa/planetlab/plslices.py b/sfa/planetlab/plslices.py index 2645dedf..54cfaa19 100644 --- a/sfa/planetlab/plslices.py +++ b/sfa/planetlab/plslices.py @@ -159,6 +159,25 @@ class PlSlices: return sfa_peer + def verify_slice_leases(self, slice, requested_leases, kept_leases, peer): + + leases = self.driver.shell.GetLeases({'name':slice['name']}, ['lease_id']) + current_leases = [lease['lease_id'] for lease in leases] + deleted_leases = list(set(current_leases).difference(kept_leases)) + + try: + if peer: + self.driver.shell.UnBindObjectFromPeer('slice', slice['slice_id'], peer['shortname']) + deleted=self.driver.shell.DeleteLeases(deleted_leases) + for lease in requested_leases: + added=self.driver.shell.AddLeases(lease['hostname'], slice['name'], int(lease['t_from']), int(lease['t_until'])) + + except: + logger.log_exc('Failed to add/remove slice leases') + + return leases + + def verify_slice_nodes(self, slice, requested_slivers, peer): nodes = self.driver.shell.GetNodes(slice['node_ids'], ['node_id', 'hostname', 'interface_ids']) diff --git a/sfa/rspecs/elements/granularity.py b/sfa/rspecs/elements/granularity.py new file mode 100644 index 00000000..16d30a01 --- /dev/null +++ b/sfa/rspecs/elements/granularity.py @@ -0,0 +1,7 @@ +from sfa.rspecs.elements.element import Element + +class Granularity(Element): + + fields = [ + 'grain', + ] diff --git a/sfa/rspecs/elements/lease.py b/sfa/rspecs/elements/lease.py new file mode 100644 index 00000000..d329a8cb --- /dev/null +++ b/sfa/rspecs/elements/lease.py @@ -0,0 +1,11 @@ +from sfa.rspecs.elements.element import Element + +class Lease(Element): + + fields = [ + 'lease_id', + 'component_id', + 'slice_id' + 't_from', + 't_until', + ] diff --git a/sfa/rspecs/elements/versions/sfav1Lease.py b/sfa/rspecs/elements/versions/sfav1Lease.py new file mode 100644 index 00000000..7a2320e3 --- /dev/null +++ b/sfa/rspecs/elements/versions/sfav1Lease.py @@ -0,0 +1,62 @@ +from sfa.util.sfalogging import logger +from sfa.util.xml import XpathFilter +from sfa.util.xrn import Xrn + +from sfa.rspecs.elements.element import Element +from sfa.rspecs.elements.node import Node +from sfa.rspecs.elements.sliver import Sliver +from sfa.rspecs.elements.location import Location +from sfa.rspecs.elements.hardware_type import HardwareType +from sfa.rspecs.elements.disk_image import DiskImage +from sfa.rspecs.elements.interface import Interface +from sfa.rspecs.elements.bwlimit import BWlimit +from sfa.rspecs.elements.pltag import PLTag +from sfa.rspecs.elements.versions.sfav1Sliver import SFAv1Sliver +from sfa.rspecs.elements.versions.sfav1PLTag import SFAv1PLTag +from sfa.rspecs.elements.versions.pgv2Services import PGv2Services +from sfa.rspecs.elements.lease import Lease + +from sfa.planetlab.plxrn import xrn_to_hostname + +class SFAv1Lease: + + @staticmethod + def add_leases(xml, leases): + + network_elems = xml.xpath('//network') + if len(network_elems) > 0: + network_elem = network_elems[0] + elif len(leases) > 0: + network_urn = Xrn(leases[0]['component_id']).get_authority_urn().split(':')[0] + network_elem = xml.add_element('network', name = network_urn) + else: + network_elem = xml + + lease_elems = [] + for lease in leases: + lease_fields = ['lease_id', 'component_id', 'slice_id', 't_from', 't_until'] + lease_elem = network_elem.add_instance('lease', lease, lease_fields) + lease_elems.append(lease_elem) + + + @staticmethod + def get_leases(xml, filter={}): + xpath = '//lease%s | //default:lease%s' % (XpathFilter.xpath(filter), XpathFilter.xpath(filter)) + lease_elems = xml.xpath(xpath) + return SFAv1Lease.get_lease_objs(lease_elems) + + @staticmethod + def get_lease_objs(lease_elems): + leases = [] + for lease_elem in lease_elems: + lease = Lease(lease_elem.attrib, lease_elem) + if lease.get('lease_id'): + lease['lease_id'] = lease_elem.attrib['lease_id'] + lease['component_id'] = lease_elem.attrib['component_id'] + lease['slice_id'] = lease_elem.attrib['slice_id'] + lease['t_from'] = lease_elem.attrib['t_from'] + lease['t_until'] = lease_elem.attrib['t_until'] + + leases.append(lease) + return leases + diff --git a/sfa/rspecs/elements/versions/sfav1Node.py b/sfa/rspecs/elements/versions/sfav1Node.py index d8db263a..024a52e6 100644 --- a/sfa/rspecs/elements/versions/sfav1Node.py +++ b/sfa/rspecs/elements/versions/sfav1Node.py @@ -57,6 +57,12 @@ class SFAv1Node: if location: node_elem.add_instance('location', location, Location.fields) + # add granularity of the reservation system + granularity = node.get('granularity') + if granularity: + node_elem.add_instance('granularity', granularity, granularity.fields) + + if isinstance(node.get('interfaces'), list): for interface in node.get('interfaces', []): node_elem.add_instance('interface', interface, ['component_id', 'client_id', 'ipv4']) diff --git a/sfa/rspecs/rspec_elements.py b/sfa/rspecs/rspec_elements.py index ce3cac76..90f36a3d 100644 --- a/sfa/rspecs/rspec_elements.py +++ b/sfa/rspecs/rspec_elements.py @@ -20,6 +20,8 @@ RSpecElements = Enum( SERVICES='SERVICES', SLIVER='SLIVER', SLIVER_TYPE='SLIVER_TYPE', + LEASE='LEASE', + GRANULARITY='GRANULARITY', ) class RSpecElement: diff --git a/sfa/rspecs/versions/sfav1.py b/sfa/rspecs/versions/sfav1.py index 964da059..fd2e0313 100644 --- a/sfa/rspecs/versions/sfav1.py +++ b/sfa/rspecs/versions/sfav1.py @@ -8,6 +8,7 @@ from sfa.rspecs.elements.element import Element from sfa.rspecs.elements.versions.pgv2Link import PGv2Link from sfa.rspecs.elements.versions.sfav1Node import SFAv1Node from sfa.rspecs.elements.versions.sfav1Sliver import SFAv1Sliver +from sfa.rspecs.elements.versions.sfav1Lease import SFAv1Lease class SFAv1(RSpecVersion): enabled = True @@ -216,6 +217,14 @@ class SFAv1(RSpecVersion): self.xml.append(network.element) current_networks.append(current_network) + # Leases + + def get_leases(self, filter=None): + return SFAv1Lease.get_leases(self.xml, filter) + + def add_leases(self, leases, network = None, no_dupes=False): + SFAv1Lease.add_leases(self.xml, leases) + if __name__ == '__main__': from sfa.rspecs.rspec import RSpec from sfa.rspecs.rspec_elements import *