Remove nova-consoleauth

Obliterate all references to the aforementioned service. This mostly
consists of removing the core service and any references to the now
removed '[workarounds] enable_consoleauth' configuration option.

Part of blueprint remove-consoleauth

Change-Id: I0498599fd636aa9e30df932f0d893db5efa23260
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
Depends-On: Icfc175c49a1fc650d1c9ad06b77209a70c6386db
This commit is contained in:
Stephen Finucane 2019-04-16 10:52:52 +01:00 committed by Stephen Finucane
parent bedaeab074
commit 2398b78df5
24 changed files with 61 additions and 1081 deletions

View File

@ -17,7 +17,6 @@ import webob
from nova.api.openstack import wsgi
import nova.conf
from nova.consoleauth import rpcapi as consoleauth_rpcapi
from nova import context as nova_context
from nova.i18n import _
from nova import objects
@ -27,9 +26,6 @@ CONF = nova.conf.CONF
class ConsoleAuthTokensController(wsgi.Controller):
def __init__(self):
super(ConsoleAuthTokensController, self).__init__()
self._consoleauth_rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
def _show(self, req, id, rdp_only):
"""Checks a console auth token and returns the related connect info."""
@ -42,21 +38,19 @@ class ConsoleAuthTokensController(wsgi.Controller):
raise webob.exc.HTTPBadRequest(explanation=msg)
connect_info = None
if CONF.workarounds.enable_consoleauth:
connect_info = self._consoleauth_rpcapi.check_token(context, token)
else:
results = nova_context.scatter_gather_skip_cell0(
context, objects.ConsoleAuthToken.validate, token)
# NOTE(melwitt): Console token auths are stored in cell databases,
# but with only the token as a request param, we can't know which
# cell database contains the token's corresponding connection info.
# So, we must query all cells for the info and we can break the
# loop as soon as we find a result because the token is associated
# with one instance, which can only be in one cell.
for result in results.values():
if not nova_context.is_cell_failure_sentinel(result):
connect_info = result.to_dict()
break
results = nova_context.scatter_gather_skip_cell0(
context, objects.ConsoleAuthToken.validate, token)
# NOTE(melwitt): Console token auths are stored in cell databases,
# but with only the token as a request param, we can't know which
# cell database contains the token's corresponding connection info.
# So, we must query all cells for the info and we can break the
# loop as soon as we find a result because the token is associated
# with one instance, which can only be in one cell.
for result in results.values():
if not nova_context.is_cell_failure_sentinel(result):
connect_info = result.to_dict()
break
if not connect_info:
raise webob.exc.HTTPNotFound(explanation=_("Token not found"))

View File

@ -53,9 +53,6 @@ class HostController(wsgi.Controller):
| {'host_name': 'some.celly.host.name',
| 'service': 'cells',
| 'zone': 'internal'},
| {'host_name': 'console1.host.com',
| 'service': 'consoleauth',
| 'zone': 'internal'},
| {'host_name': 'network1.host.com',
| 'service': 'network',
| 'zone': 'internal'},

View File

@ -1,50 +0,0 @@
# Copyright (c) 2012 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.
"""VNC Console Proxy Server."""
import sys
from oslo_log import log as logging
from oslo_reports import guru_meditation_report as gmr
from oslo_reports import opts as gmr_opts
import nova.conf
from nova import config
from nova.consoleauth import rpcapi
from nova import objects
from nova import service
from nova import version
CONF = nova.conf.CONF
LOG = logging.getLogger('nova.consoleauth')
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-consoleauth service is deprecated as console token '
'authorization storage has moved from the nova-consoleauth '
'service backend to the database backend.')
server = service.Service.create(binary='nova-consoleauth',
topic=rpcapi.RPC_TOPIC)
service.serve(server)
service.wait()

View File

