Fix stacktraces with redis caching backend

If you use redis as a caching backend and you delete a server with
no consoleauth tokens you'll get a stacktrace as an empty list is
passed down to the redis client and ultimately the redis server
which responds with an error, complaining about a wrong number
of arguments for the del command.
The code now checks if the list of tokens is empty and only calls
the caching backend if there are tokens available to delete.
This also may improve performance, as it no longer hands down an
empty list.

Closes-Bug: #1794812
Change-Id: Iffdd4e251bfa2bac1bfd49498e32b738843709de
This commit is contained in:
Christoph Manns 2018-09-27 16:18:54 +02:00 committed by Matt Riedemann
parent 8c3d02ac3d
commit e5884a8fd5
2 changed files with 19 additions and 1 deletions

View File

@ -139,6 +139,7 @@ class ConsoleAuthManager(manager.Manager):
def delete_tokens_for_instance(self, context, instance_uuid): def delete_tokens_for_instance(self, context, instance_uuid):
tokens = self._get_tokens_for_instance(instance_uuid) tokens = self._get_tokens_for_instance(instance_uuid)
if tokens:
self.mc.delete_multi( self.mc.delete_multi(
[tok.encode('UTF-8') for tok in tokens]) [tok.encode('UTF-8') for tok in tokens])
self.mc_instance.delete(instance_uuid.encode('UTF-8')) self.mc_instance.delete(instance_uuid.encode('UTF-8'))

View File

@ -122,6 +122,23 @@ class ConsoleauthTestCase(test.NoDBTestCase):
self.assertIsNone( self.assertIsNone(
self.manager_api.check_token(self.context, token)) 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') @mock.patch('nova.objects.instance.Instance.get_by_uuid')
def test_wrong_token_has_port(self, mock_get): def test_wrong_token_has_port(self, mock_get):
mock_get.return_value = None mock_get.return_value = None