Merge branch 'geni-v3' of ssh://git.onelab.eu/git/sfa into geni-v3
[sfa.git] / sfa / iotlab / iotlabaggregate.py
index 8977e20..7b456ee 100644 (file)
@@ -3,27 +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
+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.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
-
-
-
-
+import time
 
 class IotlabAggregate:
     """Aggregate manager class for Iotlab. """
@@ -71,12 +68,11 @@ class IotlabAggregate:
             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
-        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"
@@ -109,7 +105,8 @@ class IotlabAggregate:
 
         #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
@@ -129,6 +126,17 @@ class IotlabAggregate:
         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
@@ -140,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
@@ -151,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.
 
-        :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.
@@ -181,17 +185,18 @@ class IotlabAggregate:
         #     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()
 
-        nodes = self.driver.testbed_shell.GetNodes()
+        nodes = self.driver.testbed_shell.GetNodes(node_filter_dict =
+                                                    filter_nodes)
 
         nodes_dict = {}
 
@@ -208,82 +213,28 @@ class IotlabAggregate:
                      # % (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, grain):
+    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()
+
         rspec_node = IotlabNode()
         # xxx how to retrieve site['login_base']
         #site_id=node['site_id']
@@ -354,18 +305,151 @@ class IotlabAggregate:
 
         return rspec_node
 
-    def get_all_leases(self, ldap_username):
+
+    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 sliver_allocation:
+                allocation_status = sliver_allocation.allocation_state
+                if allocation_status == 'geni_allocated':
+                    op_status =  'geni_pending_allocation'
+                elif allocation_status == 'geni_provisioned':
+                    op_status = 'geni_ready'
+                else:
+                    op_status = 'geni_unknown'
+            else:
+                allocation_status = 'geni_unallocated'
+        else:
+            allocation_status = 'geni_unallocated'
+            op_status = 'geni_failed'
+        # required fields
+        geni_sliver = {'geni_sliver_urn': rspec_node['sliver_id'],
+                       'geni_expires': rspec_node['expires'],
+                       'geni_allocation_status' : allocation_status,
+                       'geni_operational_status': op_status,
+                       'geni_error': '',
+                       }
+        return geni_sliver
+
+
+    def sliver_to_rspec_node(self, sliver, sliver_allocations):
+        """Used by describe to format node information into a rspec compliant
+        structure.
+
+        Creates a node rspec compliant structure by calling node_to_rspec_node.
+        Adds slivers, if any, to rspec node structure. Returns the updated
+        rspec node struct.
+
+        :param sliver: sliver dictionary. Contains keys: urn, slice_id, hostname
+            and slice_name.
+        :type sliver: dictionary
+        :param sliver_allocations: dictionary of slivers
+        :type sliver_allocations: dict
+
+        :returns: Node dictionary with all necessary data.
+
+        .. seealso:: node_to_rspec_node
         """
+        rspec_node = self.node_to_rspec_node(sliver)
+        rspec_node['expires'] = datetime_to_string(utcparse(sliver['expires']))
+        # add sliver info
+        logger.debug("IOTLABAGGREGATE api \t  sliver_to_rspec_node sliver \
+                        %s \r\nsliver_allocations %s" % (sliver,
+                            sliver_allocations))
+        rspec_sliver = Sliver({'sliver_id': sliver['urn'],
+                         'name': sliver['slice_id'],
+                         'type': 'iotlab-exclusive',
+                         'tags': []})
+        rspec_node['sliver_id'] = rspec_sliver['sliver_id']
+
+        if sliver['urn'] in sliver_allocations:
+            rspec_node['client_id'] = sliver_allocations[
+                                                    sliver['urn']].client_id
+            if sliver_allocations[sliver['urn']].component_id:
+                rspec_node['component_id'] = sliver_allocations[
+                                                    sliver['urn']].component_id
+        rspec_node['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
+
 
+    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):
+        """
         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,
-            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.
@@ -375,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))
-        leases = self.driver.testbed_shell.GetLeases(login=ldap_username)
+        leases = self.driver.GetLeases(login=ldap_username)
         grain = self.driver.testbed_shell.GetLeaseGranularity()
-        # site_ids = []
+
         rspec_leases = []
         for lease in leases:
             #as many leases as there are nodes in the job
@@ -437,7 +513,7 @@ class IotlabAggregate:
 
         """
 