@ -51,7 +51,6 @@ from nova.compute.utils import wrap_instance_event
from nova.compute import vm_states
from nova import conductor
import nova.conf
from nova.consoleauth import rpcapi as consoleauth_rpcapi
from nova import context as nova_context
from nova import crypto
from nova.db import base
@ -259,7 +258,6 @@ class API(base.Base):
self._placementclient = None # Lazy-load on first access.
self.security_group_api = (security_group_api or
openstack_driver.get_openstack_security_group_driver())
self.consoleauth_rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
self.compute_task_api = conductor.ComputeTaskAPI()
self.servicegroup_api = servicegroup.API()
@ -2066,13 +2064,6 @@ class API(base.Base):
instance.progress = 0
instance.save()
if CONF.workarounds.enable_consoleauth:
# TODO(melwitt): Remove the conditions for running this line
# with cells v2, when consoleauth is no longer being used by
# cells v2, in Stein.
self.consoleauth_rpcapi.delete_tokens_for_instance(
context, instance.uuid)
if not instance.host and not may_have_ports_or_volumes:
try:
with compute_utils.notify_about_instance_delete(
@ -3803,18 +3794,6 @@ class API(base.Base):
"""Get a url to an instance Console."""
connect_info = self.compute_rpcapi.get_vnc_console(context,
instance=instance, console_type=console_type)
# TODO(melwitt): In Rocky, the compute manager puts the
# console authorization in the database in the above method.
# The following will be removed when everything has been
# converted to use the database, in Stein.
if CONF.workarounds.enable_consoleauth:
self.consoleauth_rpcapi.authorize_console(context,
connect_info['token'], console_type,
connect_info['host'], connect_info['port'],
connect_info['internal_access_path'], instance.uuid,
access_url=connect_info['access_url'])
return {'url': connect_info['access_url']}
@check_instance_host
@ -3824,17 +3803,6 @@ class API(base.Base):
"""Get a url to an instance Console."""
connect_info = self.compute_rpcapi.get_spice_console(context,
instance=instance, console_type=console_type)
# TODO(melwitt): In Rocky, the compute manager puts the
# console authorization in the database in the above method.
# The following will be removed when everything has been
# converted to use the database, in Stein.
if CONF.workarounds.enable_consoleauth:
self.consoleauth_rpcapi.authorize_console(context,
connect_info['token'], console_type,
connect_info['host'], connect_info['port'],
connect_info['internal_access_path'], instance.uuid,
access_url=connect_info['access_url'])
return {'url': connect_info['access_url']}
@check_instance_host
@ -3844,17 +3812,6 @@ class API(base.Base):
"""Get a url to an instance Console."""
connect_info = self.compute_rpcapi.get_rdp_console(context,
instance=instance, console_type=console_type)
# TODO(melwitt): In Rocky, the compute manager puts the
# console authorization in the database in the above method.
# The following will be removed when everything has been
# converted to use the database, in Stein.
if CONF.workarounds.enable_consoleauth:
self.consoleauth_rpcapi.authorize_console(context,
connect_info['token'], console_type,
connect_info['host'], connect_info['port'],
connect_info['internal_access_path'], instance.uuid,
access_url=connect_info['access_url'])
return {'url': connect_info['access_url']}
@check_instance_host
@ -3864,17 +3821,6 @@ class API(base.Base):
"""Get a url to a serial console."""
connect_info = self.compute_rpcapi.get_serial_console(context,
instance=instance, console_type=console_type)
# TODO(melwitt): In Rocky, the compute manager puts the
# console authorization in the database in the above method.
# The following will be removed when everything has been
# converted to use the database, in Stein.
if CONF.workarounds.enable_consoleauth:
self.consoleauth_rpcapi.authorize_console(context,
connect_info['token'], console_type,
connect_info['host'], connect_info['port'],
connect_info['internal_access_path'], instance.uuid,
access_url=connect_info['access_url'])
return {'url': connect_info['access_url']}
@check_instance_host
@ -3884,16 +3830,6 @@ class API(base.Base):
"""Get a url to a MKS console."""
connect_info = self.compute_rpcapi.get_mks_console(context,
instance=instance, console_type=console_type)
# TODO(melwitt): In Rocky, the compute manager puts the
# console authorization in the database in the above method.
# The following will be removed when everything has been
# converted to use the database, in Stein.
if CONF.workarounds.enable_consoleauth:
self.consoleauth_rpcapi.authorize_console(context,
connect_info['token'], console_type,
connect_info['host'], connect_info['port'],
connect_info['internal_access_path'], instance.uuid,
access_url=connect_info['access_url'])
return {'url': connect_info['access_url']}
@check_instance_host
@ -4493,15 +4429,6 @@ class API(base.Base):
self._record_action_start(context, instance,
instance_actions.LIVE_MIGRATION)
# TODO(melwitt): In Rocky, we optionally store console authorizations
# in both the consoleauth service and the database while
# we convert to using the database. Remove the condition for running
# this line with cells v2, when consoleauth is no longer being used by
# cells v2, in Stein.
if CONF.workarounds.enable_consoleauth:
self.consoleauth_rpcapi.delete_tokens_for_instance(
context, instance.uuid)
# NOTE(sbauza): Force is a boolean by the new related API version
if force is False and host_name:
# Unset the host to make sure we call the scheduler

View File

@ -1289,7 +1289,7 @@ registered in the database as an enabled service. Sometimes it can be useful
to register new compute services in disabled state and then enabled them at a
later point in time. This option only sets this behavior for nova-compute
services, it does not auto-disable other services like nova-conductor,
nova-scheduler, nova-consoleauth, or nova-osapi_compute.
nova-scheduler, or nova-osapi_compute.
Possible values:

View File

@ -32,10 +32,6 @@ The lifetime of a console auth token (in seconds).
A console auth token is used in authorizing console access for a user.
Once the auth token time to live count has elapsed, the token is
considered expired. Expired tokens are then deleted.
Related options:
* ``[workarounds]/enable_consoleauth``
""")
]

View File

@ -108,24 +108,6 @@ 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'.
* An OpenStack release name, in lower case, such as 'mitaka' or
'liberty'.
"""),
cfg.StrOpt('consoleauth',
deprecated_for_removal=True,
deprecated_since='18.0.0',
deprecated_reason="""
The nova-consoleauth service was deprecated in 18.0.0 (Rocky) and will be
removed in an upcoming release.
""",
help="""
Consoleauth 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'.

View File

@ -154,38 +154,6 @@ Related options:
compute service to the scheduler service.
"""),
cfg.BoolOpt(
'enable_consoleauth',
default=False,
deprecated_for_removal=True,
deprecated_since="18.0.0",
deprecated_reason="""
This option has been added as deprecated originally because it is used
for avoiding a upgrade issue and it will not be used in the future.
See the help text for more details.
""",
help="""
Enable the consoleauth service to avoid resetting unexpired consoles.
Console token authorizations have moved from the ``nova-consoleauth`` service
to the database, so all new consoles will be supported by the database backend.
With this, consoles that existed before database backend support will be reset.
For most operators, this should be a minimal disruption as the default TTL of a
console token is 10 minutes.
Operators that have much longer token TTL configured or otherwise wish to avoid
immediately resetting all existing consoles can enable this flag to continue
using the ``nova-consoleauth`` service in addition to the database backend.
Once all of the old ``nova-consoleauth`` supported console tokens have expired,
this flag should be disabled. For example, if a deployment has configured a
token TTL of one hour, the operator may disable the flag, one hour after
deploying the new code during an upgrade.
Related options:
* ``[consoleauth]/token_ttl``
"""),
cfg.BoolOpt(
'enable_numa_live_migration',
default=False,

View File

@ -30,7 +30,6 @@ import websockify
from nova.compute import rpcapi as compute_rpcapi
import nova.conf
from nova.consoleauth import rpcapi as consoleauth_rpcapi
from nova import context
from nova import exception
from nova.i18n import _
@ -125,14 +124,8 @@ class NovaProxyRequestHandlerBase(object):
str(port),
console_type)
def _get_connect_info_consoleauth(self, ctxt, token):
# NOTE(PaulMurray) consoleauth check_token() validates the token
# and does an rpc to compute manager to check the console port
# is correct.
rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
return rpcapi.check_token(ctxt, token=token)
def _get_connect_info_database(self, ctxt, token):
def _get_connect_info(self, ctxt, token):
"""Validate the token and get the connect info."""
# NOTE(PaulMurray) ConsoleAuthToken.validate validates the token.
# We call the compute manager directly to check the console port
# is correct.
@ -147,25 +140,6 @@ class NovaProxyRequestHandlerBase(object):
return connect_info
def _get_connect_info(self, ctxt, token):
"""Validate the token and get the connect info."""
connect_info = None
# NOTE(melwitt): If consoleauth is enabled to aid in transitioning
# to the database backend, check it first before falling back to
# the database. Tokens that existed pre-database-backend will
# reside in the consoleauth service storage.
if CONF.workarounds.enable_consoleauth:
connect_info = self._get_connect_info_consoleauth(ctxt, token)
# If consoleauth is enabled to aid in transitioning to the database
# backend and we didn't find a token in the consoleauth service
# storage, check the database for a token because it's probably a
# post-database-backend token, which are stored in the database.
if not connect_info:
connect_info = self._get_connect_info_database(ctxt, token)
return connect_info
def new_websocket_client(self):
"""Called after a new WebSocket connection has been established."""
# Reopen the eventlet hub to make sure we don't share an epoll

View File

@ -1,17 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2012 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.
"""Module to authenticate Consoles."""

View File

