Allocate, Describe, Provision now working for iotlab.
[sfa.git] / sfa / iotlab / iotlabaggregate.py
index 9cc600f..d57943e 100644 (file)
@@ -3,52 +3,24 @@ 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.
 """
-from sfa.util.xrn import hrn_to_urn, urn_to_hrn, get_authority
-
+from sfa.util.sfatime import utcparse, datetime_to_string
+from sfa.util.xrn import Xrn, hrn_to_urn, urn_to_hrn, get_authority
+from sfa.iotlab.iotlabxrn import IotlabXrn
 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 Services
+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.util.xrn import Xrn
-
-
-def iotlab_xrn_to_hostname(xrn):
-    """Returns a node's hostname from its xrn.
-    :param xrn: The nodes xrn identifier.
-    :type xrn: Xrn (from sfa.util.xrn)
-
-    :returns: node's hostname.
-    :rtype: string
-
-    """
-    return Xrn.unescape(Xrn(xrn=xrn, type='node').get_leaf())
-
-
-def iotlab_xrn_object(root_auth, hostname):
-    """Creates a valid xrn object from the node's hostname and the authority
-    of the SFA server.
-
-    :param hostname: the node's hostname.
-    :param root_auth: the SFA root authority.
-    :type hostname: string
-    :type root_auth: string
-
-    :returns: the iotlab node's xrn
-    :rtype: Xrn
-
-    """
-    return Xrn('.'.join([root_auth, Xrn.escape(hostname)]), type='node')
-
+import time
 
 class IotlabAggregate:
     """Aggregate manager class for Iotlab. """
@@ -98,7 +70,8 @@ class IotlabAggregate:
         slice_hrn, _ = urn_to_hrn(slice_xrn)
         slice_name = slice_hrn
 
-        slices = self.driver.iotlab_api.GetSlices(slice_filter=str(slice_name),
+        # GetSlices always returns a list, even if there is only one element
+        slices = self.driver.testbed_shell.GetSlices(slice_filter=str(slice_name),
                                                   slice_filter_type='slice_hrn',
                                                   login=login)
 
@@ -110,43 +83,63 @@ class IotlabAggregate:
 
         # 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("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
+        # 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.iotlab_api.root_auth:
-            tmp = sfa_slice['hrn'].split('.')
-            ldap_username = tmp[1].split('_')[0]
+        # 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}
+                                             'login': ldap_username}
 
-        #TODO get_slice_and_slivers Find the login of the external user
 
         logger.debug("IOTLABAGGREGATE api get_slice_and_slivers  slivers %s "
                      % (slivers))
         return (slices, slivers)
 
+    def find_ldap_username_from_slice(self, sfa_slice):
+        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, slices=None, slivers=[], 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.
 
@@ -167,118 +160,254 @@ class IotlabAggregate:
         .. 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
-        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 []
+        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.iotlab_api.GetLeaseGranularity()
+        # grain = self.driver.testbed_shell.GetLeaseGranularity()
 
-        nodes = self.driver.iotlab_api.GetNodes()
+        nodes = self.driver.testbed_shell.GetNodes()
 
         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 = []
+        rspec_nodes = []
 
-        logger.debug("IOTLABAGGREGATE api get_nodes slices  %s "
-                     % (slices))
+        logger.debug("IOTLABAGGREGATE api get_nodes slices  %s "
+                     % (slices))
 
-
-        reserved_nodes = self.driver.iotlab_api.GetNodesCurrentlyInUse()
-        logger.debug("IOTLABAGGREGATE api get_nodes slice_nodes_list  %s "
-                     % (slice_nodes_list))
+        # 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
-            if slice_nodes_list == [] or node['hostname'] in slice_nodes_list:
-
-                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 = iotlab_xrn_object(self.driver.iotlab_api.root_auth,
-                                               node['hostname'])
-                rspec_node['component_id'] = iotlab_xrn.urn
-                rspec_node['component_name'] = node['hostname']
-                rspec_node['component_manager_id'] = \
-                                hrn_to_urn(self.driver.iotlab_api.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['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
-
-
-                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
-                #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)
+            # if slice_nodes_list == [] or node['hostname'] in slice_nodes_list:
+
+            #     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'])
+            #     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['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
+
+
+            #     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
+            #     #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)
+        return nodes_dict
+
+    def node_to_rspec_node(self, node):
+
+        grain = self.driver.testbed_shell.GetLeaseGranularity()
+
+        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'])
+        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['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
+
+
+        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})
+        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 = {}):
+        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):
+        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 sliverr  %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['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']
+                      })
+        return rspec_node
 
-        return (rspec_nodes)
 
     def get_all_leases(self, ldap_username):
         """
@@ -307,12 +436,12 @@ class IotlabAggregate:
         #if slice_record:
             #lease_filter.update({'name': slice_record['name']})
 
-        #leases = self.driver.iotlab_api.GetLeases(lease_filter)
+        #leases = self.driver.testbed_shell.GetLeases(lease_filter)
 
         logger.debug("IOTLABAGGREGATE  get_all_leases ldap_username %s "
                      % (ldap_username))
-        leases = self.driver.iotlab_api.GetLeases(login=ldap_username)
-        grain = self.driver.iotlab_api.GetLeaseGranularity()
+        leases = self.driver.testbed_shell.GetLeases(login=ldap_username)
+        grain = self.driver.testbed_shell.GetLeaseGranularity()
         # site_ids = []
         rspec_leases = []
         for lease in leases:
