]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Set timeout in RestClient calls 23224/head
authorVolker Theile <vtheile@suse.com>
Tue, 24 Jul 2018 09:52:29 +0000 (11:52 +0200)
committerVolker Theile <vtheile@suse.com>
Fri, 27 Jul 2018 12:03:06 +0000 (14:03 +0200)
Set a default timeout of 45 seconds to all REST client calls. This can be customized via 'ceph dashboard set-rest-requests-timeout <seconds>'. Currently the REST client is only used by the RGW controller.

Signed-off-by: Volker Theile <vtheile@suse.com>
doc/mgr/dashboard.rst
src/pybind/mgr/dashboard/rest_client.py
src/pybind/mgr/dashboard/settings.py
src/pybind/mgr/dashboard/tests/test_rest_client.py [new file with mode: 0644]

index 7950758ab9060740226e69b629cbfda5a5a0f575..c521a24a6442af13c677325377b97791f8d69d01 100644 (file)
@@ -190,7 +190,7 @@ commands::
 
 
 Enabling the Object Gateway management frontend
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 To use the Object Gateway management functionality of the dashboard, you will
 need to provide the login credentials of a user with the ``system`` flag
@@ -232,6 +232,13 @@ exist and you may find yourself in the situation that you have to use them::
   $ ceph dashboard set-rgw-api-admin-resource <admin_resource>
   $ ceph dashboard set-rgw-api-user-id <user_id>
 
+If the Object Gateway takes too long to process requests and the dashboard runs
+into timeouts, then you can set the timeout value to your needs::
+
+  $ ceph dashboard set-rest-requests-timeout <seconds>
+
+The default value is 45 seconds.
+
 Enabling the Embedding of Grafana Dashboards
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index 3105545fc3beb73019453542917a161e482dc4e3..6099fe945254fae52ddbd4d902877191487110da 100644 (file)
 """
 from __future__ import absolute_import
 
+from .settings import Settings
 from .tools import build_url
 import inspect
 import re
 import requests
-from requests.exceptions import ConnectionError, InvalidURL
+from requests.exceptions import ConnectionError, InvalidURL, Timeout
 from . import logger
 
 try:
@@ -26,6 +27,18 @@ except ImportError:
     from urllib3.exceptions import SSLError
 
 
+class TimeoutRequestsSession(requests.Session):
+    """
+    Set timeout argument for all requests if this is not already done.
+    """
+    def request(self, *args, **kwargs):
+        if ((args[8] if len(args) > 8 else None) is None) \
+                and kwargs.get('timeout') is None:
+            if Settings.REST_REQUESTS_TIMEOUT > 0:
+                kwargs['timeout'] = Settings.REST_REQUESTS_TIMEOUT
+        return super(TimeoutRequestsSession, self).request(*args, **kwargs)
+
+
 class RequestException(Exception):
     def __init__(self,
                  message,
@@ -315,7 +328,7 @@ class RestClient(object):
         logger.debug("REST service base URL: %s", self.base_url)
         self.headers = {'Accept': 'application/json'}
         self.auth = auth
-        self.session = requests.Session()
+        self.session = TimeoutRequestsSession()
 
     def _login(self, request=None):
         pass
@@ -465,6 +478,12 @@ class RestClient(object):
             logger.exception("%s REST API failed %s: %s", self.client_name,
                              method.upper(), str(ex))
             raise RequestException(str(ex))
+        except Timeout as ex:
+            msg = "{} REST API {} timed out after {} seconds (url={}).".format(
+                self.client_name, ex.request.method, Settings.REST_REQUESTS_TIMEOUT,
+                ex.request.url)
+            logger.exception(msg)
+            raise RequestException(msg)
 
     @staticmethod
     def api(path, **api_kwargs):
index 4d1153e9e283bbd7658f1ebebe88026c09001593..16426f48bc23add96bd0367bb31b106c24b95497 100644 (file)
@@ -19,6 +19,7 @@ class Options(object):
         GRAFANA_API_PORT = (3000, int)
     """
     ENABLE_BROWSABLE_API = (True, bool)
+    REST_REQUESTS_TIMEOUT = (45, int)
 
     # RGW settings
     RGW_API_HOST = ('', str)
diff --git a/src/pybind/mgr/dashboard/tests/test_rest_client.py b/src/pybind/mgr/dashboard/tests/test_rest_client.py
new file mode 100644 (file)
index 0000000..7a15319
--- /dev/null
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+import unittest
+
+from mock import patch
+from .. import mgr
+from ..rest_client import RestClient
+
+
+class RestClientTest(unittest.TestCase):
+    def setUp(self):
+        settings = {'REST_REQUESTS_TIMEOUT': 45}
+        mgr.get_config.side_effect = settings.get
+
+    def test_timeout_auto_set(self):
+        with patch('requests.Session.request') as mock_request:
+            rest_client = RestClient('localhost', 8000)
+            rest_client.session.request('GET', '/test')
+            mock_request.assert_called_with('GET', '/test', timeout=45)
+
+    def test_timeout_auto_set_arg(self):
+        with patch('requests.Session.request') as mock_request:
+            rest_client = RestClient('localhost', 8000)
+            rest_client.session.request(
+                'GET', '/test', None, None, None, None,
+                None, None, None)
+            mock_request.assert_called_with(
+                'GET', '/test', None, None, None, None,
+                None, None, None, timeout=45)
+
+    def test_timeout_no_auto_set_kwarg(self):
+        with patch('requests.Session.request') as mock_request:
+            rest_client = RestClient('localhost', 8000)
+            rest_client.session.request('GET', '/test', timeout=20)
+            mock_request.assert_called_with('GET', '/test', timeout=20)
+
+    def test_timeout_no_auto_set_arg(self):
+        with patch('requests.Session.request') as mock_request:
+            rest_client = RestClient('localhost', 8000)
+            rest_client.session.request(
+                'GET', '/test', None, None, None, None,
+                None, None, 40)
+            mock_request.assert_called_with(
+                'GET', '/test', None, None, None, None,
+                None, None, 40)