-        ldap_username= None
+        ldap_username = None
         rspec = None
         version_manager = VersionManager()
         version = version_manager.get_version(version)
@@ -484,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':
-            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"
@@ -526,37 +602,177 @@ class IotlabAggregate:
                        FINAL RSPEC %s \r\n" % (rspec.toxml()))
         return rspec.toxml()
 
+    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.
 
-    def list_resources(self, version = None, options={}):
+        :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:
+            xrn = IotlabXrn(xrn=urn)
+            if xrn.type == 'sliver':
+                 # id: slice_id-node_id
+                try:
+                    sliver_id_parts = xrn.get_sliver_id_parts()
+                    slice_id = int(sliver_id_parts[0])
+                    node_id = int(sliver_id_parts[1])
+                    slice_ids.add(slice_id)
+                    node_ids.append(node_id)
+                except ValueError:
+                    pass
+            else:
+                slice_names = set()
+                slice_names.add(xrn.hrn)
+
+
+        logger.debug("IotlabAggregate \t get_slivers urns %s slice_ids %s \
+                       node_ids %s\r\n" % (urns, slice_ids, node_ids))
+        logger.debug("IotlabAggregate \t get_slivers xrn %s slice_names %s \
+                       \r\n" % (xrn, slice_names))
+        filter_sliver = {}
+        if slice_names:
+            filter_sliver[SLICE_KEY] = list(slice_names)
+            slice_hrn = filter_sliver[SLICE_KEY][0]
+
+            slice_filter_type = SLICE_KEY
+
+        # if slice_ids:
+        #     filter['slice_id'] = list(slice_ids)
+        # # get slices
+        if slice_hrn:
+            logger.debug("JORDAN SLICE_HRN=%r" % slice_hrn)
+            slices = self.driver.GetSlices(slice_hrn,
+                slice_filter_type)
+            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("LOIC SLICES = %r" % slices)
+        single_slice = slices[0]
+        # get sliver users
+
+        # 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
+        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']
+
+        # 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']
+            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)
+
+        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)
+                # 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)
+                #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)
+                node['node_id'] = node_id
+                node['expires'] = current_lease['t_until']
+                node['sliver_id'] = Xrn(sliver_hrn, type='sliver').urn
+                node['urn'] = node['sliver_id']
+                node['services_user'] = [user]
+
+                slivers.append(node)
+        return slivers
+
+    def list_resources(self, version = None, options=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)
-        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)
-
+        # 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)
-            # 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
-            grain = self.driver.testbed_shell.GetLeaseGranularity()
             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, grain)
+                rspec_node = self.node_to_rspec_node(node)
                 rspec_nodes.append(rspec_node)
             rspec.version.add_nodes(rspec_nodes)
 
@@ -564,23 +780,55 @@ class IotlabAggregate:
             # 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()
-           rspec.version.add_leases(leases)
+        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={}):
+    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.
+
+        :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/CommonConcepts#urns
+        """
+        if options is None: options={}
         version_manager = VersionManager()
         version = version_manager.get_version(version)
-        rspec_version = version_manager._get_version(version.type,
-                                                     version.version, 'manifest')
+        rspec_version = version_manager._get_version(
+                                    version.type, version.version, 'manifest')
         rspec = RSpec(version=rspec_version, user_options=options)
 
         # get slivers
         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:
@@ -591,24 +839,38 @@ class IotlabAggregate:
         geni_urn = urns[0]
         sliver_ids = [sliver['sliver_id'] for sliver in slivers]
         constraint = SliverAllocation.sliver_id.in_(sliver_ids)
-        sliver_allocations = self.driver.api.dbsession().query(SliverAllocation).filter(constraint)
+        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[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)
-            geni_sliver = self.rspec_node_to_geni_sliver(rspec_node, sliver_allocation_dict)
-            geni_slivers.append(geni_sliver)
-        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(),
-                'geni_slivers': geni_slivers}
\ No newline at end of file
+                'geni_slivers': geni_slivers}