root_url = http://localhost:3000/api/grafana/proxy
-After you have configured Grafana and Prometheus, you will need to tell the
-Ceph Manager Dashboard where it can access Grafana and what the credentials are
-to do so. This can be done by using the following commands::
+After you have set up Grafana and Prometheus, you will need to configure the
+connection information that the Ceph Manager Dashboard will use to access Grafana.
+This includes setting the authentication method to be used, the corresponding login
+credentials as well as the URL at which the Grafana instance can be reached.
+
+The URL and TCP port can be set by using the following command::
$ ceph dashboard set-grafana-api-url <url> # default: 'http://localhost:3000'
- $ ceph dashboard set-grafana-api-username <username> # default: 'admin'
- $ ceph dashboard set-grafana-api-password <password> # default: 'admin'
+
+You need to tell the dashboard which authentication method should be
+used::
+
+ $ ceph dashboard set-grafana-api-auth-method <method> # default: ''
+
+Possible values are either 'password' or 'token'.
+
+To authenticate via username and password, you will need to set the following
+values::
+
+ $ ceph dashboard set-grafana-api-username <username> # default: 'admin'
+ $ ceph dashboard set-grafana-api-password <password> # default: 'admin'
+
+To use token based authentication, you will ned to set the token by issuing::
+
+ $ ceph dashboard set-grafana-api-token <token> # default: ''
Accessing the dashboard
^^^^^^^^^^^^^^^^^^^^^^^
class GrafanaRestClient(object):
_instance = None
- @staticmethod
- def _raise_for_validation(url, user, password):
+ def _raise_for_validation(self):
msg = 'No {} found or misconfigured, please consult the ' \
'documentation about how to configure Grafana for the dashboard.'
- o = urlparse(url)
+ o = urlparse(self._url)
if not (o.netloc and o.scheme):
raise LookupError(msg.format('URL'))
- if not all((user, password)):
- raise LookupError(msg.format('credentials'))
+ auth_method = 'password' if self._token is None else 'token'
+ if auth_method == 'password' and not all((self._user, self._password)):
+ raise LookupError(msg.format('username and/or password'))
+ elif auth_method == 'token' and not self._token:
+ raise LookupError(msg.format('token'))
- def __init__(self, url, username, password):
+ def __init__(self, url, username=None, password=None, token=None):
"""
:type url: str
:type username: str
:type password: str
"""
- self._raise_for_validation(url, username, password)
-
self._url = url.rstrip('/')
self._user = username
self._password = password
+ self._token = token
+
+ self._raise_for_validation()
@classmethod
def instance(cls):
:rtype: GrafanaRestClient
"""
if not cls._instance:
- url = Settings.GRAFANA_API_URL
- user = Settings.GRAFANA_API_USERNAME
- password = Settings.GRAFANA_API_PASSWORD
-
- cls._instance = GrafanaRestClient(url, user, password)
+ kwargs = {}
+ if Settings.GRAFANA_API_AUTH_METHOD.lower() == 'password':
+ kwargs['username'] = Settings.GRAFANA_API_USERNAME
+ kwargs['password'] = Settings.GRAFANA_API_PASSWORD
+ elif Settings.GRAFANA_API_AUTH_METHOD.lower() == 'token':
+ kwargs['token'] = Settings.GRAFANA_API_TOKEN
+ else:
+ raise LookupError('No or unknown authentication method '
+ 'provided. Please consult the documentation '
+ 'about how to configure the '
+ 'Grafana integration correctly.')
+ cls._instance = GrafanaRestClient(Settings.GRAFANA_API_URL,
+ **kwargs)
return cls._instance
headers = {k: v for k, v in cherrypy.request.headers.items()
if k.lower() in ('content-type', 'accept')}
+ auth = None
+ if self._token:
+ headers['Authorization'] = 'Bearer {}'.format(self._token)
+ else:
+ auth = (self._user, self._password)
+
response = requests.request(
method,
url,
params=params,
data=data,
headers=headers,
- auth=(self._user, self._password))
+ auth=auth)
logger.debug("proxying method=%s path=%s params=%s data=%s", method,
path, params, data)
GRAFANA_API_URL = ('http://localhost:3000', str)
GRAFANA_API_USERNAME = ('admin', str)
GRAFANA_API_PASSWORD = ('admin', str)
+ GRAFANA_API_TOKEN = ('', str)
+ GRAFANA_API_AUTH_METHOD = ('', str) # Either 'password' or 'token'
@staticmethod
def has_default_value(name):
class Grafana(TestCase):
def test_missing_credentials(self):
- with six.assertRaisesRegex(self, LookupError, r'^No credentials.*'):
+ with six.assertRaisesRegex(self, LookupError,
+ r'username and/or password'):
GrafanaRestClient(
url='http://localhost:3000', username='', password='admin')
-
+ with six.assertRaisesRegex(self, LookupError, r'token'):
+ GrafanaRestClient(
+ url='http://localhost:3000',
+ token='',
+ )
with six.assertRaisesRegex(self, LookupError, r'^No URL.*'):
GrafanaRestClient(
url='//localhost:3000', username='admin', password='admin')
-@Controller('/grafana/mocked')
+@Controller('grafana/mocked')
class GrafanaMockInstance(BaseController):
@Proxy()
def __call__(self, path, **params):
@classmethod
def setup_server(cls):
settings = {
- 'GRAFANA_API_URL':
- 'http://localhost:{}/grafana/mocked/'.format(54583),
+ 'GRAFANA_API_URL': 'http://localhost:{}/grafana/mocked/'.format(54583),
'GRAFANA_API_USERNAME': 'admin',
'GRAFANA_API_PASSWORD': 'admin',
+ 'GRAFANA_API_AUTH_METHOD': 'password',
}
mgr.get_config.side_effect = settings.get
GrafanaProxy._cp_config['tools.authenticate.on'] = False # pylint: disable=protected-access