Can't use sql as domain-specific driver

Bug #1217017 reported by Mark Miller
42
This bug affects 7 people
Affects Status Importance Assigned to Milestone
OpenStack Identity (keystone)
Fix Released
Medium
Henry Nash

Bug Description

File “/keystone/common/dependency.py” has a method named “requires” which is a decorator for the “Assignment” class of both files “/keystone/assignment/backends/ldap.py” and “/keystone/assignment/backends/sql.py”.

File “/keystone/assignment/backends/ldap.py”:

@dependency.requires('identity_api')
class Assignment(assignment.Driver):

File “/keystone/assignment/backends/sql.py”:

@dependency.requires('identity_api')
class Assignment(sql.Base, assignment.Driver):

When I specify the following contents for file “/etc/keystone/domains/keystone.Default.conf” I am telling Keystone to use an SQL backend for the default domain:

[assignment]
driver = keystone.assignment.backends.sql.Assignment

[identity]
driver = keystone.identity.backends.sql.Identity

[ldap]

However, there is a problem with the following line in method requires of file “dependency.py”:

    def wrapper(self, *args, **kwargs):
        """Inject each dependency from the registry."""
        self.__wrapped_init__(*args, **kwargs)

        for dependency in self._dependencies:
            if dependency not in REGISTRY:
                if dependency in _future_dependencies:
                    _future_dependencies[dependency] += [self]
                else:
                    _future_dependencies[dependency] = [self]

                continue

            setattr(self, dependency, REGISTRY[dependency])

because it is passing arguments to the constructor of the Assignment class in file “/keystone/assignment/backends/sql.py” which extends the sql.Base class (i.e. class Base(object) of file “/keystone/common/sql/core.py“) that extends class “object” which does not accept any parameters for its constructor. It took me a full day to pin this one down.

To get around this problem I added the following lines to class Base(object) of file “/keystone/common/sql/core.py“ in order to accept any number of parameters:

    def __init__(self, *args, **kwargs):
        super(Base, self).__init__()

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

I trimmed the bug description down to just the first issue. Please open a second bug for your second issue so that they can be tracked independently.

What's the actual issue you're seeing here and how do you reproduce it? You only described a cause and solution.

Changed in keystone:
status: New → Incomplete
Revision history for this message
Mark Miller (mark-m-miller) wrote :
Download full text (4.6 KiB)

Problem Description: The new multi-domain functionality breaks when you configure both an SQL domain and an LDAP domain in directory "keystone/domains". Specifically, when you configure file "keystone/domains/keystone.Default.conf" to use SQL.

File "keystone/keystone.conf" excerpt:

    [identity]
    domain_specific_drivers_enabled = True
    domain_config_dir = /etc/keystone/domains

File "keystone/domains/keystone.Default.conf":

    [assignment]
    driver = keystone.assignment.backends.sql.Assignment

    [identity]
     driver = keystone.identity.backends.sql.Identity

    [ldap]

Without the fix previously described, you get the following error:

