FIT IoT-Lab aggregate: fixed archi and radio format
[sfa.git] / sfa / iotlab / iotlabaggregate.py
index 73fca1b..3878da4 100644 (file)
-#import time
-from sfa.util.xrn import hrn_to_urn, urn_to_hrn, get_authority
+# -*- 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.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.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
 
 
-from sfa.rspecs.elements.versions.iotlabv1Node import IotlabPosition, IotlabNode, \
-                                                            IotlabLocation
-from sfa.util.sfalogging import logger
-
-from sfa.util.xrn import Xrn
-
-def iotlab_xrn_to_hostname(xrn):
-    return Xrn.unescape(Xrn(xrn=xrn, type='node').get_leaf())
-
-def iotlab_xrn_object(root_auth, hostname):
-    """Attributes are urn and hrn.
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-    Get the hostname using iotlab_xrn_to_hostname on the urn.
-
-    :return: the iotlab node's xrn
-=======
-    Get the hostname using slab_xrn_to_hostname on the urn.
-
-    :return: the senslab node's xrn
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-    :rtype: Xrn
+class IotLABAggregate(object):
+    """
+    SFA aggregate for Iot-LAB testbed
     """
-    return Xrn('.'.join( [root_auth, Xrn.escape(hostname)]), type='node')
-
-class IotlabAggregate:
-
-    sites = {}
-    nodes = {}
-    api = None
-    interfaces = {}
-    links = {}
-    node_tags = {}
-
-    prepared = False
-
-    user_options = {}
 
     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. For each slice, get the nodes in the  associated lease
-        and create a sliver with the necessary info and insertinto 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
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-        :param login: user's login on iotlab ldap
-=======
-        :param login: user's login on senslab ldap
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-
-        :type slice_xrn: string
-        :type login: string
-        :reutnr : a list of slices dict and a dictionary of Sliver object
-        :rtype: (list, dict)
-
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-        ..note: There is no slivers in iotlab, only leases.
-=======
-        ..note: There is no slivers in senslab, only leases.
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-
-        """
-        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)
-        slice_name = slice_hrn
-
-        slices = self.driver.iotlab_api.GetSlices(slice_filter= str(slice_name), \
-                                            slice_filter_type = 'slice_hrn', \
-                                            login=login)
-
-        logger.debug("Slabaggregate api \tget_slice_and_slivers \
-                        sfa_slice %s \r\n slices %s self.driver.hrn %s" \
-                        %(sfa_slice, 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:
-            try:
-                node_ids_list =  sfa_slice['node_ids']
-            except KeyError:
-                logger.log_exc("SLABAGGREGATE \t \
-                                        get_slice_and_slivers No nodes in the slice - KeyError ")
-                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'],
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-                                'type': 'iotlab-node',
-=======
-                                'type': 'slab-node',
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-                                'tags': []})
-
-                slivers[node] = sliver
-
-
-        #Add default sliver attribute :
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-        #connection information for iotlab
-        if get_authority (sfa_slice['hrn']) == self.driver.iotlab_api.root_auth:
-=======
-        #connection information for senslab
-        if get_authority (sfa_slice['hrn']) == self.driver.slab_api.root_auth:
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-            tmp = sfa_slice['hrn'].split('.')
-            ldap_username = tmp[1].split('_')[0]
-            ssh_access = None
-            slivers['default_sliver'] =  {'ssh': ssh_access , \
-                                        'login': ldap_username}
-
-        #TODO get_slice_and_slivers Find the login of the external user
-
-        logger.debug("SLABAGGREGATE api get_slice_and_slivers  slivers %s "\
-                                                             %(slivers))
-        return (slices, slivers)
-
-
-
-    def get_nodes(self, slices=None, slivers=[], options=None):
-        # 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_dict = {}
-        #if slice_xrn:
-            #if not slices or not slices['node_ids']:
-                #return ([],[])
-        #tags_filter = {}
-
-        # get the granularity in second for the reservation system
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-        grain = self.driver.iotlab_api.GetLeaseGranularity()
-
-
-        nodes = self.driver.iotlab_api.GetNodes()
-=======
-        grain = self.driver.slab_api.GetLeaseGranularity()
-
-
-        nodes = self.driver.slab_api.GetNodes()
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-        #geni_available = options.get('geni_available')
-        #if geni_available:
-            #filter['boot_state'] = 'boot'
-
-        #filter.update({'peer_id': None})
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-        #nodes = self.driver.iotlab_api.GetNodes(filter['hostname'])
-=======
-        #nodes = self.driver.slab_api.GetNodes(filter['hostname'])
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-
-        #site_ids = []
-        #interface_ids = []
-        #tag_ids = []
-        nodes_dict = {}
-
-        #for node in nodes:
-
-            #nodes_dict[node['node_id']] = node
-        #logger.debug("SLABAGGREGATE api get_nodes nodes  %s "\
-                                                             #%(nodes ))
-        # 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)
-
-        #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 = []
-        slice_nodes_list = []
-        logger.debug("SLABAGGREGATE api get_nodes slice_nodes_list  %s "\
-                                                             %(slices ))
-        if slices is not None:
-            for one_slice in slices:
-                try:
-                    slice_nodes_list = one_slice['node_ids']
-                except KeyError:
-                    pass
-                #for node in one_slice['node_ids']:
-                    #slice_nodes_list.append(node)
-
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-        reserved_nodes = self.driver.iotlab_api.GetNodesCurrentlyInUse()
-=======
-        reserved_nodes = self.driver.slab_api.GetNodesCurrentlyInUse()
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-        logger.debug("SLABAGGREGATE api get_nodes slice_nodes_list  %s "\
-                                                        %(slice_nodes_list))
-        for node in nodes:
-            nodes_dict[node['node_id']] = node
-            if slice_nodes_list == [] or node['hostname'] in slice_nodes_list:
-
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-                rspec_node = IotlabNode()
-=======
-                rspec_node = SlabNode()
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-                # 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']
-
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-                iotlab_xrn = iotlab_xrn_object(self.driver.iotlab_api.root_auth, \
-                                                    node['hostname'])
-                rspec_node['component_id'] = iotlab_xrn.urn
-=======
-                slab_xrn = slab_xrn_object(self.driver.slab_api.root_auth, \
-                                                    node['hostname'])
-                rspec_node['component_id'] = slab_xrn.urn
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-                rspec_node['component_name'] = node['hostname']
-                rspec_node['component_manager_id'] = \
-                                hrn_to_urn(self.driver.iotlab_api.root_auth, \
-                                'authority+sa')
-
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-                # Iotlab's nodes are federated : there is only one authority
-                # for all Iotlab sites, registered in SFA.
-=======
-                # Senslab's nodes are federated : there is only one authority
-                # for all Senslab sites, registered in SFA.
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-                # Removing the part including the site
-                # in authority_id SA 27/07/12
-                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['location'] = location
-
-
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-                position = IotlabPosition()
-=======
-                position = SlabPosition()
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-                for field in position :
-                    try:
-                        position[field] = node[field]
-                    except KeyError, error :
-                        logger.log_exc("SLABAGGREGATE\t get_nodes \
-                                                        position %s "%(error))
-
-                rspec_node['position'] = position
-                #rspec_node['interfaces'] = []
-
-                # Granularity
-                granularity = Granularity({'grain': grain})
-                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]
-                rspec_nodes.append(rspec_node)
-
-        return (rspec_nodes)
-    #def get_all_leases(self, slice_record = None):
-    def get_all_leases(self):
-        """
-        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.
-
-
-        ..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
-
-
-        """
-
-        #now = int(time.time())
-        #lease_filter = {'clip': now }
-
-        #if slice_record:
-            #lease_filter.update({'name': slice_record['name']})
-
-        #leases = self.driver.iotlab_api.GetLeases(lease_filter)
-        leases = self.driver.iotlab_api.GetLeases()
-        grain = self.driver.iotlab_api.GetLeaseGranularity()
-        site_ids = []
+    def leases_to_rspec_leases(self, leases):
+        """ Get leases attributes list"""
         rspec_leases = []
         for lease in leases:
-            #as many leases as there are nodes in the job
-            for node in lease['reserved_nodes']:
+            for node in lease['resources']:
                 rspec_lease = Lease()
-                rspec_lease['lease_id'] = lease['lease_id']
-                #site = node['site_id']
-                iotlab_xrn = iotlab_xrn_object(self.driver.iotlab_api.root_auth, node)
+                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['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 iotlab_xp table
-                    pass
-                rspec_lease['start_time'] = lease['t_from']
-                rspec_lease['duration'] = (lease['t_until'] - lease['t_from']) \
-                                                                    / grain
+                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):
+        """ Get node attributes """
+        rspec_node = IotlabNode()
+        rspec_node['mobile'] = node['mobile']
+        rspec_node['archi'] = node['archi']
+        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['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']
+        rspec_node['exclusive'] = 'true'
+        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:
+            position[field] = node[field]
+        granularity = Granularity({'grain': 30})
+        rspec_node['granularity'] = granularity
+        rspec_node['tags'] = []
+        return 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']))
+        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['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 list_resources(self, version=None, options=None):
+        """
+        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 = {}
 
-
-#from plc/aggregate.py
-    def get_rspec(self, slice_xrn=None, login=None, version = None, \
-                options=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)
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-        #at this point sliver may be empty if no iotlab job
-=======
-        #at this point sliver may be empty if no senslab job
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-        #is running for this user/slice.
+        rspec_version = version_manager._get_version(version.type,
+                                                     version.version,
+                                                     'ad')
         rspec = RSpec(version=rspec_version, user_options=options)
 
+        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 in nodes:
+                rspec_node = self.node_to_rspec_node(nodes[node])
+                rspec_nodes.append(rspec_node)
+            rspec.version.add_nodes(rspec_nodes)
+
+            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()
 
-        #if slice and 'expires' in slice:
-           #rspec.xml.set('expires',\
-                #datetime_to_string(utcparse(slice['expires']))
-         # add sliver defaults
-        #nodes, links = self.get_nodes(slice, slivers)
-        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(slices, slivers)
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-            logger.debug("\r\n \r\n IotlabAggregate \ lease_option %s \
-=======
-            logger.debug("\r\n \r\n SlabAggregate \ lease_option %s \
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-                                        get rspec  ******* nodes %s"\
-                                            %(lease_option, nodes[0]))
-
-            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 :
-                #Get user associated with this slice
-                #user = dbsession.query(RegRecord).filter_by(record_id = \
-                                            #slices['record_id_user']).first()
-
-                #ldap_username = (user.hrn).split('.')[1]
-
-
-                #for one_slice in slices :
-                ldap_username = slices[0]['hrn']
-                tmp = ldap_username.split('.')
-                ldap_username = tmp[1].split('_')[0]
-
-                if version.type == "Slab":
-                    rspec.version.add_connection_information(ldap_username, \
-                                                        sites_set)
-
-            default_sliver = slivers.get('default_sliver', [])
-            if default_sliver:
-                #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(slices)
-            leases = self.get_all_leases()
-            rspec.version.add_leases(leases)
+    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 _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()
+
+    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
+
+        :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>
 
-<<<<<<< HEAD:sfa/iotlab/iotlabaggregate.py
-        #logger.debug("IotlabAggregate \tget_rspec ******* rspec_toxml %s \r\n"\
-=======
-        #logger.debug("SlabAggregate \tget_rspec ******* rspec_toxml %s \r\n"\
->>>>>>> 3fe7429... SA:sfa/senslab/slabaggregate.py
-                                            #%(rspec.toxml()))
-        return rspec.toxml()
+        """
+        # 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 = RSpec(version=rspec_version, user_options=options)
+        xrn = Xrn(urns[0])
+        geni_slivers = []
+
+        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 = []
+
+            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)
+
+            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': urns[0],
+                'geni_rspec': rspec.toxml(),
+                'geni_slivers': geni_slivers}