diff --git a/doc/mgr/dashboard.rst b/doc/mgr/dashboard.rst index ff736eeaa7c..d004f3d70fc 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 1399dce3c4b..e1157553967 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 8b57d1bed4c..bda0dda0413 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 f880400b06c..aa3f9f8cb95 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)