]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/health.html
update sources to v12.2.3
[ceph.git] / ceph / src / pybind / mgr / dashboard / health.html
1
2 {% extends "base.html" %}
3
4 {% block content %}
5
6 <script>
7 $(document).ready(function(){
8 // Pre-populated initial data at page load
9 var content_data = {{ content_data }};
10
11 rivets.formatters.mon_summary = function(mon_status) {
12 var result = mon_status.monmap.mons.length.toString() + " (quorum ";
13 result += mon_status.quorum.join(", ");
14 result += ")";
15
16 return result;
17 };
18
19 rivets.formatters.mds_summary = function(fs_map) {
20 var standbys = 0;
21 var active = 0;
22 var standby_replay = 0;
23 $.each(fs_map.standbys, function(i, s) {
24 standbys += 1;
25 });
26
27 if (fs_map.standbys && !fs_map.filesystems) {
28 return standbys + ", no filesystems"
29 } else if (fs_map.filesystems.length == 0) {
30 return "no filesystems";
31 } else {
32 $.each(fs_map.filesystems, function(i, fs) {
33 $.each(fs.mdsmap.info, function(j, mds) {
34 if (mds.state == "up:standby-replay") {
35 standby_replay += 1;
36 } else {
37 active += 1;
38 }
39 });
40 });
41
42 return active + " active, " + (standbys + standby_replay) + " standby";
43 }
44 };
45
46 rivets.formatters.mgr_summary = function(mgr_map) {
47 var result = "";
48 result += "active: " + mgr_map.active_name;
49 if (mgr_map.standbys.length) {
50 result += ", " + mgr_map.standbys.length + " standbys";
51 }
52
53 return result;
54 };
55
56 rivets.formatters.log_color = function(log_line) {
57 if (log_line.priority == "[INF]") {
58 return ""; // Inherit
59 } else if (log_line.priority == "[WRN]") {
60 return "color: #FFC200";
61 } else if (log_line.priority == "[ERR]") {
62 return "color: #FF2222";
63 } else {
64 return "";
65 }
66 };
67
68 rivets.formatters.osd_summary = function(osd_map) {
69 var in_count = 0;
70 var up_count = 0;
71 $.each(osd_map.osds, function(i, osd) {
72 if (osd.in) {
73 in_count++;
74 }
75 if (osd.up) {
76 up_count++;
77 }
78 });
79
80 return osd_map.osds.length + " (" + up_count + " up, " + in_count + " in)";
81 };
82
83 rivets.formatters.pg_status_style = function(pg_status) {
84 var warning = false;
85 var error = false;
86
87 $.each(pg_status, function(state, count) {
88 if (state.includes("inconsistent") ||
89 state.includes("incomplete") ||
90 !state.includes("active")
91 ) {
92 error = true;
93 }
94
95 if (state != "active+clean"
96 && state != "active+clean+scrubbing"
97 && state != "active+clean+scrubbing+deep") {
98 warning = true;
99 }
100 });
101
102 if (error) {
103 return "color: #FF0000";
104 }
105
106 if (warning) {
107 return "color: #FFC200";
108 }
109
110 return "color: #00BB00";
111 };
112
113 rivets.formatters.pg_status = function(pg_status) {
114 var strings = [];
115 $.each(pg_status, function(state, count) {
116 strings.push(count + " " + state);
117 });
118
119 return strings.join(", ");
120 };
121
122 // An extension to Chart.js to enable rendering some
123 // text in the middle of a doughnut
124 Chart.pluginService.register({
125 beforeDraw: function(chart) {
126 if (!chart.options.center_text) {
127 return;
128 }
129 var width = chart.chart.width,
130 height = chart.chart.height,
131 ctx = chart.chart.ctx;
132
133 ctx.restore();
134 var fontSize = (height / 114).toFixed(2);
135 ctx.font = fontSize + "em sans-serif";
136 ctx.fillStyle = "#ddd";
137 ctx.textBaseline = "middle";
138
139
140 var text = chart.options.center_text,
141 textX = Math.round((width - ctx.measureText(text).width) / 2),
142 textY = height / 2;
143
144 ctx.fillText(text, textX, textY);
145 ctx.save();
146 }
147 });
148
149 var draw_usage_charts = function() {
150 var raw_usage_text = Math.round(100*(
151 content_data.df.stats.total_used_bytes
152 / content_data.df.stats.total_bytes)) + "%";
153 var raw_usage_canvas = $("#raw_usage_chart").get(0).getContext("2d");
154 var raw_usage_chart = new Chart(raw_usage_canvas, {
155 type: 'doughnut',
156 data: {
157 labels:[
158 "Raw Used",
159 "Raw Available"
160 ],
161 datasets: [
162 {
163 'label': null,
164 borderWidth: 0,
165 data:[
166 content_data.df.stats.total_used_bytes,
167 content_data.df.stats.total_avail_bytes
168 ],
169 backgroundColor: ["#424d52", "#222d32"]
170 }
171 ]
172 },
173 options: {
174 center_text: raw_usage_text,
175 responsive: true,
176 legend: {display: false},
177 animation: {duration: 0}
178 }
179 });
180
181 var colors = ['#3366CC','#DC3912','#FF9900','#109618','#990099',
182 '#3B3EAC','#0099C6','#DD4477','#66AA00','#B82E2E','#316395',
183 '#994499','#22AA99','#AAAA11','#6633CC','#E67300','#8B0707',
184 '#329262','#5574A6','#3B3EAC'];
185
186 var pool_usage_canvas = $("#pool_usage_chart").get(0).getContext("2d");
187 var pool_labels = [];
188 var pool_data = [];
189
190 $.each(content_data.df.pools, function(i, pool) {
191 pool_labels.push(pool['name']);
192 pool_data.push(pool['stats']['bytes_used']);
193 });
194
195 var pool_usage_chart = new Chart(pool_usage_canvas, {
196 type: 'doughnut',
197 data: {
198 labels:pool_labels,
199 datasets: [
200 {
201 'label': null,
202 borderWidth: 0,
203 data:pool_data,
204 backgroundColor: colors
205 }
206 ]
207 },
208 options: {
209 responsive: true,
210 legend: {display: false},
211 animation: {duration: 0}
212 }
213 });
214 }
215
216 draw_usage_charts();
217 rivets.bind($("#content"), content_data);
218
219 var refresh = function() {
220 $.get("{{ url_prefix }}/health_data", function(data) {
221 _.extend(content_data, data);
222 draw_usage_charts();
223 setTimeout(refresh, 5000);
224 });
225 };
226 setTimeout(refresh, 5000);
227 });
228 </script>
229
230 <!-- Main content -->
231 <section class="content">
232 <div class="row">
233 <div class="col-sm-6">
234 <div class="box">
235 <div class="box-header">
236 Health
237 </div>
238 <div class="box-body">
239 Overall status: <span
240 rv-style="health.status | health_color">{health.status}</span>
241
242 <ul>
243 <li rv-each-check="health.checks">
244 <span rv-style="check.severity | health_color">{check.type}</span>:
245 {check.summary.message}
246 </li>
247 </ul>
248 </div>
249 </div>
250 </div>
251 <div class="col-sm-3">
252 <div class="info-box">
253 <span class="info-box-icon bg-grey"><i
254 class="fa fa-database"></i></span>
255
256 <div class="info-box-content">
257 <span class="info-box-text">Monitors</span>
258 <span class="info-box-number">{mon_status | mon_summary}</span>
259 </div>
260 </div>
261 <div class="info-box">
262 <span class="info-box-icon bg-grey"><i
263 class="fa fa-hdd-o"></i></span>
264
265 <div class="info-box-content">
266 <span class="info-box-text">OSDs</span>
267 <span class="info-box-number">{osd_map | osd_summary}</span>
268 </div>
269 </div>
270 </div>
271
272 <div class="col-sm-3">
273 <div class="info-box">
274 <span class="info-box-icon bg-grey"><i
275 class="fa fa-folder"></i></span>
276
277 <div class="info-box-content">
278 <span class="info-box-text">Metadata servers</span>
279 <span class="info-box-number">{fs_map | mds_summary}</span>
280 </div>
281 </div>
282 <div class="info-box">
283 <span class="info-box-icon bg-grey"><i
284 class="fa fa-cog"></i></span>
285
286 <div class="info-box-content">
287 <span class="info-box-text">Manager daemons</span>
288 <span class="info-box-number">{mgr_map | mgr_summary}</span>
289 </div>
290 </div>
291 </div>
292
293 </div>
294
295 <div class="row">
296 <div class="col-sm-6">
297 <div class="box">
298 <div class="box-header">
299 Usage
300 </div>
301 <div class="box-body" style="text-align:center;">
302 <table class="ceph-chartbox">
303 <tr>
304 <td>
305 <span style="font-size: 45px;">{df.stats.total_objects | dimless}</span>
306 </td>
307 <td >
308 <div style="height:120px; width: 120px;">
309 <canvas id="raw_usage_chart"></canvas>
310 </div>
311 </td>
312 <td>
313 <div style="height:120px; width: 120px;">
314 <canvas id="pool_usage_chart"></canvas>
315 </div>
316 </td>
317 </tr>
318 <tr>
319 <td>Objects</td>
320 <td>Raw capacity<br>({df.stats.total_used_bytes | dimless_binary} used)</td>
321 <td>Usage by pool</td>
322 </tr>
323 </table>
324
325 </div>
326 </div>
327 </div>
328
329 <div class="col-sm-6">
330 <div class="box">
331 <div class="box-header">
332 Pools
333 </div>
334 <div class="box-body">
335 <table class="table table-condensed">
336 <thead>
337 <th>Name</th>
338 <th>PG status</th>
339 <th>Usage</th>
340 <th>Activity</th>
341 </thead>
342 <tbody>
343 <tr rv-each-pool="pools">
344 <td style="text-align: right;">
345 {pool.pool_name}
346 </td>
347 <td rv-style="pool.pg_status | pg_status_style">
348 {pool.pg_status | pg_status}
349 </td>
350 <td>
351 {pool.stats.bytes_used.latest | dimless} /
352 {pool.stats.max_avail.latest | dimless }
353 </td>
354 <td>
355 {pool.stats.rd_bytes.rate | dimless } rd, {
356 pool.stats.wr_bytes.rate | dimless } wr
357 </td>
358 </tr>
359 </tbody>
360 </table>
361 </div>
362 </div>
363 </div>
364 </div>
365
366 <div class="box">
367 <div class="box-body">
368 <ul class="nav nav-tabs">
369 <li class="active"><a data-toggle="tab" href="#clog">Cluster log</a></li>
370 <li><a data-toggle="tab" href="#audit_log">Audit log</a></li>
371 </ul>
372 <div class="tab-content ceph-log">
373 <div id="clog" class="tab-pane fade in active">
374 <span>
375 <span rv-each-line="clog">
376 { line.stamp }&nbsp;{line.priority}&nbsp;
377 <span rv-style="line | log_color">
378 { line.message }
379 <br>
380 </span>
381 </span>
382 </span>
383 </div>
384 <div id="audit_log" class="tab-pane fade in">
385 <span>
386 <span rv-each-line="audit_log">
387 { line.stamp }&nbsp;{line.priority}&nbsp;
388 <span rv-style="line | log_color">
389 <span style="font-weight: bold;">
390 { line.message }
391 </span><br>
392 </span>
393 </span>
394 </span>
395
396 </div>
397 </div>
398
399 </div>
400
401 </div>
402 </section>
403
404 {% endblock %}