@ -1,136 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2012 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.
"""Auth Components for Consoles."""
import time
from oslo_log import log as logging
import oslo_messaging as messaging
from oslo_serialization import jsonutils
from nova import cache_utils
from nova.compute import rpcapi as compute_rpcapi
import nova.conf
from nova import context as nova_context
from nova import manager
from nova import objects
LOG = logging.getLogger(__name__)
CONF = nova.conf.CONF
class ConsoleAuthManager(manager.Manager):
"""Manages token based authentication."""
target = messaging.Target(version='2.1')
def __init__(self, scheduler_driver=None, *args, **kwargs):
super(ConsoleAuthManager, self).__init__(service_name='consoleauth',
*args, **kwargs)
self._mc = None
self._mc_instance = None
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
@property
def mc(self):
if self._mc is None:
self._mc = cache_utils.get_client(CONF.consoleauth.token_ttl)
return self._mc
@property
def mc_instance(self):
if self._mc_instance is None:
self._mc_instance = cache_utils.get_client()
return self._mc_instance
def reset(self):
LOG.info('Reloading compute RPC API')
compute_rpcapi.LAST_VERSION = None
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
def _get_tokens_for_instance(self, instance_uuid):
tokens_str = self.mc_instance.get(instance_uuid.encode('UTF-8'))
if not tokens_str:
tokens = []
else:
tokens = jsonutils.loads(tokens_str)
return tokens
def authorize_console(self, context, token, console_type, host, port,
internal_access_path, instance_uuid,
access_url=None):
token_dict = {'token': token,
'instance_uuid': instance_uuid,
'console_type': console_type,
'host': host,
'port': port,
'internal_access_path': internal_access_path,
'access_url': access_url,
'last_activity_at': time.time()}
data = jsonutils.dumps(token_dict)
self.mc.set(token.encode('UTF-8'), data)
tokens = self._get_tokens_for_instance(instance_uuid)
# Remove the expired tokens from cache.
token_values = self.mc.get_multi(
[tok.encode('UTF-8') for tok in tokens])
tokens = [name for name, value in zip(tokens, token_values)
if value is not None]
tokens.append(token)
self.mc_instance.set(instance_uuid.encode('UTF-8'),
jsonutils.dumps(tokens))
LOG.info("Received Token: %(token)s, %(token_dict)s",
{'token': token, 'token_dict': token_dict})
def _validate_token(self, context, token):
instance_uuid = token['instance_uuid']
if instance_uuid is None:
return False
mapping = objects.InstanceMapping.get_by_instance_uuid(context,
instance_uuid)
with nova_context.target_cell(context, mapping.cell_mapping) as cctxt:
instance = objects.Instance.get_by_uuid(cctxt, instance_uuid)
return self.compute_rpcapi.validate_console_port(
cctxt,
instance,
token['port'],
token['console_type'])
def check_token(self, context, token):
token_str = self.mc.get(token.encode('UTF-8'))
token_valid = (token_str is not None)
LOG.info("Checking Token: %(token)s, %(token_valid)s",
{'token': token, 'token_valid': token_valid})
if token_valid:
token = jsonutils.loads(token_str)
if self._validate_token(context, token):
return token
def delete_tokens_for_instance(self, context, instance_uuid):
tokens = self._get_tokens_for_instance(instance_uuid)
if tokens:
self.mc.delete_multi(
[tok.encode('UTF-8') for tok in tokens])
self.mc_instance.delete(instance_uuid.encode('UTF-8'))

View File

