Add Keystone v3 API support
Keystone is used for authentication in Manila and the latter's client does not support latest version of it that exists for long time. So, add support of Keystone v3 API and make Manila client to use it at first priority if it is available. Change-Id: I3e2f505f46f7ab60c66bcb0b1d65a38bea602df4 Closes-Bug: #1499260
This commit is contained in:
parent
0a731dcafa
commit
997cc43433
manilaclient
@ -139,6 +139,13 @@ class OpenStackManilaShell(object):
|
||||
action='store_true',
|
||||
help='Delete cached password and auth token.')
|
||||
|
||||
parser.add_argument('--os-user-id',
|
||||
metavar='<auth-user-id>',
|
||||
default=cliutils.env('OS_USER_ID'),
|
||||
help=('Defaults to env [OS_USER_ID].'))
|
||||
parser.add_argument('--os_user_id',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-username',
|
||||
metavar='<auth-user-name>',
|
||||
default=cliutils.env('OS_USERNAME',
|
||||
@ -163,6 +170,16 @@ class OpenStackManilaShell(object):
|
||||
parser.add_argument('--os_tenant_name',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-project-name',
|
||||
metavar='<auth-project-name>',
|
||||
default=cliutils.env('OS_PROJECT_NAME'),
|
||||
help=('Another way to specify tenant name. '
|
||||
'This option is mutually exclusive with '
|
||||
'--os-tenant-name. '
|
||||
'Defaults to env[OS_PROJECT_NAME].'))
|
||||
parser.add_argument('--os_project_name',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-tenant-id',
|
||||
metavar='<auth-tenant-id>',
|
||||
default=cliutils.env('OS_TENANT_ID',
|
||||
@ -171,6 +188,46 @@ class OpenStackManilaShell(object):
|
||||
parser.add_argument('--os_tenant_id',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-project-id',
|
||||
metavar='<auth-project-id>',
|
||||
default=cliutils.env('OS_PROJECT_ID'),
|
||||
help=('Another way to specify tenant ID. '
|
||||
'This option is mutually exclusive with '
|
||||
'--os-tenant-id. '
|
||||
'Defaults to env[OS_PROJECT_ID].'))
|
||||
parser.add_argument('--os_project_id',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-user-domain-id',
|
||||
metavar='<auth-user-domain-id>',
|
||||
default=cliutils.env('OS_USER_DOMAIN_ID'),
|
||||
help=('OpenStack user domain ID. '
|
||||
'Defaults to env[OS_USER_DOMAIN_ID].'))
|
||||
parser.add_argument('--os_user_domain_id',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-user-domain-name',
|
||||
metavar='<auth-user-domain-name>',
|
||||
default=cliutils.env('OS_USER_DOMAIN_NAME'),
|
||||
help=('OpenStack user domain name. '
|
||||
'Defaults to env[OS_USER_DOMAIN_NAME].'))
|
||||
parser.add_argument('--os_user_domain_name',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-project-domain-id',
|
||||
metavar='<auth-project-domain-id>',
|
||||
default=cliutils.env('OS_PROJECT_DOMAIN_ID'),
|
||||
help='Defaults to env[OS_PROJECT_DOMAIN_ID].')
|
||||
parser.add_argument('--os_project_domain_id',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-project-domain-name',
|
||||
metavar='<auth-project-domain-name>',
|
||||
default=cliutils.env('OS_PROJECT_DOMAIN_NAME'),
|
||||
help='Defaults to env[OS_PROJECT_DOMAIN_NAME].')
|
||||
parser.add_argument('--os_project_domain_name',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
parser.add_argument('--os-auth-url',
|
||||
metavar='<auth-url>',
|
||||
default=cliutils.env('OS_AUTH_URL',
|
||||
@ -246,6 +303,13 @@ class OpenStackManilaShell(object):
|
||||
default=0,
|
||||
help='Number of retries.')
|
||||
|
||||
parser.add_argument('--os-cert',
|
||||
metavar='<certificate>',
|
||||
default=cliutils.env('OS_CERT'),
|
||||
help='Defaults to env[OS_CERT].')
|
||||
parser.add_argument('--os_cert',
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
return parser
|
||||
|
||||
def get_subcommand_parser(self, version):
|
||||
@ -386,12 +450,18 @@ class OpenStackManilaShell(object):
|
||||
(os_username, os_password, os_tenant_name, os_auth_url,
|
||||
os_region_name, os_tenant_id, endpoint_type, insecure,
|
||||
service_type, service_name, share_service_name,
|
||||
cacert, os_cache, os_reset_cache) = (
|
||||
cacert, os_cache, os_reset_cache, os_user_id, os_user_domain_id,
|
||||
os_user_domain_name, os_project_domain_id, os_project_domain_name,
|
||||
os_project_name, os_project_id, os_cert) = (
|
||||
args.os_username, args.os_password, args.os_tenant_name,
|
||||
args.os_auth_url, args.os_region_name, args.os_tenant_id,
|
||||
args.endpoint_type, args.insecure, args.service_type,
|
||||
args.service_name, args.share_service_name,
|
||||
args.os_cacert, args.os_cache, args.os_reset_cache)
|
||||
args.os_cacert, args.os_cache, args.os_reset_cache,
|
||||
args.os_user_id, args.os_user_domain_id, args.os_user_domain_name,
|
||||
args.os_project_domain_id, args.os_project_domain_name,
|
||||
args.os_project_name, args.os_project_id, args.os_cert,
|
||||
)
|
||||
|
||||
if share_service_name:
|
||||
service_name = share_service_name
|
||||
@ -403,29 +473,19 @@ class OpenStackManilaShell(object):
|
||||
service_type = DEFAULT_MANILA_SERVICE_TYPE
|
||||
service_type = cliutils.get_service_type(args.func) or service_type
|
||||
|
||||
# FIXME(usrleon): Here should be restrict for project id same as
|
||||
# for os_username or os_password but for compatibility it is not.
|
||||
|
||||
if not cliutils.isunauthenticated(args.func):
|
||||
if not os_username:
|
||||
raise exc.CommandError(
|
||||
"You must provide a username "
|
||||
"via either --os-username or env[OS_USERNAME]")
|
||||
|
||||
if not (os_tenant_name or os_tenant_id):
|
||||
raise exc.CommandError("You must provide a tenant_id "
|
||||
"via either --os-tenant-id or "
|
||||
"env[OS_TENANT_ID]")
|
||||
|
||||
if not os_auth_url:
|
||||
raise exc.CommandError(
|
||||
"You must provide an auth url "
|
||||
"via either --os-auth-url or env[OS_AUTH_URL]")
|
||||
|
||||
if not (os_tenant_name or os_tenant_id):
|
||||
if not (os_tenant_name or os_tenant_id or os_project_name or
|
||||
os_project_id):
|
||||
raise exc.CommandError(
|
||||
"You must provide a tenant_id "
|
||||
"via either --os-tenant-id or env[OS_TENANT_ID]")
|
||||
"You must provide a tenant_name, tenant_id, "
|
||||
"project_id or project_name (with "
|
||||
"project_domain_name or project_domain_id) via "
|
||||
"--os-tenant-name (env[OS_TENANT_NAME]), "
|
||||
"--os-tenant-id (env[OS_TENANT_ID]), "
|
||||
"--os-project-id (env[OS_PROJECT_ID]), "
|
||||
"--os-project-name (env[OS_PROJECT_NAME]), "
|
||||
"--os-project-domain-id (env[OS_PROJECT_DOMAIN_ID]) and "
|
||||
"--os-project-domain-name (env[OS_PROJECT_DOMAIN_NAME])."
|
||||
)
|
||||
|
||||
if not os_auth_url:
|
||||
raise exc.CommandError(
|
||||
@ -434,11 +494,12 @@ class OpenStackManilaShell(object):
|
||||
|
||||
self.cs = client.Client(options.os_share_api_version,
|
||||
username=os_username,
|
||||
api_key=os_password,
|
||||
project_name=os_tenant_name,
|
||||
password=os_password,
|
||||
project_name=os_project_name or os_tenant_name,
|
||||
auth_url=os_auth_url,
|
||||
insecure=insecure, region_name=os_region_name,
|
||||
tenant_id=os_tenant_id,
|
||||
insecure=insecure,
|
||||
region_name=os_region_name,
|
||||
tenant_id=os_project_id or os_tenant_id,
|
||||
endpoint_type=endpoint_type,
|
||||
extensions=self.extensions,
|
||||
service_type=service_type,
|
||||
@ -448,7 +509,13 @@ class OpenStackManilaShell(object):
|
||||
cacert=cacert,
|
||||
use_keyring=os_cache,
|
||||
force_new_token=os_reset_cache,
|
||||
api_version=options.os_share_api_version)
|
||||
api_version=options.os_share_api_version,
|
||||
user_id=os_user_id,
|
||||
user_domain_id=os_user_domain_id,
|
||||
user_domain_name=os_user_domain_name,
|
||||
project_domain_id=os_project_domain_id,
|
||||
project_domain_name=os_project_domain_name,
|
||||
cert=os_cert)
|
||||
|
||||
args.func(self.cs, args)
|
||||
|
||||
|
@ -13,16 +13,20 @@
|
||||
import re
|
||||
import sys
|
||||
|
||||
import ddt
|
||||
import fixtures
|
||||
import mock
|
||||
from six import moves
|
||||
from testtools import matchers
|
||||
|
||||
from manilaclient.common import constants
|
||||
from manilaclient import exceptions
|
||||
from manilaclient import shell
|
||||
from manilaclient.tests.unit import utils
|
||||
|
||||
|
||||
class ShellTest(utils.TestCase):
|
||||
@ddt.ddt
|
||||
class OpenstackManilaShellTest(utils.TestCase):
|
||||
|
||||
FAKE_ENV = {
|
||||
'OS_USERNAME': 'username',
|
||||
@ -32,11 +36,9 @@ class ShellTest(utils.TestCase):
|
||||
}
|
||||
|
||||
# Patch os.environ to avoid required auth info.
|
||||
def setUp(self):
|
||||
super(ShellTest, self).setUp()
|
||||
for var in self.FAKE_ENV:
|
||||
self.useFixture(fixtures.EnvironmentVariable(var,
|
||||
self.FAKE_ENV[var]))
|
||||
def set_env_vars(self, env_vars):
|
||||
for k, v in env_vars.items():
|
||||
self.useFixture(fixtures.EnvironmentVariable(k, v))
|
||||
|
||||
def shell(self, argstr):
|
||||
orig = sys.stdout
|
||||
@ -54,6 +56,70 @@ class ShellTest(utils.TestCase):
|
||||
|
||||
return out
|
||||
|
||||
@ddt.data(
|
||||
{},
|
||||
{'OS_AUTH_URL': 'http://foo.bar'},
|
||||
{'OS_AUTH_URL': 'http://foo.bar', 'OS_USERNAME': 'foo'},
|
||||
{'OS_AUTH_URL': 'http://foo.bar', 'OS_USERNAME': 'foo_user',
|
||||
'OS_PASSWORD': 'foo_password'},
|
||||
{'OS_TENANT_NAME': 'foo_tenant', 'OS_USERNAME': 'foo_user',
|
||||
'OS_PASSWORD': 'foo_password'},
|
||||
)
|
||||
def test_main_failure(self, env_vars):
|
||||
self.set_env_vars(env_vars)
|
||||
with mock.patch.object(shell, 'client') as mock_client:
|
||||
self.assertRaises(exceptions.CommandError, self.shell, 'list')
|
||||
self.assertFalse(mock_client.Client.called)
|
||||
|
||||
def test_main_success(self):
|
||||
env_vars = {
|
||||
'OS_AUTH_URL': 'http://foo.bar',
|
||||
'OS_USERNAME': 'foo_username',
|
||||
'OS_USER_ID': 'foo_user_id',
|
||||
'OS_PASSWORD': 'foo_password',
|
||||
'OS_TENANT_NAME': 'foo_tenant',
|
||||
'OS_TENANT_ID': 'foo_tenant_id',
|
||||
'OS_PROJECT_NAME': 'foo_project',
|
||||
'OS_PROJECT_ID': 'foo_project_id',
|
||||
'OS_PROJECT_DOMAIN_ID': 'foo_project_domain_id',
|
||||
'OS_PROJECT_DOMAIN_NAME': 'foo_project_domain_name',
|
||||
'OS_PROJECT_DOMAIN_ID': 'foo_project_domain_id',
|
||||
'OS_USER_DOMAIN_NAME': 'foo_user_domain_name',
|
||||
'OS_USER_DOMAIN_ID': 'foo_user_domain_id',
|
||||
'OS_CERT': 'foo_cert',
|
||||
}
|
||||
self.set_env_vars(env_vars)
|
||||
with mock.patch.object(shell, 'client') as mock_client:
|
||||
|
||||
self.shell('list')
|
||||
|
||||
mock_client.Client.assert_called_once_with(
|
||||
constants.MAX_API_VERSION,
|
||||
username=env_vars['OS_USERNAME'],
|
||||
password=env_vars['OS_PASSWORD'],
|
||||
project_name=env_vars['OS_PROJECT_NAME'],
|
||||
auth_url=env_vars['OS_AUTH_URL'],
|
||||
insecure=False,
|
||||
region_name='',
|
||||
tenant_id=env_vars['OS_PROJECT_ID'],
|
||||
endpoint_type='publicURL',
|
||||
extensions=mock.ANY,
|
||||
service_type='sharev2',
|
||||
service_name='',
|
||||
retries=0,
|
||||
http_log_debug=False,
|
||||
cacert=None,
|
||||
use_keyring=False,
|
||||
force_new_token=False,
|
||||
api_version=constants.MAX_API_VERSION,
|
||||
user_id=env_vars['OS_USER_ID'],
|
||||
user_domain_id=env_vars['OS_USER_DOMAIN_ID'],
|
||||
user_domain_name=env_vars['OS_USER_DOMAIN_NAME'],
|
||||
project_domain_id=env_vars['OS_PROJECT_DOMAIN_ID'],
|
||||
project_domain_name=env_vars['OS_PROJECT_DOMAIN_NAME'],
|
||||
cert=env_vars['OS_CERT'],
|
||||
)
|
||||
|
||||
def test_help_unknown_command(self):
|
||||
self.assertRaises(exceptions.CommandError, self.shell, 'help foofoo')
|
||||
|
||||
@ -79,3 +145,20 @@ class ShellTest(utils.TestCase):
|
||||
for r in required:
|
||||
self.assertThat(help_text,
|
||||
matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_common_args_in_help_message(self):
|
||||
expected_args = (
|
||||
'--version', '', '--debug', '--os-cache', '--os-reset-cache',
|
||||
'--os-user-id', '--os-username', '--os-password',
|
||||
'--os-tenant-name', '--os-project-name', '--os-tenant-id',
|
||||
'--os-project-id', '--os-user-domain-id', '--os-user-domain-name',
|
||||
'--os-project-domain-id', '--os-project-domain-name',
|
||||
'--os-auth-url', '--os-region-name', '--service-type',
|
||||
'--service-name', '--share-service-name', '--endpoint-type',
|
||||
'--os-share-api-version', '--os-cacert', '--retries', '--os-cert',
|
||||
)
|
||||
|
||||
help_text = self.shell('help')
|
||||
|
||||
for expected_arg in expected_args:
|
||||
self.assertIn(expected_arg, help_text)
|
||||
|
@ -13,6 +13,7 @@
|
||||
import os
|
||||
|
||||
import fixtures
|
||||
import mock
|
||||
import requests
|
||||
import testtools
|
||||
|
||||
@ -33,6 +34,20 @@ class TestCase(testtools.TestCase):
|
||||
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
|
||||
|
||||
def mock_object(self, obj, attr_name, new_attr=None, **kwargs):
|
||||
"""Mock an object attribute.
|
||||
|
||||
Use python mock to mock an object attribute
|
||||
Mocks the specified objects attribute with the given value.
|
||||
Automatically performs 'addCleanup' for the mock.
|
||||
"""
|
||||
if not new_attr:
|
||||
new_attr = mock.Mock()
|
||||
patcher = mock.patch.object(obj, attr_name, new_attr, **kwargs)
|
||||
patcher.start()
|
||||
self.addCleanup(patcher.stop)
|
||||
return new_attr
|
||||
|
||||
|
||||
class TestResponse(requests.Response):
|
||||
"""Class used to wrap requests.Response.
|
||||
|
@ -12,19 +12,19 @@
|
||||
|
||||
import uuid
|
||||
|
||||
from keystoneclient import session
|
||||
import ddt
|
||||
import mock
|
||||
|
||||
from manilaclient.common import constants
|
||||
from manilaclient import exceptions
|
||||
from manilaclient import httpclient
|
||||
from manilaclient.tests.unit import utils
|
||||
from manilaclient.v1 import client
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ClientTest(utils.TestCase):
|
||||
def setUp(self):
|
||||
super(ClientTest, self).setUp()
|
||||
super(self.__class__, self).setUp()
|
||||
self.catalog = {
|
||||
'share': [
|
||||
{'region': 'TestRegion', 'publicURL': 'http://1.2.3.4'},
|
||||
@ -36,7 +36,7 @@ class ClientTest(utils.TestCase):
|
||||
retries = 3
|
||||
base_url = uuid.uuid4().hex
|
||||
|
||||
s = session.Session()
|
||||
s = client.session.Session()
|
||||
c = client.Client(session=s, api_version=constants.MAX_API_VERSION,
|
||||
service_catalog_url=base_url, retries=retries,
|
||||
input_auth_token='token')
|
||||
@ -50,7 +50,7 @@ class ClientTest(utils.TestCase):
|
||||
input_auth_token="token")
|
||||
|
||||
def test_auth_via_token_and_session(self):
|
||||
s = session.Session()
|
||||
s = client.session.Session()
|
||||
base_url = uuid.uuid4().hex
|
||||
c = client.Client(input_auth_token='token',
|
||||
service_catalog_url=base_url, session=s,
|
||||
@ -69,9 +69,9 @@ class ClientTest(utils.TestCase):
|
||||
self.assertIsNotNone(c.client)
|
||||
self.assertIsNone(c.keystone_client)
|
||||
|
||||
@mock.patch.object(httpclient, 'HTTPClient', mock.Mock())
|
||||
@mock.patch.object(client.Client, '_get_keystone_client', mock.Mock())
|
||||
def test_valid_region_name(self):
|
||||
self.mock_object(client.httpclient, 'HTTPClient')
|
||||
kc = client.Client._get_keystone_client.return_value
|
||||
kc.service_catalog = mock.Mock()
|
||||
kc.service_catalog.get_endpoints = mock.Mock(return_value=self.catalog)
|
||||
@ -79,7 +79,7 @@ class ClientTest(utils.TestCase):
|
||||
region_name='TestRegion')
|
||||
self.assertTrue(client.Client._get_keystone_client.called)
|
||||
kc.service_catalog.get_endpoints.assert_called_once_with('share')
|
||||
httpclient.HTTPClient.assert_called_once_with(
|
||||
client.httpclient.HTTPClient.assert_called_once_with(
|
||||
'http://1.2.3.4',
|
||||
mock.ANY,
|
||||
'python-manilaclient',
|
||||
@ -99,12 +99,13 @@ class ClientTest(utils.TestCase):
|
||||
self.assertRaises(RuntimeError, client.Client,
|
||||
api_version=constants.MAX_API_VERSION,
|
||||
region_name='FakeRegion')
|
||||
|
||||
self.assertTrue(client.Client._get_keystone_client.called)
|
||||
kc.service_catalog.get_endpoints.assert_called_once_with('share')
|
||||
|
||||
@mock.patch.object(httpclient, 'HTTPClient', mock.Mock())
|
||||
@mock.patch.object(client.Client, '_get_keystone_client', mock.Mock())
|
||||
def test_regions_with_same_name(self):
|
||||
self.mock_object(client.httpclient, 'HTTPClient')
|
||||
catalog = {
|
||||
'share': [
|
||||
{'region': 'FirstRegion', 'publicURL': 'http://1.2.3.4'},
|
||||
@ -119,7 +120,7 @@ class ClientTest(utils.TestCase):
|
||||
region_name='SecondRegion')
|
||||
self.assertTrue(client.Client._get_keystone_client.called)
|
||||
kc.service_catalog.get_endpoints.assert_called_once_with('share')
|
||||
httpclient.HTTPClient.assert_called_once_with(
|
||||
client.httpclient.HTTPClient.assert_called_once_with(
|
||||
'http://2.2.2.2',
|
||||
mock.ANY,
|
||||
'python-manilaclient',
|
||||
@ -130,3 +131,166 @@ class ClientTest(utils.TestCase):
|
||||
http_log_debug=False,
|
||||
api_version=constants.MAX_API_VERSION)
|
||||
self.assertIsNotNone(c.client)
|
||||
|
||||
def _get_client_args(self, **kwargs):
|
||||
client_args = {
|
||||
'auth_url': 'both',
|
||||
'api_version': constants.MAX_API_VERSION,
|
||||
'username': 'fake_username',
|
||||
'service_type': 'sharev2',
|
||||
'region_name': 'SecondRegion',
|
||||
'input_auth_token': None,
|
||||
'session': None,
|
||||
'service_catalog_url': None,
|
||||
'user_id': 'foo_user_id',
|
||||
'user_domain_name': 'foo_user_domain_name',
|
||||
'user_domain_id': 'foo_user_domain_id',
|
||||
'project_name': 'foo_project_name',
|
||||
'project_domain_name': 'foo_project_domain_name',
|
||||
'project_domain_id': 'foo_project_domain_id',
|
||||
'endpoint_type': 'publicUrl',
|
||||
'cert': 'foo_cert',
|
||||
}
|
||||
client_args.update(kwargs)
|
||||
return client_args
|
||||
|
||||
@ddt.data(
|
||||
{'auth_url': 'only_v3', 'api_key': 'password_backward_compat',
|
||||
'endpoint_type': 'publicURL', 'project_id': 'foo_tenant_project_id'},
|
||||
{'password': 'renamed_api_key', 'endpoint_type': 'public',
|
||||
'tenant_id': 'foo_tenant_project_id'},
|
||||
)
|
||||
def test_client_init_no_session_no_auth_token_v3(self, kwargs):
|
||||
def fake_url_for(version):
|
||||
if version == 'v3.0':
|
||||
return 'url_v3.0'
|
||||
elif version == 'v2.0' and self.auth_url == 'both':
|
||||
return 'url_v2.0'
|
||||
else:
|
||||
return None
|
||||
|
||||
self.mock_object(client.httpclient, 'HTTPClient')
|
||||
self.mock_object(client.ks_client, 'Client')
|
||||
self.mock_object(client.discover, 'Discover')
|
||||
self.mock_object(client.session, 'Session')
|
||||
client_args = self._get_client_args(**kwargs)
|
||||
self.auth_url = client_args['auth_url']
|
||||
catalog = {
|
||||
'share': [
|
||||
{'region': 'SecondRegion', 'region_id': 'SecondRegion',
|
||||
'url': 'http://4.4.4.4', 'interface': 'public',
|
||||
},
|
||||
],
|
||||
'sharev2': [
|
||||
{'region': 'FirstRegion', 'interface': 'public',
|
||||
'region_id': 'SecondRegion', 'url': 'http://1.1.1.1'},
|
||||
{'region': 'secondregion', 'interface': 'public',
|
||||
'region_id': 'SecondRegion', 'url': 'http://2.2.2.2'},
|
||||
{'region': 'SecondRegion', 'interface': 'internal',
|
||||
'region_id': 'SecondRegion', 'url': 'http://3.3.3.1'},
|
||||
{'region': 'SecondRegion', 'interface': 'public',
|
||||
'region_id': 'SecondRegion', 'url': 'http://3.3.3.3'},
|
||||
{'region': 'SecondRegion', 'interface': 'admin',
|
||||
'region_id': 'SecondRegion', 'url': 'http://3.3.3.2'},
|
||||
],
|
||||
}
|
||||
client.discover.Discover.return_value.url_for.side_effect = (
|
||||
fake_url_for)
|
||||
client.ks_client.Client.return_value.auth_token.return_value = (
|
||||
'fake_token')
|
||||
mocked_ks_client = client.ks_client.Client.return_value
|
||||
mocked_ks_client.service_catalog.get_endpoints.return_value = catalog
|
||||
|
||||
client.Client(**client_args)
|
||||
|
||||
client.httpclient.HTTPClient.assert_called_once_with(
|
||||
'http://3.3.3.3', mock.ANY, 'python-manilaclient', insecure=False,
|
||||
cacert=None, timeout=None, retries=None, http_log_debug=False,
|
||||
api_version=constants.MAX_API_VERSION)
|
||||
client.ks_client.Client.assert_called_once_with(
|
||||
version=(3, 0), auth_url='url_v3.0',
|
||||
username=client_args['username'],
|
||||
password=client_args.get('password', client_args.get('api_key')),
|
||||
user_id=client_args['user_id'],
|
||||
user_domain_name=client_args['user_domain_name'],
|
||||
user_domain_id=client_args['user_domain_id'],
|
||||
project_id=client_args.get('tenant_id',
|
||||
client_args.get('project_id')),
|
||||
project_name=client_args['project_name'],
|
||||
project_domain_name=client_args['project_domain_name'],
|
||||
project_domain_id=client_args['project_domain_id'],
|
||||
region_name=client_args['region_name'],
|
||||
)
|
||||
mocked_ks_client.service_catalog.get_endpoints.assert_called_once_with(
|
||||
client_args['service_type'])
|
||||
mocked_ks_client.authenticate.assert_called_once_with()
|
||||
|
||||
@ddt.data(
|
||||
{'auth_url': 'only_v2', 'api_key': 'foo', 'project_id': 'bar'},
|
||||
{'password': 'foo', 'tenant_id': 'bar'},
|
||||
)
|
||||
def test_client_init_no_session_no_auth_token_v2(self, kwargs):
|
||||
self.mock_object(client.httpclient, 'HTTPClient')
|
||||
self.mock_object(client.ks_client, 'Client')
|
||||
self.mock_object(client.discover, 'Discover')
|
||||
self.mock_object(client.session, 'Session')
|
||||
client_args = self._get_client_args(**kwargs)
|
||||
self.auth_url = client_args['auth_url']
|
||||
catalog = {
|
||||
'share': [
|
||||
{'region': 'SecondRegion', 'publicUrl': 'http://4.4.4.4'},
|
||||
],
|
||||
'sharev2': [
|
||||
{'region': 'FirstRegion', 'publicUrl': 'http://1.1.1.1'},
|
||||
{'region': 'secondregion', 'publicUrl': 'http://2.2.2.2'},
|
||||
{'region': 'SecondRegion', 'internalUrl': 'http://3.3.3.1',
|
||||
'publicUrl': 'http://3.3.3.3', 'adminUrl': 'http://3.3.3.2'},
|
||||
],
|
||||
}
|
||||
client.discover.Discover.return_value.url_for.side_effect = (
|
||||
lambda v: 'url_v2.0' if v == 'v2.0' else None)
|
||||
client.ks_client.Client.return_value.auth_token.return_value = (
|
||||
'fake_token')
|
||||
mocked_ks_client = client.ks_client.Client.return_value
|
||||
mocked_ks_client.service_catalog.get_endpoints.return_value = catalog
|
||||
|
||||
client.Client(**client_args)
|
||||
|
||||
client.httpclient.HTTPClient.assert_called_once_with(
|
||||
'http://3.3.3.3', mock.ANY, 'python-manilaclient', insecure=False,
|
||||
cacert=None, timeout=None, retries=None, http_log_debug=False,
|
||||
api_version=constants.MAX_API_VERSION)
|
||||
client.ks_client.Client.assert_called_once_with(
|
||||
version=(2, 0), auth_url='url_v2.0',
|
||||
username=client_args['username'],
|
||||
password=client_args.get('password', client_args.get('api_key')),
|
||||
tenant_id=client_args.get('tenant_id',
|
||||
client_args.get('project_id')),
|
||||
tenant_name=client_args['project_name'],
|
||||
region_name=client_args['region_name'], cert=client_args['cert'],
|
||||
use_keyring=False, force_new_token=False, stale_duration=300)
|
||||
mocked_ks_client.service_catalog.get_endpoints.assert_called_once_with(
|
||||
client_args['service_type'])
|
||||
mocked_ks_client.authenticate.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(client.ks_client, 'Client', mock.Mock())
|
||||
@mock.patch.object(client.discover, 'Discover', mock.Mock())
|
||||
@mock.patch.object(client.session, 'Session', mock.Mock())
|
||||
def test_client_init_no_session_no_auth_token_endpoint_not_found(self):
|
||||
self.mock_object(client.httpclient, 'HTTPClient')
|
||||
client_args = self._get_client_args(
|
||||
auth_urli='fake_url',
|
||||
password='foo_password',
|
||||
tenant_id='foo_tenant_id')
|
||||
client.discover.Discover.return_value.url_for.return_value = None
|
||||
mocked_ks_client = client.ks_client.Client.return_value
|
||||
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, client.Client, **client_args)
|
||||
|
||||
self.assertTrue(client.session.Session.called)
|
||||
self.assertTrue(client.discover.Discover.called)
|
||||
self.assertFalse(client.httpclient.HTTPClient.called)
|
||||
self.assertFalse(client.ks_client.Client.called)
|
||||
self.assertFalse(mocked_ks_client.service_catalog.get_endpoints.called)
|
||||
self.assertFalse(mocked_ks_client.authenticate.called)
|
||||
|
@ -99,6 +99,69 @@ class ShellTest(test_utils.TestCase):
|
||||
def assert_called_anytime(self, method, url, body=None):
|
||||
return self.shell.cs.assert_called_anytime(method, url, body)
|
||||
|
||||
@ddt.data(
|
||||
{'serviceCatalog': [{'name': 'foo', 'endpoints': ['bar']}]},
|
||||
{'catalog': [{'name': 'foo', 'endpoints': ['bar']}]},
|
||||
{'serviceCatalog': [{'name': 'foo', 'endpoints': ['bar']}],
|
||||
'catalog': 'fake'},
|
||||
)
|
||||
def test_do_endpoints(self, catalog):
|
||||
cs = type('Fake', (object, ), {'keystone_client': type(
|
||||
'FakeKeystoneClient', (object, ), {
|
||||
'service_catalog': type('FakeCatalog', (object, ), {
|
||||
'catalog': catalog})})})
|
||||
|
||||
with mock.patch.object(
|
||||
shell_v1.cliutils, 'print_dict') as mock_print_dict:
|
||||
shell_v1.do_endpoints(cs, ('no', 'args'))
|
||||
|
||||
mock_print_dict.assert_has_calls([
|
||||
mock.call('bar', 'foo'),
|
||||
])
|
||||
|
||||
@ddt.data(
|
||||
{'version': 'v3',
|
||||
'user': 'foo_user',
|
||||
'issued_at': 'foo_issued_at',
|
||||
'expires_at': 'foo_expires',
|
||||
'auth_token': 'foo_ids',
|
||||
'audit_ids': 'foo_audit_ids',
|
||||
'project': 'foo_tenant_project',
|
||||
'redundant_key': 'should not be used',
|
||||
},
|
||||
{'version': 'v2.0',
|
||||
'user': 'foo_user',
|
||||
'token': {
|
||||
'issued_at': 'foo_issued_at',
|
||||
'expires': 'foo_expires',
|
||||
'id': 'foo_ids',
|
||||
'audit_ids': 'foo_audit_ids',
|
||||
'tenant': 'foo_tenant_project',
|
||||
},
|
||||
},
|
||||
)
|
||||
def test_do_credentials(self, catalog):
|
||||
cs = type('Fake', (object, ), {'keystone_client': type(
|
||||
'FakeKeystoneClient', (object, ), {
|
||||
'service_catalog': type('FakeCatalog', (object, ), {
|
||||
'catalog': catalog})})})
|
||||
expected_call_data = {
|
||||
'issued_at': 'foo_issued_at',
|
||||
'expires': 'foo_expires',
|
||||
'id': 'foo_ids',
|
||||
'audit_ids': 'foo_audit_ids',
|
||||
'tenant': 'foo_tenant_project',
|
||||
}
|
||||
|
||||
with mock.patch.object(
|
||||
shell_v1.cliutils, 'print_dict') as mock_print_dict:
|
||||
shell_v1.do_credentials(cs, ('no', 'args'))
|
||||
|
||||
mock_print_dict.assert_has_calls([
|
||||
mock.call('foo_user', 'User Credentials'),
|
||||
mock.call(expected_call_data, 'Token'),
|
||||
])
|
||||
|
||||
def test_list(self):
|
||||
self.run_command('list')
|
||||
# NOTE(jdg): we default to detail currently
|
||||
|
@ -13,8 +13,9 @@
|
||||
import warnings
|
||||
|
||||
from keystoneclient import adapter
|
||||
from keystoneclient.v2_0 import client as keystone_client_v2
|
||||
from keystoneclient.v3 import client as keystone_client_v3
|
||||
from keystoneclient import client as ks_client
|
||||
from keystoneclient import discover
|
||||
from keystoneclient import session
|
||||
import six
|
||||
|
||||
from manilaclient.common import constants
|
||||
@ -72,7 +73,41 @@ class Client(object):
|
||||
service_catalog_url=None, user_agent='python-manilaclient',
|
||||
use_keyring=False, force_new_token=False,
|
||||
cached_token_lifetime=300,
|
||||
api_version=constants.V1_API_VERSION, **kwargs):
|
||||
api_version=constants.V1_API_VERSION,
|
||||
user_id=None,
|
||||
user_domain_id=None,
|
||||
user_domain_name=None,
|
||||
project_domain_id=None,
|
||||
project_domain_name=None,
|
||||
cert=None,
|
||||
password=None,
|
||||
**kwargs):
|
||||
|
||||
self.username = username
|
||||
self.password = password or api_key
|
||||
self.tenant_id = tenant_id or project_id
|
||||
self.tenant_name = project_name
|
||||
|
||||
self.user_id = user_id
|
||||
self.project_id = project_id or tenant_id
|
||||
self.project_name = project_name
|
||||
self.user_domain_id = user_domain_id
|
||||
self.user_domain_name = user_domain_name
|
||||
self.project_domain_id = project_domain_id
|
||||
self.project_domain_name = project_domain_name
|
||||
|
||||
self.endpoint_type = endpoint_type
|
||||
self.auth_url = auth_url
|
||||
self.region_name = region_name
|
||||
|
||||
self.cacert = cacert
|
||||
self.cert = cert
|
||||
self.insecure = insecure
|
||||
|
||||
self.use_keyring = use_keyring
|
||||
self.force_new_token = force_new_token
|
||||
self.cached_token_lifetime = cached_token_lifetime
|
||||
|
||||
service_name = kwargs.get("share_service_name", service_name)
|
||||
|
||||
def check_deprecated_arguments():
|
||||
@ -80,7 +115,8 @@ class Client(object):
|
||||
'share_service_name': 'service_name',
|
||||
'proxy_tenant_id': None,
|
||||
'proxy_token': None,
|
||||
'os_cache': 'use_keyring'
|
||||
'os_cache': 'use_keyring',
|
||||
'api_key': 'password',
|
||||
}
|
||||
|
||||
for arg, replacement in six.iteritems(deprecated):
|
||||
@ -124,15 +160,7 @@ class Client(object):
|
||||
input_auth_token = self.keystone_client.session.get_token(auth)
|
||||
|
||||
else:
|
||||
self.keystone_client = self._get_keystone_client(
|
||||
username=username,
|
||||
api_key=api_key,
|
||||
auth_url=auth_url,
|
||||
project_id=self.project_id,
|
||||
project_name=project_name,
|
||||
use_keyring=use_keyring,
|
||||
force_new_token=force_new_token,
|
||||
stale_duration=cached_token_lifetime)
|
||||
self.keystone_client = self._get_keystone_client()
|
||||
input_auth_token = self.keystone_client.auth_token
|
||||
|
||||
if not input_auth_token:
|
||||
@ -145,19 +173,18 @@ class Client(object):
|
||||
elif not service_catalog_url:
|
||||
catalog = self.keystone_client.service_catalog.get_endpoints(
|
||||
service_type)
|
||||
if service_type in catalog:
|
||||
if not region_name:
|
||||
catalog_entry = catalog.get(service_type)[0]
|
||||
else:
|
||||
for catalog_entry in catalog.get(service_type):
|
||||
if catalog_entry.get("region") == region_name:
|
||||
break
|
||||
else:
|
||||
catalog_entry = {}
|
||||
for e_type, endpoint in catalog_entry.items():
|
||||
if str(e_type).lower() == str(endpoint_type).lower():
|
||||
service_catalog_url = endpoint
|
||||
break
|
||||
for catalog_entry in catalog.get(service_type, []):
|
||||
if (catalog_entry.get("interface") == (
|
||||
endpoint_type.lower().split("url")[0]) or
|
||||
catalog_entry.get(endpoint_type)):
|
||||
if (region_name and not region_name == (
|
||||
catalog_entry.get(
|
||||
"region",
|
||||
catalog_entry.get("region_id")))):
|
||||
continue
|
||||
service_catalog_url = catalog_entry.get(
|
||||
"url", catalog_entry.get(endpoint_type))
|
||||
break
|
||||
|
||||
if not service_catalog_url:
|
||||
raise RuntimeError("Could not find Manila endpoint in catalog")
|
||||
@ -203,33 +230,6 @@ class Client(object):
|
||||
if extension.manager_class:
|
||||
setattr(self, extension.name, extension.manager_class(self))
|
||||
|
||||
def _get_keystone_client(self, username=None, api_key=None, auth_url=None,
|
||||
token=None, project_id=None, project_name=None,
|
||||
use_keyring=False, force_new_token=False,
|
||||
stale_duration=0):
|
||||
if not auth_url:
|
||||
raise RuntimeError("No auth url specified")
|
||||
|
||||
if not getattr(self, "keystone_client", None):
|
||||
imported_client = (keystone_client_v2 if "v2.0" in auth_url
|
||||
else keystone_client_v3)
|
||||
|
||||
self.keystone_client = imported_client.Client(
|
||||
username=username,
|
||||
password=api_key,
|
||||
token=token,
|
||||
tenant_id=project_id,
|
||||
tenant_name=project_name,
|
||||
auth_url=auth_url,
|
||||
endpoint=auth_url,
|
||||
use_keyring=use_keyring,
|
||||
force_new_token=force_new_token,
|
||||
stale_duration=stale_duration)
|
||||
|
||||
self.keystone_client.authenticate()
|
||||
|
||||
return self.keystone_client
|
||||
|
||||
def authenticate(self):
|
||||
"""Authenticate against the server.
|
||||
|
||||
@ -242,3 +242,54 @@ class Client(object):
|
||||
warnings.warn("authenticate() method is deprecated. "
|
||||
"Client automatically makes authentication call "
|
||||
"in the constructor.")
|
||||
|
||||
def _get_keystone_client(self):
|
||||
# First create a Keystone session
|
||||
if self.insecure:
|
||||
verify = False
|
||||
else:
|
||||
verify = self.cacert or True
|
||||
ks_session = session.Session(verify=verify, cert=self.cert)
|
||||
|
||||
# Discover the supported keystone versions using the given url
|
||||
ks_discover = discover.Discover(
|
||||
session=ks_session, auth_url=self.auth_url)
|
||||
|
||||
# Inspect the auth_url to see the supported version. If both v3 and v2
|
||||
# are supported, then use the highest version if possible.
|
||||
v2_auth_url = ks_discover.url_for('v2.0')
|
||||
v3_auth_url = ks_discover.url_for('v3.0')
|
||||
|
||||
if v3_auth_url:
|
||||
keystone_client = ks_client.Client(
|
||||
version=(3, 0),
|
||||
auth_url=v3_auth_url,
|
||||
username=self.username,
|
||||
password=self.password,
|
||||
user_id=self.user_id,
|
||||
user_domain_name=self.user_domain_name,
|
||||
user_domain_id=self.user_domain_id,
|
||||
project_id=self.project_id or self.tenant_id,
|
||||
project_name=self.project_name,
|
||||
project_domain_name=self.project_domain_name,
|
||||
project_domain_id=self.project_domain_id,
|
||||
region_name=self.region_name)
|
||||
elif v2_auth_url:
|
||||
keystone_client = ks_client.Client(
|
||||
version=(2, 0),
|
||||
auth_url=v2_auth_url,
|
||||
username=self.username,
|
||||
password=self.password,
|
||||
tenant_id=self.tenant_id,
|
||||
tenant_name=self.tenant_name,
|
||||
region_name=self.region_name,
|
||||
cert=self.cert,
|
||||
use_keyring=self.use_keyring,
|
||||
force_new_token=self.force_new_token,
|
||||
stale_duration=self.cached_token_lifetime)
|
||||
else:
|
||||
raise exceptions.CommandError(
|
||||
'Unable to determine the Keystone version to authenticate '
|
||||
'with using the given auth_url.')
|
||||
keystone_client.authenticate()
|
||||
return keystone_client
|
||||
|
@ -201,7 +201,7 @@ def do_api_version(cs, args):
|
||||
def do_endpoints(cs, args):
|
||||
"""Discover endpoints that get returned from the authenticate services."""
|
||||
catalog = cs.keystone_client.service_catalog.catalog
|
||||
for e in catalog['serviceCatalog']:
|
||||
for e in catalog.get('serviceCatalog', catalog.get('catalog')):
|
||||
cliutils.print_dict(e['endpoints'][0], e['name'])
|
||||
|
||||
|
||||
@ -209,7 +209,17 @@ def do_credentials(cs, args):
|
||||
"""Show user credentials returned from auth."""
|
||||
catalog = cs.keystone_client.service_catalog.catalog
|
||||
cliutils.print_dict(catalog['user'], "User Credentials")
|
||||
cliutils.print_dict(catalog['token'], "Token")
|
||||
if not catalog['version'] == 'v3':
|
||||
data = catalog['token']
|
||||
else:
|
||||
data = {
|
||||
'issued_at': catalog['issued_at'],
|
||||
'expires': catalog['expires_at'],
|
||||
'id': catalog['auth_token'],
|
||||
'audit_ids': catalog['audit_ids'],
|
||||
'tenant': catalog['project'],
|
||||
}
|
||||
cliutils.print_dict(data, "Token")
|
||||
|
||||
_quota_resources = [
|
||||
'shares',
|
||||
|
Loading…
x
Reference in New Issue
Block a user