Merge branch 'geni-v3' of ssh://git.onelab.eu/git/sfa into geni-v3
[sfa.git] / sfa / iotlab / iotlabaggregate.py
index d57943e..7b456ee 100644 (file)
@@ -4,13 +4,13 @@ Contains methods to get information on slice, slivers, nodes and leases,
 formatting them and turn it into a RSpec.
 """
 from sfa.util.sfatime import utcparse, datetime_to_string
 formatting them and turn it into a RSpec.
 """
 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.util.xrn import Xrn, hrn_to_urn, urn_to_hrn
 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.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 ServicesElement
+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.elements.sliver import Sliver
 from sfa.rspecs.elements.lease import Lease
 from sfa.rspecs.elements.granularity import Granularity
@@ -68,12 +68,11 @@ class IotlabAggregate:
             return (sfa_slice, slivers)
         slice_urn = hrn_to_urn(slice_xrn, 'slice')
         slice_hrn, _ = urn_to_hrn(slice_xrn)
             return (sfa_slice, slivers)
         slice_urn = hrn_to_urn(slice_xrn, 'slice')
         slice_hrn, _ = urn_to_hrn(slice_xrn)
-        slice_name = slice_hrn
 
         # GetSlices always returns a list, even if there is only one element
 
         # 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)
+        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"
 
         logger.debug("IotlabAggregate api \tget_slice_and_slivers \
                       slice_hrn %s \r\n slices %s self.driver.hrn %s"
@@ -106,7 +105,8 @@ class IotlabAggregate:
 
         #Add default sliver attribute :
         #connection information for iotlab
 
         #Add default sliver attribute :
         #connection information for iotlab
-        # if get_authority(sfa_slice['hrn']) == self.driver.testbed_shell.root_auth:
+        # 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
         #     tmp = sfa_slice['hrn'].split('.')
         #     ldap_username = tmp[1].split('_')[0]
         #     ssh_access = None
@@ -126,6 +126,17 @@ class IotlabAggregate:
         return (slices, slivers)
 
     def find_ldap_username_from_slice(self, sfa_slice):
         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
         researchers = [sfa_slice['reg_researchers'][0].__dict__]
         # look in ldap:
         ldap_username = None
@@ -137,7 +148,7 @@ class IotlabAggregate:
 
 
 
 
 
 
-    def get_nodes(self, slices=None, slivers=[], options=None):
+    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
     # 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
@@ -148,10 +159,6 @@ class IotlabAggregate:
         it. If the slice does not have any job running or scheduled, that is
         it has no reserved nodes, then returns an empty list.
 
         it. If the slice does not have any job running or scheduled, that is
         it has no reserved nodes, then returns an empty list.
 
-        :param slices: list of slices (record dictionaries)
-        :param slivers: the list of slivers in all the slices
-        :type slices: list of dicts
-        :type slivers: list of Sliver object (dictionaries)
         :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.
         :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.
@@ -178,17 +185,18 @@ class IotlabAggregate:
         #     for one_slice in slices:
         #         try:
         #             slice_nodes_list = one_slice['node_ids']
         #     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.
+    #              # 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()
 
         #         except KeyError:
         #             return []
 
         # get the granularity in second for the reservation system
         # grain = self.driver.testbed_shell.GetLeaseGranularity()
 
-        nodes = self.driver.testbed_shell.GetNodes()
+        nodes = self.driver.testbed_shell.GetNodes(node_filter_dict =
+                                                    filter_nodes)
 
         nodes_dict = {}
 
 
         nodes_dict = {}
 
@@ -205,82 +213,25 @@ class IotlabAggregate:
                      # % (slice_nodes_list))
         for node in nodes:
             nodes_dict[node['node_id']] = node
                      # % (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 = 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):
         return nodes_dict
 
     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()
 
 
         grain = self.driver.testbed_shell.GetLeaseGranularity()
 
@@ -355,7 +306,27 @@ class IotlabAggregate:
         return rspec_node
 
 
         return rspec_node
 
 
-    def rspec_node_to_geni_sliver(self, rspec_node, sliver_allocations = {}):
+    def rspec_node_to_geni_sliver(self, rspec_node, sliver_allocations = None):
+        """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 sliver_allocations is None: 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 rspec_node['sliver_id'] in sliver_allocations:
             # set sliver allocation and operational status
             sliver_allocation = sliver_allocations[rspec_node['sliver_id']]
@@ -383,20 +354,41 @@ class IotlabAggregate:
 
 
     def sliver_to_rspec_node(self, sliver, sliver_allocations):
 
 
     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
+        """
         rspec_node = self.node_to_rspec_node(sliver)
         rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
         # add sliver info
         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))
