FIT IoT-Lab aggregate: fixed archi and radio format
[sfa.git] / sfa / iotlab / iotlabaggregate.py
index 25b1445..3878da4 100644 (file)
-"""
-File providing methods to generate valid RSpecs for the Iotlab testbed.
-Contains methods to get information on slice, slivers, nodes and leases,
-formatting them and turn it into a RSpec.
-"""
+# -*- coding:utf-8 -*-
+""" aggregate class management """
+
+from sfa.util.xrn import Xrn, hrn_to_urn
 from sfa.util.sfatime import utcparse, datetime_to_string
-from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn
-from sfa.iotlab.iotlabxrn import IotlabXrn
+from sfa.util.sfalogging import logger
 from sfa.rspecs.rspec import RSpec
-#from sfa.rspecs.elements.location import Location
 from sfa.rspecs.elements.hardware_type import HardwareType
-from sfa.rspecs.elements.login import Login
-# from sfa.rspecs.elements.services import ServicesElement
-from sfa.rspecs.elements.sliver import Sliver
 from sfa.rspecs.elements.lease import Lease
 from sfa.rspecs.elements.granularity import Granularity
 from sfa.rspecs.version_manager import VersionManager
-from sfa.storage.model import SliverAllocation
-from sfa.rspecs.elements.versions.iotlabv1Node import IotlabPosition, \
-    IotlabNode, IotlabLocation
-from sfa.iotlab.iotlabxrn import xrn_object
-from sfa.util.sfalogging import logger
+from sfa.rspecs.elements.services import ServicesElement
+from sfa.rspecs.elements.login import Login
+from sfa.rspecs.elements.sliver import Sliver
+from sfa.rspecs.elements.versions.iotlabv1Node import IotlabPosition
+from sfa.rspecs.elements.versions.iotlabv1Node import IotlabNode
+from sfa.rspecs.elements.versions.iotlabv1Node import IotlabLocation
+from sfa.iotlab.iotlablease import LeaseTable
 import time
+import datetime
 
-class IotlabAggregate:
-    """Aggregate manager class for Iotlab. """
-
-    sites = {}
-    nodes = {}
-    api = None
-    interfaces = {}
-    links = {}
-    node_tags = {}
-
-    prepared = False
 
-    user_options = {}
+class IotLABAggregate(object):
+    """
+    SFA aggregate for Iot-LAB testbed
+    """
 
     def __init__(self, driver):
         self.driver = driver
 
