List Trusts generates HTTP Error 500

Bug #1245590 reported by Mark Miller
14
This bug affects 2 people
Affects Status Importance Assigned to Milestone
OpenStack Identity (keystone)
Fix Released
Medium
Steven Hardy
Havana
Fix Released
Medium
Jamie Lennox

Bug Description

We are getting an HTTP 500 error when we try to list all trusts. We can list individual trusts, but not the generic list.

GET REST Request:

curl -v -X GET http://10.1.8.20:35357/v3/OS-TRUST/trusts -H "X-Auth-Token: ed241ae1e986319086f3"

 ------------------------

REST Response:

{
    "error": {
        "message": "An unexpected error prevented the server from fulfilling your request. 'id'",
        "code": 500,
        "title": "Internal Server Error"
    }
}

-------------------------

/var/log/keystone/keystone.log file entry:

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/keystone/common/wsgi.py", line 238, in __call__
    result = method(context, **params)
  File "/usr/local/lib/python2.7/dist-packages/keystone/common/controller.py", line 158, in inner
    return f(self, context, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/keystone/trust/controllers.py", line 213, in list_trusts
    self._fill_in_roles(context, trust, global_roles)
  File "/usr/local/lib/python2.7/dist-packages/keystone/trust/controllers.py", line 109, in _fill_in_roles
    if x['id'] == trust_role['id']]
KeyError: 'id'
2013-10-28 09:49:04 INFO [access] 15.253.57.88 - - [28/Oct/2013:16:49:04 +0000] "GET http://havanatest:35357/v3/OS-TRUST/trusts HTTP/1.0" 500 148

------------------------------

/var/log/keystone/keystone.log file entry with "ERROR" debug statements added:

2013-10-28 09:49:04 ERROR [keystone.trust.controllers] QQQQQQQQQQQQQQQQQQ trust_role = {u'name': u'disney_user'}
2013-10-28 09:49:04 ERROR [keystone.trust.controllers] QQQQQQQQQQQQQQQQQQ trust_role = {u'name': u'disney_user'}
2013-10-28 09:49:04 ERROR [keystone.common.wsgi] 'id'
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/keystone/common/wsgi.py", line 238, in __call__
    result = method(context, **params)
  File "/usr/local/lib/python2.7/dist-packages/keystone/common/controller.py", line 158, in inner
    return f(self, context, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/keystone/trust/controllers.py", line 213, in list_trusts
    self._fill_in_roles(context, trust, global_roles)
  File "/usr/local/lib/python2.7/dist-packages/keystone/trust/controllers.py", line 110, in _fill_in_roles
    if x['id'] == trust_role['id']]
KeyError: 'id'
2013-10-28 09:49:04 INFO [access] 15.253.57.88 - - [28/Oct/2013:16:49:04 +0000] "GET http://havanatest:35357/v3/OS-TRUST/trusts HTTP/1.0" 500 148

--------------

Method causing the error with inserted LOG statements:

    def _fill_in_roles(self, context, trust, global_roles):
        if trust.get('expires_at') is not None:
            trust['expires_at'] = (timeutils.isotime
                                   (trust['expires_at'],
                                    subsecond=True))

        if 'roles' not in trust:
            trust['roles'] = []
        trust_full_roles = []
        for trust_role in trust['roles']:
            LOG.error(_("QQQQQQQQQQQQQQQQQQ trust_role = %s") % trust_role )
             if isinstance(trust_role, basestring):
                trust_role = {'id': trust_role}
            LOG.error(_("QQQQQQQQQQQQQQQQQQ trust_role = %s") % trust_role )

            matching_roles = [x for x in global_roles
                              if x['id'] == trust_role['id']]
            if matching_roles:
                full_role = identity.controllers.RoleV3.wrap_member(
                    context, matching_roles[0])['role']
                trust_full_roles.append(full_role)
        trust['roles'] = trust_full_roles
        trust['roles_links'] = {
            'self': (self.base_url() + "/%s/roles" % trust['id']),
            'next': None,
            'previous': None}

-----------------------------

Quick change I made to get around the problem:

       def _fill_in_roles(self, context, trust, global_roles):
        if trust.get('expires_at') is not None:
            trust['expires_at'] = (timeutils.isotime
                                   (trust['expires_at'],
                                    subsecond=True))

        if 'roles' not in trust:
            trust['roles'] = []
        trust_full_roles = []
        for trust_role in trust['roles']:
            LOG.error(_("QQQQQQQQQQQQQQQQQQ trust_role = %s") % trust_role )
            if isinstance(trust_role, basestring):
                trust_role = {'id': trust_role}

            # Inserted if statement below to fix HTTP 500 error
            if not 'id' in trust_role:
                trust_role = {'id': trust_role}
            LOG.error(_("QQQQQQQQQQQQQQQQQQ trust_role = %s") % trust_role )

            matching_roles = [x for x in global_roles
                              if x['id'] == trust_role['id']]
            if matching_roles:
                full_role = identity.controllers.RoleV3.wrap_member(
                    context, matching_roles[0])['role']
                trust_full_roles.append(full_role)
        trust['roles'] = trust_full_roles
        trust['roles_links'] = {
            'self': (self.base_url() + "/%s/roles" % trust['id']),
            'next': None,
            'previous': None}

----------------------------

Summary:

In the code above, the trust_role is not a basestring so the "trust_role = {'id':trust_role}" assignment is not occurring, but the
trust_role Dictionary (trust_role = {u'name': u'disney_user'}) does not have an 'id' key in it so the line " if x['id'] == trust_role['id']]"
throws an exception. I added the following conditional check and it seems to work now:

            if not 'id' in trust_role:
                trust_role = {'id': trust_role}

