From 446881f8fe26b5af5d535d72f912d16dbd01b500 Mon Sep 17 00:00:00 2001 From: Volker Theile Date: Tue, 31 Jul 2018 10:43:06 +0200 Subject: [PATCH] mgr/dashboard: RestClient can't handle ProtocolError exceptions Fixes: https://tracker.ceph.com/issues/25190 Signed-off-by: Volker Theile --- src/pybind/mgr/dashboard/rest_client.py | 7 ++- .../mgr/dashboard/tests/test_rest_client.py | 52 ++++++++++++++++++- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/pybind/mgr/dashboard/rest_client.py b/src/pybind/mgr/dashboard/rest_client.py index 6099fe94525..a8ac9f8ea6f 100644 --- a/src/pybind/mgr/dashboard/rest_client.py +++ b/src/pybind/mgr/dashboard/rest_client.py @@ -439,8 +439,11 @@ class RestClient(object): logger.error("%s REST API failed %s, SSL error.", self.client_name, method.upper()) else: - match = re.match(r'.*: \[Errno (-?\d+)\] (.+)', - ex.args[0].reason.args[0]) + try: + match = re.match(r'.*: \[Errno (-?\d+)\] (.+)', + ex.args[0].reason.args[0]) + except AttributeError: + match = False if match: errno = match.group(1) strerror = match.group(2) diff --git a/src/pybind/mgr/dashboard/tests/test_rest_client.py b/src/pybind/mgr/dashboard/tests/test_rest_client.py index 7a15319ff9e..f1f0267abd5 100644 --- a/src/pybind/mgr/dashboard/tests/test_rest_client.py +++ b/src/pybind/mgr/dashboard/tests/test_rest_client.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- import unittest +import requests.exceptions from mock import patch +from urllib3.exceptions import MaxRetryError, ProtocolError from .. import mgr -from ..rest_client import RestClient +from ..rest_client import RequestException, RestClient class RestClientTest(unittest.TestCase): @@ -42,3 +44,51 @@ class RestClientTest(unittest.TestCase): mock_request.assert_called_with( 'GET', '/test', None, None, None, None, None, None, 40) + + +class RestClientDoRequestTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.mock_requests = patch('requests.Session').start() + cls.rest_client = RestClient('localhost', 8000, 'UnitTest') + + def test_do_request_exception_no_args(self): + self.mock_requests().get.side_effect = requests.exceptions.ConnectionError() + with self.assertRaises(RequestException) as context: + self.rest_client.do_request('GET', '/test') + self.assertEqual('UnitTest REST API cannot be reached. Please ' + 'check your configuration and that the API ' + 'endpoint is accessible', + context.exception.message) + + def test_do_request_exception_args_1(self): + self.mock_requests().post.side_effect = requests.exceptions.ConnectionError( + MaxRetryError('Abc', 'http://xxx.yyy', 'too many redirects')) + with self.assertRaises(RequestException) as context: + self.rest_client.do_request('POST', '/test') + self.assertEqual('UnitTest REST API cannot be reached. Please ' + 'check your configuration and that the API ' + 'endpoint is accessible', + context.exception.message) + + def test_do_request_exception_args_2(self): + self.mock_requests().put.side_effect = requests.exceptions.ConnectionError( + ProtocolError('Connection broken: xyz')) + with self.assertRaises(RequestException) as context: + self.rest_client.do_request('PUT', '/test') + self.assertEqual('UnitTest REST API cannot be reached. Please ' + 'check your configuration and that the API ' + 'endpoint is accessible', + context.exception.message) + + def test_do_request_exception_nested_args(self): + self.mock_requests().delete.side_effect = requests.exceptions.ConnectionError( + MaxRetryError('Xyz', 'https://foo.bar', + Exception('Foo: [Errno -42] bla bla bla'))) + with self.assertRaises(RequestException) as context: + self.rest_client.do_request('DELETE', '/test') + self.assertEqual('UnitTest REST API cannot be reached: bla ' + 'bla bla [errno -42]. Please check your ' + 'configuration and that the API endpoint ' + 'is accessible', + context.exception.message) -- 2.39.5