-    def get_slice_and_slivers(self, slice_xrn, login=None):
-        """
-        Get the slices and the associated leases if any from the iotlab
-            testbed. One slice can have mutliple leases.
-            For each slice, get the nodes in the  associated lease
-            and create a sliver with the necessary info and insert it into the
-            sliver dictionary, keyed on the node hostnames.
-            Returns a dict of slivers based on the sliver's node_id.
-            Called by get_rspec.
-
-
-        :param slice_xrn: xrn of the slice
-        :param login: user's login on iotlab ldap
-
-        :type slice_xrn: string
-        :type login: string
-        :returns: a list of slices dict and a list of Sliver object
-        :rtype: (list, list)
-
-        .. note: There is no real slivers in iotlab, only leases. The goal
-            is to be consistent with the SFA standard.
-
-        """
-        slivers = {}
-        sfa_slice = None
-        if slice_xrn is None:
-            return (sfa_slice, slivers)
-        slice_urn = hrn_to_urn(slice_xrn, 'slice')
-        slice_hrn, _ = urn_to_hrn(slice_xrn)
-
-        # GetSlices always returns a list, even if there is only one element
-        slices = self.driver.GetSlices(
-                                        slice_filter=str(slice_hrn),
-                                        slice_filter_type='slice_hrn',
-                                        login=login)
-
-        logger.debug("IotlabAggregate api \tget_slice_and_slivers \
-                      slice_hrn %s \r\n slices %s self.driver.hrn %s"
-                     % (slice_hrn, slices, self.driver.hrn))
-        if slices == []:
-            return (sfa_slice, slivers)
-
-        # sort slivers by node id , if there is a job
-        #and therefore, node allocated to this slice
-        # for sfa_slice in slices:
-        sfa_slice = slices[0]
-        try:
-            node_ids_list = sfa_slice['node_ids']
-        except KeyError:
-            logger.log_exc("IOTLABAGGREGATE \t \
-                        get_slice_and_slivers No nodes in the slice \
-                        - KeyError ")
-            node_ids_list = []
-            # continue
-
-        for node in node_ids_list:
-            sliver_xrn = Xrn(slice_urn, type='sliver', id=node)
-            sliver_xrn.set_authority(self.driver.hrn)
-            sliver = Sliver({'sliver_id': sliver_xrn.urn,
-                            'name': sfa_slice['hrn'],
-                            'type': 'iotlab-node',
-                            'tags': []})
-
-            slivers[node] = sliver
-
-        #Add default sliver attribute :
-        #connection information for iotlab
-        # if get_authority(sfa_slice['hrn']) == \
-            # self.driver.testbed_shell.root_auth:
-        #     tmp = sfa_slice['hrn'].split('.')
-        #     ldap_username = tmp[1].split('_')[0]
-        #     ssh_access = None
-        #     slivers['default_sliver'] = {'ssh': ssh_access,
-        #                                  'login': ldap_username}
-        # look in ldap:
-        ldap_username = self.find_ldap_username_from_slice(sfa_slice)
-
-        if ldap_username is not None:
-            ssh_access = None
-            slivers['default_sliver'] = {'ssh': ssh_access,
-                                             'login': ldap_username}
-
-
-        logger.debug("IOTLABAGGREGATE api get_slice_and_slivers  slivers %s "
-                     % (slivers))
-        return (slices, slivers)
-
-    def find_ldap_username_from_slice(self, sfa_slice):
-        """
-        Gets the ldap username of the user based on the information contained
-        in ist sfa_slice record.
-
-        :param sfa_slice: the user's slice record. Must contain the
-            reg_researchers key.
-        :type sfa_slice: dictionary
-        :returns: ldap_username, the ldap user's login.
-        :rtype: string
-
-        """
-        researchers = [sfa_slice['reg_researchers'][0].__dict__]
-        # look in ldap:
-        ldap_username = None
-        ret =  self.driver.testbed_shell.GetPersons(researchers)
-        if len(ret) != 0:
-            ldap_username = ret[0]['uid']
-
-        return ldap_username
-
-
-
-    def get_nodes(self, options=None):
-    # def node_to_rspec_node(self, node, sites, node_tags,
-    #     grain=None, options={}):
-        """Returns the nodes in the slice using the rspec format, with all the
-        nodes' properties.
-
-        Fetch the nodes ids in the slices dictionary and get all the nodes
-        properties from OAR. Makes a rspec dicitonary out of this and returns
-        it. If the slice does not have any job running or scheduled, that is
-        it has no reserved nodes, then returns an empty list.
-
-        :returns: An empty list if the slice has no reserved nodes, a rspec
-            list with all the nodes and their properties (a dict per node)
-            otherwise.
-        :rtype: list
-
-        .. seealso:: get_slice_and_slivers
-
-        """
-
-        # NT: the semantic of this function is not clear to me :
-        # if slice is not defined, then all the nodes should be returned
-        # if slice is defined, we should return only the nodes that
-        # are part of this slice
-        # but what is the role of the slivers parameter ?
-        # So i assume that slice['node_ids'] will be the same as slivers for us
-        filter_nodes = None
-        if options:
-            geni_available = options.get('geni_available')
-            if geni_available == True:
-                filter_nodes['boot_state'] = ['Alive']
-
-        # slice_nodes_list = []
-        # if slices is not None:
-        #     for one_slice in slices:
-        #         try:
-        #             slice_nodes_list = one_slice['node_ids']
-    #              # if we are dealing with a slice that has no node just
-    #              # return an empty list. In iotlab a slice can have multiple
-    #              # jobs scheduled, so it either has at least one lease or
-    #              # not at all.
-        #         except KeyError:
-        #             return []
-
-        # get the granularity in second for the reservation system
-        # grain = self.driver.testbed_shell.GetLeaseGranularity()
-
-        nodes = self.driver.testbed_shell.GetNodes(node_filter_dict =
-                                                    filter_nodes)
-
-        nodes_dict = {}
-
-        #if slices, this means we got to list all the nodes given to this slice
-        # Make a list of all the nodes in the slice before getting their
-        #attributes
-        # rspec_nodes = []
-
-        # logger.debug("IOTLABAGGREGATE api get_nodes slices  %s "
-                     # % (slices))
-
-        # reserved_nodes = self.driver.testbed_shell.GetNodesCurrentlyInUse()
-        # logger.debug("IOTLABAGGREGATE api get_nodes slice_nodes_list  %s "
-                     # % (slice_nodes_list))
-        for node in nodes:
-            nodes_dict[node['node_id']] = node
-
-        return nodes_dict
+    def leases_to_rspec_leases(self, leases):
+        """ Get leases attributes list"""
+        rspec_leases = []
+        for lease in leases:
+            for node in lease['resources']:
+                rspec_lease = Lease()
+                rspec_lease['lease_id'] = lease['id']
+                iotlab_xrn = Xrn('.'.join([self.driver.root_auth,
+                                           Xrn.escape(node)]),
+                                 type='node')
+                rspec_lease['component_id'] = iotlab_xrn.urn
+                rspec_lease['start_time'] = str(lease['date'])
+                # duration in minutes
+                duration = int(lease['duration']) / 60
+                rspec_lease['duration'] = duration
+                rspec_lease['slice_id'] = lease['slice_id']
+                rspec_leases.append(rspec_lease)
+        return rspec_leases
 
     def node_to_rspec_node(self, node):
-        """ Creates a rspec node structure with the appropriate information
-        based on the node information that can be found in the node dictionary.
-
-        :param node: node data. this dict contains information about the node
-            and must have the following keys : mobile, radio, archi, hostname,
-            boot_state, site, x, y ,z (position).
-        :type node: dictionary.
-
-        :returns: node dictionary containing the following keys : mobile, archi,
-            radio, component_id, component_name, component_manager_id,
-            authority_id, boot_state, exclusive, hardware_types, location,
-            position, granularity, tags.
-        :rtype: dict
-
-        """
-
-        grain = self.driver.testbed_shell.GetLeaseGranularity()
-
+        """ Get node attributes """
         rspec_node = IotlabNode()
-        # xxx how to retrieve site['login_base']
-        #site_id=node['site_id']
-        #site=sites_dict[site_id]
-
         rspec_node['mobile'] = node['mobile']
         rspec_node['archi'] = node['archi']
