]>
Commit | Line | Data |
---|---|---|
81eedcae TL |
1 | # -*- coding: utf-8 -*- |
2 | from __future__ import absolute_import | |
3 | ||
4 | import json | |
9f95a23c | 5 | import logging |
81eedcae TL |
6 | import os |
7 | import time | |
f67539c2 | 8 | |
81eedcae TL |
9 | import requests |
10 | ||
81eedcae TL |
11 | from .exceptions import GrafanaError |
12 | from .settings import Settings | |
13 | ||
9f95a23c TL |
14 | logger = logging.getLogger('grafana') |
15 | ||
16 | ||
81eedcae TL |
17 | class GrafanaRestClient(object): |
18 | ||
19 | @staticmethod | |
20 | def url_validation(method, path): | |
21 | response = requests.request( | |
22 | method, | |
92f5a8d4 TL |
23 | path, |
24 | verify=Settings.GRAFANA_API_SSL_VERIFY) | |
81eedcae TL |
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), | |
92f5a8d4 | 54 | verify=Settings.GRAFANA_API_SSL_VERIFY |
81eedcae TL |
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 |