2013-08-28 15:26:33,776 INFO sqlalchemy.engine.base.Engine SELECT domain.id AS domain_id, domain.name AS domain_name, domain.enabled AS domain_enabled, domain.extra AS domain_extra
FROM domain
WHERE domain.name = %s
2013-08-28 15:26:33 INFO [sqlalchemy.engine.base.Engine] SELECT domain.id AS domain_id, domain.name AS domain_name, domain.enabled AS domain_enabled, domain.extra AS domain_extra
FROM domain
WHERE domain.name = %s
2013-08-28 15:26:33,777 INFO sqlalchemy.engine.base.Engine ('MyDomain',)
2013-08-28 15:26:33 INFO [sqlalchemy.engine.base.Engine] ('MyDomain',)
2013-08-28 15:26:33,780 INFO sqlalchemy.engine.base.Engine SELECT project.id AS project_id, project.name AS project_name, project.domain_id AS project_domain_id, project.description AS project_description, project.enabled AS project_enabled, project.extra AS project_extra
FROM project
WHERE project.name = %s AND project.domain_id = %s
2013-08-28 15:26:33 INFO [sqlalchemy.engine.base.Engine] SELECT project.id AS project_id, project.name AS project_name, project.domain_id AS project_domain_id, project.description AS project_description, project.enabled AS project_enabled, project.extra AS project_extra
FROM project
WHERE project.name = %s AND project.domain_id = %s
2013-08-28 15:26:33,781 INFO sqlalchemy.engine.base.Engine ('myapp', '464bdc5784a446378a85f99a25d216b4')
2013-08-28 15:26:33 INFO [sqlalchemy.engine.base.Engine] ('myapp', '464bdc5784a446378a85f99a25d216b4')
2013-08-28 15:26:33,784 INFO sqlalchemy.engine.base.Engine SELECT domain.id AS domain_id, domain.name AS domain_name, domain.enabled AS domain_enabled, domain.extra AS domain_extra
FROM domain
WHERE domain.name = %s
2013-08-28 15:26:33 INFO [sqlalchemy.engine.base.Engine] SELECT domain.id AS domain_id, domain.name AS domain_name, domain.enabled AS domain_enabled, domain.extra AS domain_extra
FROM domain
WHERE domain.name = %s
2013-08-28 15:26:33,785 INFO sqlalchemy.engine.base.Engine ('Default',)
2013-08-28 15:26:33 INFO [sqlalchemy.engine.base.Engine] ('Default',)
2013-08-28 15:26:33 ERROR [keystone.common.wsgi] object.__init__() takes no parameters
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/keystone/common/wsgi.py", line 237, in __call__
    result = method(context, **params)
  File "/usr/local/lib/python2.7/dist-packages/keystone/auth/controllers.py", line 287, in authenticate_for_token
    self.authenticate(context, auth_info, auth_context)
  File "/usr/local/lib/python2.7/dist-packages/keystone/a...

Read more...

Revision history for this message
Dolph Mathews (dolph) wrote : Re: dependency injection fails to init domain-specific identity drivers

Thank you for the follow up!

summary: - Split LDAP/SQL Identity Frontend Domain Selection Bug
+ dependency injection fails to init domain-specific identity drivers
Changed in keystone:
status: Incomplete → Triaged
importance: Undecided → Medium
Revision history for this message
David Stanek (dstanek) wrote :

Mark,

Is this an issue on startup or is it during runtime? I'm trying to find a way to reproduce this so that I can create a fix.

Changed in keystone:
status: Triaged → Incomplete
Revision history for this message
Mark Miller (mark-m-miller) wrote :

This problem occurs during run time. All I have to do to reproduce this problem is to attempt to get a project scoped token for a user who is defined in the LDAP domain but not the SQL domain. To get a token the Keystone code must authenticate the user against the read-only LDAP domain and then retrieve the project/role information from the Keystone SQL domain. The code fails to go back to the LDAP server for the various "get_user" calls.

Revision history for this message
Mark Miller (mark-m-miller) wrote :

You asked me to split the 2 problems I found with "failed dependency injection" into 2 separate bug reports, but I had to "fix" both of them to get it working. Here is the link to the other one "https://bugs.launchpad.net/keystone/+bug/1218094".

Dolph Mathews (dolph)
Changed in keystone:
milestone: none → next
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/45486

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

Reviewed: https://review.openstack.org/45486
Committed: http://github.com/openstack/keystone/commit/160b969945a98d3f18683f2553ab38437df5745d
Submitter: Jenkins
Branch: master

commit 160b969945a98d3f18683f2553ab38437df5745d
Author: Dolph Mathews <email address hidden>
Date: Fri Sep 6 15:08:20 2013 -0500

    domain-specific drivers experimental in havana

    Related-Bug: 1218094
    Related-Bug: 1217017
    Change-Id: I5fecaa8c6531b2b38c914908ecff8a33de67857c

Revision history for this message
Pablo Fernando Cargnelutti (pablo-fernando-cargnelutti) wrote : Re: dependency injection fails to init domain-specific identity drivers

This is still an issue?

Revision history for this message
Mahesh Sawaiker (mahesh-sawaiker) wrote :

I found a similar problem with keystone.identity.backends.sql.py. Had to add a constructor with
 arguments that calls the no arg constructor.