-        rspec_node['radio'] = node['radio']
-
-        iotlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
-                                       node['hostname'])
+        if ':' in node['archi']:
+            rspec_node['radio'] = (node['archi'].split(':'))[1]
+        else:
+            rspec_node['radio'] = node['archi']
+        iotlab_xrn = Xrn('.'.join([self.driver.root_auth,
+                                   Xrn.escape(node['network_address'])]),
+                         type='node')
+        # rspec_node['boot_state'] = 'true'
+        if node['state'] == 'Absent' or \
+           node['state'] == 'Suspected' or \
+           node['state'] == 'Dead' or \
+           node['state'] == 'Busy':
+            rspec_node['available'] = 'false'
+        else:
+            rspec_node['available'] = 'true'
         rspec_node['component_id'] = iotlab_xrn.urn
-        rspec_node['component_name'] = node['hostname']
-        rspec_node['component_manager_id'] = \
-                        hrn_to_urn(self.driver.testbed_shell.root_auth,
-                        'authority+sa')
-
-        # Iotlab's nodes are federated : there is only one authority
-        # for all Iotlab sites, registered in SFA.
-        # Removing the part including the site
-        # in authority_id SA 27/07/12
+        rspec_node['component_name'] = node['network_address']
+        rspec_node['component_manager_id'] = hrn_to_urn(self.driver.root_auth,
+                                                        'authority+sa')
         rspec_node['authority_id'] = rspec_node['component_manager_id']
-
-        # do not include boot state (<available> element)
-        #in the manifest rspec
-
-
-        rspec_node['boot_state'] = node['boot_state']
-        # if node['hostname'] in reserved_nodes:
-        #     rspec_node['boot_state'] = "Reserved"
         rspec_node['exclusive'] = 'true'
-        rspec_node['hardware_types'] = [HardwareType({'name': \
-                                        'iotlab-node'})]
-
-        location = IotlabLocation({'country':'France', 'site': \
-                                    node['site']})
+        rspec_node['hardware_types'] = \
+            [HardwareType({'name': node['archi']})]
+        location = IotlabLocation({'country': 'France',
+                                   'site': node['site']})
         rspec_node['location'] = location
-
-
         position = IotlabPosition()
-        for field in position :
-            try:
-                position[field] = node[field]
-            except KeyError, error :
-                logger.log_exc("IOTLABAGGREGATE\t get_nodes \
-                                                position %s "% (error))
-
-        rspec_node['position'] = position
-
-
-        # Granularity
-        granularity = Granularity({'grain': grain})
+        for field in position:
+            position[field] = node[field]
+        granularity = Granularity({'grain': 30})
         rspec_node['granularity'] = granularity
         rspec_node['tags'] = []
-        # if node['hostname'] in slivers:
-        #     # add sliver info
-        #     sliver = slivers[node['hostname']]
-        #     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]
-
         return rspec_node
 
-
-    def rspec_node_to_geni_sliver(self, rspec_node, sliver_allocations = {}):
-        """Makes a geni sliver structure from all the nodes allocated
-        to slivers in the sliver_allocations dictionary. Returns the states
-        of the sliver.
-
-        :param rspec_node: Node information contained in a rspec data structure
-            fashion.
-        :type rspec_node: dictionary
-        :param sliver_allocations:
-        :type sliver_allocations: dictionary
-
-        :returns: Dictionary with the following keys: geni_sliver_urn,
-            geni_expires, geni_allocation_status, geni_operational_status,
-            geni_error.
-
-        :rtype: dictionary
-
-        .. seealso:: node_to_rspec_node
-
-        """
-        if rspec_node['sliver_id'] in sliver_allocations:
-            # set sliver allocation and operational status
-            sliver_allocation = sliver_allocations[rspec_node['sliver_id']]
-            if sliver_allocation:
-                allocation_status = sliver_allocation.allocation_state
-                if allocation_status == 'geni_allocated':
-                    op_status =  'geni_pending_allocation'
-                elif allocation_status == 'geni_provisioned':
-                    op_status = 'geni_ready'
-                else:
-                    op_status = 'geni_unknown'
-            else:
-                allocation_status = 'geni_unallocated'
-        else:
-            allocation_status = 'geni_unallocated'
-            op_status = 'geni_failed'
-        # required fields
-        geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
-                       'geni_expires': rspec_node['expires'],
-                       'geni_allocation_status' : allocation_status,
-                       'geni_operational_status': op_status,
-                       'geni_error': '',
-                       }
-        return geni_sliver
-
-
-    def sliver_to_rspec_node(self, sliver, sliver_allocations):
-        """Used by describe to format node information into a rspec compliant
-        structure.
-
-        Creates a node rspec compliant structure by calling node_to_rspec_node.
-        Adds slivers, if any, to rspec node structure. Returns the updated
-        rspec node struct.
-
-        :param sliver: sliver dictionary. Contains keys: urn, slice_id, hostname
-            and slice_name.
-        :type sliver: dictionary
-        :param sliver_allocations: dictionary of slivers
-        :type sliver_allocations: dict
-
-        :returns: Node dictionary with all necessary data.
-
-        .. seealso:: node_to_rspec_node
-        """
+    def sliver_to_rspec_node(self, sliver):
+        """ Get node and sliver attributes """
         rspec_node = self.node_to_rspec_node(sliver)
         rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
