From 9ec9fdce626d5e2937c6e0664621ad590f958e13 Mon Sep 17 00:00:00 2001 From: Russell Bryant Date: Fri, 4 May 2012 22:56:11 -0400 Subject: Add version to consoleauth rpc API. Part of blueprint versioned-rpc-apis. Change-Id: I9682bdbd06d744141b94385992b37cd2e55b8f5e --- nova/compute/api.py | 13 ++---- nova/consoleauth/manager.py | 2 + nova/consoleauth/rpcapi.py | 53 +++++++++++++++++++++ nova/tests/consoleauth/__init__.py | 19 ++++++++ nova/tests/consoleauth/test_consoleauth.py | 55 ++++++++++++++++++++++ nova/tests/consoleauth/test_rpcapi.py | 74 ++++++++++++++++++++++++++++++ nova/tests/test_compute.py | 17 +++---- nova/tests/test_consoleauth.py | 55 ---------------------- nova/vnc/xvp_proxy.py | 8 ++-- 9 files changed, 218 insertions(+), 78 deletions(-) create mode 100644 nova/consoleauth/rpcapi.py create mode 100644 nova/tests/consoleauth/__init__.py create mode 100644 nova/tests/consoleauth/test_consoleauth.py create mode 100644 nova/tests/consoleauth/test_rpcapi.py delete mode 100644 nova/tests/test_consoleauth.py diff --git a/nova/compute/api.py b/nova/compute/api.py index 7ede3c8ec..c01b1dcfc 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -33,6 +33,7 @@ from nova.compute import power_state from nova.compute import task_states from nova.compute import vm_states from nova import crypto +from nova.consoleauth import rpcapi as consoleauth_rpcapi from nova.db import base from nova import exception from nova import flags @@ -162,6 +163,7 @@ class API(BaseAPI): self.network_api = network_api or network.API() self.volume_api = volume_api or volume.API() + self.consoleauth_rpcapi = consoleauth_rpcapi.ConsoleAuthAPI() super(API, self).__init__(**kwargs) def _check_injected_file_quota(self, context, injected_files): @@ -1630,14 +1632,9 @@ class API(BaseAPI): connect_info = self._call_compute_message('get_vnc_console', context, instance, params={"console_type": console_type}) - rpc.call(context, '%s' % FLAGS.consoleauth_topic, - {'method': 'authorize_console', - 'args': {'token': connect_info['token'], - 'console_type': console_type, - 'host': connect_info['host'], - 'port': connect_info['port'], - 'internal_access_path': - connect_info['internal_access_path']}}) + self.consoleauth_rpcapi.authorize_console(context, + connect_info['token'], console_type, connect_info['host'], + connect_info['port'], connect_info['internal_access_path']) return {'url': connect_info['access_url']} diff --git a/nova/consoleauth/manager.py b/nova/consoleauth/manager.py index 27e3cb74d..a5c133e7a 100644 --- a/nova/consoleauth/manager.py +++ b/nova/consoleauth/manager.py @@ -45,6 +45,8 @@ FLAGS.register_opts(consoleauth_opts) class ConsoleAuthManager(manager.Manager): """Manages token based authentication.""" + RPC_API_VERSION = '1.0' + def __init__(self, scheduler_driver=None, *args, **kwargs): super(ConsoleAuthManager, self).__init__(*args, **kwargs) self.tokens = {} diff --git a/nova/consoleauth/rpcapi.py b/nova/consoleauth/rpcapi.py new file mode 100644 index 000000000..5cb940a34 --- /dev/null +++ b/nova/consoleauth/rpcapi.py @@ -0,0 +1,53 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012, Red Hat, Inc. +# +# 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. + +""" +Client side of the consoleauth RPC API. +""" + +from nova import flags +import nova.rpc.proxy + + +FLAGS = flags.FLAGS + + +class ConsoleAuthAPI(nova.rpc.proxy.RpcProxy): + '''Client side of the consoleauth rpc API. + + API version history: + + 1.0 - Initial version. + ''' + + RPC_API_VERSION = '1.0' + + def __init__(self): + super(ConsoleAuthAPI, self).__init__(topic=FLAGS.consoleauth_topic, + default_version=self.RPC_API_VERSION) + + def authorize_console(self, ctxt, token, console_type, host, port, + internal_access_path): + # The remote side doesn't return anything, but we want to block + # until it completes. + return self.call(ctxt, + self.make_msg('authorize_console', + token=token, console_type=console_type, + host=host, port=port, + internal_access_path=internal_access_path)) + + def check_token(self, ctxt, token): + return self.call(ctxt, self.make_msg('check_token', token=token)) diff --git a/nova/tests/consoleauth/__init__.py b/nova/tests/consoleauth/__init__.py new file mode 100644 index 000000000..7e04e7c73 --- /dev/null +++ b/nova/tests/consoleauth/__init__.py @@ -0,0 +1,19 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# 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. + +# NOTE(vish): this forces the fixtures from tests/__init.py:setup() to work +from nova.tests import * diff --git a/nova/tests/consoleauth/test_consoleauth.py b/nova/tests/consoleauth/test_consoleauth.py new file mode 100644 index 000000000..fd30bc2d2 --- /dev/null +++ b/nova/tests/consoleauth/test_consoleauth.py @@ -0,0 +1,55 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 OpenStack LLC. +# Administrator of the National Aeronautics and Space Administration. +# 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. +""" +Tests for Consoleauth Code. + +""" + +import time + +from nova.consoleauth import manager +from nova import context +from nova import db +from nova import flags +from nova import log as logging +from nova.openstack.common import importutils +from nova import test +from nova import utils + + +FLAGS = flags.FLAGS +LOG = logging.getLogger(__name__) + + +class ConsoleauthTestCase(test.TestCase): + """Test Case for consoleauth.""" + + def setUp(self): + super(ConsoleauthTestCase, self).setUp() + self.manager = manager.ConsoleAuthManager() + self.context = context.get_admin_context() + + def test_tokens_expire(self): + """Test that tokens expire correctly.""" + token = 'mytok' + self.flags(console_token_ttl=1) + self.manager.authorize_console(self.context, token, 'novnc', + '127.0.0.1', 'host', '') + self.assertTrue(self.manager.check_token(self.context, token)) + time.sleep(1.1) + self.assertFalse(self.manager.check_token(self.context, token)) diff --git a/nova/tests/consoleauth/test_rpcapi.py b/nova/tests/consoleauth/test_rpcapi.py new file mode 100644 index 000000000..546183185 --- /dev/null +++ b/nova/tests/consoleauth/test_rpcapi.py @@ -0,0 +1,74 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012, Red Hat, Inc. +# +# 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. + +""" +Unit Tests for nova.consoleauth.rpcapi +""" + +from nova.consoleauth import rpcapi as consoleauth_rpcapi +from nova import context +from nova import flags +from nova import rpc +from nova import test + + +FLAGS = flags.FLAGS + + +class ConsoleAuthRpcAPITestCase(test.TestCase): + + def setUp(self): + super(ConsoleAuthRpcAPITestCase, self).setUp() + + def tearDown(self): + super(ConsoleAuthRpcAPITestCase, self).tearDown() + + def _test_consoleauth_api(self, method, **kwargs): + ctxt = context.RequestContext('fake_user', 'fake_project') + rpcapi = consoleauth_rpcapi.ConsoleAuthAPI() + expected_retval = 'foo' + expected_msg = rpcapi.make_msg(method, **kwargs) + expected_msg['version'] = rpcapi.RPC_API_VERSION + + self.call_ctxt = None + self.call_topic = None + self.call_msg = None + self.call_timeout = None + + def _fake_call(_ctxt, _topic, _msg, _timeout): + self.call_ctxt = _ctxt + self.call_topic = _topic + self.call_msg = _msg + self.call_timeout = _timeout + return expected_retval + + self.stubs.Set(rpc, 'call', _fake_call) + + retval = getattr(rpcapi, method)(ctxt, **kwargs) + + self.assertEqual(retval, expected_retval) + self.assertEqual(self.call_ctxt, ctxt) + self.assertEqual(self.call_topic, FLAGS.consoleauth_topic) + self.assertEqual(self.call_msg, expected_msg) + self.assertEqual(self.call_timeout, None) + + def test_authorize_console(self): + self._test_consoleauth_api('authorize_console', token='token', + console_type='ctype', host='h', port='p', + internal_access_path='iap') + + def test_check_token(self): + self._test_consoleauth_api('check_token', token='t') diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 265edf8a9..deb852e68 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -3484,26 +3484,23 @@ class ComputeAPITestCase(BaseTestCase): 'console_type': fake_console_type, 'host': 'fake_console_host', 'port': 'fake_console_port', - 'internal_access_path': 'fake_access_path', - 'access_url': 'fake_console_url'} + 'internal_access_path': 'fake_access_path'} + fake_connect_info2 = copy.deepcopy(fake_connect_info) + fake_connect_info2['access_url'] = 'fake_console_url' self.mox.StubOutWithMock(rpc, 'call') rpc_msg1 = {'method': 'get_vnc_console', 'args': {'instance_uuid': fake_instance['uuid'], 'console_type': fake_console_type}} - # 2nd rpc.call receives almost everything from fake_connect_info - # except 'access_url' - rpc_msg2_args = dict([(k, v) - for k, v in fake_connect_info.items() - if k != 'access_url']) rpc_msg2 = {'method': 'authorize_console', - 'args': rpc_msg2_args} + 'args': fake_connect_info, + 'version': '1.0'} rpc.call(self.context, 'compute.%s' % fake_instance['host'], - rpc_msg1).AndReturn(fake_connect_info) + rpc_msg1).AndReturn(fake_connect_info2) rpc.call(self.context, FLAGS.consoleauth_topic, - rpc_msg2).AndReturn(None) + rpc_msg2, None).AndReturn(None) self.mox.ReplayAll() diff --git a/nova/tests/test_consoleauth.py b/nova/tests/test_consoleauth.py deleted file mode 100644 index ba336ccd5..000000000 --- a/nova/tests/test_consoleauth.py +++ /dev/null @@ -1,55 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 OpenStack LLC. -# Administrator of the National Aeronautics and Space Administration. -# 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. -""" -Tests for Consoleauth Code. - -""" - -import time - -from nova.consoleauth import manager -from nova import context -from nova import db -from nova import flags -from nova import log as logging -from nova.openstack.common import importutils -from nova import test -from nova import utils - - -FLAGS = flags.FLAGS -LOG = logging.getLogger(__name__) - - -class ConsoleauthTestCase(test.TestCase): - """Test Case for consoleauth.""" - - def setUp(self): - super(ConsoleauthTestCase, self).setUp() - self.manager = importutils.import_object(FLAGS.consoleauth_manager) - self.context = context.get_admin_context() - - def test_tokens_expire(self): - """Test that tokens expire correctly.""" - token = 'mytok' - self.flags(console_token_ttl=1) - self.manager.authorize_console(self.context, token, 'novnc', - '127.0.0.1', 'host', '') - self.assertTrue(self.manager.check_token(self.context, token)) - time.sleep(1.1) - self.assertFalse(self.manager.check_token(self.context, token)) diff --git a/nova/vnc/xvp_proxy.py b/nova/vnc/xvp_proxy.py index 5aedfe0fb..1eca54530 100644 --- a/nova/vnc/xvp_proxy.py +++ b/nova/vnc/xvp_proxy.py @@ -26,6 +26,7 @@ import eventlet.green import eventlet.greenio import eventlet.wsgi +from nova.consoleauth import rpcapi as consoleauth_rpcapi from nova import context from nova import flags from nova import log as logging @@ -49,8 +50,6 @@ xvp_proxy_opts = [ FLAGS = flags.FLAGS FLAGS.register_opts(xvp_proxy_opts) -flags.DECLARE('consoleauth_topic', 'nova.consoleauth') - class XCPVNCProxy(object): """Class to use the xvp auth protocol to proxy instance vnc consoles.""" @@ -145,9 +144,8 @@ class XCPVNCProxy(object): return "Invalid Request" ctxt = context.get_admin_context() - connect_info = rpc.call(ctxt, FLAGS.consoleauth_topic, - {'method': 'check_token', - 'args': {'token': token}}) + api = consoleauth_rpcapi.ConsoleAuthAPI() + connect_info = api.check_token(ctxt, token) if not connect_info: LOG.audit(_("Request made with invalid token: %s"), req) -- cgit