+        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']
         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:
         if sliver['urn'] in sliver_allocations:
-            rspec_node['client_id'] = sliver_allocations[sliver['urn']].client_id
+            rspec_node['client_id'] = sliver_allocations[
+                                                    sliver['urn']].client_id
             if sliver_allocations[sliver['urn']].component_id:
             if sliver_allocations[sliver['urn']].component_id:
-                rspec_node['component_id'] = 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
         rspec_node['slivers'] = [rspec_sliver]
 
         # slivers always provide the ssh service
@@ -409,18 +401,55 @@ class IotlabAggregate:
         return rspec_node
 
 
         return rspec_node
 
 
+    def get_leases(self, slice=None, options=None):
+        if options is None: options={}
+        filter={}
+        if slice:
+           #filter.update({'name':slice['slice_name']}) # JORDAN: this is = "upmc" !!!
+           filter.update({'slice_hrn':slice['slice_hrn']}) # JORDAN: this is = "upmc" !!!
+            # slice_hrn = "ple.upmc.myslicedemo
+        #return_fields = ['lease_id', 'hostname', 'site_id', 'name', 't_from', 't_until']
+        leases = self.driver.GetLeases(lease_filter_dict=filter)
+        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_all_leases(self, ldap_username):
         """
     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
         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.
+            belonging to this user.
         :type ldap_username: string
         :returns: rspec lease dictionary with keys lease_id, component_id,
         :type ldap_username: string
         :returns: rspec lease dictionary with keys lease_id, component_id,
-            slice_id, start_time, duration.
+            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.
         :rtype: dict
 
         .. note::There is no filtering of leases within a given time frame.
@@ -430,19 +459,11 @@ class IotlabAggregate:
 
         """
 
 
         """
 
-        #now = int(time.time())
-        #lease_filter = {'clip': now }
-
-        #if slice_record:
-            #lease_filter.update({'name': slice_record['name']})
-
-        #leases = self.driver.testbed_shell.GetLeases(lease_filter)
-
         logger.debug("IOTLABAGGREGATE  get_all_leases ldap_username %s "
                      % (ldap_username))
         logger.debug("IOTLABAGGREGATE  get_all_leases ldap_username %s "
                      % (ldap_username))
-        leases = self.driver.testbed_shell.GetLeases(login=ldap_username)
+        leases = self.driver.GetLeases(login=ldap_username)
         grain = self.driver.testbed_shell.GetLeaseGranularity()
         grain = self.driver.testbed_shell.GetLeaseGranularity()
-        # site_ids = []
+
         rspec_leases = []
         for lease in leases:
             #as many leases as there are nodes in the job
         rspec_leases = []
         for lease in leases:
             #as many leases as there are nodes in the job
@@ -492,7 +513,7 @@ class IotlabAggregate:
 
         """
 
 
         """
 
-        ldap_username= None
+        ldap_username = None
         rspec = None
         version_manager = VersionManager()
         version = version_manager.get_version(version)
         rspec = None
         version_manager = VersionManager()
         version = version_manager.get_version(version)
@@ -539,7 +560,7 @@ class IotlabAggregate:
         if lease_option in ['all', 'resources']:
         #if not options.get('list_leases') or options.get('list_leases')
         #and options['list_leases'] != 'leases':
         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)
+            nodes = self.get_nodes()
             logger.debug("\r\n")
             logger.debug("IotlabAggregate \t lease_option %s \
                           get rspec  ******* nodes %s"
             logger.debug("\r\n")
             logger.debug("IotlabAggregate \t lease_option %s \
                           get rspec  ******* nodes %s"
@@ -581,12 +602,23 @@ class IotlabAggregate:
                        FINAL RSPEC %s \r\n" % (rspec.toxml()))
         return rspec.toxml()
 
                        FINAL RSPEC %s \r\n" % (rspec.toxml()))
         return rspec.toxml()
 
-    def get_slivers(self, urns, options={}):
-        """
+    def get_slivers(self, urns, options=None):
+        """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_KEY = 'slice_hrn' # slice_hrn
+        if options is None: options={}
         slice_ids = set()
         node_ids = []
         for urn in urns:
         slice_ids = set()
         node_ids = []
         for urn in urns:
@@ -610,70 +642,65 @@ class IotlabAggregate:
                        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))
                        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 = {}
+        filter_sliver = {}
         if slice_names:
         if slice_names:
-            filter['slice_hrn'] = list(slice_names)
-            slice_hrn = filter['slice_hrn'][0]
+            filter_sliver[SLICE_KEY] = list(slice_names)
+            slice_hrn = filter_sliver[SLICE_KEY][0]
+
+            slice_filter_type = SLICE_KEY
 
 
-            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:
         # if slice_ids:
         #     filter['slice_id'] = list(slice_ids)
         # # get slices
         if slice_hrn:
-            slices = self.driver.testbed_shell.GetSlices(slice_hrn,
+            logger.debug("JORDAN SLICE_HRN=%r" % slice_hrn)
+            slices = self.driver.GetSlices(slice_hrn,
                 slice_filter_type)
                 slice_filter_type)
-            leases = self.driver.testbed_shell.GetLeases(
-                                                {'slice_hrn':slice_hrn})
+            leases = self.driver.GetLeases({SLICE_KEY:slice_hrn})
         logger.debug("IotlabAggregate \t get_slivers \
                        slices %s leases %s\r\n" % (slices, leases ))
         if not slices:
             return []
         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
+
+        logger.debug("LOIC SLICES = %r" % slices)
         single_slice = slices[0]
         # get sliver users
         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__
+
+        # XXX LOIC !!! XXX QUICK AND DIRTY - Let's try...
+        logger.debug("LOIC Number of reg_researchers = %s" % len(single_slice['reg_researchers']))
+        if 'reg_researchers' in single_slice and len(single_slice['reg_researchers'])==0:
+            user = {'uid':single_slice['user']}
+        else:
+            user = single_slice['reg_researchers'][0].__dict__
         logger.debug("IotlabAggregate \t get_slivers user %s \
                        \r\n" % (user))
 
         # construct user key info
         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))
         person = self.driver.testbed_shell.ldap.LdapFindUser(record=user)
         logger.debug("IotlabAggregate \t get_slivers person %s \
                        \r\n" % (person))
-        name = person['last_name']
+        name = person['last_name']
         user['login'] = person['uid']
         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)
+
+        # XXX LOIC !!! if we have more info, let's fill user
+        if 'hrn' in user:
+            user['user_urn'] = hrn_to_urn(user['hrn'], 'user')
+        if 'keys' in user:
+            user['keys'] = person['pkey']
+
 
         try:
             node_ids = single_slice['node_ids']
 
         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])
+            node_list = self.driver.testbed_shell.GetNodes()
+# JORDAN REMOVED FILTER so that next check always succeed
+#                    {'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)
         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']:
         slivers = []
         for current_lease in leases:
             for hostname in current_lease['reserved_nodes']:
@@ -686,8 +713,13 @@ class IotlabAggregate:
                 node_id = current_lease['resource_ids'][index]
                 # node['slice_name'] = user['login']
                 # node.update(single_slice)
                 node_id = current_lease['resource_ids'][index]
                 # node['slice_name'] = user['login']
                 # node.update(single_slice)
+                # JORDAN XXX This fails sometimes when hostname not in the list
+                #if hostname in node_by_hostname:
                 more_info = node_by_hostname[hostname]
                 node.update(more_info)
                 more_info = node_by_hostname[hostname]
                 node.update(more_info)
+                #else:
+                #    # This can happen when specifying a lease without the resource, then all subsequent calls will fail
+                #    logger.debug("Ignored missing hostname for now one")
                 # oar_job_id is the slice_id (lease_id)
                 sliver_hrn = '%s.%s-%s' % (self.driver.hrn,
                             current_lease['lease_id'], node_id)
                 # oar_job_id is the slice_id (lease_id)
                 sliver_hrn = '%s.%s-%s' % (self.driver.hrn,
                             current_lease['lease_id'], node_id)
@@ -696,42 +728,50 @@ class IotlabAggregate:
                 node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
                 node['urn'] = node['sliver_id']
                 node['services_user'] = [user]
                 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
 
                 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
+        """
 
 
+        if options is None: options={}
         version_manager = VersionManager()
         version = version_manager.get_version(version)
         version_manager = VersionManager()
         version = version_manager.get_version(version)