-        # add sliver info
-        logger.debug("IOTLABAGGREGATE api \t  sliver_to_rspec_node sliver \
-                        %s \r\nsliver_allocations %s" % (sliver,
-                            sliver_allocations))
-        rspec_sliver = Sliver({'sliver_id': sliver['urn'],
-                         'name': sliver['slice_id'],
-                         'type': 'iotlab-exclusive',
-                         'tags': []})
-        rspec_node['sliver_id'] = rspec_sliver['sliver_id']
-
-        if sliver['urn'] in sliver_allocations:
-            rspec_node['client_id'] = sliver_allocations[
-                                                    sliver['urn']].client_id
-            if sliver_allocations[sliver['urn']].component_id:
-                rspec_node['component_id'] = sliver_allocations[
-                                                    sliver['urn']].component_id
+        rspec_node['sliver_id'] = sliver['sliver_id']
+        rspec_sliver = Sliver({'sliver_id': sliver['sliver_id'],
+                               'name': sliver['name'],
+                               'type': sliver['archi'],
+                               'tags': []})
         rspec_node['slivers'] = [rspec_sliver]
-
         # slivers always provide the ssh service
         login = Login({'authentication': 'ssh-keys',
                        'hostname': sliver['hostname'],
-                       'port':'22',
-                       'username': sliver['slice_name'],
-                       'login': sliver['slice_name']
-                      })
+                       'port': '22',
+                       'username': sliver['name'],
+                       'login': sliver['name']
+                       })
+        service = ServicesElement({'login': login})
+        rspec_node['services'] = [service]
         return rspec_node
 
+    @classmethod
+    def rspec_node_to_geni_sliver(cls, rspec_node):
+        """ Get sliver status """
+        geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
+                       'geni_expires': rspec_node['expires'],
+                       'geni_allocation_status': 'geni_allocated',
+                       'geni_operational_status': 'geni_pending_allocation',
+                       'geni_error': '',
+                       }
+        return geni_sliver
 
