From: Volker Theile Date: Thu, 24 Oct 2019 11:51:08 +0000 (+0200) Subject: mgr/dashboard: Dashboard can't handle self-signed cert on Grafana API X-Git-Tag: v14.2.8~98^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=a83e839b215f3ee89dfc6b249d4bd1db3798068d;p=ceph.git mgr/dashboard: Dashboard can't handle self-signed cert on Grafana API To configure SSL certificate verification use the following command: $ ceph dashboard set-grafana-api-ssl-verify true|false Fixes: https://tracker.ceph.com/issues/42445 Signed-off-by: Volker Theile (cherry picked from commit e047ffd20d4c73bae5ca88303a8ca65f51d73e9d) --- diff --git a/doc/mgr/dashboard.rst b/doc/mgr/dashboard.rst index 8ba2111d2ac18..26c95ca0316ee 100644 --- a/doc/mgr/dashboard.rst +++ b/doc/mgr/dashboard.rst @@ -425,6 +425,12 @@ The format of url is : `::` above, check your browser's documentation on how to unblock mixed content. Alternatively, consider enabling SSL/TLS support in Grafana. +If you are using a self-signed certificate in your Grafana setup, then you should +disable certificate verification in the dashboard to avoid refused connections, +e.g. caused by certificates signed by unknown CA or not matching the host name:: + + $ ceph dashboard set-grafana-api-ssl-verify False + You can directly access Grafana Instance as well to monitor your cluster. .. _dashboard-sso-support: diff --git a/src/pybind/mgr/dashboard/grafana.py b/src/pybind/mgr/dashboard/grafana.py index 1399dce3c4b23..e115755396754 100644 --- a/src/pybind/mgr/dashboard/grafana.py +++ b/src/pybind/mgr/dashboard/grafana.py @@ -17,8 +17,8 @@ class GrafanaRestClient(object): def url_validation(method, path): response = requests.request( method, - path) - + path, + verify=Settings.GRAFANA_API_SSL_VERIFY) return response.status_code @staticmethod @@ -48,6 +48,7 @@ class GrafanaRestClient(object): data=json.dumps(payload), auth=(Settings.GRAFANA_API_USERNAME, Settings.GRAFANA_API_PASSWORD), + verify=Settings.GRAFANA_API_SSL_VERIFY ) except requests.ConnectionError: raise GrafanaError("Could not connect to Grafana server") diff --git a/src/pybind/mgr/dashboard/settings.py b/src/pybind/mgr/dashboard/settings.py index 8b57d1bed4c17..bda0dda04133d 100644 --- a/src/pybind/mgr/dashboard/settings.py +++ b/src/pybind/mgr/dashboard/settings.py @@ -39,6 +39,7 @@ class Options(object): GRAFANA_API_URL = ('', str) GRAFANA_API_USERNAME = ('admin', str) GRAFANA_API_PASSWORD = ('admin', str) + GRAFANA_API_SSL_VERIFY = (True, bool) GRAFANA_UPDATE_DASHBOARDS = (False, bool) # NFS Ganesha settings diff --git a/src/pybind/mgr/dashboard/tests/test_grafana.py b/src/pybind/mgr/dashboard/tests/test_grafana.py index f880400b06c22..aa3f9f8cb9503 100644 --- a/src/pybind/mgr/dashboard/tests/test_grafana.py +++ b/src/pybind/mgr/dashboard/tests/test_grafana.py @@ -1,5 +1,15 @@ -from . import ControllerTestCase +import json +import unittest + +try: + from mock import patch +except ImportError: + from unittest.mock import patch + +from . import ControllerTestCase, KVStoreMockMixin from ..controllers.grafana import Grafana +from ..grafana import GrafanaRestClient +from ..settings import Settings from .. import mgr @@ -48,3 +58,57 @@ class GrafanaTest(ControllerTestCase): self.server_settings(password=None) self._post('/api/grafana/dashboards') self.assertStatus(500) + + +class GrafanaRestClientTest(unittest.TestCase, KVStoreMockMixin): + headers = { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + } + payload = json.dumps({ + 'dashboard': 'foo', + 'overwrite': True + }) + + def setUp(self): + self.mock_kv_store() + Settings.GRAFANA_API_URL = 'https://foo/bar' + Settings.GRAFANA_API_USERNAME = 'xyz' + Settings.GRAFANA_API_PASSWORD = 'abc' + Settings.GRAFANA_API_SSL_VERIFY = True + + def test_ssl_verify_url_validation(self): + with patch('requests.request') as mock_request: + rest_client = GrafanaRestClient() + rest_client.url_validation('FOO', Settings.GRAFANA_API_URL) + mock_request.assert_called_with('FOO', Settings.GRAFANA_API_URL, + verify=True) + + def test_no_ssl_verify_url_validation(self): + Settings.GRAFANA_API_SSL_VERIFY = False + with patch('requests.request') as mock_request: + rest_client = GrafanaRestClient() + rest_client.url_validation('BAR', Settings.GRAFANA_API_URL) + mock_request.assert_called_with('BAR', Settings.GRAFANA_API_URL, + verify=False) + + def test_ssl_verify_push_dashboard(self): + with patch('requests.post') as mock_request: + rest_client = GrafanaRestClient() + rest_client.push_dashboard('foo') + mock_request.assert_called_with( + Settings.GRAFANA_API_URL + '/api/dashboards/db', + auth=(Settings.GRAFANA_API_USERNAME, + Settings.GRAFANA_API_PASSWORD), + data=self.payload, headers=self.headers, verify=True) + + def test_no_ssl_verify_push_dashboard(self): + Settings.GRAFANA_API_SSL_VERIFY = False + with patch('requests.post') as mock_request: + rest_client = GrafanaRestClient() + rest_client.push_dashboard('foo') + mock_request.assert_called_with( + Settings.GRAFANA_API_URL + '/api/dashboards/db', + auth=(Settings.GRAFANA_API_USERNAME, + Settings.GRAFANA_API_PASSWORD), + data=self.payload, headers=self.headers, verify=False)