]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/grafana.py
import 15.2.0 Octopus source
[ceph.git] / ceph / src / pybind / mgr / dashboard / grafana.py
1 # -*- coding: utf-8 -*-
2 from __future__ import absolute_import
3
4 import json
5 import logging
6 import os
7 import time
8 import requests
9
10 from .exceptions import GrafanaError
11 from .settings import Settings
12
13
14 logger = logging.getLogger('grafana')
15
16
17 class GrafanaRestClient(object):
18
19 @staticmethod
20 def url_validation(method, path):
21 response = requests.request(
22 method,
23 path,
24 verify=Settings.GRAFANA_API_SSL_VERIFY)
25 return response.status_code
26
27 @staticmethod
28 def push_dashboard(dashboard_obj):
29 if not Settings.GRAFANA_API_URL:
30 raise GrafanaError("The Grafana API URL is not set")
31 if not Settings.GRAFANA_API_URL.startswith('http'):
32 raise GrafanaError("The Grafana API URL is invalid")
33 if not Settings.GRAFANA_API_USERNAME:
34 raise GrafanaError("The Grafana API username is not set")
35 if not Settings.GRAFANA_API_PASSWORD:
36 raise GrafanaError("The Grafana API password is not set")
37 url = Settings.GRAFANA_API_URL.rstrip('/') + \
38 '/api/dashboards/db'
39 headers = {
40 'Accept': 'application/json',
41 'Content-Type': 'application/json',
42 }
43 payload = {
44 'dashboard': dashboard_obj,
45 'overwrite': True,
46 }
47 try:
48 response = requests.post(
49 url,
50 headers=headers,
51 data=json.dumps(payload),
52 auth=(Settings.GRAFANA_API_USERNAME,
53 Settings.GRAFANA_API_PASSWORD),
54 verify=Settings.GRAFANA_API_SSL_VERIFY
55 )
56 except requests.ConnectionError:
57 raise GrafanaError("Could not connect to Grafana server")
58 response.raise_for_status()
59 return response.status_code, response.json()
60
61
62 class Retrier(object):
63 def __init__(self, tries, sleep, func, *args, **kwargs):
64 """
65 Wraps a function. An instance of this class may be called to call that
66 function, retrying if it raises an exception. Sleeps between retries,
67 eventually reraising the original exception when retries are exhausted.
68 Once the function returns a value, that value is returned.
69
70 :param tries: How many times to try, before reraising the exception
71 :type tries: int
72 :param sleep: How many seconds to wait between tries
73 :type sleep: int|float
74 :param func: The function to execute
75 :type func: function
76 :param args: Any arguments to pass to the function
77 :type args: list
78 :param kwargs: Any keyword arguments to pass to the function
79 :type kwargs: dict
80 """
81 assert tries >= 1
82 self.tries = int(tries)
83 self.tried = 0
84 self.sleep = sleep
85 self.func = func
86 self.args = args
87 self.kwargs = kwargs
88
89 def __call__(self):
90 result = None
91 while self.tried < self.tries:
92 try:
93 result = self.func(*self.args, **self.kwargs)
94 except Exception: # pylint: disable=broad-except
95 if self.tried == self.tries - 1:
96 raise
97 else:
98 self.tried += 1
99 time.sleep(self.sleep)
100 else:
101 return result
102
103
104 def load_local_dashboards():
105 if os.environ.get('CEPH_DEV') == '1' or 'UNITTEST' in os.environ:
106 path = os.path.abspath(os.path.join(
107 os.path.dirname(__file__),
108 '../../../../monitoring/grafana/dashboards/'
109 ))
110 else:
111 path = '/etc/grafana/dashboards/ceph-dashboard'
112 dashboards = dict()
113 for item in [p for p in os.listdir(path) if p.endswith('.json')]:
114 db_path = os.path.join(path, item)
115 with open(db_path) as f:
116 dashboards[item] = json.loads(f.read())
117 return dashboards
118
119
120 def push_local_dashboards(tries=1, sleep=0):
121 try:
122 dashboards = load_local_dashboards()
123 except (EnvironmentError, ValueError):
124 logger.exception("Failed to load local dashboard files")
125 raise
126
127 def push():
128 try:
129 grafana = GrafanaRestClient()
130 for body in dashboards.values():
131 grafana.push_dashboard(body)
132 except Exception:
133 logger.exception("Failed to push dashboards to Grafana")
134 raise
135 retry = Retrier(tries, sleep, push)
136 retry()
137 return True