-        rspec_version = version_manager._get_version(version.type, version.version, 'ad')
+        rspec_version = version_manager._get_version(version.type,
+                                                    version.version, 'ad')
         rspec = RSpec(version=rspec_version, user_options=options)
         rspec = RSpec(version=rspec_version, user_options=options)
-        # variable ldap_username to be compliant with the get_all_leases
+        # 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)
         # 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()
+
+            # no interfaces on iotlab nodes
             # convert nodes to rspec nodes
             rspec_nodes = []
             for node_id in nodes_dict:
                 node = nodes_dict[node_id]
             # 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)
                 rspec_node = self.node_to_rspec_node(node)
                 rspec_nodes.append(rspec_node)
             rspec.version.add_nodes(rspec_nodes)
@@ -748,33 +788,37 @@ class IotlabAggregate:
         return rspec.toxml()
 
 
         return rspec.toxml()
 
 
-    def describe(self, urns, version=None, options={}):
+    def describe(self, urns, version=None, options=None):
         """
         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.
 
         """
         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.>
-                       },
-                 ]}
+        :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
+
+        :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.>}
+
         .. seealso:: http://groups.geni.net/geni/wiki/GAPI_AM_API_V3#Describe
         .. 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
         """
         """
+        if options is None: options={}
         version_manager = VersionManager()
         version = version_manager.get_version(version)
         rspec_version = version_manager._get_version(
         version_manager = VersionManager()
         version = version_manager.get_version(version)
         rspec_version = version_manager._get_version(
@@ -784,6 +828,7 @@ class IotlabAggregate:
         # get slivers
         geni_slivers = []
         slivers = self.get_slivers(urns, options)
         # get slivers
         geni_slivers = []
         slivers = self.get_slivers(urns, options)
+        logger.debug("SLIVERS=%r" % slivers)
         if slivers:
             rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
         else:
         if slivers:
             rspec_expires = datetime_to_string(utcparse(slivers[0]['expires']))
         else:
@@ -793,37 +838,39 @@ class IotlabAggregate:
         # lookup the sliver allocations
         geni_urn = urns[0]
         sliver_ids = [sliver['sliver_id'] for sliver in slivers]
         # 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)
         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))