-    def get_all_leases(self, ldap_username):
-        """
-        Get list of lease dictionaries which all have the mandatory keys
-        ('lease_id', 'hostname', 'site_id', 'name', 'start_time', 'duration').
-        All the leases running or scheduled are returned.
-
-        :param ldap_username: if ldap uid is not None, looks for the leases
-            belonging to this user.
-        :type ldap_username: string
-        :returns: rspec lease dictionary with keys lease_id, component_id,
-            slice_id, start_time, duration where the lease_id is the oar job id,
-            component_id is the node's urn, slice_id is the slice urn,
-            start_time is the timestamp starting time and duration is expressed
-            in terms of the testbed's granularity.
-        :rtype: dict
-
-        .. note::There is no filtering of leases within a given time frame.
-            All the running or scheduled leases are returned. options
-            removed SA 15/05/2013
-
-
-        """
-
-        logger.debug("IOTLABAGGREGATE  get_all_leases ldap_username %s "
-                     % (ldap_username))
-        leases = self.driver.GetLeases(login=ldap_username)
-        grain = self.driver.testbed_shell.GetLeaseGranularity()
-
-        rspec_leases = []
-        for lease in leases:
-            #as many leases as there are nodes in the job
-            for node in lease['reserved_nodes']:
-                rspec_lease = Lease()
-                rspec_lease['lease_id'] = lease['lease_id']
-                #site = node['site_id']
-                iotlab_xrn = xrn_object(self.driver.testbed_shell.root_auth,
-                                               node)
-                rspec_lease['component_id'] = iotlab_xrn.urn
-                #rspec_lease['component_id'] = hostname_to_urn(self.driver.hrn,\
-                                        #site, node['hostname'])
-                try:
-                    rspec_lease['slice_id'] = lease['slice_id']
-                except KeyError:
-                    #No info on the slice used in testbed_xp table
-                    pass
-                rspec_lease['start_time'] = lease['t_from']
-                rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
-                     / grain
-                rspec_leases.append(rspec_lease)
-        return rspec_leases
-
-    def get_rspec(self, slice_xrn=None, login=None, version=None,
-                  options=None):
-        """
-        Returns xml rspec:
-        - a full advertisement rspec with the testbed resources if slice_xrn is
-        not specified.If a lease option is given, also returns the leases
-        scheduled on the testbed.
-        - a manifest Rspec with the leases and nodes in slice's leases if
-        slice_xrn is not None.
-
-        :param slice_xrn: srn of the slice
-        :type slice_xrn: string
-        :param login: user'uid (ldap login) on iotlab
-        :type login: string
-        :param version: can be set to sfa or iotlab
-        :type version: RSpecVersion
-        :param options: used to specify if the leases should also be included in
-            the returned rspec.
-        :type options: dict
-
-        :returns: Xml Rspec.
-        :rtype: XML
-
-
-        """
-
-        ldap_username = None
-        rspec = None
-        version_manager = VersionManager()
-        version = version_manager.get_version(version)
-        logger.debug("IotlabAggregate \t get_rspec ***version %s \
-                    version.type %s  version.version %s options %s \r\n"
-                     % (version, version.type, version.version, options))
-
-        if slice_xrn is None:
-            rspec_version = version_manager._get_version(version.type,
-                                                         version.version, 'ad')
-
-        else:
-            rspec_version = version_manager._get_version(
-                version.type, version.version, 'manifest')
-
-        slices, slivers = self.get_slice_and_slivers(slice_xrn, login)
-        if slice_xrn and slices is not None:
-            #Get user associated with this slice
-            #for one_slice in slices :
-            ldap_username = self.find_ldap_username_from_slice(slices[0])
-            # ldap_username = slices[0]['reg_researchers'][0].__dict__['hrn']
-            #  # ldap_username = slices[0]['user']
-            # tmp = ldap_username.split('.')
-            # ldap_username = tmp[1]
-            logger.debug("IotlabAggregate \tget_rspec **** \
-                    LDAP USERNAME %s \r\n" \
-                    % (ldap_username))
-        #at this point sliver may be empty if no iotlab job
-        #is running for this user/slice.
-        rspec = RSpec(version=rspec_version, user_options=options)
-
-        logger.debug("\r\n \r\n IotlabAggregate \tget_rspec *** \
-                      slice_xrn %s slices  %s\r\n \r\n"
-                     % (slice_xrn, slices))
-
-        if options is not None:
-            lease_option = options['list_leases']
-        else:
-            #If no options are specified, at least print the resources
-            lease_option = 'all'
-           #if slice_xrn :
-               #lease_option = 'all'
-
-        if lease_option in ['all', 'resources']:
-        #if not options.get('list_leases') or options.get('list_leases')
-        #and options['list_leases'] != 'leases':
-            nodes = self.get_nodes()
-            logger.debug("\r\n")
-            logger.debug("IotlabAggregate \t lease_option %s \
-                          get rspec  ******* nodes %s"
-                         % (lease_option, nodes))
-
-            sites_set = set([node['location']['site'] for node in nodes])
-
-            #In case creating a job,  slice_xrn is not set to None
-            rspec.version.add_nodes(nodes)
-            if slice_xrn and slices is not None:
-            #     #Get user associated with this slice
-            #     #for one_slice in slices :
-            #     ldap_username = slices[0]['reg_researchers']
-            #      # ldap_username = slices[0]['user']
-            #     tmp = ldap_username.split('.')
-            #     ldap_username = tmp[1]
-            #      # ldap_username = tmp[1].split('_')[0]
-
-                logger.debug("IotlabAggregate \tget_rspec **** \
-                        version type %s ldap_ user %s \r\n" \
-                        % (version.type, ldap_username))
-                if version.type == "Iotlab":
-                    rspec.version.add_connection_information(
-                        ldap_username, sites_set)
-
-            default_sliver = slivers.get('default_sliver', [])
-            if default_sliver and len(nodes) is not 0:
-                #default_sliver_attribs = default_sliver.get('tags', [])
-                logger.debug("IotlabAggregate \tget_rspec **** \
-                        default_sliver%s \r\n" % (default_sliver))
-                for attrib in default_sliver:
-                    rspec.version.add_default_sliver_attribute(
-                        attrib, default_sliver[attrib])
-
-        if lease_option in ['all','leases']:
-            leases = self.get_all_leases(ldap_username)
-            rspec.version.add_leases(leases)
-            logger.debug("IotlabAggregate \tget_rspec **** \
-                       FINAL RSPEC %s \r\n" % (rspec.toxml()))
-        return rspec.toxml()
-
-    def get_slivers(self, urns, options={}):
-        """Get slivers of the given slice urns. Slivers contains slice, node and
-        user information.
-
-        For Iotlab, returns the leases with sliver ids and their allocation
-        status.
-
-        :param urns: list of  slice urns.
-        :type urns: list of strings
-        :param options: unused
-        :type options: unused
-
-        .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#urns
-        """
-
-
-        slice_ids = set()
-        node_ids = []
-        for urn in urns:
-            xrn = IotlabXrn(xrn=urn)
-            if xrn.type == 'sliver':
-                 # id: slice_id-node_id
-                try:
-                    sliver_id_parts = xrn.get_sliver_id_parts()
-                    slice_id = int(sliver_id_parts[0])
-                    node_id = int(sliver_id_parts[1])
-                    slice_ids.add(slice_id)
-                    node_ids.append(node_id)
-                except ValueError:
-                    pass
-            else:
-                slice_names = set()
-                slice_names.add(xrn.hrn)
-
-
-        logger.debug("IotlabAggregate \t get_slivers urns %s slice_ids %s \
-                       node_ids %s\r\n" % (urns, slice_ids, node_ids))
-        logger.debug("IotlabAggregate \t get_slivers xrn %s slice_names %s \
-                       \r\n" % (xrn, slice_names))
-        filter_sliver = {}
-        if slice_names:
-            filter_sliver['slice_hrn'] = list(slice_names)
-            slice_hrn = filter_sliver['slice_hrn'][0]
-
-            slice_filter_type = 'slice_hrn'
-
-        # if slice_ids:
-        #     filter['slice_id'] = list(slice_ids)
-        # # get slices
-        if slice_hrn:
-            slices = self.driver.GetSlices(slice_hrn,
-                slice_filter_type)
-            leases = self.driver.GetLeases({'slice_hrn':slice_hrn})
-        logger.debug("IotlabAggregate \t get_slivers \
-                       slices %s leases %s\r\n" % (slices, leases ))
-        if not slices:
-            return []
-
-        single_slice = slices[0]
-        # get sliver users
-        user = single_slice['reg_researchers'][0].__dict__
-        logger.debug("IotlabAggregate \t get_slivers user %s \
-                       \r\n" % (user))
-
-        # construct user key info
-        person = self.driver.testbed_shell.ldap.LdapFindUser(record=user)
-        logger.debug("IotlabAggregate \t get_slivers person %s \
-                       \r\n" % (person))
-        # name = person['last_name']
-        user['login'] = person['uid']
-        user['user_urn'] = hrn_to_urn(user['hrn'], 'user')
-        user['keys'] = person['pkey']
-
-
-        try:
-            node_ids = single_slice['node_ids']
-            node_list = self.driver.testbed_shell.GetNodes(
-                    {'hostname':single_slice['node_ids']})
-            node_by_hostname = dict([(node['hostname'], node)
-                                        for node in node_list])
-        except KeyError:
-            logger.warning("\t get_slivers No slivers in slice")
-            # slice['node_ids'] = node_ids
-        # nodes_dict = self.get_slice_nodes(slice, options)
-
-        slivers = []
-        for current_lease in leases:
-            for hostname in current_lease['reserved_nodes']:
-                node = {}
-                node['slice_id'] = current_lease['slice_id']
-                node['slice_hrn'] = current_lease['slice_hrn']
-                slice_name = current_lease['slice_hrn'].split(".")[1]
-                node['slice_name'] = slice_name
-                index = current_lease['reserved_nodes'].index(hostname)
-                node_id = current_lease['resource_ids'][index]
-                # node['slice_name'] = user['login']
-                # node.update(single_slice)
-                more_info = node_by_hostname[hostname]
-                node.update(more_info)
-                # oar_job_id is the slice_id (lease_id)
-                sliver_hrn = '%s.%s-%s' % (self.driver.hrn,
-                            current_lease['lease_id'], node_id)
-                node['node_id'] = node_id
-                node['expires'] = current_lease['t_until']
-                node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
-                node['urn'] = node['sliver_id']
-                node['services_user'] = [user]
-
-                slivers.append(node)
-        return slivers
-
-    def list_resources(self, version = None, options={}):
+    def list_resources(self, version=None, options=None):
         """
-        Returns an advertisement Rspec of available resources at this
-        aggregate. This Rspec contains a resource listing along with their
-        description, providing sufficient information for clients to be able to
-        select among available resources.
-
-        :param options: various options. The valid options are: {boolean
-            geni_compressed <optional>; struct geni_rspec_version { string type;
-            #case insensitive , string version; # case insensitive}} . The only
-            mandatory options if options is specified is geni_rspec_version.
-        :type options: dictionary
-
-        :returns: On success, the value field of the return struct will contain
-            a geni.rspec advertisment RSpec
-        :rtype: Rspec advertisement in xml.
-
-        .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#RSpecdatatype
-        .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#ListResources
+        list_resources method sends a RSpec with all Iot-LAB testbed nodes
+        and leases (OAR job submission). For leases we get all OAR jobs with
+        state Waiting or Running. If we have an entry in SFA database
+        (lease table) with OAR job id this submission was launched by SFA
+        driver, otherwise it was launched by Iot-LAB Webportal or CLI-tools
+
+        :Example:
+        <rspec>
+        ...
+        <node component_manager_id="urn:publicid:IDN+iotlab+authority+sa"
+              component_id=
+                  "urn:publicid:IDN+iotlab+node+m3-10.devgrenoble.iot-lab.info"
+              exclusive="true" component_name="m3-10.devgrenoble.iot-lab.info">
+            <hardware_type name="iotlab-node"/>
+            <location country="France"/>
+            <granularity grain="60"/>
+            ...
+        </node>
+        ...
+        <lease slice_id="urn:publicid:IDN+onelab:inria+slice+test_iotlab"
+            start_time="1427792400" duration="30">
+            <node component_id=
+                "urn:publicid:IDN+iotlab+node+m3-10.grenoble.iot-lab.info"/>
+        </lease>
+        ...
+        </rspec>
         """
