blob: 49371dffa4c3252c781575015d462eef77fbc877 [file] [log] [blame]
Alexdcb792f2021-10-04 14:24:21 -05001<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>Ceph cluster info</title>
6 {% include 'common_styles.j2' %}
7 {% include 'common_scripts.j2' %}
8 <style>
9 table.cluster_nodes {
10 width: 100%;
11 margin-left: 1%;
12 margin-right: 1%;
13 }
14 .barcontent {
15 margin: auto;
16 width: 1350px;
17 padding: 10px;
18 }
19 .bar-centered {
20 float: none;
21 transform: translate(25%);
22 }
23
24 /* Node rows*/
25 .node {
26 font-family: "LaoSangamMN", Monaco, monospace;
27 font-size: 0.8em;
28 display: flex;
29 background-color: white;
30 align-items: center;
31 }
32 .collapsable {
33 font-family: "LaoSangamMN", Monaco, monospace;
34 font-size: 0.8em;
35 display: none;
36 background-color: white;
37 visibility: hidden;
38 }
39 .collapsable.in {
40 visibility: visible;
41 display: inline-block;
42 }
43
44 .row_button {
45 background-color: #468;
46 color: #fff;
47 cursor: pointer;
48 padding: 5px;
49 width: 100%;
50 border: none;
51 text-align: left;
52 outline: none;
53 font-size: 13px;
54 }
55 .row_button:after {
56 content: '\02795'; /* Unicode character for "plus" sign (+) */
57 font-size: 13px;
58 color: white;
59 float: left;
60 margin-left: 5px;
61 }
62
63 .row_active:after {
64 content: "\2796"; /* Unicode character for "minus" sign (-) */
65 color: white
66 }
67
68 .row_active, .row_button:hover {
69 background-color: #68a;
70 color: white
71 }
72
73 .cell_button {
74 color: darkgreen;
75 cursor: pointer;
76 padding: 5px;
77 width: 100%;
78 border: none;
79 text-align: center;
80 outline: none;
81 }
82 .cell_button:hover {
83 background-color: gray;
84 }
85
86 .row_content {
Alex41dd0cc2022-02-09 17:33:23 -060087 font-family: "LaoSangamMN", Monaco, monospace;
88 font-size: 0.8em;
Alexdcb792f2021-10-04 14:24:21 -050089 padding: 0 18px;
90 background-color: white;
91 max-height: 0;
92 overflow: hidden;
93 transition: max-height 0.2s ease-out;
94 border-width: 1px;
95 border-color: #68a;
96 border-style: solid;
97 }
98
99 div.services > .collapsable.in {
100 display: table-row;
101 }
102 tr:nth-child(even) {
103 background-color: #eee;
104 }
105 tr:nth-child(odd) {
106 background-color: #fff;
107 }
108
109 tr.node > td, tr.collapsable > td {
110 display: block;
111 float: left;
112 padding: 1px;
113 margin: 2px;
114 }
115 td > .osd_group {
116 display: grid;
117 grid-template-columns: 40px 25px 25px 70px;
118 padding-left: 0px;
119 padding-right: 0px;
120 margin: 1px;
121 }
122 td > .pg_group {
123 display: grid;
124 grid-template-columns: 50px 40px 60px 65px 60px 65px 65px;;
125 padding-left: 0px;
126 padding-right: 0px;
127 margin: 1px;
128 }
129 td > .bench_group {
130 display: grid;
131 grid-template-columns: 80px 80px 75px 75px;
132 padding-left: 0px;
133 padding-right: 0px;
134 margin: 1px;
135 }
136 td > .meta_group {
137 display: inline-block;
138 grid-template-columns: repeat(4, auto);
139 padding-left: 0px;
140 padding-right: 0px;
141 margin: 1px;
142 }
Alex41dd0cc2022-02-09 17:33:23 -0600143 td > .osdconf_group {
144 display: inline-block;
Alex0bcf31b2022-03-29 17:38:58 -0500145 grid-template-columns: repeat(4, auto);
Alex41dd0cc2022-02-09 17:33:23 -0600146 padding-left: 0px;
147 padding-right: 0px;
148 margin: 1px;
149 }
Alexdcb792f2021-10-04 14:24:21 -0500150 .item {
151 display: inline-grid;
152 border-width: 1px;
153 border-style: solid;
154 margin: 1px 1px 1px 1px;
155 padding: 0px 1px 0px 1px;
156 }
157
158 .spacer { border-radius: 2px; width: 20px;}
159 .status { border-radius: 10px; width: 120px; text-align: center;}
160 .health_ok { background-color: #393; color: white;}
161 .health_error { background-color: #933; color: white;}
162 .health_warn { background-color: #eb3; color: #333;}
163 .checks_code { border-radius: 2px; width: 20%; background-color: transparent; color: darkred;}
164
165 .head { height: 18px; background-color: transparent; border-color: transparent; border: 0px;}
166 .centered { text-align: center;}
167 .right { text-align: right;}
168 .col_shortmessage { min-width: 300px; }
169 .col_longmessage { width: auto; }
170 .col_properties { width: auto;}
171
172 .srv_name { width: 300px }
173 .srv_path { width: 250px }
174 .srv_timestamp { width: 250px }
175 .srv_addr { width: 450px }
176
177 .id { width: 30px }
178 .bucket_name { width: 365px }
179 .bucket_type { width: 50px }
180 .bucket_params { width: 200px }
181 .bucket_items { width: 630px }
182
183 .df_name { width: 300px }
184 .df_total { width: 150px }
185 .df_avail { width: 150px }
186 .df_used { width: 150px }
187 .df_used_raw { width: 150px }
188 .df_used_raw_rate { width: 150px }
189
190 .rdf_name { width: 200px; }
191 .rdf_obj { width: 75px; }
192 .rdf_total { width: 100px; }
193 .rdf_used { width: 100px; }
194 .rdf_bench { width: 100px; }
195
196 .dev_name { width: 300px; }
197 .dev_param { width: 100px; }
198
199 .mon_name { width: 100px }
200 .mon_url { width: 500px }
201
202 .meters {
203 display: inline-block;
204 margin: 1px;
205 }
206 .meters > .meter {
207 display: block;
208 float: left;
209 border-width: 1px;
210 border-style: solid;
211 margin: 0px 1px 0px 1px;
212 padding: 0px 1px 0px 1px;
213
214 }
215 .meters > .warn {
216 border-color: #d3a200;
217 background-color: rgb(255, 216, 133);
218 }
219 .meters > .fail {
220 border-color: #bb0000;
221 background-color: rgb(250, 135, 135);
222 }
223 .osd { border-color: #a0c0a0; background-color: rgb(252, 248, 248); text-align: center;}
224 .pg { border-color: #c0c0a0; background-color: rgb(255, 255, 251); text-align: right; }
225 .bench { border-color: #a0c0c0; background-color: rgb(255, 250, 250); text-align: right; }
226 .lat_commit { border-color: #a0c0c0; background-color: rgb(255, 250, 250); text-align: right; width: 45px}
227 .lat_apply { border-color: #a0c0c0; background-color: rgb(255, 250, 250); text-align: left; width: 35px}
228 .meta_name { border-color: #c4b890; background-color: #e7dbb6; text-align: left; width: 150px;}
229 .meta_value { border-color: #c6c3ba;background-color: #d4d4d4; text-align: left; width: 480px;}
Alex0bcf31b2022-03-29 17:38:58 -0500230 .conf_name, .conf_name_uniq { border-color: #c4b890; background-color: #e7dbb6; text-align: left; width: 295px; word-break: break-all;}
231 .conf_value, .conf_value_uniq { border-color: #c6c3ba;background-color: #d4d4d4; text-align: left; width: 280px; word-break: break-all;}
232 .conf_source, .conf_source_uniq { border-color: #c6c3ba;background-color: #a4a4a4; text-align: left; width: 50px;}
233 .osd_name { border-color: gray; background-color: #bdb396; text-align: left; width: 120px;}
234 .conf_name_uniq { width: 410px;}
235 .conf_value_uniq { width: 600px;}
236 .conf_source_uniq { width: 140px;}
Alexdcb792f2021-10-04 14:24:21 -0500237
238 .map_grid {
239 display: grid;
240 grid-template-columns: auto auto auto auto auto auto auto auto auto auto;
241 grid-column-gap: 20px;
242 padding-left: 0px;
243 padding-right: 0px;
244 margin: 1px;
245 margin-left: 20px;
246
247 }
248 .map_item {
249 display: inline-grid;
250 border-width: 0px;
251 border-style: solid;
252 margin: 1px 1px 1px 1px;
253 padding: 0px 1px 0px 1px;
254 }
255
256 .map_grid > .ok {
257 color: #80a080;
258 }
259 .map_grid > .warn {
260 color: #d3a200;
261 }
262 .map_grid > .fail {
263 color: #bb0000;
264 }
265
266 .modules {
267 font-family: "LaoSangamMN", Monaco, monospace;
268 font-size: 0.8em;
269 background-color: white;
270 }
271 .module_node {
272 margin-bottom: 2px;
273 display: flex;
274 }
275 .module_name, .node_name {
276 text-align: center;
277 border-width: 0px;
278 border-style: solid;
279 margin: 1px 1px 1px 1px;
280 padding: 0px 1px 0px 1px;
281 min-width: 250px;
282 border-radius: 10px;
283 }
284 .node_name {
285 background-color: #ddd;
286 }
287 .module_grid {
288 display: grid;
289 grid-template-columns: repeat(8, 100px);
290 grid-template-rows: repeat(6, auto);
291 grid-auto-flow: column;
292 grid-column-gap: 10px;
293 padding-left: 0px;
294 padding-right: 0px;
295 margin: 1px;
296 margin-left: 20px;
297 }
298 .module {
299 display: inline-grid;
300 text-align: center;
301 border-width: 0px;
302 border-style: solid;
303 margin: 1px 1px 1px 1px;
304 padding: 0px 1px 0px 1px;
305 min-width: 100px;
306 border-radius: 10px;
307 }
308
309 .module_grid > .on, .service_node > .ok {
310 background-color: #8c8;
311 }
312 .module_grid > .off, .service_node > .off{
313 background-color: #9aa;
314 }
315 .module_grid > .fail, .service_node > .fail {
316 background-color: #a33;
317 }
318 .module_grid > .always, .service_node > .fail {
319 background-color: #282;
320 }
321
322 .tooltiptext {
323 transform: translate(100px);
324 }
325
326 .console {
327 background-color: black;
328 font-family: "Lucida Console", Monaco, monospace;
329 font-size: 0.5em;
330 width: auto;
331 color: #fff;
332 border-radius: 6px;
333 padding: 5px 5px;
334 }
335
336 </style>
337</head>
338<body onload="init()">
339
340<div class="header">
341 <div class="label">Ceph version:</div>
342 <div class="text">{{ ceph_version }}</div>
343 <div class="label">Image:</div>
344 <div class="text">{{ cluster.image }}</div>
345 <div class="label date">generated on: {{ gen_date }}</div>
346</div>
347
348<div class="bar">
349 <div class="bar-centered">
350 <button class="bar-item" onclick="openBar(event, 'status')">Status</button>
351 <button class="bar-item" onclick="openBar(event, 'latency')">Latency</button>
352 <button class="bar-item" onclick="openBar(event, 'crush')">CRUSH Map</button>
Alex41dd0cc2022-02-09 17:33:23 -0600353 <button class="bar-item" onclick="openBar(event, 'osdconf')">OSD Conf</button>
Alexdcb792f2021-10-04 14:24:21 -0500354 <button class="bar-item" onclick="openBar(event, 'mondump')">Monitors</button>
355 <button class="bar-item" onclick="openBar(event, 'df')">Pools</button>
356 <button class="bar-item" onclick="openBar(event, 'dfrados')">Rados</button>
357 <button class="bar-item" onclick="openBar(event, 'auth')">Auth list</button>
358 <button class="bar-item" onclick="openBar(event, 'dhealth')">Device Health</button>
359 </div>
360</div>
361
362{% macro status_page(info, id_label) %}
363<div id="{{ id_label }}" class="barcontent">
364 <h5>{{ caller() }}</h5>
365 <hr>
366 <table class="ceph_status">
367 <tr class="node">
368 <td class="status">Cluster status</td>
369 <td class="col_shortmessage">Status summary</td>
370 <td class="col_osd">
371 <div class="osd_group">
372 <div class="item osd">OSDs</div>
373 <div class="item osd">Up</div>
374 <div class="item osd">In</div>
375 <div class="item osd">Remap PGs</div>
376 </div>
377 </td>
378 <td class="col_pgs">
379 <div class="pg_group">
380 <div class="item pg">PGs</div>
381 <div class="item pg">Pools</div>
382 <div class="item pg">Objects</div>
383 <div class="item pg">Data, GB</div>
384 <div class="item pg">Used, GB</div>
385 <div class="item pg">Avail, GB</div>
386 <div class="item pg">Total, GB</div>
387 </div>
388 </td>
389 <td class="col_bench">
390 <div class="bench_group">
391 <div class="item bench">Read, MB/sec</div>
392 <div class="item bench">Write, MB/sec</div>
393 <div class="item bench">Read, op/sec</div>
394 <div class="item bench">Write, op/sec</div>
395 </div>
396 </td>
397 </tr>
398 {% set hdetail = info["health_detail"]["data"] %}
399 {% set cs = info["cluster_status"]["data"] %}
400 {% set osdmap = cs | get_osdmap %}
401 <tr class="node" onclick="toggleClassByID('health_data')" id="health_data_button">
402 <td class="status {{ hdetail["status"] | lower }}">{{ hdetail["status"] }}</td>
403 <td class="col_shortmessage">
404 {% for code,dt in hdetail["checks"].items() %}
405 {{ dt["summary"]["message"] }}<br>
406 {% endfor %}
407 </td>
408 <!-- background: linear-gradient(to right, gray 0% 20%, transparent 20% 100%); -->
409 <td class="col_osd">
410 <div class="osd_group">
411 <div class="item osd">{{ osdmap["num_osds"] }}</div>
412 <div class="item osd">{{ osdmap["num_up_osds"] }}</div>
413 <div class="item osd">{{ osdmap["num_in_osds"] }}</div>
414 <div class="item osd">{{ osdmap["num_remapped_pgs"] }}</div>
415 </div>
416 </td>
417 {% set pgmap = cs["pgmap"] %}
418 <td class="col_pgs">
419 <div class="pg_group">
420 <div class="item pg">{{ pgmap["num_pgs"] }}</div>
421 <div class="item pg">{{ pgmap["num_pools"] }}</div>
422 <div class="item pg">{{ pgmap["num_objects"] }}</div>
423 <div class="item pg">{{ pgmap["data_bytes"] | to_gb }}</div>
424 <div class="item pg">{{ pgmap["bytes_used"] | to_gb }}</div>
425 <div class="item pg">{{ pgmap["bytes_avail"] | to_gb }}</div>
426 <div class="item pg">{{ pgmap["bytes_total"] | to_gb }}</div>
427 </div>
428 </td>
429 <td class="col_bench">
430 <div class="bench_group">
431 {% if "read_bytes_sec" in pgmap %}
432 <div class="item bench">{{ pgmap["read_bytes_sec"] | to_mb }}</div>
433 {% else %}
434 <div class="item bench">0</div>
435 {% endif %}
436 {% if "write_bytes_sec" in pgmap %}
437 <div class="item bench">{{ pgmap["write_bytes_sec"] | to_mb }}</div>
438 {% else %}
439 <div class="item bench">0</div>
440 {% endif %}
441 {% if "read_op_per_sec" in pgmap %}
442 <div class="item bench">{{ pgmap["read_op_per_sec"] }}</div>
443 {% else %}
444 <div class="item bench">0</div>
445 {% endif %}
446 {% if "write_op_per_sec" in pgmap %}
447 <div class="item bench">{{ pgmap["write_op_per_sec"] }}</div>
448 {% else %}
449 <div class="item bench">0</div>
450 {% endif %}
451 </div>
452 </td>
453 </tr>
454 <tr class="collapsable in" id="health_data"><td colspan=3>
455 <table><tbody>
456 {% for code,dt in hdetail["checks"].items() %}
457 <tr>
458 <td class="spacer"></td>
459 <td class="status {{ dt["severity"] | lower }}">{{ dt["severity"] }}</td>
460 <td class="checks_code">{{ code }}</td>
461 <td class="col_longmessage">
462 <table><tbody>
463 {% for detail in dt["detail"] %}
464 <tr><td>{{ detail["message"] }}</td></tr>
465 {% endfor %}
466 </tbody></table>
467 </td>
468 </tr>
469 {% endfor %}
470 </tbody></table>
471 </td></tr>
472 </table>
473 <hr>
474 <!-- Services -->
475 {% set sm = info["cluster_status"]["data"]["servicemap"] %}
476 <h5>Services: {{ sm["services"] | count }} running. Last modification: {{ sm["modified"] }}</h5>
477 <table class="ceph_status">
478 <tr class="node">
479 <td class="srv_name">Name</td>
480 <td class="srv_path">Subpath</td>
481 <td class="srv_timestamp">Start time</td>
482 <td class="srv_addr">Address</td>
483 </tr>
484 {% for name, d1 in sm["services"].items() %}
485 {% if "daemons" in d1 %}
486 {% set d2 = d1["daemons"] %}
487 {% for key, d3 in d2.items() %}
488 {% if key.startswith("rgw.store") %}
489 <tr class="node" onclick="toggleClassByID('{{ name }}_service_data')" id="{{ name }}_service_data_button">
490 <td class="srv_name">{{ name }} ({{ d3["gid"] }})</td>
491 <td class="srv_path">daemons:{{ key }}</td>
492 <td class="srv_timestamp">{{ d3["start_stamp"] }}</td>
493 <td class="srv_addr">{{ d3["addr"] }}</td>
494 </tr>
495 <tr class="collapsable in" id="{{ name}}_service_data"><td colspan=4>
496 <table><tbody>
497 <tr><td class="metadata">
498 {% for mname, mvalue in d3["metadata"].items() %}
499 <div class="meta_group">
500 <div class="item meta_name">{{ mname }}</div>
501 <div class="item meta_value">{{ mvalue }}</div>
502 </div>
503 {% endfor %}
504 </td></tr>
505 </tbody></table>
506 </td></tr>
507 {% endif %}
508 {% endfor %}
509 {% endif %}
510 {% endfor %}
511 </table>
512 <hr>
513 <!-- Modules -->
514 {% set mgrmap = info["cluster_status"]["data"]["mgrmap"] %}
515 {% set mods = mgrmap["modules"] %}
516 {% set avail = mgrmap["available_modules"] %}
517 {% if "always_on_modules" in mgrmap %}
518 {% set always_on = mgrmap["always_on_modules"].values() | list %}
519 {% set always_on = always_on[0] %}
520 {% else %}
521 {% set always_on = [] %}
522 {% endif %}
523 <h5>Modules: {{ mods | count}} active. {{ always_on | count }} always on. {{ avail | count }} available.</h5>
524 <div class="modules">
525 <div class="module_grid">
526 {% for mod in avail %}
527 {% if mod["name"] in always_on %}
528 <div class="module always">{{ mod["name"] }}</div>
529 {% elif mod["name"] in mods %}
530 <div class="module on">{{ mod["name"] }}</div>
531 {% elif not mod["can_run"] %}
532 <div class="module fail tooltip">
533 <div class="module fail">{{ mod["name"] }}</div>
534 <pre class="tooltiptext">{{ mod["error_string"] | linebreaks }}</pre>
535 </div>
536 {% else %}
537 <div class="module">{{ mod["name"] }}</div>
538 {% endif %}
539 {% endfor %}
540 </div>
541 </div>
542 <hr>
543</div>
544{% endmacro %}
545
546<!-- CRUSH MAP -->
547{% macro crush_page(info, id_label) %}
548<div id="{{ id_label }}" class="barcontent">
549 <h5>{{ caller() }}</h5>
550 <hr>
551 {% set cmap = info["crushmap_json"]["data"] %}
552 <button type="button" class="row_button">{{ cmap["tunables"] | length }} tunable parameters</button>
553 <div class="row_content">
554 <table class="ceph_status"><tbody>
555 <tr><td class="metadata">
556 {% for tname, tvalue in cmap["tunables"].items() %}
557 <div class="meta_group">
558 <div class="item meta_name">{{ tname }}</div>
559 <div class="item meta_value">{{ tvalue }}</div>
560 </div>
561 {% endfor %}
562 </td></tr>
563 </tbody></table>
564 </div>
565
566 <button type="button" class="row_button">{{ cmap["devices"] | length }} devices</button>
567 <div class="row_content">
568 <table class="ceph_status"><tbody>
569 <tr><td class="metadata">
570 {% for dev in cmap["devices"] %}
571 <div class="meta_group">
572 <div class="item meta_name">{{ dev["name"] }}</div>
573 <div class="item meta_value">id: {{ dev["id"] }}, class: {{ dev["class"] }}</div>
574 </div>
575 {% endfor %}
576 </td></tr>
577 </tbody></table>
578 </div>
579
580 <button type="button" class="row_button">{{ cmap["types"] | length }} types</button>
581 <div class="row_content">
582 <table class="ceph_status"><tbody>
583 <tr><td class="metadata">
584 {% for dtyp in cmap["types"] %}
585 <div class="meta_group">
586 <div class="item meta_name">type_id: {{ dtyp["type_id"] }}</div>
587 <div class="item meta_value">{{ dtyp["name"] }}</div>
588 </div>
589 {% endfor %}
590 </td></tr>
591 </tbody></table>
592 </div>
593
594 <button type="button" class="row_button">{{ cmap["buckets"] | length }} buckets</button>
595 <div class="row_content">
596 <table class="ceph_status"><tbody>
597 <tr class="node">
598 <td class="id">ID</td>
599 <td class="bucket_name">Bucket name</td>
600 <td class="bucket_type">Type</td>
601 <td class="bucket_params">Weight, algorithm, hash</td>
602 <td class="bucket_items">Items</td>
603 </tr>
604 {% for buck in cmap["buckets"] %}
605 <tr class="node">
606 <td class="id">{{ buck["id"] }}</td>
607 <td class="bucket_name">{{ buck["name"] }}</td>
608 <td class="bucket_type">{{ buck["type_name"] }}</td>
609 <td class="bucket_params">{{ buck["weight"] }}, {{ buck["alg"] }}, {{ buck["hash"] }}</td>
610 <td class="bucket_items">
611 {% for bitem in buck["items"] %}
612 {{ bitem["pos"] }}: {{ bitem["id"] | get_bucket_item_name(cmap) }}, weight {{ bitem["weight"] }}<br>
613 {% endfor %}
614 </td>
615 </tr>
616 {% endfor %}
617 </td></tr>
618 </tbody></table>
619 </div>
620
621 <button type="button" class="row_button">{{ cmap["rules"] | length }} rules</button>
622 <div class="row_content">
623 <table class="ceph_status"><tbody>
624 <tr class="node">
625 <td class="id">ID</td>
626 <td class="bucket_name">Rule name</td>
627 <td class="bucket_type">Type</td>
628 <td class="bucket_params">Min/Max Size</td>
629 <td class="bucket_items">Steps</td>
630 </tr>
631 {% for rule in cmap["rules"] %}
632 <tr class="node">
633 <td class="id">{{ rule["rule_id"] }}</td>
634 <td class="bucket_name">{{ rule["rule_name"] }}</td>
635 <td class="bucket_type">{{ rule["type"] }}</td>
636 <td class="bucket_params">{{ rule["min_size"] }}/{{ rule["max_size"] }}</td>
637 <td class="bucket_items">
638 {% for step in rule["steps"] | get_rule_steps %}
639 {{ step }}<br>
640 {% endfor %}
641 </td>
642 </tr>
643 {% endfor %}
644 </td></tr>
645 </tbody></table>
646 </div>
647</div>
648{% endmacro %}
649
Alex41dd0cc2022-02-09 17:33:23 -0600650<!-- OSD Configuration -->
651{% macro osdconf_page(info, id_label) %}
652<div id="{{ id_label }}" class="barcontent">
653 <h5>{{ caller() }}</h5>
654 <hr>
655 {% set cbase = info["osd_config_data"]["data"]["common"] %}
656 {% set cuniq = info["osd_config_data"]["data"]["uniq"] %}
657 <button type="button" class="row_button">{{ cbase | length }} common configuration values</button>
658 <div class="row_content">
659 <table class="ceph_status"><tbody>
660 <tr><td class="metadata">
661 {% for tname, tdata in cbase.items() %}
662 <div class="osdconf_group">
663 <div class="item conf_name">{{ tname }}</div>
664 <div class="item conf_value">{{ tdata["value"] }}</div>
665 <div class="item conf_source">{{ tdata["source"] }}</div>
666 </div>
667 {% endfor %}
668 </td></tr>
669 </tbody></table>
670 </div>
Alex0bcf31b2022-03-29 17:38:58 -0500671 <button type="button" class="row_button">Uniq values</button>
Alex41dd0cc2022-02-09 17:33:23 -0600672 <div class="row_content">
673 <table class="ceph_status"><tbody>
Alex0bcf31b2022-03-29 17:38:58 -0500674 {% for osdname in cuniq.keys() | sort %}
Alex41dd0cc2022-02-09 17:33:23 -0600675 <tr><td class="metadata">
676 {% for tname, tdata in cuniq[osdname].items() %}
677 <div class="osdconf_group">
Alex0bcf31b2022-03-29 17:38:58 -0500678 <div class="item osd_name">{{ osdname }}</div>
679 <div class="item conf_name_uniq">{{ tname }}</div>
680 <div class="item conf_value_uniq">{{ tdata["value"] }}</div>
681 <div class="item conf_source_uniq">{{ tdata["source"] }}</div>
Alex41dd0cc2022-02-09 17:33:23 -0600682 </div>
683 {% endfor %}
684 </td></tr>
Alex0bcf31b2022-03-29 17:38:58 -0500685 {% endfor %}
Alex41dd0cc2022-02-09 17:33:23 -0600686 </tbody></table>
687 </div>
Alex41dd0cc2022-02-09 17:33:23 -0600688</div>
689{% endmacro %}
690
Alexdcb792f2021-10-04 14:24:21 -0500691<!-- Latency -->
692{% macro latency_page(lat, id_label) %}
693<div id="{{ id_label }}" class="barcontent">
694 {% set lat = info["osd_latency_data"]["data"] %}
695 {% set ldelay = lat["delay"] %}
696 {% set ltotal = lat["total"] %}
697 {% set ldata = lat["data"] %}
698 {% set ltable = info["osd_latency_data"]["table"] %}
699 <h5>{{ caller() }}: {{ ltotal }} iterations, {{ ldelay }} delay between iterations</h5>
700 <hr>
701 <table class="ceph_status">
702 {% for osd, llist in ltable.items() %}
703 <tr class="node">
704 {% if osd == "<dev>" %}
705 <td class="status">ODS node (ms)</td>
706 <td class="col_latency">
707 <div class="meters">
708 {% for ii in llist %}
709 <div class="meter lat_commit">Commit</div>
710 <div class="meter lat_apply">Apply</div>
711 {% endfor %}
712 </div>
713 </td>
714 {% else %}
715 <td class="status">{{ osd }}</td>
716 <td class="col_latency">
717 <div class="meters">
718 {% for ii in llist %}
719 <div class="meter lat_commit">{{ ii["commit_latency_ms"] }}</div>
720 <div class="meter lat_apply">{{ ii["apply_latency_ms"] }}</div>
721 {% endfor %}
722 </div>
723 </td>
724 {% endif %}
725 </tr>
726 {% endfor %}
727 </table>
728</div>
729{% endmacro %}
730
731<!-- Mon Dump -->
732{% macro mondump_page(mondump, id_label) %}
733<div id="{{ id_label }}" class="barcontent">
734 {% set mons = info["monmap"]["data"] %}
735 <h5>{{ caller() }} : v{{ mons["min_mon_release"] }}/{{ mons["min_mon_release_name"] }} and higher</h5>
736 <div class="note">Persistent: {{ mons["features"]["persistent"] | join(", ") }}</div>
737 {% if mons["features"]["optional"] | length > 0 %}
738 <div class="note">Optional: {{ mons["features"]["optional"] | join(", ") }}</div>
739 {% else %}
740 <div class="note">Optional: no</div>
741 {% endif %}
742 <hr>
743 <table class="ceph_status">
744 <tr class="node">
745 <td class="id centered">Rank</td>
746 <td class="mon_name">Name</td>
747 <td class="mon_url">Address</td>
748 <td class="mon_url">Public address</td>
749 </tr>
750 {% for mon in mons["mons"] %}
751 <tr class="node">
752 <td class="id centered">{{ mon["rank"] }}</td>
753 <td class="mon_name">{{ mon["name"] }}</td>
754 <td class="mon_url">{{ mon["addr"] }}</td>
755 <td class="mon_url">{{ mon["public_addr"] }}</td>
756 </tr>
757 {% endfor %}
758 </table>
759</div>
760{% endmacro %}
761
762<!-- DF -->
763{% macro df_page(info, id_label) %}
764<div id="{{ id_label }}" class="barcontent">
765 {% set df = info["ceph_df"]["data"] %}
766 <h5>{{ caller() }}</h5>
767 <div class="note">{{ df["stats"]["num_osds"] }} OSD nodes, {{ df["stats"]["num_per_pool_osds"] }} per pool</div>
768 <hr>
769 <table class="ceph_status">
770 <tr class="node">
771 <td class="df_name">Scope</td>
772 <td class="df_total right">Total, GB</td>
773 <td class="df_avail right">Available, GB</td>
774 <td class="df_used right">Used, GB</td>
775 <td class="df_used_raw right">Used raw, GB</td>
776 <td class="df_used_raw_rate right">Raw ratio</td>
777 </tr>
778 <tr class="node">
779 <td class="df_name">All</td>
780 <td class="df_total right">{{ df["stats"]["total_bytes"] | to_gb }}</td>
781 <td class="df_avail right">{{ df["stats"]["total_avail_bytes"] | to_gb }}</td>
782 <td class="df_used right">{{ df["stats"]["total_used_bytes"] | to_gb }}</td>
783 <td class="df_used_raw right">{{ df["stats"]["total_used_raw_bytes"] | to_gb }}</td>
784 <td class="df_used_raw_rate right">{{ "%0.4f" | format(df["stats"]["total_used_raw_ratio"]|float) }}</td>
785 </tr>
786 {% for class, stat in df["stats_by_class"].items() %}
787 <tr class="node">
788 <td class="df_name">{{ class }}</td>
789 <td class="df_total right">{{ stat["total_bytes"] | to_gb }}</td>
790 <td class="df_avail right">{{ stat["total_avail_bytes"] | to_gb }}</td>
791 <td class="df_used right">{{ stat["total_used_bytes"] | to_gb }}</td>
792 <td class="df_used_raw right">{{ stat["total_used_raw_bytes"] | to_gb }}</td>
793 <td class="df_used_raw_rate right">{{ "%0.4f" | format(stat["total_used_raw_ratio"]|float) }}</td>
794 </tr>
795 {% endfor %}
796 </table>
797 <hr>
798 <table class="ceph_status">
799 <tr class="node">
800 <td class="id centered">ID</td>
801 <td class="df_name">Name</td>
802 <td class="df_total centered">Objects</td>
803 <td class="df_avail right">Stored, GB</td>
804 <td class="df_used right">Used, GB</td>
805 <td class="df_used_raw centered">Used, %</td>
806 <td class="df_used_raw_rate right">Max Available, GB</td>
807 <td class="df_total centered">Placement Groups</td>
808 </tr>
809
810 {% for pool in df["pools"] %}
811 {% set pool_stats = pool["id"] | get_pool_stats(info["ceph_pg_dump"]["data"]) %}
812 <tr class="node">
813 <td class="id centered">{{ pool["id"] }}</td>
814 <td class="df_name">{{ pool["name"] }}</td>
815 <td class="df_total centered">{{ pool["stats"]["objects"] }}</td>
816 <td class="df_avail right">{{ pool["stats"]["stored"] | to_gb }}</td>
817 <td class="df_used right">{{ pool["stats"]["bytes_used"] | to_gb }}</td>
818 <td class="df_used_raw centered">{{ "%0.2f" | format(pool["stats"]["percent_used"]|float) }}</td>
819 <td class="df_used_raw_rate right">{{ pool["stats"]["max_avail"] | to_gb }}</td>
820 <td class="df_total centered">{{ pool_stats["num_pg"] }}</td>
821 </tr>
822 {% endfor %}
823 </table>
824
825</div>
826{% endmacro %}
827
828<!-- RADOS DF -->
829{% macro dfrados_page(info, id_label) %}
830<div id="{{ id_label }}" class="barcontent">
831 {% set rdf = info["rados_df"]["data"] %}
832 <h5>{{ caller() }}</h5>
833 <hr>
834 <table class="ceph_status">
835 <tr class="node">
836 <td class="df_name">Stats</td>
837 <td class="df_total right">Total objects</td>
838 <td class="df_avail right">Total used, GB</td>
839 <td class="df_used right">Total Available, GB</td>
840 <td class="df_used_raw right">Total space, GB</td>
841 </tr>
842 <tr class="node">
843 <td class="df_name">Rados DF</td>
844 <td class="df_total right">{{ rdf["total_objects"] }}</td>
845 <td class="df_avail right">{{ rdf["total_used"] | to_gb }}</td>
846 <td class="df_used right">{{ rdf["total_avail"] | to_gb }}</td>
847 <td class="df_used_raw right">{{ rdf["total_space"] | to_gb }}</td>
848 </tr>
849 </table>
850 <hr>
851 <table class="ceph_status">
852 <tr class="node">
853 <td class="id centered">ID</td>
854 <td class="rdf_name">Name</td>
855 <td class="rdf_obj centered">Objects</td>
856 <td class="rdf_obj centered">Clones</td>
857 <td class="rdf_obj centered">Copies</td>
858 <td class="rdf_obj centered">Unfound</td>
859 <td class="rdf_obj centered">Degraded</td>
860 <td class="rdf_obj centered">Missing</td>
861
862 <td class="rdf_used right">Size, GB</td>
863 <td class="rdf_used right">Compressed, GB</td>
864 <td class="rdf_used right">Real, GB</td>
865
866 <td class="rdf_bench right">Read, MB/s</td>
867 <td class="rdf_bench right">Read, IOPS</td>
868
869 <td class="rdf_bench right">Write, MB/s</td>
870 <td class="rdf_bench right">Write, IOPS</td>
871 </tr>
872 {% for pool in rdf["pools"] | sort(attribute='id') %}
873 <tr class="node">
874 <td class="id centered">{{ pool["id"] }}</td>
875 <td class="rdf_name">{{ pool["name"] }}</td>
876 <td class="rdf_obj centered">{{ pool["num_objects"] }}</td>
877 <td class="rdf_obj centered">{{ pool["num_object_clones"] }}</td>
878 <td class="rdf_obj centered">{{ pool["num_object_copies"] }}</td>
879 <td class="rdf_obj centered">{{ pool["num_objects_unfound"] }}</td>
880 <td class="rdf_obj centered">{{ pool["num_objects_degraded"] }}</td>
881 <td class="rdf_obj centered">{{ pool["num_objects_missing_on_primary"] }}</td>
882
883 <td class="rdf_total right">{{ pool["size_bytes"] | to_gb }}</td>
884 <td class="rdf_used right">{{ pool["compress_bytes_used"] | to_gb }}</td>
885 <td class="rdf_used right">{{ pool["compress_under_bytes"] | to_gb }}</td>
886
887 <td class="rdf_bench right">{{ pool["read_bytes"] | to_mb }}</td>
888 <td class="rdf_bench right">{{ pool["read_ops"] }}</td>
889
890 <td class="rdf_bench right">{{ pool["write_bytes"] | to_mb }}</td>
891 <td class="rdf_bench right">{{ pool["write_ops"] }}</td>
892 </tr>
893 {% endfor %}
894 </table>
895 <hr>
896</div>
897{% endmacro %}
898
899<!-- Auth ls -->
900{% macro auth_page(info, id_label) %}
901<div id="{{ id_label }}" class="barcontent">
902 {% set auth = info["ceph_auth_ls"]["data"] %}
903 <h5>{{ caller() }}</h5>
904 <hr>
905 <table class="ceph_status">
906 <tr class="node">
907 <td class="bucket_name">Entity</td>
908 <td class="bucket_items">Caps</td>
909 </tr>
910 {% for ath in auth["auth_dump"] | sort(attribute='entity') %}
911 <tr class="node">
912 <td class="bucket_name">{{ ath["entity"] }}</td>
913 <td class="bucket_items">
914 {% for scope, value in ath["caps"].items() %}
915 {{ scope }}: {{ value }}<br>
916 {% endfor %}
917 </td>
918 </tr>
919 {% endfor %}
920 </table>
921 <hr>
922</div>
923{% endmacro %}
924
925<!-- Device Health -->
926{% macro dhealth_page(info, id_label) %}
927<div id="{{ id_label }}" class="barcontent">
928 {% set dh = info["ceph_health"]["latest"] %}
929 <h5>{{ caller() }}: {{ dh | count }} devices</h5>
930 <div class="note">Data collection timestamp is '{{ info["ceph_health"]['date'] }}'</div>
931 <hr>
932 <table class="ceph_status">
933 <tr class="node">
934 <td class="dev_name">Name</td>
935 <td class="dev_param centered">Device</td>
936 <td class="dev_param centered">Protocol</td>
937 <td class="dev_param centered">Firmware</td>
938 <td class="dev_param centered">Speed<div class='note'>current/max</div></td>
939 <td class="dev_param centered">Block size<div class='note'>physical/logical</div></td>
940 <td class="dev_param centered">Power cycles</td>
941 <td class="dev_param centered">Temperature</td>
942 <td class="dev_param centered">Smart Status</td>
943 <td class="dev_param centered">Smart data</td>
944 </tr>
Alex90ac1532021-12-09 11:13:14 -0600945 {% for _d, _p in dh.items() | sort(attribute='0') if _p %}
Alexdcb792f2021-10-04 14:24:21 -0500946 <tr class="node">
947 <td class="dev_name">
948 <div class="text">{{ _p['model_name'] }}, {{ _p['serial_number'] }}</div><br>
Alexdf9cc3a2021-10-12 14:37:28 -0500949 {% if "model_family" in _p %}
950 <div class="note">{{ _p['model_family'] }}</div>
951 {% endif %}
952 <div class="note">{{ _p['node_name'] }}:{{ _p['osd_name'] }}</div>
Alexdcb792f2021-10-04 14:24:21 -0500953 </td>
954 <td class="dev_param centered">{{ _p['device']['info_name'] }}</td>
955 <td class="dev_param centered">{{ _p['device']['protocol'] }}</td>
956 <td class="dev_param centered">{{ _p['firmware_version'] }}</td>
Alexdf9cc3a2021-10-12 14:37:28 -0500957 {% if "interface_speed" in _p %}
Alexdcb792f2021-10-04 14:24:21 -0500958 <td class="dev_param centered">{{ _p['interface_speed']['current']['string'] }} / {{ _p['interface_speed']['max']['string'] }}</td>
Alexdf9cc3a2021-10-12 14:37:28 -0500959 {% else %}
960 <td class="dev_param centered">- / -</td>
961 {% endif%}
962 {% if "physical_block_size" in _p %}
Alexdcb792f2021-10-04 14:24:21 -0500963 <td class="dev_param centered">{{ _p['physical_block_size'] }} / {{ _p['logical_block_size'] }}</td>
Alexdf9cc3a2021-10-12 14:37:28 -0500964 {% else %}
965 <td class="dev_param centered">- / {{ _p['logical_block_size'] }}</td>
966 {% endif %}
Alexdcb792f2021-10-04 14:24:21 -0500967 <td class="dev_param centered">{{ _p['power_cycle_count'] }}</td>
968 <td class="dev_param centered">{{ _p['temperature']['current'] }}</td>
969 {% if _p['smart_status']['passed'] %}
970 <td class="dev_param centered" style="color: green">Passed</td>
971 {% else %}
972 <td class="dev_param centered" style="color: red;">Failed</td>
973 {% endif %}
974 <td class="dev_param centered">
975 <div class="cell_button" onclick="toggleClassByID('{{ _d }}_smart_output')" id="{{ _d }}_smart_output_button">Show/Hide</div>
976 </td>
977 </tr>
978 <tr class="collapsable" id="{{ _d }}_smart_output"><td colspan=10>
979 <div class="console">
980 <pre>
981 {% for line in _p['smartctl']['output'] %}
982 {{ line }}
983 {% endfor %}
984 </pre>
985 </div>
986 </td></tr>
987 {% endfor %}
988 </table>
989 <hr>
990</div>
991{% endmacro %}
992
993<!-- ================================= -->
994<!-- Cluster nodes page -->
995{% call status_page(info, "status") %}
996 Cluster status
997{% endcall %}
998
999{% call crush_page(info, "crush") %}
1000 CRUSH map
1001{% endcall %}
1002
Alex41dd0cc2022-02-09 17:33:23 -06001003{% call osdconf_page(info, "osdconf") %}
1004 OSD configs
1005{% endcall %}
1006
Alexdcb792f2021-10-04 14:24:21 -05001007{% call latency_page(info['osd_latency_data'], "latency") %}
1008 Quick latency check for all OSDs
1009{% endcall %}
1010
1011{% call mondump_page(info['monmap'], "mondump") %}
1012 Ceph monitors
1013{% endcall %}
1014
1015{% call df_page(info, "df") %}
1016 Pool list with additional data
1017{% endcall %}
1018
1019{% call dfrados_page(info, "dfrados") %}
1020 Rados pools list with additional details
1021{% endcall %}
1022
1023{% call auth_page(info, "auth") %}
1024 Anonymized auth list
1025{% endcall %}
1026
1027{% call dhealth_page(info, "dhealth") %}
1028 Device health status and S.M.A.R.T. outputs
1029{% endcall %}
1030</body>
1031</html>