@dependency.requires('assignment_api')
class Identity(identity.Driver):

    def __init__(self, *args, **kwargs):
        super(identity.Driver, self).__init__()

Revision history for this message
Marcus Klein (marcus-klein) wrote :

I have this problem, too:

2014-08-29 10:51:18.487 25057 ERROR keystone.common.wsgi [-] object.__init__() takes no parameters
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi Traceback (most recent call last):
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/common/wsgi.py", line 220, in __call__
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi result = method(context, **params)
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/token/controllers.py", line 100, in authenticate
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi context, auth)
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/token/controllers.py", line 287, in _authenticate_local
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi username, CONF.identity.default_domain_id)
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/identity/core.py", line 181, in wrapper
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi self.driver, self.assignment_api)
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/identity/core.py", line 137, in setup_domain_drivers
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi -len(DOMAIN_CONF_FTAIL)])
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/identity/core.py", line 116, in _load_config
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi self._load_driver(assignment_api, domain)
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/identity/core.py", line 93, in _load_driver
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi domain_config['cfg'].identity.driver, domain_config['cfg']))
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/openstack/common/importutils.py", line 38, in import_object
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi return import_class(import_str)(*args, **kwargs)
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/common/dependency.py", line 166, in wrapper
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi self.__wrapped_init__(*args, **kwargs)
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi TypeError: object.__init__() takes no parameters
2014-08-29 10:51:18.487 25057 TRACE keystone.common.wsgi

I configured:

Default Domain = LDAP
Secondary Domain = SQL (Heat)

See bug 1362678

Revision history for this message
Marcus Klein (marcus-klein) wrote :

Fix of comment 10 solves the TypeError problem for me.

Revision history for this message
Bruno Bompastor (bruno-bompastor) wrote :

Comment 10 also fixed this for me.

Revision history for this message
Bruno Bompastor (bruno-bompastor) wrote :

Hi,

Is there any chance that fix will be included on the Juno release?

Revision history for this message
Marcus Klein (kleini76) wrote :

IMHO this is a MUST to get this fixed für the Juno release. Otherwise the domain specific drivers features does not work at all. This can easily be reproduce by configuring LDAP driver for the default domain and SQL for a secondary domain like the one for Heat.

Changed in keystone:
status: Incomplete → New
status: New → Invalid
Marcus Klein (kleini76)
Changed in keystone:
status: Invalid → New
Henry Nash (henry-nash)
Changed in keystone:
assignee: nobody → Henry Nash (henry-nash)
Revision history for this message
David Stanek (dstanek) wrote :

The title for this is a little misleading. It's not the DI that is failing, it's the loading of the driver[1]. The code assumes that all of the drivers will be constructed with the config options from the domain specific config.

While the provided fix works (stops the traceback), I don't think it's the right one. The drivers should all be accepting the ConfigOpts instance in their __init__ and use it instead of the global conf. This would allow the driver to be configured by the domain specific file.

1. http://git.openstack.org/cgit/openstack/keystone/tree/keystone/identity/core.py#n91

Revision history for this message
Henry Nash (henry-nash) wrote :

I think @dstanek nailed it...that's exactly the problem. I'll fix that up.

Changed in keystone:
milestone: next → juno-rc1
Revision history for this message
David Stanek (dstanek) wrote :

The complicated part is that there needs to be either a way to fall back to the global config or explicit documentation saying that we don't do that. The original bug reported only had the driver listed in the config. If that's the case where do we get the other config options?

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/121246

Changed in keystone:
status: New → In Progress
Changed in keystone:
assignee: Henry Nash (henry-nash) → Brant Knudson (blk-u)
Revision history for this message
Brant Knudson (blk-u) wrote :

I changed the title since this has nothing to do with dependency injection as far as I can tell. If there's a problem with dependency injection then you can change the title back.

Changed in keystone:
assignee: Brant Knudson (blk-u) → Henry Nash (henry-nash)
summary: - dependency injection fails to init domain-specific identity drivers
+ Can't use sql as domain-specific driver
Changed in keystone:
assignee: Henry Nash (henry-nash) → Morgan Fainberg (mdrnstm)
Changed in keystone:
assignee: Morgan Fainberg (mdrnstm) → Henry Nash (henry-nash)
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix merged to keystone (master)

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