+        # pylint:disable=R0914,W0212
+        logger.warning("iotlabaggregate list_resources")
+        logger.warning("iotlabaggregate list_resources options %s" % options)
+        if not options:
+            options = {}
 
         version_manager = VersionManager()
         version = version_manager.get_version(version)
         rspec_version = version_manager._get_version(version.type,
-                                                    version.version, 'ad')
+                                                     version.version,
+                                                     'ad')
         rspec = RSpec(version=rspec_version, user_options=options)
-        # variable ldap_username to be compliant with  get_all_leases
-        # prototype. Now unused in geni-v3 since we are getting all the leases
-        # here
-        ldap_username = None
-        if not options.get('list_leases') or options['list_leases'] != 'leases':
-            # get nodes
-            nodes_dict  = self.get_nodes(options)
 
-            # no interfaces on iotlab nodes
+        nodes = self.driver.shell.get_nodes()
+        reserved_nodes = self.driver.shell.get_reserved_nodes()
+        if 'error' not in nodes and 'error' not in reserved_nodes:
             # convert nodes to rspec nodes
             rspec_nodes = []
-            for node_id in nodes_dict:
-                node = nodes_dict[node_id]
-                rspec_node = self.node_to_rspec_node(node)
+            for node in nodes:
+                rspec_node = self.node_to_rspec_node(nodes[node])
                 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)