@ -1,103 +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 consoleauth RPC API.
"""
import oslo_messaging as messaging
import nova.conf
from nova import profiler
from nova import rpc
CONF = nova.conf.CONF
RPC_TOPIC = 'consoleauth'
@profiler.trace_cls("rpc")
class ConsoleAuthAPI(object):
'''Client side of the consoleauth rpc API.
API version history:
* 1.0 - Initial version.
* 1.1 - Added get_backdoor_port()
* 1.2 - Added instance_uuid to authorize_console, and
delete_tokens_for_instance
... Grizzly and Havana support message version 1.2. 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 1.2.
* 2.0 - Major API rev for Icehouse
... Icehouse and Juno 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.
* 2.1 - Added access_url to authorize_console
... Kilo, Liberty, Mitaka, Newton, and Ocata support message version
2.1. 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.1.
'''
VERSION_ALIASES = {
'grizzly': '1.2',
'havana': '1.2',
'icehouse': '2.0',
'juno': '2.0',
'kilo': '2.1',
'liberty': '2.1',
'mitaka': '2.1',
'newton': '2.1',
'ocata': '2.1',
}
def __init__(self):
super(ConsoleAuthAPI, self).__init__()
target = messaging.Target(topic=RPC_TOPIC, version='2.1')
version_cap = self.VERSION_ALIASES.get(CONF.upgrade_levels.consoleauth,
CONF.upgrade_levels.consoleauth)
self.client = rpc.get_client(target, version_cap=version_cap)
def authorize_console(self, ctxt, token, console_type, host, port,
internal_access_path, instance_uuid,
access_url):
# The remote side doesn't return anything, but we want to block
# until it completes.'
msg_args = dict(token=token, console_type=console_type,
host=host, port=port,
internal_access_path=internal_access_path,
instance_uuid=instance_uuid,
access_url=access_url)
version = '2.1'
if not self.client.can_send_version('2.1'):
version = '2.0'
del msg_args['access_url']
cctxt = self.client.prepare(version=version)
return cctxt.call(ctxt, 'authorize_console', **msg_args)
def check_token(self, ctxt, token):
cctxt = self.client.prepare()
return cctxt.call(ctxt, 'check_token', token=token)
def delete_tokens_for_instance(self, ctxt, instance_uuid):
cctxt = self.client.prepare()
return cctxt.cast(ctxt,
'delete_tokens_for_instance',
instance_uuid=instance_uuid)

View File

@ -765,6 +765,8 @@ class NotificationSource(BaseNovaEnum):
CONDUCTOR = 'nova-conductor'
SCHEDULER = 'nova-scheduler'
NETWORK = 'nova-network'
# TODO(stephenfin): Remove 'CONSOLEAUTH' when 'NotificationPublisher' is
# updated to version 3.0
CONSOLEAUTH = 'nova-consoleauth'
# TODO(stephenfin): Remove when 'NotificationPublisher' object version is
# bumped to 3.0

View File

@ -55,7 +55,6 @@ CONF = nova.conf.CONF
SERVICE_MANAGERS = {
'nova-compute': 'nova.compute.manager.ComputeManager',
'nova-console': 'nova.console.manager.ConsoleProxyManager',
'nova-consoleauth': 'nova.consoleauth.manager.ConsoleAuthManager',
'nova-conductor': 'nova.conductor.manager.ConductorManager',
'nova-metadata': 'nova.api.manager.MetadataManager',
'nova-scheduler': 'nova.scheduler.manager.SchedulerManager',

View File

@ -15,21 +15,18 @@
import copy
import ddt
import mock
import webob
from nova.api.openstack import api_version_request
from nova.api.openstack.compute import console_auth_tokens \
as console_auth_tokens_v21
from nova.consoleauth import rpcapi as consoleauth_rpcapi
from nova import exception
from nova import objects
from nova import test
from nova.tests.unit.api.openstack import fakes
@ddt.ddt
class ConsoleAuthTokensExtensionTestV21(test.NoDBTestCase):
controller_class = console_auth_tokens_v21
@ -52,86 +49,35 @@ class ConsoleAuthTokensExtensionTestV21(test.NoDBTestCase):
self.req = fakes.HTTPRequest.blank('', use_admin_context=True)
self.context = self.req.environ['nova.context']
@ddt.data(True, False)
@mock.patch('nova.objects.ConsoleAuthToken.validate',
return_value=objects.ConsoleAuthToken(
instance_uuid=fakes.FAKE_UUID, host='fake_host',
port='1234', internal_access_path='fake_access_path',
console_type='rdp-html5', token=fakes.FAKE_UUID))
@mock.patch.object(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token',
return_value={
'instance_uuid': fakes.FAKE_UUID,
'host': 'fake_host',
'port': '1234',
'internal_access_path': 'fake_access_path',
'console_type': 'rdp-html5'})
def test_get_console_connect_info(self, enable_consoleauth,
mock_check_token, mock_validate):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_get_console_connect_info(self, mock_validate):
output = self.controller.show(self.req, fakes.FAKE_UUID)
if enable_consoleauth:
self.assertEqual(self._EXPECTED_OUTPUT, output)
mock_check_token.assert_called_once_with(self.context,
fakes.FAKE_UUID)
mock_validate.assert_not_called()
else:
self.assertEqual(self._EXPECTED_OUTPUT_DB, output)
mock_validate.assert_called_once_with(self.context,
fakes.FAKE_UUID)
mock_check_token.assert_not_called()
self.assertEqual(self._EXPECTED_OUTPUT_DB, output)
mock_validate.assert_called_once_with(self.context, fakes.FAKE_UUID)
@ddt.data(True, False)
@mock.patch('nova.objects.ConsoleAuthToken.validate',
side_effect=exception.InvalidToken(token='***'))
@mock.patch.object(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token',
return_value=None)
def test_get_console_connect_info_token_not_found(self, enable_consoleauth,
mock_check_token,
mock_validate):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_get_console_connect_info_token_not_found(self, mock_validate):
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show, self.req, fakes.FAKE_UUID)
if enable_consoleauth:
mock_check_token.assert_called_once_with(self.context,
fakes.FAKE_UUID)
mock_validate.assert_not_called()
else:
mock_validate.assert_called_once_with(self.context,
fakes.FAKE_UUID)
mock_check_token.assert_not_called()
mock_validate.assert_called_once_with(self.context, fakes.FAKE_UUID)
@ddt.data(True, False)
@mock.patch('nova.objects.ConsoleAuthToken.validate',
return_value=objects.ConsoleAuthToken(
instance_uuid=fakes.FAKE_UUID, host='fake_host',
port='1234', internal_access_path='fake_access_path',
console_type='unauthorized_console_type',
token=fakes.FAKE_UUID))
@mock.patch.object(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token',
return_value={
'instance_uuid': fakes.FAKE_UUID,
'host': 'fake_host',
'port': '1234',
'internal_access_path': 'fake_access_path',
'console_type': 'unauthorized_console_type'})
def test_get_console_connect_info_nonrdp_console_type(self,
enable_consoleauth,
mock_check_token,
mock_validate):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_get_console_connect_info_nonrdp_console_type(self, mock_validate):
self.assertRaises(webob.exc.HTTPUnauthorized,
self.controller.show, self.req, fakes.FAKE_UUID)
if enable_consoleauth:
mock_check_token.assert_called_once_with(self.context,
fakes.FAKE_UUID)
mock_validate.assert_not_called()
else:
mock_validate.assert_called_once_with(self.context,
fakes.FAKE_UUID)
mock_check_token.assert_not_called()
mock_validate.assert_called_once_with(self.context, fakes.FAKE_UUID)
@ddt.ddt
class ConsoleAuthTokensExtensionTestV231(ConsoleAuthTokensExtensionTestV21):
def setUp(self):
@ -139,30 +85,13 @@ class ConsoleAuthTokensExtensionTestV231(ConsoleAuthTokensExtensionTestV21):
self.req.api_version_request = api_version_request.APIVersionRequest(
'2.31')
@ddt.data(True, False)
@mock.patch('nova.objects.ConsoleAuthToken.validate')
@mock.patch.object(consoleauth_rpcapi.ConsoleAuthAPI, 'check_token')
def test_get_console_connect_info_nonrdp_console_type(self,
enable_consoleauth,
mock_check,
mock_validate):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
mock_validate.return_value = objects.ConsoleAuthToken(
instance_uuid=fakes.FAKE_UUID, host='fake_host', port='1234',
internal_access_path='fake_access_path', console_type='webmks',
token=fakes.FAKE_UUID)
mock_check.return_value = {'instance_uuid': fakes.FAKE_UUID,
'host': 'fake_host',
'port': '1234',
'internal_access_path': 'fake_access_path',
'console_type': 'webmks'}
@mock.patch('nova.objects.ConsoleAuthToken.validate',
return_value = objects.ConsoleAuthToken(
instance_uuid=fakes.FAKE_UUID, host='fake_host',
port='1234', internal_access_path='fake_access_path',
console_type='webmks',
token=fakes.FAKE_UUID))
def test_get_console_connect_info_nonrdp_console_type(self, mock_validate):
output = self.controller.show(self.req, fakes.FAKE_UUID)
if enable_consoleauth:
self.assertEqual(self._EXPECTED_OUTPUT, output)
mock_check.assert_called_once_with(self.context, fakes.FAKE_UUID)
mock_validate.assert_not_called()
else:
self.assertEqual(self._EXPECTED_OUTPUT_DB, output)
mock_validate.assert_called_once_with(self.context,
fakes.FAKE_UUID)
mock_check.assert_not_called()
self.assertEqual(self._EXPECTED_OUTPUT_DB, output)
mock_validate.assert_called_once_with(self.context, fakes.FAKE_UUID)

View File

@ -10157,12 +10157,8 @@ class ComputeAPITestCase(BaseTestCase):
self.assertRaises(exception.InvalidVolume,
self.compute_api.rescue, self.context, instance)
@ddt.data(True, False)
@mock.patch.object(compute_rpcapi.ComputeAPI, 'get_vnc_console')
@mock.patch.object(compute.consoleauth_rpcapi.ConsoleAuthAPI,
'authorize_console')
def test_vnc_console(self, enable_consoleauth, mock_auth, mock_get):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_vnc_console(self, mock_get):
# Make sure we can a vnc console for an instance.
fake_instance = self._fake_instance(
@ -10185,14 +10181,6 @@ class ComputeAPITestCase(BaseTestCase):
mock_get.assert_called_once_with(
self.context, instance=fake_instance,
console_type=fake_console_type)
if enable_consoleauth:
mock_auth.assert_called_once_with(
self.context, 'fake_token', fake_console_type,
'fake_console_host', 'fake_console_port', 'fake_access_path',
'f3000000-0000-0000-0000-000000000000',
access_url='fake_console_url')
else:
mock_auth.assert_not_called()
def test_get_vnc_console_no_host(self):
instance = self._create_fake_instance_obj(params={'host': ''})
@ -10201,12 +10189,8 @@ class ComputeAPITestCase(BaseTestCase):
self.compute_api.get_vnc_console,
self.context, instance, 'novnc')
@ddt.data(True, False)
@mock.patch.object(compute.consoleauth_rpcapi.ConsoleAuthAPI,
'authorize_console')
@mock.patch.object(compute_rpcapi.ComputeAPI, 'get_spice_console')
def test_spice_console(self, enable_consoleauth, mock_spice, mock_auth):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_spice_console(self, mock_spice):
# Make sure we can a spice console for an instance.
fake_instance = self._fake_instance(
@ -10229,14 +10213,6 @@ class ComputeAPITestCase(BaseTestCase):
mock_spice.assert_called_once_with(self.context,
instance=fake_instance,
console_type=fake_console_type)
if enable_consoleauth:
mock_auth.assert_called_once_with(
self.context, 'fake_token', fake_console_type,
'fake_console_host', 'fake_console_port', 'fake_access_path',
'f3000000-0000-0000-0000-000000000000',
access_url='fake_console_url')
else:
mock_auth.assert_not_called()
def test_get_spice_console_no_host(self):
instance = self._create_fake_instance_obj(params={'host': ''})
@ -10264,12 +10240,8 @@ class ComputeAPITestCase(BaseTestCase):
getattr(self.compute_api, 'get_%s_console' % console_type),
self.context, instance, console_type)
@ddt.data(True, False)
@mock.patch.object(compute.consoleauth_rpcapi.ConsoleAuthAPI,
'authorize_console')
@mock.patch.object(compute_rpcapi.ComputeAPI, 'get_rdp_console')
def test_rdp_console(self, enable_consoleauth, mock_rdp, mock_auth):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_rdp_console(self, mock_rdp):
# Make sure we can a rdp console for an instance.
fake_instance = self._fake_instance({
'uuid': 'f3000000-0000-0000-0000-000000000000',
@ -10290,14 +10262,6 @@ class ComputeAPITestCase(BaseTestCase):
self.assertEqual(console, {'url': 'fake_console_url'})
mock_rdp.assert_called_once_with(self.context, instance=fake_instance,
console_type=fake_console_type)
if enable_consoleauth:
mock_auth.assert_called_once_with(
self.context, 'fake_token', fake_console_type,
'fake_console_host', 'fake_console_port', 'fake_access_path',
'f3000000-0000-0000-0000-000000000000',
access_url='fake_console_url')
else:
mock_auth.assert_not_called()
def test_get_rdp_console_no_host(self):
instance = self._create_fake_instance_obj(params={'host': ''})
@ -10321,21 +10285,8 @@ class ComputeAPITestCase(BaseTestCase):
'instance_uuid': fake_instance.uuid,
'access_url': 'fake_access_url'}
rpcapi = compute_rpcapi.ComputeAPI
with test.nested(
mock.patch.object(rpcapi, 'get_serial_console',
return_value=fake_connect_info),
mock.patch.object(self.compute_api.consoleauth_rpcapi,
'authorize_console')
) as (mock_get_serial_console, mock_authorize_console):
self.compute_api.consoleauth_rpcapi.authorize_console(
self.context, 'fake_token', fake_console_type,
'fake_serial_host', 'fake_tcp_port',
'fake_access_path',
'f3000000-0000-0000-0000-000000000000',
access_url='fake_access_url')
with mock.patch.object(self.compute_api.compute_rpcapi,
'get_serial_console', return_value=fake_connect_info):
console = self.compute_api.get_serial_console(self.context,
fake_instance,
fake_console_type)
@ -10362,13 +10313,8 @@ class ComputeAPITestCase(BaseTestCase):
'instance_uuid': fake_instance.uuid,
'access_url': 'fake_access_url'}
with test.nested(
mock.patch.object(self.compute_api.compute_rpcapi,
'get_mks_console',
return_value=fake_connect_info),
mock.patch.object(self.compute_api.consoleauth_rpcapi,
'authorize_console')
) as (mock_get_mks_console, mock_authorize_console):
with mock.patch.object(self.compute_api.compute_rpcapi,
'get_mks_console', return_value=fake_connect_info):
console = self.compute_api.get_mks_console(self.context,
fake_instance,
fake_console_type)
@ -11433,17 +11379,14 @@ class ComputeAPITestCase(BaseTestCase):
instance, instance_uuid = self._run_instance()
rpcapi = self.compute_api.compute_task_api
consoleauth_rpcapi = self.compute_api.consoleauth_rpcapi
fake_spec = objects.RequestSpec()
@mock.patch.object(consoleauth_rpcapi, 'delete_tokens_for_instance')
@mock.patch.object(rpcapi, 'live_migrate_instance')
@mock.patch.object(objects.ComputeNodeList, 'get_all_by_host')
@mock.patch.object(objects.RequestSpec, 'get_by_instance_uuid')
@mock.patch.object(self.compute_api, '_record_action_start')
def do_test(record_action_start, get_by_instance_uuid,
get_all_by_host, live_migrate_instance,
delete_tokens_for_instance):
get_all_by_host, live_migrate_instance):
get_by_instance_uuid.return_value = fake_spec
get_all_by_host.return_value = objects.ComputeNodeList(
objects=[objects.ComputeNode(
@ -11468,12 +11411,6 @@ class ComputeAPITestCase(BaseTestCase):
disk_over_commit=True,
request_spec=fake_spec, async_=False)
if CONF.workarounds.enable_consoleauth:
delete_tokens_for_instance.assert_called_once_with(
self.context, instance.uuid)
else:
delete_tokens_for_instance.assert_not_called()
do_test()
instance.refresh()
self.assertEqual(instance['task_state'], task_states.MIGRATING)
@ -11484,19 +11421,13 @@ class ComputeAPITestCase(BaseTestCase):
self.assertEqual('fake_dest_host', req_dest.host)
self.assertEqual('fake_dest_node', req_dest.node)
@ddt.data(True, False)
def test_live_migrate(self, enable_consoleauth):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_live_migrate(self):
self._test_live_migrate()
@ddt.data(True, False)
def test_live_migrate_with_not_forced_host(self, enable_consoleauth):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_live_migrate_with_not_forced_host(self):
self._test_live_migrate(force=False)
@ddt.data(True, False)
def test_live_migrate_with_forced_host(self, enable_consoleauth):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_live_migrate_with_forced_host(self):
self._test_live_migrate(force=True)
def test_fail_live_migrate_with_non_existing_destination(self):

View File

@ -37,7 +37,6 @@ from nova.compute import utils as compute_utils
from nova.compute import vm_states
from nova import conductor
import nova.conf
from nova.consoleauth import rpcapi as consoleauth_rpcapi
from nova import context
from nova.db import api as db
from nova import exception
@ -992,8 +991,6 @@ class _ComputeAPIUnitTestMixIn(object):
@mock.patch.object(image_api.API, 'delete')
@mock.patch.object(objects.InstanceMapping, 'save')
@mock.patch.object(objects.InstanceMapping, 'get_by_instance_uuid')
@mock.patch.object(consoleauth_rpcapi.ConsoleAuthAPI,
'delete_tokens_for_instance')
@mock.patch.object(compute_utils,
'notify_about_instance_usage')
@mock.patch.object(db, 'instance_destroy')
@ -1010,7 +1007,7 @@ class _ComputeAPIUnitTestMixIn(object):
def _test_delete(self, delete_type, mock_save, mock_bdm_get, mock_elevated,
mock_get_cn, mock_up, mock_record, mock_inst_update,
mock_deallocate, mock_inst_meta, mock_inst_destroy,
mock_notify_legacy, mock_del_token, mock_get_inst,
mock_notify_legacy, mock_get_inst,
mock_save_im, mock_image_delete, mock_mig_get,
mock_notify, **attrs):
expected_save_calls = [mock.call()]
@ -1175,11 +1172,6 @@ class _ComputeAPIUnitTestMixIn(object):
mock_terminate.assert_called_once_with(
self.context, inst, [])
if CONF.workarounds.enable_consoleauth:
mock_del_token.assert_called_once_with(self.context, instance_uuid)
else:
mock_del_token.assert_not_called()
if is_shelved:
mock_image_delete.assert_called_once_with(self.context,
snapshot_id)
@ -1204,9 +1196,7 @@ class _ComputeAPIUnitTestMixIn(object):
task_state=task_states.RESIZE_FINISH,
old_flavor=old_flavor)
@ddt.data(True, False)
def test_delete_in_resized(self, enable_consoleauth):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_delete_in_resized(self):
self._test_delete('delete', vm_state=vm_states.RESIZED)
def test_delete_shelved(self):
@ -1215,9 +1205,7 @@ class _ComputeAPIUnitTestMixIn(object):
vm_state=vm_states.SHELVED,
system_metadata=fake_sys_meta)
@ddt.data(True, False)
def test_delete_shelved_offloaded(self, enable_consoleauth):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_delete_shelved_offloaded(self):
fake_sys_meta = {'shelved_image_id': SHELVED_IMAGE}
self._test_delete('delete',
vm_state=vm_states.SHELVED_OFFLOADED,
@ -1235,9 +1223,7 @@ class _ComputeAPIUnitTestMixIn(object):
vm_state=vm_states.SHELVED_OFFLOADED,
system_metadata=fake_sys_meta)
@ddt.data(True, False)
def test_delete_shelved_exception(self, enable_consoleauth):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_delete_shelved_exception(self):
fake_sys_meta = {'shelved_image_id': SHELVED_IMAGE_EXCEPTION}
self._test_delete('delete',
vm_state=vm_states.SHELVED,
@ -1252,9 +1238,7 @@ class _ComputeAPIUnitTestMixIn(object):
def test_delete_soft_in_resized(self):
self._test_delete('soft_delete', vm_state=vm_states.RESIZED)
@ddt.data(True, False)
def test_delete_soft(self, enable_consoleauth):
self.flags(enable_consoleauth=enable_consoleauth, group='workarounds')
def test_delete_soft(self):
self._test_delete('soft_delete')
def test_delete_forced(self):

View File

@ -66,10 +66,9 @@ class NovaProxyRequestHandlerDBTestCase(test.TestCase):
@mock.patch('nova.objects.ConsoleAuthToken.validate')
@mock.patch('nova.objects.Instance.get_by_uuid')
@mock.patch('nova.compute.rpcapi.ComputeAPI.validate_console_port')
@mock.patch('nova.consoleauth.rpcapi.ConsoleAuthAPI.check_token')
def test_new_websocket_client_db(
self, mock_ca_check, mock_validate_port, mock_inst_get,
mock_validate, internal_access_path=None,
self, mock_validate_port, mock_inst_get, mock_validate,
internal_access_path=None,
instance_not_found=False):
db_obj = self._fake_console_db(
@ -113,7 +112,6 @@ class NovaProxyRequestHandlerDBTestCase(test.TestCase):
mock_validate_port.assert_called_once_with(
ctxt, mock_inst_get.return_value, str(db_obj['port']),
db_obj['console_type'])
mock_ca_check.assert_not_called()
self.wh.socket.assert_called_with('node1', 10000, connect=True)
@ -201,60 +199,6 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
'Host': 'example.net:6080',
}
@mock.patch('nova.consoleauth.rpcapi.ConsoleAuthAPI.check_token')
def test_new_websocket_client_enable_consoleauth(self, check_token):
self.flags(enable_consoleauth=True, group='workarounds')
check_token.return_value = {
'host': 'node1',
'port': '10000',
'console_type': 'novnc',
'access_url': 'https://example.net:6080'
}
self.wh.socket.return_value = '<socket>'
self.wh.path = "http://127.0.0.1/?%s" % self.path
self.wh.headers = self.fake_header
self.wh.new_websocket_client()
check_token.assert_called_with(mock.ANY, token="123-456-789")
self.wh.socket.assert_called_with('node1', 10000, connect=True)
self.wh.do_proxy.assert_called_with('<socket>')
@mock.patch('nova.consoleauth.rpcapi.ConsoleAuthAPI.check_token',
return_value=None)
@mock.patch('nova.console.websocketproxy.NovaProxyRequestHandlerBase.'
'_check_console_port')
@mock.patch('nova.objects.ConsoleAuthToken.validate')
def test_new_websocket_client_enable_consoleauth_fallback(self, validate,
check_port,
check_token):
# Since consoleauth is enabled, it should be called first before
# falling back to the database.
self.flags(enable_consoleauth=True, group='workarounds')
params = {
'id': 1,
'token': '123-456-789',
'instance_uuid': uuids.instance,
'host': 'node1',
'port': '10000',
'console_type': 'novnc',
'access_url_base': 'https://example.net:6080'
}
validate.return_value = objects.ConsoleAuthToken(**params)
self.wh.socket.return_value = '<socket>'
self.wh.path = "http://127.0.0.1/?%s" % self.path
self.wh.headers = self.fake_header
self.wh.new_websocket_client()
check_token.assert_called_with(mock.ANY, token="123-456-789")
validate.assert_called_with(mock.ANY, "123-456-789")
self.wh.socket.assert_called_with('node1', 10000, connect=True)
self.wh.do_proxy.assert_called_with('<socket>')
@mock.patch('nova.console.websocketproxy.NovaProxyRequestHandlerBase.'
'_check_console_port')
@mock.patch('nova.objects.ConsoleAuthToken.validate')
@ -441,23 +385,6 @@ class NovaProxyRequestHandlerBaseTestCase(test.NoDBTestCase):
self.wh.socket.assert_called_with('node1', 10000, connect=True)
self.wh.do_proxy.assert_called_with('<socket>')
@mock.patch.object(websocketproxy, 'sys')
@mock.patch('nova.consoleauth.rpcapi.ConsoleAuthAPI.check_token')
def test_new_websocket_client_py273_special_scheme(
self, check_token, mock_sys):
mock_sys.version_info = (2, 7, 3)
check_token.return_value = {
'host': 'node1',
'port': '10000',
'console_type': 'novnc'
}
self.wh.socket.return_value = '<socket>'
self.wh.path = "ws://127.0.0.1/?%s" % self.path
self.wh.headers = self.fake_header
self.assertRaises(exception.NovaException,
self.wh.new_websocket_client)
@mock.patch('socket.getfqdn')
def test_address_string_doesnt_do_reverse_dns_lookup(self, getfqdn):
request_mock = mock.MagicMock()

View File

@ -1,240 +0,0 @@
# Copyright 2012 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 Consoleauth Code.
"""
import mock
from oslo_utils.fixture import uuidsentinel as uuids
from oslo_utils import timeutils
import six
from nova.consoleauth import manager
from nova import context
from nova import objects
from nova import test
class ConsoleauthTestCase(test.NoDBTestCase):
"""Test Case for consoleauth."""
rpcapi = 'nova.compute.rpcapi.ComputeAPI.'
def setUp(self):
super(ConsoleauthTestCase, self).setUp()
self.manager_api = self.manager = manager.ConsoleAuthManager()
self.context = context.get_admin_context()
self.instance_uuid = '00000000-0000-0000-0000-000000000000'
self.is_cells = False
def test_reset(self):
with mock.patch('nova.compute.rpcapi.ComputeAPI') as mock_rpc:
old_rpcapi = self.manager_api.compute_rpcapi
self.manager_api.reset()
mock_rpc.assert_called_once_with()
self.assertNotEqual(old_rpcapi,
self.manager_api.compute_rpcapi)
@mock.patch('nova.objects.instance.Instance.get_by_uuid')
def test_tokens_expire(self, mock_get):
mock_get.return_value = None
# NOTE(danms): Get the faked InstanceMapping from the SingleCellSimple
# fixture so we can return it from our own mock to verify
# that it was called
fake_im = objects.InstanceMapping.get_by_instance_uuid(self.context,
uuids.instance)
# Test that tokens expire correctly.
self.useFixture(test.TimeOverride())
token = u'mytok'
self.flags(token_ttl=1, group='consoleauth')
self._stub_validate_console_port(True)
self.manager_api.authorize_console(self.context, token, 'novnc',
'127.0.0.1', '8080', 'host',
self.instance_uuid)
with mock.patch('nova.objects.InstanceMapping.'
'get_by_instance_uuid') as mock_get:
mock_get.return_value = fake_im
self.assertIsNotNone(self.manager_api.check_token(self.context,
token))
timeutils.advance_time_seconds(1)
self.assertIsNone(self.manager_api.check_token(self.context,
token))
if not self.is_cells:
mock_get.assert_called_once_with(self.context,
self.instance_uuid)
def _stub_validate_console_port(self, result):
def fake_validate_console_port(self, ctxt, instance,
port, console_type):
return result
self.stub_out(self.rpcapi + 'validate_console_port',
fake_validate_console_port)
@mock.patch('nova.objects.instance.Instance.get_by_uuid')
def test_multiple_tokens_for_instance(self, mock_get):
mock_get.return_value = None
tokens = [u"token" + str(i) for i in range(10)]
self._stub_validate_console_port(True)
for token in tokens:
self.manager_api.authorize_console(self.context, token, 'novnc',
'127.0.0.1', '8080', 'host',
self.instance_uuid)
for token in tokens:
self.assertIsNotNone(
self.manager_api.check_token(self.context, token))
def test_delete_tokens_for_instance(self):
tokens = [u"token" + str(i) for i in range(10)]
for token in tokens:
self.manager_api.authorize_console(self.context, token, 'novnc',
'127.0.0.1', '8080', 'host',
self.instance_uuid)
self.manager_api.delete_tokens_for_instance(self.context,
self.instance_uuid)
stored_tokens = self.manager._get_tokens_for_instance(
self.instance_uuid)
self.assertEqual(len(stored_tokens), 0)
for token in tokens:
self.assertIsNone(
self.manager_api.check_token(self.context, token))
def test_delete_tokens_for_instance_no_tokens(self):
with test.nested(
mock.patch.object(self.manager, '_get_tokens_for_instance',
return_value=[]),
mock.patch.object(self.manager.mc, 'delete_multi'),
mock.patch.object(self.manager.mc_instance, 'delete')
) as (
mock_get_tokens, mock_delete_multi, mock_delete
):
self.manager.delete_tokens_for_instance(
self.context, self.instance_uuid)
# Since here were no tokens, we didn't try to clear anything
# from the cache.
mock_delete_multi.assert_not_called()
mock_delete.assert_called_once_with(
self.instance_uuid.encode('UTF-8'))
@mock.patch('nova.objects.instance.Instance.get_by_uuid')
def test_wrong_token_has_port(self, mock_get):
mock_get.return_value = None
token = u'mytok'
self._stub_validate_console_port(False)
self.manager_api.authorize_console(self.context, token, 'novnc',
'127.0.0.1', '8080', 'host',
instance_uuid=self.instance_uuid)
self.assertIsNone(self.manager_api.check_token(self.context, token))
def test_delete_expired_tokens(self):
self.useFixture(test.TimeOverride())
token = u'mytok'
self.flags(token_ttl=1, group='consoleauth')
self._stub_validate_console_port(True)
self.manager_api.authorize_console(self.context, token, 'novnc',
'127.0.0.1', '8080', 'host',
self.instance_uuid)
timeutils.advance_time_seconds(1)
self.assertIsNone(self.manager_api.check_token(self.context, token))
token1 = u'mytok2'
self.manager_api.authorize_console(self.context, token1, 'novnc',
'127.0.0.1', '8080', 'host',
self.instance_uuid)
stored_tokens = self.manager._get_tokens_for_instance(
self.instance_uuid)
# when trying to store token1, expired token is removed fist.
self.assertEqual(len(stored_tokens), 1)
self.assertEqual(stored_tokens[0], token1)
class ControlauthMemcacheEncodingTestCase(test.NoDBTestCase):
def setUp(self):
super(ControlauthMemcacheEncodingTestCase, self).setUp()
self.manager = manager.ConsoleAuthManager()
self.context = context.get_admin_context()
self.u_token = u"token"
self.u_instance = u"instance"
def test_authorize_console_encoding(self):
with test.nested(
mock.patch.object(self.manager.mc_instance,
'set', return_value=None),
mock.patch.object(self.manager.mc_instance,
'get', return_value='["token"]'),
mock.patch.object(self.manager.mc,
'set', return_value=None),
mock.patch.object(self.manager.mc,
'get', return_value=None),
mock.patch.object(self.manager.mc,
'get_multi', return_value=["token1"]),
) as (
mock_instance_set,
mock_instance_get,
mock_set,
mock_get,
mock_get_multi):
self.manager.authorize_console(self.context, self.u_token,
'novnc', '127.0.0.1', '8080',
'host', self.u_instance)
mock_set.assert_has_calls([mock.call(b'token', mock.ANY)])
mock_instance_get.assert_has_calls([mock.call(b'instance')])
mock_get_multi.assert_has_calls([mock.call([b'token'])])
mock_instance_set.assert_has_calls(
[mock.call(b'instance', mock.ANY)])
def test_check_token_encoding(self):
with mock.patch.object(self.manager.mc,
"get",
return_value=None) as mock_get:
self.manager.check_token(self.context, self.u_token)
mock_get.assert_called_once_with(test.MatchType(six.binary_type))
def test_delete_tokens_for_instance_encoding(self):
with test.nested(
mock.patch.object(self.manager.mc_instance,
'get', return_value='["token"]'),
mock.patch.object(self.manager.mc_instance,
'delete', return_value=True),
mock.patch.object(self.manager.mc,
'get'),
mock.patch.object(self.manager.mc,
'delete_multi', return_value=True),
) as (
mock_instance_get,
mock_instance_delete,
mock_get,
mock_delete_multi):
self.manager.delete_tokens_for_instance(self.context,
self.u_instance)
mock_instance_get.assert_has_calls([mock.call(b'instance')])
mock_instance_delete.assert_has_calls([mock.call(b'instance')])
mock_delete_multi.assert_has_calls([mock.call([b'token'])])