commit 8e6e6b392caa962c629c3505eaed66dcef8cbfee
Author: Henry Nash <email address hidden>
Date: Wed Sep 10 12:18:27 2014 +0100

    Ensure identity sql driver supports domain-specific configuration.

    For an identity driver to be used with a domain-specific config file,
    it must accept a ConfigOpts as an optional parameter. The ldap driver
    already supported this - so this patch adds this to the sql driver.

    The above change is trivial, but the rest of the patch is enhancing
    our testing to validate this operation, as well as enforcing the
    limitation listed below.

    Limitation:

    Currently Keystone only supports one SQL driver - this patch
    does not change that. What it does enable is for that one SQL
    driver to be assigned to a specific domain, as opposed to being just
    a catch-all for domains without a specific configuration file.
    This at least enables the (often requested) scenario of service users
    to be stored in SQL in a predominantly LDAP installation.

    Closes-Bug: 1217017
    Change-Id: Ic531ebae28680fc518d8e036db516f5982241c40

Changed in keystone:
status: In Progress → Fix Committed
Thierry Carrez (ttx)
Changed in keystone:
status: Fix Committed → Fix Released
Thierry Carrez (ttx)
Changed in keystone:
milestone: juno-rc1 → 2014.2
Revision history for this message
Bruno Bompastor (bruno-bompastor) wrote :

I think this is present on rc2, isnt it?

Revision history for this message
Henry Nash (henry-nash) wrote : Re: [Bug 1217017] Re: Can't use sql as domain-specific driver

Yes, it is.

Henry
On 16 Oct 2014, at 09:56, Bruno Bompastor <email address hidden> wrote:

> I think this is present on rc2, isnt it?
>
> --
> You received this bug notification because you are subscribed to the bug
> report.
> https://bugs.launchpad.net/bugs/1217017
>
> Title:
> Can't use sql as domain-specific driver
>
> Status in OpenStack Identity (Keystone):
> Fix Released
>
> Bug description:
> File “/keystone/common/dependency.py” has a method named “requires”
> which is a decorator for the “Assignment” class of both files
> “/keystone/assignment/backends/ldap.py” and
> “/keystone/assignment/backends/sql.py”.
>
> File “/keystone/assignment/backends/ldap.py”:
>
> @dependency.requires('identity_api')
> class Assignment(assignment.Driver):
>
> File “/keystone/assignment/backends/sql.py”:
>
> @dependency.requires('identity_api')
> class Assignment(sql.Base, assignment.Driver):
>
> When I specify the following contents for file
> “/etc/keystone/domains/keystone.Default.conf” I am telling Keystone to
> use an SQL backend for the default domain:
>
> [assignment]
> driver = keystone.assignment.backends.sql.Assignment
>
> [identity]
> driver = keystone.identity.backends.sql.Identity
>
> [ldap]
>
> However, there is a problem with the following line in method requires
> of file “dependency.py”:
>
> def wrapper(self, *args, **kwargs):
> """Inject each dependency from the registry."""
> self.__wrapped_init__(*args, **kwargs)
>
> for dependency in self._dependencies:
> if dependency not in REGISTRY:
> if dependency in _future_dependencies:
> _future_dependencies[dependency] += [self]
> else:
> _future_dependencies[dependency] = [self]
>
> continue
>
> setattr(self, dependency, REGISTRY[dependency])
>
> because it is passing arguments to the constructor of the Assignment
> class in file “/keystone/assignment/backends/sql.py” which extends the
> sql.Base class (i.e. class Base(object) of file
> “/keystone/common/sql/core.py“) that extends class “object” which does
> not accept any parameters for its constructor. It took me a full day
> to pin this one down.
>
> To get around this problem I added the following lines to class
> Base(object) of file “/keystone/common/sql/core.py“ in order to accept
> any number of parameters:
>
> def __init__(self, *args, **kwargs):
> super(Base, self).__init__()
>
> To manage notifications about this bug go to:
> https://bugs.launchpad.net/keystone/+bug/1217017/+subscriptions
>

Dolph Mathews (dolph)
tags: added: juno-backport-potential
tags: removed: juno-backport-potential
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.