summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cinderclient/auth_plugin.py143
-rw-r--r--cinderclient/client.py29
-rw-r--r--cinderclient/exceptions.py9
-rw-r--r--cinderclient/shell.py48
-rw-r--r--cinderclient/tests/test_auth_plugins.py346
-rw-r--r--cinderclient/utils.py10
-rw-r--r--cinderclient/v1/client.py8
-rw-r--r--cinderclient/v2/client.py8
-rw-r--r--tools/install_venv_common.py3
9 files changed, 583 insertions, 21 deletions
diff --git a/cinderclient/auth_plugin.py b/cinderclient/auth_plugin.py
new file mode 100644
index 0000000..2101b93
--- /dev/null
+++ b/cinderclient/auth_plugin.py
@@ -0,0 +1,143 @@
+# Copyright 2013 OpenStack Foundation
+# Copyright 2013 Spanish National Research Council.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import logging
+import pkg_resources
+
+import six
+
+from cinderclient import exceptions
+from cinderclient import utils
+
+
+logger = logging.getLogger(__name__)
+
+
+_discovered_plugins = {}
+
+
+def discover_auth_systems():
+ """Discover the available auth-systems.
+
+ This won't take into account the old style auth-systems.
+ """
+ ep_name = 'openstack.client.auth_plugin'
+ for ep in pkg_resources.iter_entry_points(ep_name):
+ try:
+ auth_plugin = ep.load()
+ except (ImportError, pkg_resources.UnknownExtra, AttributeError) as e:
+ logger.debug("ERROR: Cannot load auth plugin %s" % ep.name)
+ logger.debug(e, exc_info=1)
+ else:
+ _discovered_plugins[ep.name] = auth_plugin
+
+
+def load_auth_system_opts(parser):
+ """Load options needed by the available auth-systems into a parser.
+
+ This function will try to populate the parser with options from the
+ available plugins.
+ """
+ for name, auth_plugin in six.iteritems(_discovered_plugins):
+ add_opts_fn = getattr(auth_plugin, "add_opts", None)
+ if add_opts_fn:
+ group = parser.add_argument_group("Auth-system '%s' options" %
+ name)
+ add_opts_fn(group)
+
+
+def load_plugin(auth_system):
+ if auth_system in _discovered_plugins:
+ return _discovered_plugins[auth_system]()
+
+ # NOTE(aloga): If we arrive here, the plugin will be an old-style one,
+ # so we have to create a fake AuthPlugin for it.
+ return DeprecatedAuthPlugin(auth_system)
+
+
+class BaseAuthPlugin(object):
+ """Base class for authentication plugins.
+
+ An authentication plugin needs to override at least the authenticate
+ method to be a valid plugin.
+ """
+ def __init__(self):
+ self.opts = {}
+
+ def get_auth_url(self):
+ """Return the auth url for the plugin (if any)."""
+ return None
+
+ @staticmethod
+ def add_opts(parser):
+ """Populate and return the parser with the options for this plugin.
+
+ If the plugin does not need any options, it should return the same
+ parser untouched.
+ """
+ return parser
+
+ def parse_opts(self, args):
+ """Parse the actual auth-system options if any.
+
+ This method is expected to populate the attribute self.opts with a
+ dict containing the options and values needed to make authentication.
+ If the dict is empty, the client should assume that it needs the same
+ options as the 'keystone' auth system (i.e. os_username and
+ os_password).
+
+ Returns the self.opts dict.
+ """
+ return self.opts
+
+ def authenticate(self, cls, auth_url):
+ """Authenticate using plugin defined method."""
+ raise exceptions.AuthSystemNotFound(self.auth_system)
+
+
+class DeprecatedAuthPlugin(object):
+ """Class to mimic the AuthPlugin class for deprecated auth systems.
+
+ Old auth systems only define two entry points: openstack.client.auth_url
+ and openstack.client.authenticate. This class will load those entry points
+ into a class similar to a valid AuthPlugin.
+ """
+ def __init__(self, auth_system):
+ self.auth_system = auth_system
+
+ def authenticate(cls, auth_url):
+ raise exceptions.AuthSystemNotFound(self.auth_system)
+
+ self.opts = {}
+
+ self.get_auth_url = lambda: None
+ self.authenticate = authenticate
+
+ self._load_endpoints()
+
+ def _load_endpoints(self):
+ ep_name = 'openstack.client.auth_url'
+ fn = utils._load_entry_point(ep_name, name=self.auth_system)
+ if fn:
+ self.get_auth_url = fn
+
+ ep_name = 'openstack.client.authenticate'
+ fn = utils._load_entry_point(ep_name, name=self.auth_system)
+ if fn:
+ self.authenticate = fn
+
+ def parse_opts(self, args):
+ return self.opts
diff --git a/cinderclient/client.py b/cinderclient/client.py
index 314c852..f0c31c9 100644
--- a/cinderclient/client.py
+++ b/cinderclient/client.py
@@ -55,16 +55,26 @@ class HTTPClient(object):
USER_AGENT = 'python-cinderclient'
- def __init__(self, user, password, projectid, auth_url, insecure=False,
- timeout=None, tenant_id=None, proxy_tenant_id=None,
- proxy_token=None, region_name=None,
+ def __init__(self, user, password, projectid, auth_url=None,
+ insecure=False, timeout=None, tenant_id=None,
+ proxy_tenant_id=None, proxy_token=None, region_name=None,
endpoint_type='publicURL', service_type=None,
service_name=None, volume_service_name=None, retries=None,
- http_log_debug=False, cacert=None):
+ http_log_debug=False, cacert=None,
+ auth_system='keystone', auth_plugin=None):
self.user = user
self.password = password
self.projectid = projectid
self.tenant_id = tenant_id
+
+ if auth_system and auth_system != 'keystone' and not auth_plugin:
+ raise exceptions.AuthSystemNotFound(auth_system)
+
+ if not auth_url and auth_system and auth_system != 'keystone':
+ auth_url = auth_plugin.get_auth_url()
+ if not auth_url:
+ raise exceptions.EndpointNotFound()
+
self.auth_url = auth_url.rstrip('/')
self.version = 'v1'
self.region_name = region_name
@@ -89,6 +99,9 @@ class HTTPClient(object):
else:
self.verify_cert = True
+ self.auth_system = auth_system
+ self.auth_plugin = auth_plugin
+
self._logger = logging.getLogger(__name__)
if self.http_log_debug and not self._logger.handlers:
ch = logging.StreamHandler()
@@ -294,7 +307,10 @@ class HTTPClient(object):
auth_url = self.auth_url
if self.version == "v2.0":
while auth_url:
- auth_url = self._v2_auth(auth_url)
+ if not self.auth_system or self.auth_system == 'keystone':
+ auth_url = self._v2_auth(auth_url)
+ else:
+ auth_url = self._plugin_auth(auth_url)
# Are we acting on behalf of another user via an
# existing token? If so, our actual endpoints may
@@ -340,6 +356,9 @@ class HTTPClient(object):
else:
raise exceptions.from_response(resp, body)
+ def _plugin_auth(self, auth_url):
+ return self.auth_plugin.authenticate(self, auth_url)
+
def _v2_auth(self, url):
"""Authenticate against a v2.0 auth service."""
body = {"auth": {
diff --git a/cinderclient/exceptions.py b/cinderclient/exceptions.py
index 1e3050c..41796e3 100644
--- a/cinderclient/exceptions.py
+++ b/cinderclient/exceptions.py
@@ -41,6 +41,15 @@ class NoUniqueMatch(Exception):
pass
+class AuthSystemNotFound(Exception):
+ """When the user specify a AuthSystem but not installed."""
+ def __init__(self, auth_system):
+ self.auth_system = auth_system
+
+ def __str__(self):
+ return "AuthSystemNotFound: %s" % repr(self.auth_system)
+
+
class NoTokenLookupException(Exception):
"""This form of authentication does not support looking up
endpoints from an existing token.
diff --git a/cinderclient/shell.py b/cinderclient/shell.py
index 385b05d..17e7d77 100644
--- a/cinderclient/shell.py
+++ b/cinderclient/shell.py
@@ -29,6 +29,7 @@ import pkgutil
import sys
import logging
+import cinderclient.auth_plugin
from cinderclient import client
from cinderclient import exceptions as exc
import cinderclient.extension
@@ -142,6 +143,13 @@ class OpenStackCinderShell(object):
parser.add_argument('--os_region_name',
help=argparse.SUPPRESS)
+ parser.add_argument('--os-auth-system',
+ metavar='<auth-system>',
+ default=utils.env('OS_AUTH_SYSTEM'),
+ help='Defaults to env[OS_AUTH_SYSTEM].')
+ parser.add_argument('--os_auth_system',
+ help=argparse.SUPPRESS)
+
parser.add_argument('--service-type',
metavar='<service-type>',
help='Defaults to volume for most actions')
@@ -225,6 +233,10 @@ class OpenStackCinderShell(object):
default=utils.env('CINDER_URL'),
help=argparse.SUPPRESS)
+ # The auth-system-plugins might require some extra options
+ cinderclient.auth_plugin.discover_auth_systems()
+ cinderclient.auth_plugin.load_auth_system_opts(parser)
+
return parser
def get_subcommand_parser(self, version):
@@ -372,7 +384,8 @@ class OpenStackCinderShell(object):
(os_username, os_password, os_tenant_name, os_auth_url,
os_region_name, os_tenant_id, endpoint_type, insecure,
service_type, service_name, volume_service_name,
- username, apikey, projectid, url, region_name, cacert) = (
+ username, apikey, projectid, url, region_name, cacert,
+ os_auth_system) = (
args.os_username, args.os_password,
args.os_tenant_name, args.os_auth_url,
args.os_region_name, args.os_tenant_id,
@@ -380,7 +393,13 @@ class OpenStackCinderShell(object):
args.service_type, args.service_name,
args.volume_service_name, args.username,
args.apikey, args.projectid,
- args.url, args.region_name, args.os_cacert)
+ args.url, args.region_name, args.os_cacert,
+ args.os_auth_system)
+
+ if os_auth_system and os_auth_system != "keystone":
+ auth_plugin = cinderclient.auth_plugin.load_plugin(os_auth_system)
+ else:
+ auth_plugin = None
if not endpoint_type:
endpoint_type = DEFAULT_CINDER_ENDPOINT_TYPE
@@ -393,13 +412,17 @@ class OpenStackCinderShell(object):
# for os_username or os_password but for compatibility it is not.
if not utils.isunauthenticated(args.func):
- if not os_username:
- if not username:
- raise exc.CommandError(
- "You must provide a username "
- "via either --os-username or env[OS_USERNAME]")
- else:
- os_username = username
+ if auth_plugin:
+ auth_plugin.parse_opts(args)
+
+ if not auth_plugin or not auth_plugin.opts:
+ if not os_username:
+ if not username:
+ raise exc.CommandError(
+ "You must provide a username "
+ "via either --os-username or env[OS_USERNAME]")
+ else:
+ os_username = username
if not os_password:
if not apikey:
@@ -418,6 +441,10 @@ class OpenStackCinderShell(object):
os_tenant_name = projectid
if not os_auth_url:
+ if os_auth_system and os_auth_system != 'keystone':
+ os_auth_url = auth_plugin.get_auth_url()
+
+ if not os_auth_url:
if not url:
raise exc.CommandError(
"You must provide an auth url "
@@ -449,7 +476,8 @@ class OpenStackCinderShell(object):
volume_service_name=volume_service_name,
retries=options.retries,
http_log_debug=args.debug,
- cacert=cacert)
+ cacert=cacert, auth_system=os_auth_system,
+ auth_plugin=auth_plugin)
try:
if not utils.isunauthenticated(args.func):
diff --git a/cinderclient/tests/test_auth_plugins.py b/cinderclient/tests/test_auth_plugins.py
new file mode 100644
index 0000000..9a95114
--- /dev/null
+++ b/cinderclient/tests/test_auth_plugins.py
@@ -0,0 +1,346 @@
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import argparse
+import mock
+import pkg_resources
+import requests
+
+try:
+ import json
+except ImportError:
+ import simplejson as json
+
+from cinderclient import auth_plugin
+from cinderclient import exceptions
+from cinderclient.tests import utils
+from cinderclient.v1 import client
+
+
+def mock_http_request(resp=None):
+ """Mock an HTTP Request."""
+ if not resp:
+ resp = {
+ "access": {
+ "token": {
+ "expires": "12345",
+ "id": "FAKE_ID",
+ "tenant": {
+ "id": "FAKE_TENANT_ID",
+ }
+ },
+ "serviceCatalog": [
+ {
+ "type": "volume",
+ "endpoints": [
+ {
+ "region": "RegionOne",
+ "adminURL": "http://localhost:8774/v1.1",
+ "internalURL": "http://localhost:8774/v1.1",
+ "publicURL": "http://localhost:8774/v1.1/",
+ },
+ ],
+ },
+ ],
+ },
+ }
+
+ auth_response = utils.TestResponse({
+ "status_code": 200,
+ "text": json.dumps(resp),
+ })
+ return mock.Mock(return_value=(auth_response))
+
+
+def requested_headers(cs):
+ """Return requested passed headers."""
+ return {
+ 'User-Agent': cs.client.USER_AGENT,
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ }
+
+
+class DeprecatedAuthPluginTest(utils.TestCase):
+ def test_auth_system_success(self):
+ class MockEntrypoint(pkg_resources.EntryPoint):
+ def load(self):
+ return self.authenticate
+
+ def authenticate(self, cls, auth_url):
+ cls._authenticate(auth_url, {"fake": "me"})
+
+ def mock_iter_entry_points(_type, name):
+ if _type == 'openstack.client.authenticate':
+ return [MockEntrypoint("fake", "fake", ["fake"])]
+ else:
+ return []
+
+ mock_request = mock_http_request()
+
+ @mock.patch.object(pkg_resources, "iter_entry_points",
+ mock_iter_entry_points)
+ @mock.patch.object(requests, "request", mock_request)
+ def test_auth_call():
+ plugin = auth_plugin.DeprecatedAuthPlugin("fake")
+ cs = client.Client("username", "password", "project_id",
+ "auth_url/v2.0", auth_system="fake",
+ auth_plugin=plugin)
+ cs.client.authenticate()
+
+ headers = requested_headers(cs)
+ token_url = cs.client.auth_url + "/tokens"
+
+ mock_request.assert_called_with(
+ "POST",
+ token_url,
+ headers=headers,
+ data='{"fake": "me"}',
+ allow_redirects=True,
+ **self.TEST_REQUEST_BASE)
+
+ test_auth_call()
+
+ def test_auth_system_not_exists(self):
+ def mock_iter_entry_points(_t, name=None):
+ return [pkg_resources.EntryPoint("fake", "fake", ["fake"])]
+
+ mock_request = mock_http_request()
+
+ @mock.patch.object(pkg_resources, "iter_entry_points",
+ mock_iter_entry_points)
+ @mock.patch.object(requests.Session, "request", mock_request)
+ def test_auth_call():
+ auth_plugin.discover_auth_systems()
+ plugin = auth_plugin.DeprecatedAuthPlugin("notexists")
+ cs = client.Client("username", "password", "project_id",
+ "auth_url/v2.0", auth_system="notexists",
+ auth_plugin=plugin)
+ self.assertRaises(exceptions.AuthSystemNotFound,
+ cs.client.authenticate)
+
+ test_auth_call()
+
+ def test_auth_system_defining_auth_url(self):
+ class MockAuthUrlEntrypoint(pkg_resources.EntryPoint):
+ def load(self):
+ return self.auth_url
+
+ def auth_url(self):
+ return "http://faked/v2.0"
+
+ class MockAuthenticateEntrypoint(pkg_resources.EntryPoint):
+ def load(self):
+ return self.authenticate
+
+ def authenticate(self, cls, auth_url):
+ cls._authenticate(auth_url, {"fake": "me"})
+
+ def mock_iter_entry_points(_type, name):
+ if _type == 'openstack.client.auth_url':
+ return [MockAuthUrlEntrypoint("fakewithauthurl",
+ "fakewithauthurl",
+ ["auth_url"])]
+ elif _type == 'openstack.client.authenticate':
+ return [MockAuthenticateEntrypoint("fakewithauthurl",
+ "fakewithauthurl",
+ ["authenticate"])]
+ else:
+ return []
+
+ mock_request = mock_http_request()
+
+ @mock.patch.object(pkg_resources, "iter_entry_points",
+ mock_iter_entry_points)
+ @mock.patch.object(requests.Session, "request", mock_request)
+ def test_auth_call():
+ plugin = auth_plugin.DeprecatedAuthPlugin("fakewithauthurl")
+ cs = client.Client("username", "password", "project_id",
+ auth_system="fakewithauthurl",
+ auth_plugin=plugin)
+ cs.client.authenticate()
+ self.assertEqual(cs.client.auth_url, "http://faked/v2.0")
+
+ test_auth_call()
+
+ @mock.patch.object(pkg_resources, "iter_entry_points")
+ def test_client_raises_exc_without_auth_url(self, mock_iter_entry_points):
+ class MockAuthUrlEntrypoint(pkg_resources.EntryPoint):
+ def load(self):
+ return self.auth_url
+
+ def auth_url(self):
+ return None
+
+ mock_iter_entry_points.side_effect = lambda _t, name: [
+ MockAuthUrlEntrypoint("fakewithauthurl",
+ "fakewithauthurl",
+ ["auth_url"])]
+
+ plugin = auth_plugin.DeprecatedAuthPlugin("fakewithauthurl")
+ self.assertRaises(
+ exceptions.EndpointNotFound,
+ client.Client, "username", "password", "project_id",
+ auth_system="fakewithauthurl", auth_plugin=plugin)
+
+
+class AuthPluginTest(utils.TestCase):
+ @mock.patch.object(requests, "request")
+ @mock.patch.object(pkg_resources, "iter_entry_points")
+ def test_auth_system_success(self, mock_iter_entry_points, mock_request):
+ """Test that we can authenticate using the auth system."""
+ class MockEntrypoint(pkg_resources.EntryPoint):
+ def load(self):
+ return FakePlugin
+
+ class FakePlugin(auth_plugin.BaseAuthPlugin):
+ def authenticate(self, cls, auth_url):
+ cls._authenticate(auth_url, {"fake": "me"})
+
+ mock_iter_entry_points.side_effect = lambda _t: [
+ MockEntrypoint("fake", "fake", ["FakePlugin"])]
+
+ mock_request.side_effect = mock_http_request()
+
+ auth_plugin.discover_auth_systems()
+ plugin = auth_plugin.load_plugin("fake")
+ cs = client.Client("username", "password", "project_id",
+ "auth_url/v2.0", auth_system="fake",
+ auth_plugin=plugin)
+ cs.client.authenticate()
+
+ headers = requested_headers(cs)
+ token_url = cs.client.auth_url + "/tokens"
+
+ mock_request.assert_called_with(
+ "POST",
+ token_url,
+ headers=headers,
+ data='{"fake": "me"}',
+ allow_redirects=True,
+ **self.TEST_REQUEST_BASE)
+
+ @mock.patch.object(pkg_resources, "iter_entry_points")
+ def test_discover_auth_system_options(self, mock_iter_entry_points):
+ """Test that we can load the auth system options."""
+ class FakePlugin(auth_plugin.BaseAuthPlugin):
+ @staticmethod
+ def add_opts(parser):
+ parser.add_argument('--auth_system_opt',
+ default=False,
+ action='store_true',
+ help="Fake option")
+ return parser
+
+ class MockEntrypoint(pkg_resources.EntryPoint):
+ def load(self):
+ return FakePlugin
+
+ mock_iter_entry_points.side_effect = lambda _t: [
+ MockEntrypoint("fake", "fake", ["FakePlugin"])]
+
+ parser = argparse.ArgumentParser()
+ auth_plugin.discover_auth_systems()
+ auth_plugin.load_auth_system_opts(parser)
+ opts, args = parser.parse_known_args(['--auth_system_opt'])
+
+ self.assertTrue(opts.auth_system_opt)
+
+ @mock.patch.object(pkg_resources, "iter_entry_points")
+ def test_parse_auth_system_options(self, mock_iter_entry_points):
+ """Test that we can parse the auth system options."""
+ class MockEntrypoint(pkg_resources.EntryPoint):
+ def load(self):
+ return FakePlugin
+
+ class FakePlugin(auth_plugin.BaseAuthPlugin):
+ def __init__(self):
+ self.opts = {"fake_argument": True}
+
+ def parse_opts(self, args):
+ return self.opts
+
+ mock_iter_entry_points.side_effect = lambda _t: [
+ MockEntrypoint("fake", "fake", ["FakePlugin"])]
+
+ auth_plugin.discover_auth_systems()
+ plugin = auth_plugin.load_plugin("fake")
+
+ plugin.parse_opts([])
+ self.assertIn("fake_argument", plugin.opts)
+
+ @mock.patch.object(pkg_resources, "iter_entry_points")
+ def test_auth_system_defining_url(self, mock_iter_entry_points):
+ """Test the auth_system defining an url."""
+ class MockEntrypoint(pkg_resources.EntryPoint):
+ def load(self):
+ return FakePlugin
+
+ class FakePlugin(auth_plugin.BaseAuthPlugin):
+ def get_auth_url(self):
+ return "http://faked/v2.0"
+
+ mock_iter_entry_points.side_effect = lambda _t: [
+ MockEntrypoint("fake", "fake", ["FakePlugin"])]
+
+ auth_plugin.discover_auth_systems()
+ plugin = auth_plugin.load_plugin("fake")
+
+ cs = client.Client("username", "password", "project_id",
+ auth_system="fakewithauthurl",
+ auth_plugin=plugin)
+ self.assertEqual(cs.client.auth_url, "http://faked/v2.0")
+
+ @mock.patch.object(pkg_resources, "iter_entry_points")
+ def test_exception_if_no_authenticate(self, mock_iter_entry_points):
+ """Test that no authenticate raises a proper exception."""
+ class MockEntrypoint(pkg_resources.EntryPoint):
+ def load(self):
+ return FakePlugin
+
+ class FakePlugin(auth_plugin.BaseAuthPlugin):
+ pass
+
+ mock_iter_entry_points.side_effect = lambda _t: [
+ MockEntrypoint("fake", "fake", ["FakePlugin"])]
+
+ auth_plugin.discover_auth_systems()
+ plugin = auth_plugin.load_plugin("fake")
+
+ self.assertRaises(
+ exceptions.EndpointNotFound,
+ client.Client, "username", "password", "project_id",
+ auth_system="fake", auth_plugin=plugin)
+
+ @mock.patch.object(pkg_resources, "iter_entry_points")
+ def test_exception_if_no_url(self, mock_iter_entry_points):
+ """Test that no auth_url at all raises exception."""
+ class MockEntrypoint(pkg_resources.EntryPoint):
+ def load(self):
+ return FakePlugin
+
+ class FakePlugin(auth_plugin.BaseAuthPlugin):
+ pass
+
+ mock_iter_entry_points.side_effect = lambda _t: [
+ MockEntrypoint("fake", "fake", ["FakePlugin"])]
+
+ auth_plugin.discover_auth_systems()
+ plugin = auth_plugin.load_plugin("fake")
+
+ self.assertRaises(
+ exceptions.EndpointNotFound,
+ client.Client, "username", "password", "project_id",
+ auth_system="fake", auth_plugin=plugin)
diff --git a/cinderclient/utils.py b/cinderclient/utils.py
index a941873..018f12a 100644
--- a/cinderclient/utils.py
+++ b/cinderclient/utils.py
@@ -16,6 +16,7 @@
from __future__ import print_function
import os
+import pkg_resources
import re
import sys
import uuid
@@ -286,6 +287,15 @@ def import_class(import_str):
__import__(mod_str)
return getattr(sys.modules[mod_str], class_str)
+
+def _load_entry_point(ep_name, name=None):
+ """Try to load the entry point ep_name that matches name."""
+ for ep in pkg_resources.iter_entry_points(ep_name, name=name):
+ try:
+ return ep.load()
+ except (ImportError, pkg_resources.UnknownExtra, AttributeError):
+ continue
+
_slugify_strip_re = re.compile(r'[^\w\s-]')
_slugify_hyphenate_re = re.compile(r'[-\s]+')
diff --git a/cinderclient/v1/client.py b/cinderclient/v1/client.py
index 82d1ee0..c352927 100644
--- a/cinderclient/v1/client.py
+++ b/cinderclient/v1/client.py
@@ -50,8 +50,8 @@ class Client(object):
endpoint_type='publicURL', extensions=None,
service_type='volume', service_name=None,
volume_service_name=None, retries=None,
- http_log_debug=False,
- cacert=None):
+ http_log_debug=False, cacert=None,
+ auth_system='keystone', auth_plugin=None):
# FIXME(comstud): Rename the api_key argument above when we
# know it's not being used as keyword argument
password = api_key
@@ -97,7 +97,9 @@ class Client(object):
volume_service_name=volume_service_name,
retries=retries,
http_log_debug=http_log_debug,
- cacert=cacert)
+ cacert=cacert,
+ auth_system=auth_system,
+ auth_plugin=auth_plugin)
def authenticate(self):
"""
diff --git a/cinderclient/v2/client.py b/cinderclient/v2/client.py
index 7b91c23..aa0526f 100644
--- a/cinderclient/v2/client.py
+++ b/cinderclient/v2/client.py
@@ -48,8 +48,8 @@ class Client(object):
endpoint_type='publicURL', extensions=None,
service_type='volumev2', service_name=None,
volume_service_name=None, retries=None,
- http_log_debug=False,
- cacert=None):
+ http_log_debug=False, cacert=None,
+ auth_system='keystone', auth_plugin=None):
# FIXME(comstud): Rename the api_key argument above when we
# know it's not being used as keyword argument
password = api_key
@@ -95,7 +95,9 @@ class Client(object):
volume_service_name=volume_service_name,
retries=retries,
http_log_debug=http_log_debug,
- cacert=cacert)
+ cacert=cacert,
+ auth_system=auth_system,
+ auth_plugin=auth_plugin)
def authenticate(self):
"""Authenticate against the server.
diff --git a/tools/install_venv_common.py b/tools/install_venv_common.py
index 46822e3..3b7ac10 100644
--- a/tools/install_venv_common.py
+++ b/tools/install_venv_common.py
@@ -128,6 +128,9 @@ class InstallVenv(object):
"install")
return parser.parse_args(argv[1:])[0]
+ def post_process(self, **kwargs):
+ pass
+
class Distro(InstallVenv):