From f50ce35c9cf2e05d205485586da1cb6d5433ba56 Mon Sep 17 00:00:00 2001 From: Russell Bryant Date: Wed, 16 May 2012 16:31:39 -0400 Subject: Add version to console rpc API. Part of blueprint versioned-rpc-apis. Change-Id: I17d6e3094c56d8628688dabdc8d40b2f4f815af4 --- nova/console/api.py | 23 +++----- nova/console/manager.py | 2 + nova/console/rpcapi.py | 47 +++++++++++++++ nova/tests/console/__init__.py | 19 ++++++ nova/tests/console/test_console.py | 118 +++++++++++++++++++++++++++++++++++++ nova/tests/console/test_rpcapi.py | 66 +++++++++++++++++++++ nova/tests/test_console.py | 118 ------------------------------------- 7 files changed, 261 insertions(+), 132 deletions(-) create mode 100644 nova/console/rpcapi.py create mode 100644 nova/tests/console/__init__.py create mode 100644 nova/tests/console/test_console.py create mode 100644 nova/tests/console/test_rpcapi.py delete mode 100644 nova/tests/test_console.py diff --git a/nova/console/api.py b/nova/console/api.py index dd166052f..0feaae488 100644 --- a/nova/console/api.py +++ b/nova/console/api.py @@ -17,6 +17,7 @@ """Handles ConsoleProxy API requests.""" +from nova.console import rpcapi as console_rpcapi from nova.db import base from nova import flags from nova import rpc @@ -42,16 +43,11 @@ class API(base.Base): def delete_console(self, context, instance_id, console_id): instance_id = self._translate_uuid_if_necessary(context, instance_id) - console = self.db.console_get(context, - console_id, - instance_id) - pool = console['pool'] - rpc.cast(context, - self.db.queue_get_for(context, - FLAGS.console_topic, - pool['host']), - {'method': 'remove_console', - 'args': {'console_id': console['id']}}) + console = self.db.console_get(context, console_id, instance_id) + topic = self.db.queue_get_for(context, FLAGS.console_topic, + pool['host']) + rpcapi = console_rpcapi.ConsoleAPI(topic=topic) + rpcapi.remove_console(context, console['id']) def create_console(self, context, instance_id): #NOTE(mdragon): If we wanted to return this the console info @@ -60,10 +56,9 @@ class API(base.Base): # console info. I am not sure which is better # here. instance = self._get_instance(context, instance_id) - rpc.cast(context, - self._get_console_topic(context, instance['host']), - {'method': 'add_console', - 'args': {'instance_id': instance['id']}}) + topic = self._get_console_topic(context, instance['host']), + rpcapi = console_rpcapi.ConsoleAPI(topic=topic) + rpcapi.add_console(context, instance['id']) def _get_console_topic(self, context, instance_host): topic = self.db.queue_get_for(context, diff --git a/nova/console/manager.py b/nova/console/manager.py index 335de3284..8a42b449a 100644 --- a/nova/console/manager.py +++ b/nova/console/manager.py @@ -53,6 +53,8 @@ class ConsoleProxyManager(manager.Manager): """ + RPC_API_VERSION = '1.0' + def __init__(self, console_driver=None, *args, **kwargs): if not console_driver: console_driver = FLAGS.console_driver diff --git a/nova/console/rpcapi.py b/nova/console/rpcapi.py new file mode 100644 index 000000000..8f0c5b97f --- /dev/null +++ b/nova/console/rpcapi.py @@ -0,0 +1,47 @@ +# 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 console RPC API. +""" + +from nova import flags +import nova.rpc.proxy + + +FLAGS = flags.FLAGS + + +class ConsoleAPI(nova.rpc.proxy.RpcProxy): + '''Client side of the console rpc API. + + API version history: + + 1.0 - Initial version. + ''' + + RPC_API_VERSION = '1.0' + + def __init__(self, topic=None): + topic = topic if topic else FLAGS.console_topic + super(ConsoleAPI, self).__init__(topic=topic, + default_version=self.RPC_API_VERSION) + + def add_console(self, ctxt, instance_id): + self.cast(ctxt, self.make_msg('add_console', instance_id=instance_id)) + + def remove_console(self, ctxt, console_id): + self.cast(ctxt, self.make_msg('remove_console', console_id=console_id)) diff --git a/nova/tests/console/__init__.py b/nova/tests/console/__init__.py new file mode 100644 index 000000000..7e04e7c73 --- /dev/null +++ b/nova/tests/console/__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/console/test_console.py b/nova/tests/console/test_console.py new file mode 100644 index 000000000..626cf2206 --- /dev/null +++ b/nova/tests/console/test_console.py @@ -0,0 +1,118 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2010 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 Console proxy.""" + +from nova import context +from nova import db +from nova import exception +from nova import flags +from nova.openstack.common import importutils +from nova import test + +FLAGS = flags.FLAGS +flags.DECLARE('console_driver', 'nova.console.manager') + + +class ConsoleTestCase(test.TestCase): + """Test case for console proxy""" + def setUp(self): + super(ConsoleTestCase, self).setUp() + self.flags(console_driver='nova.console.fake.FakeConsoleProxy', + stub_compute=True) + self.console = importutils.import_object(FLAGS.console_manager) + self.user_id = 'fake' + self.project_id = 'fake' + self.context = context.RequestContext(self.user_id, self.project_id) + self.host = 'test_compute_host' + + def _create_instance(self): + """Create a test instance""" + inst = {} + #inst['host'] = self.host + #inst['name'] = 'instance-1234' + inst['image_id'] = 1 + inst['reservation_id'] = 'r-fakeres' + inst['launch_time'] = '10' + inst['user_id'] = self.user_id + inst['project_id'] = self.project_id + inst['instance_type_id'] = 1 + inst['ami_launch_index'] = 0 + return db.instance_create(self.context, inst)['id'] + + def test_get_pool_for_instance_host(self): + pool = self.console.get_pool_for_instance_host(self.context, + self.host) + self.assertEqual(pool['compute_host'], self.host) + + def test_get_pool_creates_new_pool_if_needed(self): + self.assertRaises(exception.NotFound, + db.console_pool_get_by_host_type, + self.context, + self.host, + self.console.host, + self.console.driver.console_type) + pool = self.console.get_pool_for_instance_host(self.context, + self.host) + pool2 = db.console_pool_get_by_host_type(self.context, + self.host, + self.console.host, + self.console.driver.console_type) + self.assertEqual(pool['id'], pool2['id']) + + def test_get_pool_does_not_create_new_pool_if_exists(self): + pool_info = {'address': '127.0.0.1', + 'username': 'test', + 'password': '1234pass', + 'host': self.console.host, + 'console_type': self.console.driver.console_type, + 'compute_host': 'sometesthostname'} + new_pool = db.console_pool_create(self.context, pool_info) + pool = self.console.get_pool_for_instance_host(self.context, + 'sometesthostname') + self.assertEqual(pool['id'], new_pool['id']) + + def test_add_console(self): + instance_id = self._create_instance() + self.console.add_console(self.context, instance_id) + instance = db.instance_get(self.context, instance_id) + pool = db.console_pool_get_by_host_type(self.context, + instance['host'], self.console.host, + self.console.driver.console_type) + + console_instances = [con['instance_id'] for con in pool.consoles] + self.assert_(instance_id in console_instances) + db.instance_destroy(self.context, instance_id) + + def test_add_console_does_not_duplicate(self): + instance_id = self._create_instance() + cons1 = self.console.add_console(self.context, instance_id) + cons2 = self.console.add_console(self.context, instance_id) + self.assertEqual(cons1, cons2) + db.instance_destroy(self.context, instance_id) + + def test_remove_console(self): + instance_id = self._create_instance() + console_id = self.console.add_console(self.context, instance_id) + self.console.remove_console(self.context, console_id) + + self.assertRaises(exception.NotFound, + db.console_get, + self.context, + console_id) + db.instance_destroy(self.context, instance_id) diff --git a/nova/tests/console/test_rpcapi.py b/nova/tests/console/test_rpcapi.py new file mode 100644 index 000000000..132657697 --- /dev/null +++ b/nova/tests/console/test_rpcapi.py @@ -0,0 +1,66 @@ +# 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.console.rpcapi +""" + +from nova.console import rpcapi as console_rpcapi +from nova import context +from nova import flags +from nova import rpc +from nova import test + + +FLAGS = flags.FLAGS + + +class ConsoleRpcAPITestCase(test.TestCase): + + def setUp(self): + super(ConsoleRpcAPITestCase, self).setUp() + + def tearDown(self): + super(ConsoleRpcAPITestCase, self).tearDown() + + def _test_console_api(self, method, **kwargs): + ctxt = context.RequestContext('fake_user', 'fake_project') + rpcapi = console_rpcapi.ConsoleAPI() + expected_msg = rpcapi.make_msg(method, **kwargs) + expected_msg['version'] = rpcapi.RPC_API_VERSION + + self.cast_ctxt = None + self.cast_topic = None + self.cast_msg = None + + def _fake_cast(_ctxt, _topic, _msg): + self.cast_ctxt = _ctxt + self.cast_topic = _topic + self.cast_msg = _msg + + self.stubs.Set(rpc, 'cast', _fake_cast) + + getattr(rpcapi, method)(ctxt, **kwargs) + + self.assertEqual(self.cast_ctxt, ctxt) + self.assertEqual(self.cast_topic, FLAGS.console_topic) + self.assertEqual(self.cast_msg, expected_msg) + + def test_add_console(self): + self._test_console_api('add_console', instance_id='i') + + def test_remove_console(self): + self._test_console_api('remove_console', console_id='i') diff --git a/nova/tests/test_console.py b/nova/tests/test_console.py deleted file mode 100644 index c65d3c126..000000000 --- a/nova/tests/test_console.py +++ /dev/null @@ -1,118 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2010 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 Console proxy.""" - -from nova import context -from nova import db -from nova import exception -from nova import flags -from nova.openstack.common import importutils -from nova import test - -FLAGS = flags.FLAGS -flags.DECLARE('console_driver', 'nova.console.manager') - - -class ConsoleTestCase(test.TestCase): - """Test case for console proxy""" - def setUp(self): - super(ConsoleTestCase, self).setUp() - self.flags(console_driver='nova.console.fake.FakeConsoleProxy', - stub_compute=True) - self.console = importutils.import_object(FLAGS.console_manager) - self.user_id = 'fake' - self.project_id = 'fake' - self.context = context.RequestContext(self.user_id, self.project_id) - self.host = 'test_compute_host' - - def _create_instance(self): - """Create a test instance""" - inst = {} - #inst['host'] = self.host - #inst['name'] = 'instance-1234' - inst['image_id'] = 1 - inst['reservation_id'] = 'r-fakeres' - inst['launch_time'] = '10' - inst['user_id'] = self.user_id - inst['project_id'] = self.project_id - inst['instance_type_id'] = 1 - inst['ami_launch_index'] = 0 - return db.instance_create(self.context, inst)['id'] - - def test_get_pool_for_instance_host(self): - pool = self.console.get_pool_for_instance_host(self.context, self.host) - self.assertEqual(pool['compute_host'], self.host) - - def test_get_pool_creates_new_pool_if_needed(self): - self.assertRaises(exception.NotFound, - db.console_pool_get_by_host_type, - self.context, - self.host, - self.console.host, - self.console.driver.console_type) - pool = self.console.get_pool_for_instance_host(self.context, - self.host) - pool2 = db.console_pool_get_by_host_type(self.context, - self.host, - self.console.host, - self.console.driver.console_type) - self.assertEqual(pool['id'], pool2['id']) - - def test_get_pool_does_not_create_new_pool_if_exists(self): - pool_info = {'address': '127.0.0.1', - 'username': 'test', - 'password': '1234pass', - 'host': self.console.host, - 'console_type': self.console.driver.console_type, - 'compute_host': 'sometesthostname'} - new_pool = db.console_pool_create(self.context, pool_info) - pool = self.console.get_pool_for_instance_host(self.context, - 'sometesthostname') - self.assertEqual(pool['id'], new_pool['id']) - - def test_add_console(self): - instance_id = self._create_instance() - self.console.add_console(self.context, instance_id) - instance = db.instance_get(self.context, instance_id) - pool = db.console_pool_get_by_host_type(self.context, - instance['host'], - self.console.host, - self.console.driver.console_type) - - console_instances = [con['instance_id'] for con in pool.consoles] - self.assert_(instance_id in console_instances) - db.instance_destroy(self.context, instance_id) - - def test_add_console_does_not_duplicate(self): - instance_id = self._create_instance() - cons1 = self.console.add_console(self.context, instance_id) - cons2 = self.console.add_console(self.context, instance_id) - self.assertEqual(cons1, cons2) - db.instance_destroy(self.context, instance_id) - - def test_remove_console(self): - instance_id = self._create_instance() - console_id = self.console.add_console(self.context, instance_id) - self.console.remove_console(self.context, console_id) - - self.assertRaises(exception.NotFound, - db.console_get, - self.context, - console_id) - db.instance_destroy(self.context, instance_id) -- cgit