Revision history for this message
Steven Hardy (shardy) wrote :

Confirmed, I'm seeing the same issue @ f4a441c38a1486c789a70f3de7b419f11c386048

Adam Young (ayoung)
Changed in keystone:
assignee: nobody → Adam Young (ayoung)
Dolph Mathews (dolph)
Changed in keystone:
importance: Undecided → Medium
tags: added: havana-backport-potential
Changed in keystone:
status: New → Confirmed
Revision history for this message
Steven Hardy (shardy) wrote :

So looking at this in a bit more detail, it would appear that we're returning (or in this case trying to return) the roles key in the response from GET /OS-TRUST/trusts, but the docs don't say that roles are included this the response:

https://github.com/openstack/identity-api/blob/master/openstack-identity-api/v3/src/markdown/identity-api-v3-os-trust-ext.md

Says:

Request:

GET /OS-TRUST/trusts?trustor_user_id=a0fdfd
Response:

Status: 200 OK

{
    "trusts": [
        {
            "id": "1ff900",
            "impersonation": false,
            "links": {
                "self": "http://identity:35357/v3/OS-TRUST/trusts/1ff900"
            },
            "project_id": "0f1233",
            "trustee_user_id": "86c0d5",
            "trustor_user_id": "a0fdfd"
        }
    ]
}

So no roles, but the actual response is:
REQ: curl -i -X GET http://192.168.122.156:5000/v3/OS-TRUST/trusts?trustor_user_id=859896e71bdb4357bc743ed8653e057a -H "User-Agent: python-keystoneclient" -H "X-Auth-Token: 6e69525085664484b0be2faf934e3ee7"
RESP: [200] {'date': 'Thu, 05 Dec 2013 14:18:21 GMT', 'content-type': 'application/json', 'content-length': '496', 'vary': 'X-Auth-Token'}
RESP BODY: {"links": {"self": "http://127.0.0.1:5000/v3/OS-TRUST/OS-TRUST/trusts", "previous": null, "next": null}, "trusts": [{"impersonation": false, "trustor_user_id": "859896e71bdb4357bc743ed8653e057a", "links": {"self": "http://127.0.0.1:5000/v3/OS-TRUST/trusts/511acf70a9ed4b53a2188b9d241c97de"}, "roles": [{"name": "MyFancyRole"}], "expires_at": null, "trustee_user_id": "c52e506897254fc59120a5c456ea9153", "project_id": "0be4fcc804754c48aa028c8bb050bc6c", "id": "511acf70a9ed4b53a2188b9d241c97de"}]}

Which contains the role (I commented out the broken call to _fill_in_roles to avoid the 500)

So would the right solution be to delete the roles key for list_trusts to align with the docs, or update the docs?

Seems like removing the roles from list_trusts may be best, as list provides the summary and get_trust provides the detail including role name and id?

Revision history for this message
Steven Hardy (shardy) wrote :

Also, there is inconsistency with the expires_at field, in the docs this is returned in the response to the POST when we create the trust, but not in any of the GET responses, whereas we appear to be including it in all of the actual GET responses in the API.

Need clarification from ayoung re which of these (if any) are docs oversights vs real issues in the code.

Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix proposed to keystone (master)

Fix proposed to branch: master
Review: https://review.openstack.org/60301

Changed in keystone:
assignee: Adam Young (ayoung) → Steven Hardy (shardy)
status: Confirmed → In Progress
Revision history for this message
Dolph Mathews (dolph) wrote :

expires_at sounds like a minor doc issue. The attribute is optional, and hence excluded, but could be included in examples as a null value if desired. Opened a separate bug to track:

  https://bugs.launchpad.net/openstack-api-site/+bug/1258273

Changed in keystone:
assignee: Steven Hardy (shardy) → Dolph Mathews (dolph)
Changed in keystone:
assignee: Dolph Mathews (dolph) → Steven Hardy (shardy)
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix merged to keystone (master)

Reviewed: https://review.openstack.org/60301
Committed: https://git.openstack.org/cgit/openstack/keystone/commit/?id=ab0e2c7667a9adc46fece742e1ee8160879b497b
Submitter: Jenkins
Branch: master

commit ab0e2c7667a9adc46fece742e1ee8160879b497b
Author: Steven Hardy <email address hidden>
Date: Thu Dec 5 17:37:49 2013 +0000

    Remove roles from OS-TRUST list responses

    According to the docs, the list responses should not contain
    the roles, only the detailed response when you get a trust
    explicitly by ID. So remove the roles and modify the tests
    appropriately.

    Note it was also observed that expires_at is present in all
    GET resonses, but not in the docs, but this has been agreed
    as a docs error so will be addressed via a docs patch.

    Change-Id: I5387021a53f3284add9e5e71e9e005c4dd31b76c
    Closes-Bug: #1245590

Changed in keystone:
status: In Progress → Fix Committed
Revision history for this message
Jamie Lennox (jamielennox) wrote :

Is this something that we can/should backport to havana?

Revision history for this message
Steven Hardy (shardy) wrote :

> Is this something that we can/should backport to havana?

Certainly looks like it:

https://github.com/openstack/keystone/blob/stable/havana/keystone/trust/controllers.py#L208

Thierry Carrez (ttx)
Changed in keystone:
milestone: none → icehouse-2
status: Fix Committed → Fix Released
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix proposed to keystone (stable/havana)

Fix proposed to branch: stable/havana
Review: https://review.openstack.org/69514

Alan Pevec (apevec)
tags: removed: havana-backport-potential
Thierry Carrez (ttx)
Changed in keystone:
milestone: icehouse-2 → 2014.1
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Duplicates of this bug

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.