-
-        if not options.get('list_leases') or options.get('list_leases') \
-            and options['list_leases'] != 'resources':
-            leases = self.get_all_leases(ldap_username)
-            rspec.version.add_leases(leases)
-
+            leases = []
+            db_leases = {}
+            # find OAR jobs id for all slices in SFA database
+            for lease in self.driver.api.dbsession().query(LeaseTable).all():
+                db_leases[lease.job_id] = lease.slice_hrn
+
+            for lease_id in reserved_nodes:
+                # onelab slice = job submission from OneLAB
+                if lease_id in db_leases:
+                    reserved_nodes[lease_id]['slice_id'] = \
+                        hrn_to_urn(db_leases[lease_id],
+                                   'slice')
+                # iotlab slice = job submission from Iot-LAB
+                else:
+                    reserved_nodes[lease_id]['slice_id'] = \
+                        hrn_to_urn(self.driver.root_auth + '.' +
+                                   reserved_nodes[lease_id][
+                                       'owner'] + "_slice",
+                                   'slice')
+                leases.append(reserved_nodes[lease_id])
+
+            rspec_leases = self.leases_to_rspec_leases(leases)
+            rspec.version.add_leases(rspec_leases)
         return rspec.toxml()
 
+    def get_slivers(self, urns, leases, nodes):
+        """ Get slivers attributes list """
+        logger.warning("iotlabaggregate get_slivers")
+        logger.warning("iotlabaggregate get_slivers urns %s" % urns)
+        slivers = []
+        for lease in leases:
+            for node in lease['resources']:
+                network_address = node.split(".")
+                sliver_node = nodes[node]
+                sliver_hrn = '%s.%s-%s' % (self.driver.hrn,
+                                           lease['id'],
+                                           network_address[0])
+                start_time = datetime.datetime.fromtimestamp(lease['date'])
+                duration = datetime.timedelta(seconds=int(lease['duration']))
+                sliver_node['expires'] = start_time + duration
+                sliver_node['sliver_id'] = Xrn(sliver_hrn,
+                                               type='sliver').urn
+                # frontend SSH hostname
+                sliver_node['hostname'] = '.'.join(network_address[1:])
+                # user login
+                sliver_node['name'] = lease['owner']
+                slivers.append(sliver_node)
+        return slivers
 
-    def describe(self, urns, version=None, options={}):
-        """
-        Retrieve a manifest RSpec describing the resources contained by the
-        named entities, e.g. a single slice or a set of the slivers in a slice.
-        This listing and description should be sufficiently descriptive to allow
-        experimenters to use the resources.
+    def _delete_db_lease(self, job_id):
+        """ Delete lease table row in SFA database """
+        logger.warning("iotlabdriver _delete_db_lease lease job_id : %s"
+                       % job_id)
+        self.driver.api.dbsession().query(LeaseTable).filter(
+            LeaseTable.job_id == job_id).delete()
+        self.driver.api.dbsession().commit()
 
-        :param urns: If a slice urn is supplied and there are no slivers in the
-            given slice at this aggregate, then geni_rspec shall be a valid
-            manifest RSpec, containing no node elements - no resources.
-        :type urns: list  or strings
-        :param options: various options. the valid options are: {boolean
-            geni_compressed <optional>; struct geni_rspec_version { string type;
-            #case insensitive , string version; # case insensitive}}
-        :type options: dictionary
+    def describe(self, urns, version=None, options=None):
+        """
+        describe method returns slice slivers (allocated resources) and leases
+        (OAR job submission). We search in lease table of SFA database all OAR
+        jobs id for this slice and match OAR jobs with state Waiting or
+        Running. If OAR job id doesn't exist the experiment is terminated and
+        we delete the database table entry. Otherwise we add slivers and leases
+        in the response
+
+        :returns:
+            geni_slivers : a list of allocated slivers with information about
+                           their allocation and operational state
+            geni_urn : the URN of the slice in which the sliver has been
+                       allocated
+            geni_rspec:  a RSpec describing the allocated slivers and leases
+        :rtype: dict
 