+        query = self.driver.api.dbsession().query(SliverAllocation)
+        sliver_allocations = query.filter((constraint)).all()
         sliver_allocation_dict = {}
         for sliver_allocation in sliver_allocations:
             geni_urn = sliver_allocation.slice_urn
         sliver_allocation_dict = {}
         for sliver_allocation in sliver_allocations:
             geni_urn = sliver_allocation.slice_urn
-            sliver_allocation_dict[sliver_allocation.sliver_id] = sliver_allocation
+            sliver_allocation_dict[sliver_allocation.sliver_id] = \
+                                                            sliver_allocation
+        show_leases = options.get('list_leases')
+        if show_leases in ['resources', 'all']:
+        #if not options.get('list_leases') or options['list_leases'] != 'leases':                                                    
+            # 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)
+                geni_sliver = self.rspec_node_to_geni_sliver(rspec_node,
+                                sliver_allocation_dict)
+                geni_slivers.append(geni_sliver)
+            rspec.version.add_nodes(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)
-
-        logger.debug(" IOTLAB_API.PY \tDescribe rspec_nodes %s\
-                        rspec %s "
-                     % (rspec_nodes, rspec))
-        rspec.version.add_nodes(rspec_nodes)
+        logger.debug("SHOW LEASES = %r" % show_leases)
+        if show_leases in ['leases', 'all']:
+        #if not options.get('list_leases') or options['list_leases'] == 'resources':
+            if slivers:
+                leases = self.get_leases(slice=slivers[0])
+                logger.debug("JORDAN: getting leases from slice: %r" % slivers[0])
+                rspec.version.add_leases(leases)
 
         return {'geni_urn': geni_urn,
                 'geni_rspec': rspec.toxml(),
 
         return {'geni_urn': geni_urn,
                 'geni_rspec': rspec.toxml(),
-                'geni_slivers': geni_slivers}
\ No newline at end of file
+                'geni_slivers': geni_slivers}