@@ -321,7 +450,7 @@ class IotlabAggregate:
                 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,
+                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,\
@@ -329,7 +458,7 @@ class IotlabAggregate:
                 try:
                     rspec_lease['slice_id'] = lease['slice_id']
                 except KeyError:
-                    #No info on the slice used in iotlab_xp table
+                    #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']) \
@@ -383,10 +512,11 @@ class IotlabAggregate:
         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'][0].__dict__['hrn']
-             # ldap_username = slices[0]['user']
-            tmp = ldap_username.split('.')
-            ldap_username = tmp[1]
+            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))
@@ -450,3 +580,250 @@ class IotlabAggregate:
             logger.debug("IotlabAggregate \tget_rspec **** \
                        FINAL RSPEC %s \r\n" % (rspec.toxml()))
         return rspec.toxml()
+
+    def get_slivers(self, urns, options={}):
+        """
+
+        """
+
+
+        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 = {}
+        if slice_names:
+            filter['slice_hrn'] = list(slice_names)
+            slice_hrn = filter['slice_hrn'][0]
+
+            slice_filter_type = 'slice_hrn'
+            logger.debug("IotlabAggregate \t get_slivers  slice_hrn%s \
+                       \r\n" % (slice_hrn ))
+        # if slice_ids:
+        #     filter['slice_id'] = list(slice_ids)
+        # # get slices
+        if slice_hrn:
+            slices = self.driver.testbed_shell.GetSlices(slice_hrn,
+                slice_filter_type)
+            leases = self.driver.testbed_shell.GetLeases(
+                                                {'slice_hrn':slice_hrn})
+        logger.debug("IotlabAggregate \t get_slivers \
+                       slices %s leases %s\r\n" % (slices, leases ))
+        if not slices:
+            return []
+        # slice = slices[0]
+        # slice['hrn'] = DummyXrn(auth=self.driver.hrn, slicename=slice['slice_name']).hrn
+        single_slice = slices[0]
+        # get sliver users
+        # users = []
+        # user_ids = []
+        # for slice in slices:
+        #     user_ids.extend(slice['user_ids'])
+        # if user_ids:
+        #     users = self.driver.shell.GetUsers({'user_ids': user_ids})
+
+        user = single_slice['reg_researchers'][0].__dict__
+        logger.debug("IotlabAggregate \t get_slivers user %s \
+                       \r\n" % (user))
+
+        # construct user key info
+        # users_list = []
+        # for user in users:
+        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']
+            # name = user['email'][0:user['email'].index('@')]
+            # user = {
+            #     'login': slice['slice_name'],
+            #     'user_urn': Xrn('%s.%s' % (self.driver.hrn, name), type='user').urn,
+            #     'keys': user['keys']
+            # }
+            # users_list.append(user)
+
+        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)
+        logger.debug("IotlabAggregate \t get_slivers  node_by_hostname%s \
+                       \r\n" % (node_by_hostname))
+        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]
+                logger.debug("IotlabAggregate \t get_slivers node %s current_lease %s\
+                       \r\n more_info %s" % (node, current_lease, more_info))
+                slivers.append(node)
+        return slivers
+
+    def list_resources(self, version = None, options={}):
+
+        version_manager = VersionManager()
+        version = version_manager.get_version(version)
+        rspec_version = version_manager._get_version(version.type, version.version, 'ad')
+        rspec = RSpec(version=rspec_version, user_options=options)
+        # variable ldap_username to be compliant with the 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)
+            # site_ids = []
+            # interface_ids = []
+            # tag_ids = []
+            # nodes_dict = {}
+            # for node in nodes:
+            #     site_ids.append(node['site_id'])
+            #     interface_ids.extend(node['interface_ids'])
+            #     tag_ids.extend(node['node_tag_ids'])
+            #     nodes_dict[node['node_id']] = node
+            # sites = self.get_sites({'site_id': site_ids})
+            # interfaces = self.get_interfaces({'interface_id':interface_ids})
+            # node_tags = self.get_node_tags({'node_tag_id': tag_ids})
+            # pl_initscripts = self.get_pl_initscripts()
+            # convert nodes to rspec nodes
+            rspec_nodes = []
+            for node_id in nodes_dict:
+                node = nodes_dict[node_id]
+                # rspec_node = self.node_to_rspec_node(node, sites, interfaces, node_tags, pl_initscripts)
+                rspec_node = self.node_to_rspec_node(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)
+
+        return rspec.toxml()
+
+
+    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.
+
+        returns: On success returns the following struct:
+        {
+           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.>
+                       },
+                 ]}
+        .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#Describe
+        """
+        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)
+
+        # get slivers
+        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)
+        logger.debug(" IOTLAB_API.PY \tDescribe  constraint %s "
+                     % (constraint))
+        sliver_allocations = self.driver.api.dbsession().query(SliverAllocation).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
+
+        # 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)
+
+        logger.debug(" IOTLAB_API.PY \tDescribe rspec_nodes %s\
+                        rspec %s "
+                     % (rspec_nodes, rspec))
+        rspec.version.add_nodes(rspec_nodes)
+
+        return {'geni_urn': geni_urn,
+                'geni_rspec': rspec.toxml(),
+                'geni_slivers': geni_slivers}
\ No newline at end of file