View File

@ -1,90 +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.
"""
Unit Tests for nova.consoleauth.rpcapi
"""
import mock
from nova.consoleauth import rpcapi as consoleauth_rpcapi
from nova import context
from nova import test
class ConsoleAuthRpcAPITestCase(test.NoDBTestCase):
DROPPED_ARG = object()
def _test_consoleauth_api(self, method, **kwargs):
do_cast = kwargs.pop('_do_cast', False)
ctxt = context.RequestContext('fake_user', 'fake_project')
rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
self.assertIsNotNone(rpcapi.client)
self.assertEqual(rpcapi.client.target.topic,
consoleauth_rpcapi.RPC_TOPIC)
orig_prepare = rpcapi.client.prepare
version = kwargs.pop('version', None)
rpc_kwargs = {k: v for k, v in kwargs.items()
if v is not self.DROPPED_ARG}
with test.nested(
mock.patch.object(rpcapi.client, 'cast' if do_cast else 'call'),
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 = None if do_cast else 'foo'
def fake_csv(v):
if version:
return orig_prepare(
version_cap=version).can_send_version(version=v)
else:
return orig_prepare().can_send_version()
csv_mock.side_effect = fake_csv
retval = getattr(rpcapi, method)(ctxt, **kwargs)
self.assertEqual(retval, rpc_mock.return_value)
if version:
prepare_mock.assert_called_once_with(version=version)
else:
prepare_mock.assert_called_once_with()
rpc_mock.assert_called_once_with(ctxt, method, **rpc_kwargs)
def test_authorize_console(self):
self._test_consoleauth_api('authorize_console', token='token',
console_type='ctype', host='h', port='p',
internal_access_path='iap', instance_uuid="instance",
access_url=self.DROPPED_ARG, version='2.0')
def test_authorize_console_access_url(self):
self._test_consoleauth_api('authorize_console', token='token',
console_type='ctype', host='h', port='p',
internal_access_path='iap', instance_uuid="instance",
access_url="fake_access_url", version='2.1')
def test_check_token(self):
self._test_consoleauth_api('check_token', token='t')
def test_delete_tokens_for_instnace(self):
self._test_consoleauth_api('delete_tokens_for_instance',
_do_cast=True,
instance_uuid="instance")

View File

@ -57,8 +57,6 @@ class TestProfiler(test.NoDBTestCase):
'nova.conductor.rpcapi.ConductorAPI',
'nova.console.manager.ConsoleProxyManager',
'nova.console.rpcapi.ConsoleAPI',
'nova.consoleauth.manager.ConsoleAuthManager',
'nova.consoleauth.rpcapi.ConsoleAuthAPI',
'nova.image.api.API',
'nova.network.api.API',
'nova.network.manager.FlatDHCPManager',

View File

@ -0,0 +1,9 @@
---
upgrade:
- |
The ``nova-consoleauth`` service has been deprecated since the 18.0.0
Rocky release and has now been removed. The following configuration
options have been removed:
* ``[upgrade_levels] consoleauth``
* ``[workarounds] enable_consoleauth``

View File

@ -59,7 +59,6 @@ console_scripts =
nova-compute = nova.cmd.compute:main
nova-conductor = nova.cmd.conductor:main
nova-console = nova.cmd.console:main
nova-consoleauth = nova.cmd.consoleauth:main
nova-dhcpbridge = nova.cmd.dhcpbridge:main
nova-manage = nova.cmd.manage:main
nova-network = nova.cmd.network:main