diff --git a/doc/source/_extra/.htaccess b/doc/source/_extra/.htaccess index 252c414f41fe..a06ebeb3a4bb 100644 --- a/doc/source/_extra/.htaccess +++ b/doc/source/_extra/.htaccess @@ -31,7 +31,6 @@ redirectmatch 301 ^/nova/([^/]+)/man/nova-cells.html$ /nova/$1/cli/nova-cells.ht # this is gone and never coming back, indicate that to the end users redirectmatch 301 ^/nova/([^/]+)/man/nova-compute.html$ /nova/$1/cli/nova-compute.html redirectmatch 301 ^/nova/([^/]+)/man/nova-conductor.html$ /nova/$1/cli/nova-conductor.html -redirectmatch 301 ^/nova/([^/]+)/man/nova-console.html$ /nova/$1/cli/nova-console.html redirectmatch 301 ^/nova/([^/]+)/man/nova-dhcpbridge.html$ /nova/$1/cli/nova-dhcpbridge.html redirectmatch 301 ^/nova/([^/]+)/man/nova-manage.html$ /nova/$1/cli/nova-manage.html redirectmatch 301 ^/nova/([^/]+)/man/nova-network.html$ /nova/$1/cli/nova-network.html diff --git a/doc/source/cli/index.rst b/doc/source/cli/index.rst index 7aae96aae501..1ce869fb223e 100644 --- a/doc/source/cli/index.rst +++ b/doc/source/cli/index.rst @@ -87,5 +87,4 @@ deployments, but are documented for existing ones. nova-dhcpbridge nova-network - nova-console nova-xvpvncproxy diff --git a/doc/source/cli/nova-console.rst b/doc/source/cli/nova-console.rst deleted file mode 100644 index e7e752ad3953..000000000000 --- a/doc/source/cli/nova-console.rst +++ /dev/null @@ -1,54 +0,0 @@ -============ -nova-console -============ - -------------------- -Nova Console Server -------------------- - -:Author: openstack@lists.openstack.org -:Copyright: OpenStack Foundation -:Manual section: 1 -:Manual group: cloud computing - -Synopsis -======== - -:: - - nova-console [options] - -Description -=========== - -:program:`nova-console` is a server daemon that serves the Nova Console -service, which is a console proxy to set up multi-tenant VM console access, -e.g. with *XVP*. - -.. deprecated:: 19.0.0 - - :program:`nova-console` is deprecated since 19.0.0 (Stein) and will be - removed in an upcoming release. - -Options -======= - -**General options** - -Files -===== - -* ``/etc/nova/nova.conf`` -* ``/etc/nova/policy.json`` -* ``/etc/nova/rootwrap.conf`` -* ``/etc/nova/rootwrap.d/`` - -See Also -======== - -* :nova-doc:`OpenStack Nova <>` - -Bugs -==== - -* Nova bugs are managed at `Launchpad `__ diff --git a/doc/source/conf.py b/doc/source/conf.py index cd96c37cb27e..775509aa6bb1 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -86,7 +86,6 @@ _man_pages = [ ('nova-api-os-compute', u'Cloud controller fabric'), ('nova-compute', u'Cloud controller fabric'), ('nova-conductor', u'Cloud controller fabric'), - ('nova-console', u'Cloud controller fabric'), ('nova-dhcpbridge', u'Cloud controller fabric'), ('nova-manage', u'Cloud controller fabric'), ('nova-network', u'Cloud controller fabric'), diff --git a/doc/test/redirect-tests.txt b/doc/test/redirect-tests.txt index 425fed542cad..0bbe64cd1f7b 100644 --- a/doc/test/redirect-tests.txt +++ b/doc/test/redirect-tests.txt @@ -31,7 +31,6 @@ /nova/latest/man/nova-cells.html 301 /nova/latest/cli/nova-cells.html /nova/latest/man/nova-compute.html 301 /nova/latest/cli/nova-compute.html /nova/latest/man/nova-conductor.html 301 /nova/latest/cli/nova-conductor.html -/nova/latest/man/nova-console.html 301 /nova/latest/cli/nova-console.html /nova/latest/man/nova-dhcpbridge.html 301 /nova/latest/cli/nova-dhcpbridge.html /nova/latest/man/nova-manage.html 301 /nova/latest/cli/nova-manage.html /nova/latest/man/nova-network.html 301 /nova/latest/cli/nova-network.html diff --git a/nova/cmd/console.py b/nova/cmd/console.py deleted file mode 100644 index b5736b83d149..000000000000 --- a/nova/cmd/console.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) 2010 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. - -"""Starter script for Nova Console Proxy.""" - -import sys - -from oslo_config import cfg -from oslo_log import log as logging -from oslo_reports import guru_meditation_report as gmr -from oslo_reports import opts as gmr_opts - -from nova import config -from nova.console import rpcapi as console_rpcapi -from nova import objects -from nova import service -from nova import version - -CONF = cfg.CONF -LOG = logging.getLogger('nova.console') - - -def main(): - config.parse_args(sys.argv) - logging.setup(CONF, "nova") - objects.register_all() - gmr_opts.set_defaults(CONF) - - gmr.TextGuruMeditation.setup_autorun(version, conf=CONF) - - LOG.warning('The nova-console service is deprecated as it is Xen ' - 'specific, does not function properly in a multi-cell ' - 'environment, and has effectively been replaced by noVNC ' - 'and the nova-novncproxy service.') - - server = service.Service.create(binary='nova-console', - topic=console_rpcapi.RPC_TOPIC) - service.serve(server) - service.wait() diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 9d75675b6c06..6042c16591ff 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -69,7 +69,6 @@ from nova.compute.utils import wrap_instance_event from nova.compute import vm_states from nova import conductor import nova.conf -from nova.console import rpcapi as console_rpcapi import nova.context from nova import exception from nova import exception_wrapper @@ -1522,6 +1521,7 @@ class ComputeManager(manager.Manager): except exception.InstanceNotFound: return power_state.NOSTATE + # TODO(stephenfin): Remove this once we bump the compute API to v6.0 def get_console_topic(self, context): """Retrieves the console host for a project on this host. @@ -1529,7 +1529,7 @@ class ComputeManager(manager.Manager): """ # TODO(mdragon): perhaps make this variable by console_type? - return '%s.%s' % (console_rpcapi.RPC_TOPIC, CONF.console_host) + return 'console.%s' % CONF.console_host @wrap_exception() def get_console_pool_info(self, context, console_type): diff --git a/nova/compute/rpcapi.py b/nova/compute/rpcapi.py index b2445daa445f..75c3b804e642 100644 --- a/nova/compute/rpcapi.py +++ b/nova/compute/rpcapi.py @@ -709,6 +709,7 @@ class ComputeAPI(object): return cctxt.call(ctxt, 'get_console_pool_info', console_type=console_type) + # TODO(stephenfin): This is no longer used and can be removed in v6.0 def get_console_topic(self, ctxt, host): version = '5.0' cctxt = self.router.client(ctxt).prepare( diff --git a/nova/conf/upgrade_levels.py b/nova/conf/upgrade_levels.py index 07dc5fe84a02..19cc5e23b3b6 100644 --- a/nova/conf/upgrade_levels.py +++ b/nova/conf/upgrade_levels.py @@ -96,18 +96,6 @@ Conductor RPC API version cap. Possible values: -* By default send the latest version the client knows about -* A string representing a version number in the format 'N.N'; - for example, possible values might be '1.12' or '2.0'. -* An OpenStack release name, in lower case, such as 'mitaka' or - 'liberty'. -"""), - cfg.StrOpt('console', - help=""" -Console RPC API version cap. - -Possible values: - * By default send the latest version the client knows about * A string representing a version number in the format 'N.N'; for example, possible values might be '1.12' or '2.0'. diff --git a/nova/console/api.py b/nova/console/api.py deleted file mode 100644 index e5204d9bb4f9..000000000000 --- a/nova/console/api.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (c) 2010 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. - -"""Handles ConsoleProxy API requests.""" - - -from nova.compute import rpcapi as compute_rpcapi -from nova.console import rpcapi as console_rpcapi -from nova.db import base -from nova import objects - - -class API(base.Base): - """API for spinning up or down console proxy connections.""" - def get_consoles(self, context, instance_uuid): - return self.db.console_get_all_by_instance(context, instance_uuid, - columns_to_join=['pool']) - - def get_console(self, context, instance_uuid, console_uuid): - return self.db.console_get(context, console_uuid, instance_uuid) - - def delete_console(self, context, instance_uuid, console_uuid): - console = self.db.console_get(context, console_uuid, instance_uuid) - rpcapi = console_rpcapi.ConsoleAPI(topic=console_rpcapi.RPC_TOPIC, - server=console['pool']['host']) - rpcapi.remove_console(context, console['id']) - - def create_console(self, context, instance_uuid): - # NOTE(mdragon): If we wanted to return this the console info - # here, as we would need to do a call. - # They can just do an index later to fetch - # console info. I am not sure which is better - # here. - instance = objects.Instance.get_by_uuid(context, instance_uuid) - topic = self._get_console_topic(context, instance.host) - server = None - if '.' in topic: - topic, server = topic.split('.', 1) - rpcapi = console_rpcapi.ConsoleAPI(topic=topic, server=server) - rpcapi.add_console(context, instance.id) - - def _get_console_topic(self, context, instance_host): - rpcapi = compute_rpcapi.ComputeAPI() - return rpcapi.get_console_topic(context, instance_host) diff --git a/nova/console/manager.py b/nova/console/manager.py deleted file mode 100644 index a67abf4c8886..000000000000 --- a/nova/console/manager.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (c) 2010 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. - -"""Console Proxy Service.""" - -from oslo_log import log as logging -import oslo_messaging as messaging - -from nova.compute import rpcapi as compute_rpcapi -import nova.conf -from nova.console import xvp -from nova import exception -from nova import manager -from nova import objects -from nova import utils - - -CONF = nova.conf.CONF -LOG = logging.getLogger(__name__) - - -class ConsoleProxyManager(manager.Manager): - """Sets up and tears down any console proxy connections. - - Needed for accessing instance consoles securely. - - """ - - target = messaging.Target(version='2.0') - - def __init__(self, *args, **kwargs): - self.driver = xvp.XVPConsoleProxy() - super(ConsoleProxyManager, self).__init__(service_name='console', - *args, **kwargs) - self.driver.host = self.host - self.compute_rpcapi = compute_rpcapi.ComputeAPI() - - def reset(self): - LOG.info('Reloading compute RPC API') - compute_rpcapi.LAST_VERSION = None - self.compute_rpcapi = compute_rpcapi.ComputeAPI() - - def init_host(self): - self.driver.init_host() - - def add_console(self, context, instance_id): - instance = objects.Instance.get_by_id(context, instance_id) - host = instance.host - name = instance.name - pool = self._get_pool_for_instance_host(context, host) - try: - console = self.db.console_get_by_pool_instance(context, - pool['id'], - instance.uuid) - except exception.NotFound: - LOG.debug('Adding console', instance=instance) - password = utils.generate_password(8) - port = self.driver.get_port(context) - console_data = {'instance_name': name, - 'instance_uuid': instance.uuid, - 'password': password, - 'pool_id': pool['id']} - if port: - console_data['port'] = port - console = self.db.console_create(context, console_data) - self.driver.setup_console(context, console) - - return console['id'] - - def remove_console(self, context, console_id): - try: - console = self.db.console_get(context, console_id) - except exception.NotFound: - LOG.debug('Tried to remove non-existent console ' - '%(console_id)s.', - {'console_id': console_id}) - return - self.db.console_delete(context, console_id) - self.driver.teardown_console(context, console) - - def _get_pool_for_instance_host(self, context, instance_host): - context = context.elevated() - console_type = self.driver.console_type - try: - pool = self.db.console_pool_get_by_host_type(context, - instance_host, - self.host, - console_type) - except exception.NotFound: - # NOTE(mdragon): Right now, the only place this info exists is the - # compute worker's flagfile, at least for - # xenserver. Thus we need to ask. - pool_info = self.compute_rpcapi.get_console_pool_info(context, - instance_host, console_type) - pool_info['password'] = self.driver.fix_pool_password( - pool_info['password']) - pool_info['host'] = self.host - pool_info['public_hostname'] = \ - CONF.xenserver.console_public_hostname - pool_info['console_type'] = self.driver.console_type - pool_info['compute_host'] = instance_host - pool = self.db.console_pool_create(context, pool_info) - return pool diff --git a/nova/console/rpcapi.py b/nova/console/rpcapi.py deleted file mode 100644 index e1765561f391..000000000000 --- a/nova/console/rpcapi.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2013 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. -""" - -import oslo_messaging as messaging - -import nova.conf -from nova import profiler -from nova import rpc - -CONF = nova.conf.CONF -RPC_TOPIC = "console" - - -@profiler.trace_cls("rpc") -class ConsoleAPI(object): - '''Client side of the console rpc API. - - API version history: - - 1.0 - Initial version. - 1.1 - Added get_backdoor_port() - - ... Grizzly and Havana support message version 1.1. So, any changes to - existing methods in 1.x after that point should be done such that they - can handle the version_cap being set to 1.1. - - 2.0 - Major API rev for Icehouse - - ... Icehouse, Juno, Kilo, Liberty, Mitaka, Newton, and Ocata support - message version 2.0. So, any changes to existing methods in 2.x after - that point should be done such that they can handle the version_cap - being set to 2.0. - - ''' - - VERSION_ALIASES = { - 'grizzly': '1.1', - 'havana': '1.1', - 'icehouse': '2.0', - 'juno': '2.0', - 'kilo': '2.0', - 'liberty': '2.0', - 'mitaka': '2.0', - 'newton': '2.0', - 'ocata': '2.0', - } - - def __init__(self, topic=None, server=None): - super(ConsoleAPI, self).__init__() - topic = topic if topic else RPC_TOPIC - target = messaging.Target(topic=topic, server=server, version='2.0') - version_cap = self.VERSION_ALIASES.get(CONF.upgrade_levels.console, - CONF.upgrade_levels.console) - self.client = rpc.get_client(target, version_cap=version_cap) - - def add_console(self, ctxt, instance_id): - cctxt = self.client.prepare() - cctxt.cast(ctxt, 'add_console', instance_id=instance_id) - - def remove_console(self, ctxt, console_id): - cctxt = self.client.prepare() - cctxt.cast(ctxt, 'remove_console', console_id=console_id) diff --git a/nova/db/api.py b/nova/db/api.py index 5828970b4906..c9b6da6bdf4c 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -1413,21 +1413,7 @@ def project_get_networks(context, project_id, associate=True): return IMPL.project_get_networks(context, project_id, associate) -################### - - -def console_pool_create(context, values): - """Create console pool.""" - return IMPL.console_pool_create(context, values) - - -def console_pool_get_by_host_type(context, compute_host, proxy_host, - console_type): - """Fetch a console pool for a given proxy host, compute host, and type.""" - return IMPL.console_pool_get_by_host_type(context, - compute_host, - proxy_host, - console_type) +################## def console_pool_get_all_by_host_type(context, host, console_type): @@ -1437,31 +1423,6 @@ def console_pool_get_all_by_host_type(context, host, console_type): console_type) -def console_create(context, values): - """Create a console.""" - return IMPL.console_create(context, values) - - -def console_delete(context, console_id): - """Delete a console.""" - return IMPL.console_delete(context, console_id) - - -def console_get_by_pool_instance(context, pool_id, instance_uuid): - """Get console entry for a given instance and pool.""" - return IMPL.console_get_by_pool_instance(context, pool_id, instance_uuid) - - -def console_get_all_by_instance(context, instance_uuid, columns_to_join=None): - """Get consoles for a given instance.""" - return IMPL.console_get_all_by_instance(context, instance_uuid, - columns_to_join) - - -def console_get(context, console_id, instance_uuid=None): - """Get a specific console (possibly on a given instance).""" - return IMPL.console_get(context, console_id, instance_uuid) - ################## diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index af39e9e234d0..1191f2e5e236 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -4487,40 +4487,6 @@ def migration_migrate_to_uuid(context, count): ################## -@pick_context_manager_writer -def console_pool_create(context, values): - pool = models.ConsolePool() - pool.update(values) - try: - pool.save(context.session) - except db_exc.DBDuplicateEntry: - raise exception.ConsolePoolExists( - host=values["host"], - console_type=values["console_type"], - compute_host=values["compute_host"], - ) - return pool - - -@pick_context_manager_reader -def console_pool_get_by_host_type(context, compute_host, host, - console_type): - - result = model_query(context, models.ConsolePool, read_deleted="no").\ - filter_by(host=host).\ - filter_by(console_type=console_type).\ - filter_by(compute_host=compute_host).\ - options(joinedload('consoles')).\ - first() - - if not result: - raise exception.ConsolePoolNotFoundForHostType( - host=host, console_type=console_type, - compute_host=compute_host) - - return result - - @pick_context_manager_reader def console_pool_get_all_by_host_type(context, host, console_type): return model_query(context, models.ConsolePool, read_deleted="no").\ @@ -4530,71 +4496,6 @@ def console_pool_get_all_by_host_type(context, host, console_type): all() -################## - - -@pick_context_manager_writer -def console_create(context, values): - console = models.Console() - console.update(values) - console.save(context.session) - return console - - -@pick_context_manager_writer -def console_delete(context, console_id): - # NOTE(mdragon): consoles are meant to be transient. - context.session.query(models.Console).\ - filter_by(id=console_id).\ - delete() - - -@pick_context_manager_reader -def console_get_by_pool_instance(context, pool_id, instance_uuid): - result = model_query(context, models.Console, read_deleted="yes").\ - filter_by(pool_id=pool_id).\ - filter_by(instance_uuid=instance_uuid).\ - options(joinedload('pool')).\ - first() - - if not result: - raise exception.ConsoleNotFoundInPoolForInstance( - pool_id=pool_id, instance_uuid=instance_uuid) - - return result - - -@pick_context_manager_reader -def console_get_all_by_instance(context, instance_uuid, columns_to_join=None): - query = model_query(context, models.Console, read_deleted="yes").\ - filter_by(instance_uuid=instance_uuid) - if columns_to_join: - for column in columns_to_join: - query = query.options(joinedload(column)) - return query.all() - - -@pick_context_manager_reader -def console_get(context, console_id, instance_uuid=None): - query = model_query(context, models.Console, read_deleted="yes").\ - filter_by(id=console_id).\ - options(joinedload('pool')) - - if instance_uuid is not None: - query = query.filter_by(instance_uuid=instance_uuid) - - result = query.first() - - if not result: - if instance_uuid: - raise exception.ConsoleNotFoundForInstance( - instance_uuid=instance_uuid) - else: - raise exception.ConsoleNotFound(console_id=console_id) - - return result - - ######################## # User-provided metadata diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index fcfad5d7a362..5fef1a8372c6 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -1001,6 +1001,7 @@ class ConsolePool(BASE, NovaBase, models.SoftDeleteMixin): compute_host = Column(String(255)) +# TODO(stephenfin): Remove in V or later class Console(BASE, NovaBase, models.SoftDeleteMixin): """Represents a console session for an instance.""" __tablename__ = 'consoles' diff --git a/nova/exception.py b/nova/exception.py index 11fca3f2856e..6da5c0544d28 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -1203,35 +1203,10 @@ class ConsoleLogOutputException(NovaException): "%(instance_id)s. Reason: %(reason)s") -class ConsolePoolExists(NovaException): - msg_fmt = _("Console pool with host %(host)s, console_type " - "%(console_type)s and compute_host %(compute_host)s " - "already exists.") - - -class ConsolePoolNotFoundForHostType(NotFound): - msg_fmt = _("Console pool of type %(console_type)s " - "for compute host %(compute_host)s " - "on proxy host %(host)s not found.") - - -class ConsoleNotFound(NotFound): - msg_fmt = _("Console %(console_id)s could not be found.") - - -class ConsoleNotFoundForInstance(ConsoleNotFound): - msg_fmt = _("Console for instance %(instance_uuid)s could not be found.") - - class ConsoleNotAvailable(NotFound): msg_fmt = _("Guest does not have a console available.") -class ConsoleNotFoundInPoolForInstance(ConsoleNotFound): - msg_fmt = _("Console for instance %(instance_uuid)s " - "in pool %(pool_id)s could not be found.") - - class ConsoleTypeInvalid(Invalid): msg_fmt = _("Invalid console type %(console_type)s") diff --git a/nova/objects/fields.py b/nova/objects/fields.py index 9a44dd42f91c..05074bad8cbe 100644 --- a/nova/objects/fields.py +++ b/nova/objects/fields.py @@ -796,6 +796,8 @@ class NotificationSource(BaseNovaEnum): # TODO(stephenfin): Remove when 'NotificationPublisher' object version is # bumped to 3.0 CELLS = 'nova-cells' + # TODO(stephenfin): Remove when 'NotificationPublisher' object version is + # bumped to 3.0 CONSOLE = 'nova-console' METADATA = 'nova-metadata' diff --git a/nova/service.py b/nova/service.py index 7aa62b3ead97..24aa7332895a 100644 --- a/nova/service.py +++ b/nova/service.py @@ -54,7 +54,6 @@ CONF = nova.conf.CONF SERVICE_MANAGERS = { 'nova-compute': 'nova.compute.manager.ComputeManager', - 'nova-console': 'nova.console.manager.ConsoleProxyManager', 'nova-conductor': 'nova.conductor.manager.ConductorManager', 'nova-metadata': 'nova.api.manager.MetadataManager', 'nova-scheduler': 'nova.scheduler.manager.SchedulerManager', diff --git a/nova/tests/unit/console/test_console.py b/nova/tests/unit/console/test_console.py deleted file mode 100644 index c9496e061898..000000000000 --- a/nova/tests/unit/console/test_console.py +++ /dev/null @@ -1,199 +0,0 @@ -# Copyright (c) 2010 OpenStack Foundation -# 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.""" - -import fixtures -import mock - -from nova.compute import rpcapi as compute_rpcapi -from nova.console import api as console_api -from nova.console import manager as console_manager -from nova import context -from nova.db import api as db -from nova import exception -from nova import objects -from nova import test -from nova.tests.unit import fake_instance -from nova.tests.unit import fake_xvp_console_proxy - - -class ConsoleTestCase(test.TestCase): - """Test case for console proxy manager.""" - def setUp(self): - super(ConsoleTestCase, self).setUp() - self.useFixture(fixtures.MonkeyPatch( - 'nova.console.manager.xvp.XVPConsoleProxy', - fake_xvp_console_proxy.FakeConsoleProxy)) - self.console = console_manager.ConsoleProxyManager() - self.user_id = 'fake' - self.project_id = 'fake' - self.context = context.RequestContext(self.user_id, self.project_id) - self.host = 'test_compute_host' - self.pool_info = {'address': '127.0.0.1', - 'username': 'test', - 'password': '1234pass'} - - def test_reset(self): - with mock.patch('nova.compute.rpcapi.ComputeAPI') as mock_rpc: - old_rpcapi = self.console.compute_rpcapi - self.console.reset() - mock_rpc.assert_called_once_with() - self.assertNotEqual(old_rpcapi, - self.console.compute_rpcapi) - - def _create_instance(self): - """Create a test instance.""" - inst = {} - inst['image_id'] = 1 - inst['reservation_id'] = 'r-fakeres' - inst['user_id'] = self.user_id - inst['project_id'] = self.project_id - inst['instance_type_id'] = 1 - inst['ami_launch_index'] = 0 - return fake_instance.fake_instance_obj(self.context, **inst) - - @mock.patch.object(compute_rpcapi.ComputeAPI, 'get_console_pool_info') - def test_get_pool_for_instance_host(self, mock_get): - mock_get.return_value = self.pool_info - pool = self.console._get_pool_for_instance_host(self.context, - self.host) - self.assertEqual(pool['compute_host'], self.host) - - @mock.patch.object(compute_rpcapi.ComputeAPI, 'get_console_pool_info') - def test_get_pool_creates_new_pool_if_needed(self, mock_get): - mock_get.return_value = self.pool_info - 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']) - - @mock.patch.object(compute_rpcapi.ComputeAPI, 'get_console_pool_info') - @mock.patch('nova.objects.instance.Instance.get_by_id') - def test_add_console(self, mock_id, mock_get): - mock_get.return_value = self.pool_info - - instance = self._create_instance() - mock_id.return_value = instance - self.console.add_console(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_uuid'] for con in pool['consoles']] - self.assertIn(instance.uuid, console_instances) - - @mock.patch.object(compute_rpcapi.ComputeAPI, 'get_console_pool_info') - @mock.patch('nova.objects.instance.Instance.get_by_id') - def test_add_console_does_not_duplicate(self, mock_id, mock_get): - mock_get.return_value = self.pool_info - - instance = self._create_instance() - mock_id.return_value = instance - cons1 = self.console.add_console(self.context, instance.id) - cons2 = self.console.add_console(self.context, instance.id) - self.assertEqual(cons1, cons2) - - @mock.patch.object(compute_rpcapi.ComputeAPI, 'get_console_pool_info') - @mock.patch('nova.objects.instance.Instance.get_by_id') - def test_remove_console(self, mock_id, mock_get): - mock_get.return_value = self.pool_info - - instance = self._create_instance() - mock_id.return_value = 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) - - -class ConsoleAPITestCase(test.NoDBTestCase): - """Test case for console API.""" - def setUp(self): - super(ConsoleAPITestCase, self).setUp() - - self.context = context.RequestContext('fake', 'fake') - self.console_api = console_api.API() - self.fake_uuid = '00000000-aaaa-bbbb-cccc-000000000000' - self.fake_instance = { - 'id': 1, - 'uuid': self.fake_uuid, - 'host': 'fake_host' - } - self.fake_console = { - 'pool': {'host': 'fake_host'}, - 'id': 'fake_id' - } - - def _fake_db_console_get(_ctxt, _console_uuid, _instance_uuid): - return self.fake_console - self.stub_out('nova.db.api.console_get', _fake_db_console_get) - - def _fake_db_console_get_all_by_instance(_ctxt, _instance_uuid, - columns_to_join): - return [self.fake_console] - self.stub_out('nova.db.api.console_get_all_by_instance', - _fake_db_console_get_all_by_instance) - - def test_get_consoles(self): - console = self.console_api.get_consoles(self.context, self.fake_uuid) - self.assertEqual(console, [self.fake_console]) - - def test_get_console(self): - console = self.console_api.get_console(self.context, self.fake_uuid, - 'fake_id') - self.assertEqual(console, self.fake_console) - - @mock.patch('nova.console.rpcapi.ConsoleAPI.remove_console') - def test_delete_console(self, mock_remove): - self.console_api.delete_console(self.context, self.fake_uuid, - 'fake_id') - mock_remove.assert_called_once_with(self.context, 'fake_id') - - @mock.patch.object(compute_rpcapi.ComputeAPI, 'get_console_topic', - return_value='compute.fake_host') - @mock.patch.object(objects.Instance, 'get_by_uuid') - def test_create_console(self, mock_get_instance_by_uuid, - mock_get_console_topic): - mock_get_instance_by_uuid.return_value = objects.Instance( - **self.fake_instance) - self.console_api.create_console(self.context, self.fake_uuid) - mock_get_console_topic.assert_called_once_with(self.context, - 'fake_host') diff --git a/nova/tests/unit/console/test_rpcapi.py b/nova/tests/unit/console/test_rpcapi.py deleted file mode 100644 index 34650a479508..000000000000 --- a/nova/tests/unit/console/test_rpcapi.py +++ /dev/null @@ -1,61 +0,0 @@ -# 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 -""" - -import mock - -from nova.console import rpcapi as console_rpcapi -from nova import context -from nova import test - - -class ConsoleRpcAPITestCase(test.NoDBTestCase): - def _test_console_api(self, method, rpc_method, **kwargs): - ctxt = context.RequestContext('fake_user', 'fake_project') - - rpcapi = console_rpcapi.ConsoleAPI() - self.assertIsNotNone(rpcapi.client) - self.assertEqual(rpcapi.client.target.topic, - console_rpcapi.RPC_TOPIC) - - orig_prepare = rpcapi.client.prepare - - with test.nested( - mock.patch.object(rpcapi.client, rpc_method), - mock.patch.object(rpcapi.client, 'prepare'), - mock.patch.object(rpcapi.client, 'can_send_version'), - ) as ( - rpc_mock, prepare_mock, csv_mock - ): - prepare_mock.return_value = rpcapi.client - rpc_mock.return_value = 'foo' if rpc_method == 'call' else None - csv_mock.side_effect = ( - lambda v: orig_prepare().can_send_version()) - - retval = getattr(rpcapi, method)(ctxt, **kwargs) - self.assertEqual(retval, rpc_mock.return_value) - - prepare_mock.assert_called_once_with() - rpc_mock.assert_called_once_with(ctxt, method, **kwargs) - - def test_add_console(self): - self._test_console_api('add_console', instance_id='i', - rpc_method='cast') - - def test_remove_console(self): - self._test_console_api('remove_console', console_id='i', - rpc_method='cast') diff --git a/nova/tests/unit/db/test_db_api.py b/nova/tests/unit/db/test_db_api.py index 3ae6b6c83247..bd5e2825a6fc 100644 --- a/nova/tests/unit/db/test_db_api.py +++ b/nova/tests/unit/db/test_db_api.py @@ -3210,25 +3210,6 @@ class InstanceTestCase(test.TestCase, ModelsObjectComparatorMixin): db.virtual_interface_create(ctxt, {'instance_uuid': uuid}) - pool_values = { - 'address': '192.168.10.10', - 'username': 'user1', - 'password': 'passwd1', - 'console_type': 'type1', - 'public_hostname': 'public_host1', - 'host': 'host1', - 'compute_host': 'compute_host1', - } - console_pool = db.console_pool_create(ctxt, pool_values) - console_values = { - 'instance_name': instance['name'], - 'instance_uuid': uuid, - 'password': 'pass', - 'port': 7878, - 'pool_id': console_pool['id'] - } - db.console_create(self.ctxt, console_values) - # Hard delete the instance db.instance_destroy(ctxt, uuid, hard_delete=True) @@ -3260,10 +3241,7 @@ class InstanceTestCase(test.TestCase, ModelsObjectComparatorMixin): _assert_instance_id_mapping(ctxt, self, uuid) self.assertRaises(exception.InstanceNotFound, db.instance_destroy, ctxt, uuid) - # NOTE(ttsiouts): Should these also be valid? - # instance_consoles = db.console_get_all_by_instance(ctxt, uuid) - # self.assertEqual(0, len(instance_consoles)) - # Also FixedIp has the instance_uuid as a foreign key + # NOTE(ttsiouts): FixedIp has the instance_uuid as a foreign key def test_check_instance_exists(self): instance = self.create_instance_with_args() @@ -7916,207 +7894,6 @@ class CertificateTestCase(test.TestCase, ModelsObjectComparatorMixin): self._assertEqualObjects(self.created[1], cert[0]) -class ConsoleTestCase(test.TestCase, ModelsObjectComparatorMixin): - - def setUp(self): - super(ConsoleTestCase, self).setUp() - self.ctxt = context.get_admin_context() - pools_data = [ - {'address': '192.168.10.10', - 'username': 'user1', - 'password': 'passwd1', - 'console_type': 'type1', - 'public_hostname': 'public_host1', - 'host': 'host1', - 'compute_host': 'compute_host1', - }, - {'address': '192.168.10.11', - 'username': 'user2', - 'password': 'passwd2', - 'console_type': 'type2', - 'public_hostname': 'public_host2', - 'host': 'host2', - 'compute_host': 'compute_host2', - }, - ] - self.console_pools = [db.console_pool_create(self.ctxt, val) - for val in pools_data] - instance_uuid = uuidsentinel.uuid1 - db.instance_create(self.ctxt, {'uuid': instance_uuid}) - self.console_data = [{'instance_name': 'name' + str(x), - 'instance_uuid': instance_uuid, - 'password': 'pass' + str(x), - 'port': 7878 + x, - 'pool_id': self.console_pools[x]['id']} - for x in range(len(pools_data))] - self.consoles = [db.console_create(self.ctxt, val) - for val in self.console_data] - - def test_console_create(self): - ignored_keys = ['id', 'deleted', 'deleted_at', 'created_at', - 'updated_at'] - for console in self.consoles: - self.assertIsNotNone(console['id']) - self._assertEqualListsOfObjects(self.console_data, self.consoles, - ignored_keys=ignored_keys) - - def test_console_get_by_id(self): - console = self.consoles[0] - console_get = db.console_get(self.ctxt, console['id']) - self._assertEqualObjects(console, console_get, - ignored_keys=['pool']) - - def test_console_get_by_id_uuid(self): - console = self.consoles[0] - console_get = db.console_get(self.ctxt, console['id'], - console['instance_uuid']) - self._assertEqualObjects(console, console_get, - ignored_keys=['pool']) - - def test_console_get_by_pool_instance(self): - console = self.consoles[0] - console_get = db.console_get_by_pool_instance(self.ctxt, - console['pool_id'], console['instance_uuid']) - self._assertEqualObjects(console, console_get, - ignored_keys=['pool']) - - def test_console_get_all_by_instance(self): - instance_uuid = self.consoles[0]['instance_uuid'] - consoles_get = db.console_get_all_by_instance(self.ctxt, instance_uuid) - self._assertEqualListsOfObjects(self.consoles, consoles_get) - - def test_console_get_all_by_instance_with_pool(self): - instance_uuid = self.consoles[0]['instance_uuid'] - consoles_get = db.console_get_all_by_instance(self.ctxt, instance_uuid, - columns_to_join=['pool']) - self._assertEqualListsOfObjects(self.consoles, consoles_get, - ignored_keys=['pool']) - self._assertEqualListsOfObjects([pool for pool in self.console_pools], - [c['pool'] for c in consoles_get]) - - def test_console_get_all_by_instance_empty(self): - consoles_get = db.console_get_all_by_instance(self.ctxt, - uuidsentinel.uuid2) - self.assertEqual(consoles_get, []) - - def test_console_delete(self): - console_id = self.consoles[0]['id'] - db.console_delete(self.ctxt, console_id) - self.assertRaises(exception.ConsoleNotFound, db.console_get, - self.ctxt, console_id) - - def test_console_get_by_pool_instance_not_found(self): - self.assertRaises(exception.ConsoleNotFoundInPoolForInstance, - db.console_get_by_pool_instance, self.ctxt, - self.consoles[0]['pool_id'], - uuidsentinel.uuid2) - - def test_console_get_not_found(self): - self.assertRaises(exception.ConsoleNotFound, db.console_get, - self.ctxt, 100500) - - def test_console_get_not_found_instance(self): - self.assertRaises(exception.ConsoleNotFoundForInstance, db.console_get, - self.ctxt, self.consoles[0]['id'], - uuidsentinel.uuid2) - - -class ConsolePoolTestCase(test.TestCase, ModelsObjectComparatorMixin): - def setUp(self): - super(ConsolePoolTestCase, self).setUp() - - self.ctxt = context.get_admin_context() - self.test_console_pool_1 = { - 'address': '192.168.2.10', - 'username': 'user_1', - 'password': 'secret_123', - 'console_type': 'type_1', - 'public_hostname': 'public_hostname_123', - 'host': 'localhost', - 'compute_host': '127.0.0.1', - } - self.test_console_pool_2 = { - 'address': '192.168.2.11', - 'username': 'user_2', - 'password': 'secret_1234', - 'console_type': 'type_2', - 'public_hostname': 'public_hostname_1234', - 'host': '127.0.0.1', - 'compute_host': 'localhost', - } - self.test_console_pool_3 = { - 'address': '192.168.2.12', - 'username': 'user_3', - 'password': 'secret_12345', - 'console_type': 'type_2', - 'public_hostname': 'public_hostname_12345', - 'host': '127.0.0.1', - 'compute_host': '192.168.1.1', - } - - def test_console_pool_create(self): - console_pool = db.console_pool_create( - self.ctxt, self.test_console_pool_1) - self.assertIsNotNone(console_pool.get('id')) - ignored_keys = ['deleted', 'created_at', 'updated_at', - 'deleted_at', 'id'] - self._assertEqualObjects( - console_pool, self.test_console_pool_1, ignored_keys) - - def test_console_pool_create_duplicate(self): - db.console_pool_create(self.ctxt, self.test_console_pool_1) - self.assertRaises(exception.ConsolePoolExists, db.console_pool_create, - self.ctxt, self.test_console_pool_1) - - def test_console_pool_get_by_host_type(self): - params = [ - self.test_console_pool_1, - self.test_console_pool_2, - ] - - for p in params: - db.console_pool_create(self.ctxt, p) - - ignored_keys = ['deleted', 'created_at', 'updated_at', - 'deleted_at', 'id', 'consoles'] - - cp = self.test_console_pool_1 - db_cp = db.console_pool_get_by_host_type( - self.ctxt, cp['compute_host'], cp['host'], cp['console_type'] - ) - self._assertEqualObjects(cp, db_cp, ignored_keys) - - def test_console_pool_get_by_host_type_no_resuls(self): - self.assertRaises( - exception.ConsolePoolNotFoundForHostType, - db.console_pool_get_by_host_type, self.ctxt, 'compute_host', - 'host', 'console_type') - - def test_console_pool_get_all_by_host_type(self): - params = [ - self.test_console_pool_1, - self.test_console_pool_2, - self.test_console_pool_3, - ] - for p in params: - db.console_pool_create(self.ctxt, p) - ignored_keys = ['deleted', 'created_at', 'updated_at', - 'deleted_at', 'id', 'consoles'] - - cp = self.test_console_pool_2 - db_cp = db.console_pool_get_all_by_host_type( - self.ctxt, cp['host'], cp['console_type']) - - self._assertEqualListsOfObjects( - db_cp, [self.test_console_pool_2, self.test_console_pool_3], - ignored_keys) - - def test_console_pool_get_all_by_host_type_no_results(self): - res = db.console_pool_get_all_by_host_type( - self.ctxt, 'cp_host', 'cp_console_type') - self.assertEqual([], res) - - class DnsdomainTestCase(test.TestCase): def setUp(self): @@ -8455,9 +8232,6 @@ class ArchiveTestCase(test.TestCase, ModelsObjectComparatorMixin): self.dns_domains = models.DNSDomain.__table__ self.shadow_dns_domains = sqlalchemyutils.get_table( self.engine, "shadow_dns_domains") - self.consoles = models.Console.__table__ - self.shadow_consoles = sqlalchemyutils.get_table( - self.engine, "shadow_consoles") self.console_pools = models.ConsolePool.__table__ self.shadow_console_pools = sqlalchemyutils.get_table( self.engine, "shadow_console_pools") @@ -8813,41 +8587,6 @@ class ArchiveTestCase(test.TestCase, ModelsObjectComparatorMixin): 'sqlite version too old for reliable SQLA foreign_keys') self.conn.execute("PRAGMA foreign_keys = ON") - def test_archive_deleted_rows_fk_constraint(self): - # consoles.pool_id depends on console_pools.id - self._check_sqlite_version_less_than_3_7() - ins_stmt = self.console_pools.insert().values(deleted=1, - deleted_at=timeutils.utcnow()) - result = self.conn.execute(ins_stmt) - id1 = result.inserted_primary_key[0] - ins_stmt = self.consoles.insert().values(deleted=1, - deleted_at=timeutils.utcnow(), - pool_id=id1) - result = self.conn.execute(ins_stmt) - result.inserted_primary_key[0] - # The first try to archive console_pools should fail, due to FK. - num = sqlalchemy_api._archive_deleted_rows_for_table(self.metadata, - "console_pools", - max_rows=None, - before=None) - self.assertEqual(num[0], 0) - # Then archiving consoles should work. - num = sqlalchemy_api._archive_deleted_rows_for_table(self.metadata, - "consoles", - max_rows=None, - before=None) - self.assertEqual(num[0], 1) - # Then archiving console_pools should work. - num = sqlalchemy_api._archive_deleted_rows_for_table(self.metadata, - "console_pools", - max_rows=None, - before=None) - self.assertEqual(num[0], 1) - self._assert_shadow_tables_empty_except( - 'shadow_console_pools', - 'shadow_consoles' - ) - def test_archive_deleted_rows_for_migrations(self): # migrations.instance_uuid depends on instances.uuid self._check_sqlite_version_less_than_3_7() diff --git a/nova/tests/unit/test_profiler.py b/nova/tests/unit/test_profiler.py index 8550010e0e12..2cef753b7c48 100644 --- a/nova/tests/unit/test_profiler.py +++ b/nova/tests/unit/test_profiler.py @@ -55,8 +55,6 @@ class TestProfiler(test.NoDBTestCase): 'nova.conductor.manager.ConductorManager', 'nova.conductor.rpcapi.ComputeTaskAPI', 'nova.conductor.rpcapi.ConductorAPI', - 'nova.console.manager.ConsoleProxyManager', - 'nova.console.rpcapi.ConsoleAPI', 'nova.image.api.API', 'nova.network.api.API', 'nova.network.manager.FlatDHCPManager', diff --git a/releasenotes/notes/remove-nova-console-5a2b86210a43e7c8.yaml b/releasenotes/notes/remove-nova-console-5a2b86210a43e7c8.yaml index 2249def097a8..8a31b98a5a64 100644 --- a/releasenotes/notes/remove-nova-console-5a2b86210a43e7c8.yaml +++ b/releasenotes/notes/remove-nova-console-5a2b86210a43e7c8.yaml @@ -1,7 +1,13 @@ --- upgrade: - | - The following APIs have been removed. Calling these APIs will + The ``nova-console`` service has been deprecated since the 19.0.0 Stein + release and has now been removed. The following configuration options are + therefore removed. + + * ``[upgrade_levels] console`` + + In addition, the following APIs have been removed. Calling these APIs will now result in a ``410 HTTPGone`` error response: * ``POST /servers/{server_id}/consoles`` @@ -9,7 +15,7 @@ upgrade: * ``GET /servers/{server_id}/consoles/{console_id}`` * ``DELETE /servers/{server_id}/consoles/{console_id}`` - In addition, the following policies are removed. These were related to the + Finally, the following policies are removed. These were related to the removed APIs listed above and no longer had any effect: * ``os_compute_api:os-consoles:index`` diff --git a/setup.cfg b/setup.cfg index 2ec22861e0d5..db858c746f80 100644 --- a/setup.cfg +++ b/setup.cfg @@ -66,7 +66,6 @@ console_scripts = nova-api-os-compute = nova.cmd.api_os_compute:main nova-compute = nova.cmd.compute:main nova-conductor = nova.cmd.conductor:main - nova-console = nova.cmd.console:main nova-dhcpbridge = nova.cmd.dhcpbridge:main nova-manage = nova.cmd.manage:main nova-network = nova.cmd.network:main