From 6a2a028c8c198d74572cf8eb4d89d0d859d8567a Mon Sep 17 00:00:00 2001 From: Michael McCune Date: Tue, 25 Aug 2015 11:30:40 -0400 Subject: [PATCH] adding neutron to sessions module this change adds neutron to the sessions module and updates the neutron client to use sessions and auth plugins. it also adjust the ssh_remote module to not pass the endpoint url as this will be determined by the session. * adding neutron to sessions module * updating neutron client to use sessions and auth plugin * removing endpoint url discovery for neutron from ssh_remote * adding neutron to session tests * fixing neutron client tests * fixing ssh_remote tests * renaming token_auth function in keystone to make it more public Change-Id: Icaa71a06d36c6828366f8d322ec3bed3e238506b Partial-Implements: blueprint keystone-sessions --- sahara/service/sessions.py | 13 +++++ sahara/tests/unit/service/test_sessions.py | 20 ++++++++ sahara/tests/unit/utils/test_neutron.py | 5 +- sahara/tests/unit/utils/test_ssh_remote.py | 3 +- sahara/utils/openstack/keystone.py | 60 ++++++++++++---------- sahara/utils/openstack/neutron.py | 28 ++++------ sahara/utils/ssh_remote.py | 6 +-- 7 files changed, 81 insertions(+), 54 deletions(-) diff --git a/sahara/service/sessions.py b/sahara/service/sessions.py index 3400e7d9..eb093de3 100644 --- a/sahara/service/sessions.py +++ b/sahara/service/sessions.py @@ -30,6 +30,7 @@ _SESSION_CACHE = None SESSION_TYPE_CINDER = 'cinder' SESSION_TYPE_GENERIC = 'generic' SESSION_TYPE_KEYSTONE = 'keystone' +SESSION_TYPE_NEUTRON = 'neutron' SESSION_TYPE_NOVA = 'nova' @@ -59,6 +60,7 @@ class SessionCache(object): SESSION_TYPE_CINDER: self.get_cinder_session, SESSION_TYPE_GENERIC: self.get_generic_session, SESSION_TYPE_KEYSTONE: self.get_keystone_session, + SESSION_TYPE_NEUTRON: self.get_neutron_session, SESSION_TYPE_NOVA: self.get_nova_session, } @@ -120,6 +122,17 @@ class SessionCache(object): self._set_session(SESSION_TYPE_KEYSTONE, session) return session + def get_neutron_session(self): + session = self._sessions.get(SESSION_TYPE_NEUTRON) + if not session: + if CONF.neutron.ca_file: + session = keystone.Session(cert=CONF.neutron.ca_file, + verify=CONF.neutron.api_insecure) + else: + session = self.get_generic_session() + self._set_session(SESSION_TYPE_NEUTRON, session) + return session + def get_nova_session(self): session = self._sessions.get(SESSION_TYPE_NOVA) if not session: diff --git a/sahara/tests/unit/service/test_sessions.py b/sahara/tests/unit/service/test_sessions.py index 8a501c4f..4202e0c6 100644 --- a/sahara/tests/unit/service/test_sessions.py +++ b/sahara/tests/unit/service/test_sessions.py @@ -91,3 +91,23 @@ class TestSessionCache(base.SaharaTestCase): keystone_session.reset_mock() sc.get_session(sessions.SESSION_TYPE_CINDER) self.assertFalse(keystone_session.called) + + @mock.patch('keystoneclient.session.Session') + def test_get_neutron_session(self, keystone_session): + sc = sessions.SessionCache() + self.override_config('ca_file', '/some/cacert', group='neutron') + self.override_config('api_insecure', True, group='neutron') + sc.get_session(sessions.SESSION_TYPE_NEUTRON) + keystone_session.assert_called_once_with(cert='/some/cacert', + verify=True) + + sc = sessions.SessionCache() + keystone_session.reset_mock() + self.override_config('ca_file', None, group='neutron') + self.override_config('api_insecure', None, group='neutron') + sc.get_session(sessions.SESSION_TYPE_NEUTRON) + keystone_session.assert_called_once_with() + + keystone_session.reset_mock() + sc.get_session(sessions.SESSION_TYPE_NEUTRON) + self.assertFalse(keystone_session.called) diff --git a/sahara/tests/unit/utils/test_neutron.py b/sahara/tests/unit/utils/test_neutron.py index 0d94a4a0..c9e1dd0d 100644 --- a/sahara/tests/unit/utils/test_neutron.py +++ b/sahara/tests/unit/utils/test_neutron.py @@ -20,11 +20,12 @@ from sahara.utils.openstack import neutron as neutron_client class NeutronClientTest(testtools.TestCase): + @mock.patch("sahara.utils.openstack.keystone.token_auth") @mock.patch("neutronclient.neutron.client.Client") - def test_get_router(self, patched): + def test_get_router(self, patched, token_auth): patched.side_effect = _test_get_neutron_client neutron = neutron_client.NeutronClient( - '33b47310-b7a8-4559-bf95-45ba669a448e', None, None, None) + '33b47310-b7a8-4559-bf95-45ba669a448e', None, None) self.assertEqual('6c4d4e32-3667-4cd4-84ea-4cc1e98d18be', neutron.get_router()) diff --git a/sahara/tests/unit/utils/test_ssh_remote.py b/sahara/tests/unit/utils/test_ssh_remote.py index 87c33e0e..2d9a3821 100644 --- a/sahara/tests/unit/utils/test_ssh_remote.py +++ b/sahara/tests/unit/utils/test_ssh_remote.py @@ -123,9 +123,10 @@ class TestInstanceInteropHelper(base.SaharaTestCase): # When use_floating_ips=False and use_namespaces=True, a netcat socket # created with 'ip netns exec qrouter-...' should be used to access # instances. + @mock.patch("sahara.utils.openstack.keystone.token_auth") @mock.patch('sahara.utils.ssh_remote._simple_exec_func') @mock.patch('sahara.utils.ssh_remote.ProxiedHTTPAdapter') - def test_use_namespaces(self, p_adapter, p_simple_exec_func): + def test_use_namespaces(self, p_adapter, p_simple_exec_func, token_auth): self.override_config('use_floating_ips', False) self.override_config('use_namespaces', True) diff --git a/sahara/utils/openstack/keystone.py b/sahara/utils/openstack/keystone.py index 372f97b0..636b92d3 100644 --- a/sahara/utils/openstack/keystone.py +++ b/sahara/utils/openstack/keystone.py @@ -77,7 +77,8 @@ CONF.register_opts(ssl_opts, group=keystone_group) def auth(): '''Return a token auth plugin for the current context.''' ctx = context.current() - return ctx.auth_plugin or _token_auth(ctx.auth_token, ctx.tenant_id) + return ctx.auth_plugin or token_auth(token=ctx.auth_token, + project_id=ctx.tenant_id) def auth_for_admin(project_name=None, trust_id=None): @@ -188,6 +189,36 @@ def session_for_admin(): return keystone_session.Session(auth=auth) +def token_auth(token, project_id=None, project_name=None, + project_domain_name='Default'): + '''Return a token auth plugin object. + + :param token: the token to use for authentication. + + :param project_id: the project(ex. tenant) id to scope the auth. + + :returns: a token auth plugin object. + ''' + token_kwargs = dict( + auth_url=base.retrieve_auth_url(), + token=token + ) + if CONF.use_identity_api_v3: + token_kwargs.update(dict( + project_id=project_id, + project_name=project_name, + project_domain_name=project_domain_name, + )) + auth = keystone_identity.v3.Token(**token_kwargs) + else: + token_kwargs.update(dict( + tenant_id=project_id, + tenant_name=project_name, + )) + auth = keystone_identity.v2.Token(**token_kwargs) + return auth + + def token_from_auth(auth): '''Return an authentication token from an auth plugin. @@ -278,30 +309,3 @@ def _password_auth(username, password, project_name, user_domain_name=None, )) auth = keystone_identity.v2.Password(**passwd_kwargs) return auth - - -def _token_auth(token, project_id, project_domain_name='Default'): - '''Return a token auth plugin object. - - :param token: the token to use for authentication. - - :param project_id: the project(ex. tenant) id to scope the auth. - - :returns: a token auth plugin object. - ''' - token_kwargs = dict( - auth_url=base.retrieve_auth_url(), - token=token - ) - if CONF.use_identity_api_v3: - token_kwargs.update(dict( - project_id=project_id, - project_domain_name=project_domain_name, - )) - auth = keystone_identity.v3.Token(**token_kwargs) - else: - token_kwargs.update(dict( - tenant_id=project_id - )) - auth = keystone_identity.v2.Token(**token_kwargs) - return auth diff --git a/sahara/utils/openstack/neutron.py b/sahara/utils/openstack/neutron.py index 6459aff0..0bbfc318 100644 --- a/sahara/utils/openstack/neutron.py +++ b/sahara/utils/openstack/neutron.py @@ -18,10 +18,11 @@ from neutronclient.neutron import client as neutron_cli from oslo_config import cfg from oslo_log import log as logging -from sahara import context from sahara import exceptions as ex from sahara.i18n import _ +from sahara.service import sessions from sahara.utils.openstack import base +from sahara.utils.openstack import keystone opts = [ @@ -44,30 +45,19 @@ LOG = logging.getLogger(__name__) def client(): - ctx = context.ctx() - args = { - 'username': ctx.username, - 'tenant_name': ctx.tenant_name, - 'tenant_id': ctx.tenant_id, - 'token': ctx.auth_token, - 'endpoint_url': base.url_for(ctx.service_catalog, 'network'), - 'ca_cert': CONF.neutron.ca_file, - 'insecure': CONF.neutron.api_insecure - } - return neutron_cli.Client('2.0', **args) + session = sessions.cache().get_session(sessions.SESSION_TYPE_NEUTRON) + neutron = neutron_cli.Client('2.0', session=session, auth=keystone.auth()) + return neutron class NeutronClient(object): neutron = None routers = {} - def __init__(self, network, uri, token, tenant_name): - self.neutron = neutron_cli.Client('2.0', - endpoint_url=uri, - token=token, - tenant_name=tenant_name, - ca_cert=CONF.neutron.ca_file, - insecure=CONF.neutron.api_insecure) + def __init__(self, network, token, tenant_name): + session = sessions.cache().get_session(sessions.SESSION_TYPE_NEUTRON) + auth = keystone.token_auth(token=token, project_name=tenant_name) + self.neutron = neutron_cli.Client('2.0', session=session, auth=auth) self.network = network def get_router(self): diff --git a/sahara/utils/ssh_remote.py b/sahara/utils/ssh_remote.py index dee26d15..130cd6bc 100644 --- a/sahara/utils/ssh_remote.py +++ b/sahara/utils/ssh_remote.py @@ -54,7 +54,6 @@ from sahara import exceptions as ex from sahara.i18n import _ from sahara.i18n import _LE from sahara.utils import crypto -from sahara.utils.openstack import base from sahara.utils.openstack import neutron from sahara.utils import procutils from sahara.utils import remote @@ -545,7 +544,6 @@ class InstanceInteropHelper(remote.Remote): neutron_info = dict() neutron_info['network'] = instance.cluster.neutron_management_network ctx = context.current() - neutron_info['uri'] = base.url_for(ctx.service_catalog, 'network') neutron_info['token'] = ctx.auth_token neutron_info['tenant'] = ctx.tenant_name neutron_info['host'] = instance.management_ip @@ -566,8 +564,8 @@ class InstanceInteropHelper(remote.Remote): # Query Neutron only if needed if '{router_id}' in command: - client = neutron.NeutronClient(info['network'], info['uri'], - info['token'], info['tenant']) + client = neutron.NeutronClient(info['network'], info['token'], + info['tenant']) keywords['router_id'] = client.get_router() keywords['host'] = instance.management_ip