-        :returns: On success returns the following dictionary {geni_rspec:
-            <geni.rspec, a Manifest RSpec>, geni_urn: <string slice urn of the
-            containing slice>, geni_slivers:{ geni_sliver_urn:
-            <string sliver urn>, geni_expires:  <dateTime.rfc3339 allocation
-            expiration string, as in geni_expires from SliversStatus>,
-            geni_allocation_status: <string sliver state - e.g. geni_allocated
-            or geni_provisioned >, geni_operational_status:
-            <string sliver operational state>, geni_error: <optional string.
-            The field may be omitted entirely but may not be null/None,
-            explaining any failure for a sliver.>}
+        :Example:
+        <rspec>
+        ...
+        <node component_manager_id="urn:publicid:IDN+iotlab+authority+sa"
+              component_id=
+                  "urn:publicid:IDN+iotlab+node+m3-10.grenoble.iot-lab.info"
+              client_id="m3-10.grenoble.iot-lab.info"
+              sliver_id="urn:publicid:IDN+iotlab+sliver+9953-m3-10"
+              exclusive="true" component_name="m3-10.grenoble.iot-lab.info">
+            <hardware_type name="iotlab-node"/>
+            <location country="France"/>
+            <granularity grain="30"/>
+            <sliver_type name="iotlab-exclusive"/>
+        </node>
+        <lease slice_id="urn:publicid:IDN+onelab:inria+slice+test_iotlab"
+               start_time="1427792428" duration="29">
+            <node component_id=
+                "urn:publicid:IDN+iotlab+node+m3-10.grenoble.iot-lab.info"/>
+        </lease>
+        ...
+        </rspec>
 
-        .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#Describe
-        .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3/CommonConcepts#urns
         """
+        # pylint:disable=R0914,W0212
+        logger.warning("iotlabaggregate describe")
+        logger.warning("iotlabaggregate describe urns : %s" % urns)
+        if not options:
+            options = {}
         version_manager = VersionManager()
         version = version_manager.get_version(version)
-        rspec_version = version_manager._get_version(
-                                    version.type, version.version, 'manifest')
+        rspec_version = version_manager._get_version(version.type,
+                                                     version.version,
+                                                     'manifest')
         rspec = RSpec(version=rspec_version, user_options=options)
-
-        # get slivers
+        xrn = Xrn(urns[0])
         geni_slivers = []
-        slivers = self.get_slivers(urns, options)
-        if slivers:
-            rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
-        else:
-            rspec_expires = datetime_to_string(utcparse(time.time()))
-        rspec.xml.set('expires',  rspec_expires)
 
-        # lookup the sliver allocations
-        geni_urn = urns[0]
-        sliver_ids = [sliver['sliver_id'] for sliver in slivers]
-        logger.debug(" IOTLAB_API.PY \tDescribe  sliver_ids %s "
-                     % (sliver_ids))
-        constraint = SliverAllocation.sliver_id.in_(sliver_ids)
-        query = self.driver.api.dbsession().query(SliverAllocation)
-        sliver_allocations = query.filter((constraint)).all()
-        logger.debug(" IOTLAB_API.PY \tDescribe  sliver_allocations %s "
-                     % (sliver_allocations))
-        sliver_allocation_dict = {}
-        for sliver_allocation in sliver_allocations:
-            geni_urn = sliver_allocation.slice_urn
-            sliver_allocation_dict[sliver_allocation.sliver_id] = \
-                                                            sliver_allocation
+        nodes = self.driver.shell.get_nodes()
+        reserved_nodes = self.driver.shell.get_reserved_nodes()
+        if 'error' not in nodes and 'error' not in reserved_nodes:
+            # find OAR jobs id for one slice in SFA database
+            db_leases = [(lease.job_id, lease.slice_hrn)
+                         for lease in self.driver.api.dbsession()
+                         .query(LeaseTable)
+                         .filter(LeaseTable.slice_hrn == xrn.hrn).all()]
+
+            leases = []
+            for job_id, slice_hrn in db_leases:
+                # OAR job terminated, we delete entry in database
+                if job_id not in reserved_nodes:
+                    self._delete_db_lease(job_id)
+                else:
+                    # onelab slice = job submission from OneLAB
+                    lease = reserved_nodes[job_id]
+                    lease['slice_id'] = hrn_to_urn(slice_hrn, 'slice')
+                    leases.append(lease)
+
+            # get slivers
+            slivers = self.get_slivers(urns, leases, nodes)
+            if slivers:
+                date = utcparse(slivers[0]['expires'])
+                rspec_expires = datetime_to_string(date)
+            else:
+                rspec_expires = datetime_to_string(utcparse(time.time()))
+            rspec.xml.set('expires', rspec_expires)
+
+            rspec_nodes = []
 
-        # add slivers
-        nodes_dict = {}
-        for sliver in slivers:
-            nodes_dict[sliver['node_id']] = sliver
-        rspec_nodes = []
-        for sliver in slivers:
-            rspec_node = self.sliver_to_rspec_node(sliver,
-                                                    sliver_allocation_dict)
-            rspec_nodes.append(rspec_node)
-            logger.debug(" IOTLAB_API.PY \tDescribe  sliver_allocation_dict %s "
-                     % (sliver_allocation_dict))
-            geni_sliver = self.rspec_node_to_geni_sliver(rspec_node,
-                            sliver_allocation_dict)
-            geni_slivers.append(geni_sliver)
+            for sliver in slivers:
+                rspec_node = self.sliver_to_rspec_node(sliver)
+                rspec_nodes.append(rspec_node)
+                geni_sliver = self.rspec_node_to_geni_sliver(rspec_node)
+                geni_slivers.append(geni_sliver)
+            logger.warning("iotlabaggregate describe geni_slivers %s" %
+                           geni_slivers)
+            rspec.version.add_nodes(rspec_nodes)
 
-        logger.debug(" IOTLAB_API.PY \tDescribe rspec_nodes %s\
-                        rspec %s "
-                     % (rspec_nodes, rspec))
-        rspec.version.add_nodes(rspec_nodes)
+            rspec_leases = self.leases_to_rspec_leases(leases)
+            logger.warning("iotlabaggregate describe rspec_leases %s" %
+                           rspec_leases)
+            rspec.version.add_leases(rspec_leases)
 
-        return {'geni_urn': geni_urn,
+        return {'geni_urn': urns[0],
                 'geni_rspec': rspec.toxml(),
-                'geni_slivers': geni_slivers}
\ No newline at end of file
+                'geni_slivers': geni_slivers}