keystoneclient unit tests fails on update tenants and users

Bug #1075376 reported by Adam Young
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
OpenStack Identity (keystone)
Fix Released
Critical
Dolph Mathews
python-keystoneclient
Fix Released
Critical
Joseph Heck

Bug Description

  File "/opt/stack/keystone/tests/test_keystoneclient.py", line 270, in test_tenant_create_update_and_delete
    self.assertEquals(tenant.description, tenant_description)
  File "/opt/stack/keystone/vendor/python-keystoneclient-master/keystoneclient/base.py", line 287, in __getattr__
    raise AttributeError(k)

Same error on test_user_create_update_and_delete

The line that is triggering the error is marked with >>:

tenant = client.tenants.update(tenant_id=tenant.id,
                                       tenant_name=tenant_name,
                                       enabled=tenant_enabled,
                                       description=tenant_description)
>> self.assertEquals(tenant.name, tenant_name)nt.description, tenant_description)

Looking in the debugger, the tenant object looks like:
Tenant: <Tenant {u'id': u'5b4785e72ee34fff9b078ee53281f08f', u'name': u'updated_tenant', u'extra': {u'enabled': False, u'description': u'Updated tenant!'}}>

So the description is in the wrong location.

Adam Young (ayoung)
Changed in keystone:
importance: Undecided → Critical
Revision history for this message
Guang Yee (guang-yee) wrote :

https://github.com/openstack/python-keystoneclient/blob/master/keystoneclient/base.py:line 91

def _create(self, url, body, response_key, return_raw=False):
        resp, body = self.api.post(url, body=body)
        if return_raw:
            return body[response_key]
        return self.resource_class(self, body[response_key], loaded=True)

This one seem to have something to do with lazy-loading. "loaded" is set to "True", which means never bother to fetch new.

https://github.com/openstack/python-keystoneclient/blob/master/keystoneclient/base.py:line 280-289

def __getattr__(self, k):
        if k not in self.__dict__:
            #NOTE(bcwaldon): disallow lazy-loading if already loaded once
            if not self.is_loaded():
                self.get()
                return self.__getattr__(k)

            raise AttributeError(k)
        else:
            return self.__dict__[k]

Question is why is "loaded" set to "True" in the latest code?

btw, this "lazy-loading" logic is convoluted. We may need to document its purpose.

Revision history for this message
Joseph Heck (heckj) wrote :

Guang -

the "loaded" is set to true because the entire resource has been retrieved in that code path, and the intention of the "loaded" attribute was to signify that maybe only a partial resource was created (it's possible to create a resource with just an ID) - at which point the first time any other attribute is used, it gets loaded in the background.

It's the common (albiet confusing and obscure) pattern behind all the manager/base resource mechanisms in the openstack clients.

Changed in keystone:
status: New → Triaged
Changed in python-keystoneclient:
status: New → Triaged
importance: Undecided → Critical
Joseph Heck (heckj)
Changed in keystone:
milestone: none → grizzly-1
Revision history for this message
Guang Yee (guang-yee) wrote :

Sounds good.

If I am reading the code correctly, on tenant update, the "description" is stashed into "extra" dict. On tenant create or get, "description" is part of "tenant" dict. Therefore, when "loaded" is set to "False", we do a tenant get when "description" is referenced and absent.

Is that by design, that "extra" is return on update only, but not on create or get?

If that's the case, the fix may be as simple as this?

def __getattr__(self, k):
        if k not in self.__dict__:
            #NOTE(bcwaldon): disallow lazy-loading if already loaded once
            if not self.is_loaded():
                self.get()
                return self.__getattr__(k)

            # check extra
            if 'extra' in self.__dict__ and \
                type(self.__dict__['extra']) is types.DictType and \
                k in self.__dict__['extra']:
                return self.__dict__['extra'].get(k)

            raise AttributeError(k)
        else:
            return self.__dict__[k]

Revision history for this message
Dolph Mathews (dolph) wrote :

description shouldn't be in 'extra' ... I don't believe extra was ever intended to be exposed by keystone, as it's really a sql backend implementation detail for non-indexed attributes. So, if the issue is that 'extra' is being returned by keystone, it's a server-side issue.

Revision history for this message
Dolph Mathews (dolph) wrote :

Potential fix was already in review in the v3 feature branch: https://review.openstack.org/#/c/12106/6/keystone/common/sql/core.py

Changed in keystone:
assignee: nobody → Dolph Mathews (dolph)
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/15513

Changed in keystone:
status: Triaged → In Progress
Dolph Mathews (dolph)
Changed in python-keystoneclient:
assignee: nobody → Joseph Heck (heckj)
status: Triaged → In Progress
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix merged to keystone (master)

Reviewed: https://review.openstack.org/15513
Committed: http://github.com/openstack/keystone/commit/df148a09fc1c7d44f2134a2dc6566ef1dbe772df
Submitter: Jenkins
Branch: master

commit df148a09fc1c7d44f2134a2dc6566ef1dbe772df
Author: Dolph Mathews <email address hidden>
Date: Tue Nov 6 17:01:59 2012 +0000

    Return non-indexed attrs, not 'extra' (bug 1075376)

    (most of this is pulled from the v3 branch)

    Change-Id: Id1118e7a2b245fb7ec95e41ec297c87036953db2

Changed in keystone:
status: In Progress → Fix Committed
Joseph Heck (heckj)
Changed in python-keystoneclient:
status: In Progress → Fix Committed
Thierry Carrez (ttx)
Changed in keystone:
status: Fix Committed → Fix Released
emo94545 (emo94545)
Changed in python-keystoneclient:
status: Fix Committed → Fix Released
Thierry Carrez (ttx)
Changed in keystone:
milestone: grizzly-1 → 2013.1
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

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