blob: a2b17a951562b3a92c60b3d55b84453633425bda [file] [log] [blame]
Alex Savatieiev9b2f6512019-02-20 18:05:00 -06001<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
Alex41485522019-04-12 17:26:18 -05005 <title>Nodes and Networks report</title>
6 {% include 'common_styles.j2' %}
7 {% include 'common_scripts.j2' %}
Alex Savatieiev9b2f6512019-02-20 18:05:00 -06008 <style>
Alex41485522019-04-12 17:26:18 -05009 table.cluster_nodes {
10 width: 90%;
11 margin-left: 5%;
12 margin-right: 5%;
Alex Savatieiev9b2f6512019-02-20 18:05:00 -060013 }
Alex41485522019-04-12 17:26:18 -050014
15 /* Node rows*/
16 .node {
Alex836fac82019-08-22 13:36:16 -050017 font-family: "LaoSangamMN", Monaco, monospace;
18 font-size: 0.8em;
Alex41485522019-04-12 17:26:18 -050019 display: inline-block;
20 background-color: white;
21 }
Alex836fac82019-08-22 13:36:16 -050022 .collapsable {
23 font-family: "LaoSangamMN", Monaco, monospace;
24 font-size: 0.8em;
25 display: none;
26 background-color: white;
27 visibility: hidden;
28 }
29 .collapsable.in {
30 visibility: visible;
31 display: inline-block;
32 }
33
34 div.services > .collapsable.in {
35 display: table-row;
36 }
Alex41485522019-04-12 17:26:18 -050037
Alex836fac82019-08-22 13:36:16 -050038 tr.node > td, tr.collapsable > td {
Alex Savatieiev9b2f6512019-02-20 18:05:00 -060039 display: block;
Alex Savatieiev9b2f6512019-02-20 18:05:00 -060040 float: left;
Alex41485522019-04-12 17:26:18 -050041 padding: 1px;
Alex41485522019-04-12 17:26:18 -050042 margin: 2px;
Alex Savatieiev9b2f6512019-02-20 18:05:00 -060043 }
Alex1839bbf2019-08-22 17:17:21 -050044 td > .kvm_group {
45 display: grid;
46 grid-template-columns: auto auto auto;
47 padding-left: 0px;
48 padding-right: 0px;
49 margin: 1px;
50 }
Alex836fac82019-08-22 13:36:16 -050051 td > .disk_group {
52 display: grid;
53 grid-template-columns: auto auto auto auto auto;
54 padding-left: 0px;
55 padding-right: 0px;
56 margin: 1px;
Alex Savatieiev9b2f6512019-02-20 18:05:00 -060057 }
Alex1839bbf2019-08-22 17:17:21 -050058 td > .ram_group, td > .net_group {
Alex836fac82019-08-22 13:36:16 -050059 display: grid;
60 grid-template-columns: auto auto auto auto;
61 padding-left: 0px;
62 padding-right: 0px;
63 margin: 1px;
64 }
Alex1839bbf2019-08-22 17:17:21 -050065 td > .net_group {
66 display: grid;
67 grid-template-columns: auto auto auto auto auto;
68 padding-left: 0px;
69 padding-right: 0px;
70 margin: 1px;
71 }
Alex836fac82019-08-22 13:36:16 -050072 td > .vcpu_group {
73 display: grid;
74 grid-template-columns: auto;
75 padding-left: 0px;
76 padding-right: 0px;
77 margin: 1px;
78 }
79
80 .item {
81 display: inline-grid;
82 border-width: 1px;
83 border-style: solid;
84 margin: 1px 1px 1px 1px;
85 padding: 0px 1px 0px 1px;
86 }
87
88 .status_none { border-radius: 10px; width: 8px; }
89 .status_up { border-radius: 10px; width: 8px; background-color: #393; color: #393; }
90 .status_down { border-radius: 10px; width: 8px; background-color: #933; color: #933; }
Alex41485522019-04-12 17:26:18 -050091
Alex836fac82019-08-22 13:36:16 -050092 .head { height: 18px; }
93 .col_name { width: 250px; }
94 .col_role { width: 150px; }
95 .col_vendor { width: 100px; }
96 .col_release { width: 100px; }
97 .col_kernel { min-width: 100px; }
98 .col_vcpu { min-width: 40px; }
Alex1839bbf2019-08-22 17:17:21 -050099 .col_net { min-width: 150px; }
Alex836fac82019-08-22 13:36:16 -0500100 .col_ram { min-width: 150px; }
101 .col_disk { min-width: 200px; }
102
Alex1839bbf2019-08-22 17:17:21 -0500103 .col_node_notes { width: 400px; }
104 .col_cpu_notes { width: 218px; }
105
Alex836fac82019-08-22 13:36:16 -0500106 .meters {
107 display: inline-block;
108 margin: 1px;
109 }
110 .meters > .meter {
Alex41485522019-04-12 17:26:18 -0500111 display: block;
112 float: left;
Alex836fac82019-08-22 13:36:16 -0500113 border-width: 1px;
114 border-style: solid;
115 margin: 0px 1px 0px 1px;
116 padding: 0px 1px 0px 1px;
117
Alex Savatieiev9b2f6512019-02-20 18:05:00 -0600118 }
Alex1839bbf2019-08-22 17:17:21 -0500119 .kvm_id, .kvm_node, .kvm_status {
120 border-width: 0px;
121 background-color: #f0f0f0;
122 }
123 .kvm_id, .kvm_status {
124 text-align: center;
125 }
Alex836fac82019-08-22 13:36:16 -0500126 .meters > .ok, .disk_group > .ok, .ram_group > .ok{
127 border-color: #80a080;
128 background-color: #efe;
129 }
130 .meters > .warn, .disk_group > .warn, .ram_group > .warn {
131 border-color: #d3a200;
132 background-color: rgb(255, 216, 133);
133 }
134 .meters > .fail, .disk_group > .fail, .ram_group > .fail {
135 border-color: #bb0000;
136 background-color: rgb(250, 135, 135);
137 }
138 .cpu { border-color: #a0c0a0; background-color: rgb(252, 248, 248); }
Alex1839bbf2019-08-22 17:17:21 -0500139 .net { border-color: #c0c0a0; background-color: rgb(255, 255, 251); text-align: right; }
140 .ram { border-color: #a0c0c0; background-color: rgb(255, 250, 250); }
Alex836fac82019-08-22 13:36:16 -0500141 .disk { border-color: #cedfdf; background-color: rgb(237, 241, 243); }
142
143 .map_grid {
144 display: grid;
145 grid-template-columns: auto auto auto auto auto auto auto auto auto auto;
146 grid-column-gap: 20px;
147 padding-left: 0px;
148 padding-right: 0px;
149 margin: 1px;
150 margin-left: 20px;
151
152 }
153 .map_item {
154 display: inline-grid;
155 border-width: 0px;
156 border-style: solid;
157 margin: 1px 1px 1px 1px;
158 padding: 0px 1px 0px 1px;
159 }
160
161 .map_grid > .ok {
162 color: #80a080;
163 }
164 .map_grid > .warn {
165 color: #d3a200;
166 }
167 .map_grid > .fail {
168 color: #bb0000;
169 }
170
171 .services {
172 font-family: "LaoSangamMN", Monaco, monospace;
173 font-size: 1.1em;
174 background-color: white;
175 }
176 .service_node {
Alex836fac82019-08-22 13:36:16 -0500177 margin-bottom: 2px;
Alex1839bbf2019-08-22 17:17:21 -0500178 display: flex;
179 }
180 .service_name, .node_name {
181 text-align: center;
182 border-width: 0px;
183 border-style: solid;
184 margin: 1px 1px 1px 1px;
185 padding: 0px 1px 0px 1px;
186 min-width: 250px;
187 border-radius: 10px;
188 }
189 .node_name {
190 background-color: #ddd;
Alex836fac82019-08-22 13:36:16 -0500191 }
192 .service_grid {
193 display: grid;
194 grid-template-columns: repeat(8, auto);
195 grid-template-rows: repeat(10, auto);
196 grid-auto-flow: column;
197 grid-column-gap: 20px;
198 padding-left: 0px;
199 padding-right: 0px;
200 margin: 1px;
201 margin-left: 20px;
202 }
203 .service {
204 display: inline-grid;
205 text-align: center;
206 border-width: 0px;
207 border-style: solid;
208 margin: 1px 1px 1px 1px;
209 padding: 0px 1px 0px 1px;
210 min-width: 150px;
211 border-radius: 10px;
212 }
213
Alex1839bbf2019-08-22 17:17:21 -0500214 .service_grid > .on, .service_node > .ok {
Alex836fac82019-08-22 13:36:16 -0500215 background-color: #8c8;
216 }
Alex1839bbf2019-08-22 17:17:21 -0500217 .service_grid > .off, .service_node > .off{
Alex836fac82019-08-22 13:36:16 -0500218 background-color: #9aa;
219 }
Alex1839bbf2019-08-22 17:17:21 -0500220 .service_grid > .fail, .service_node > .fail {
Alex836fac82019-08-22 13:36:16 -0500221 background-color: rgb(250, 135, 135);
222 }
223
Alex Savatieiev9b2f6512019-02-20 18:05:00 -0600224 </style>
Alex Savatieiev9b2f6512019-02-20 18:05:00 -0600225</head>
226<body onload="init()">
227
Alex41485522019-04-12 17:26:18 -0500228<div class="header">
229 <div class="label">OpenStack release:</div>
230 <div class="text">{{ openstack_release }}</div>
231 <div class="label">MCP Version:</div>
232 <div class="text">{{ mcp_release }}</div>
Alex836fac82019-08-22 13:36:16 -0500233 <div class="label">RAM % Warning/Critical:</div>
234 <div class="text">{{ const['ram_warn'] }}/{{ const['ram_critical'] }}</div>
235 <div class="label">Disk % Warning/Critical:</div>
236 <div class="text">{{ const['disk_warn'] }}/{{ const['disk_critical'] }}</div>
Alex41485522019-04-12 17:26:18 -0500237 <div class="label date">generated on: {{ gen_date }}</div>
238</div>
239
240<div class="bar">
241 <button class="bar-item" onclick="openBar(event, 'nodes')">Nodes</button>
242 <button class="bar-item" onclick="openBar(event, 'networks')">Networks</button>
Alex1839bbf2019-08-22 17:17:21 -0500243 <button class="bar-item" onclick="openBar(event, 'services')">Services</button>
Alex41485522019-04-12 17:26:18 -0500244</div>
245
246{% macro nodes_page(nodes, id_label) %}
247<div id="{{ id_label }}" class="barcontent">
248 <h5>{{ caller() }}</h5>
249 <hr>
250 <table class="cluster_nodes">
Alex836fac82019-08-22 13:36:16 -0500251 <tr class="node">
252 <td class="status_none"></td>
253 <td class="head col_name">Name</td>
254 <td class="head col_role">Role</td>
255 <td class="head col_vendor">Virtual</td>
256 <td class="head col_release">Linux</td>
257 <td class="head col_kernel">Kernel</td>
258
259 <td class="head col_vcpu">
260 <div class="meters vcpu">
261 <div class="meter cpu">vCPU</div>
262 </div>
263 </td>
Alex1839bbf2019-08-22 17:17:21 -0500264 <td class="head col_net">
265 <div class="meters net">
266 <div class="meter net">Total</div>
267 <div class="meter net">Dropped</div>
268 <div class="meter net">Squeeze</div>
269 <div class="meter net">Collide</div>
270 </div>
271 </td>
Alex836fac82019-08-22 13:36:16 -0500272 <td class="head col_ram">
273 <div class="meters">
274 <div class="meter ram">Total</div>
275 <div class="meter ram">Used</div>
276 <div class="meter ram">Free</div>
277 <div class="meter ram">Available</div>
278 </div>
279 </td>
280 <td class="head col_disk">
281 <div class="meters">
282 <div class="meter disk">device</div>
283 <div class="meter disk">total</div>
284 <div class="meter disk">used</div>
285 <div class="meter disk">free</div>
286 <div class="meter disk">percent</div>
287 </div>
288 </td>
289 </tr>
Alex41485522019-04-12 17:26:18 -0500290 {% for node in nodes.keys() | sort %}
291 {% set _ndat = nodes[node] %}
Alex836fac82019-08-22 13:36:16 -0500292 <tr class="node" onclick="toggleClassByID('info_{{ node }}')" id='info_{{ node }}_button'>
293 <td class="status_{{ _ndat['status'] | node_status_class }}">.</td>
294 <td class="head col_name">{{ node }}</td>
295 <td class="head col_role">{{ _ndat['role'] }}</td>
Alex1839bbf2019-08-22 17:17:21 -0500296 <td class="head col_vendor">{{ _ndat['node_type'] }}</td>
Alex836fac82019-08-22 13:36:16 -0500297 <td class="head col_release">{{ _ndat['linux_arch'] }}/{{ _ndat['linux_codename'] }}</td>
298 <td class="head col_kernel">{{ _ndat['kernel'] }}</td>
299 <td class="head col_vcpu">
300 <div class="meters vcpu">
Alex1839bbf2019-08-22 17:17:21 -0500301 <div class="meter cpu">{{ _ndat['lscpu']['cpus'] }}</div>
302 </div>
303 </td>
304 <td class="head col_net">
305 <div class="net_group">
306 <div class="item net">{{ _ndat['net_stats']['total'][0] }}</div>
307 <div class="item net">{{ _ndat['net_stats']['total'][1] }}</div>
308 <div class="item net">{{ _ndat['net_stats']['total'][2] }}</div>
309 <div class="item net">{{ _ndat['net_stats']['total'][3] }}</div>
Alex836fac82019-08-22 13:36:16 -0500310 </div>
311 </td>
312 <td class="head col_ram">
313 <div class="ram_group">
Alex1839bbf2019-08-22 17:17:21 -0500314 <div class="item ram">{{ _ndat['ram']['total'] }}</div>
315 <div class="item ram">{{ _ndat['ram']['used'] }}</div>
316 <div class="item ram">{{ _ndat['ram']['free'] }}</div>
317 <div class="item ram {{ _ndat['ram']['status'] }}">{{ _ndat['ram']['available'] }}</div>
Alex836fac82019-08-22 13:36:16 -0500318 </div>
319 </td>
320 <td class="head col_disk">
321 <div class="disk_group">
322 <div class="item disk">{{ _ndat['disk_max_dev'] }}</div>
323 {% for val in _ndat['disk'][_ndat['disk_max_dev']]['v'] %}
324 <div class="item disk {{ _ndat['disk'][_ndat['disk_max_dev']]['f'] }}">{{ val }}</div>
325 {% endfor %}
326 </div>
327 </td>
328 </tr>
329 <tr class="collapsable" id="info_{{ node }}">
330 <td class="status_none"></td>
Alex1839bbf2019-08-22 17:17:21 -0500331 <td class="col_node_notes" colspan="2">
332 {% if 'virsh' in _ndat %}
333 <div class="kvm_group">
334 {% for kvm_node in _ndat['virsh'].keys() | sort %}
335 <div class="item kvm_id">{{ _ndat['virsh'][kvm_node]['id'] }}</div>
336 <div class="item kvm_node">{{ kvm_node }}</div>
337 <div class="item kvm_status">{{ _ndat['virsh'][kvm_node]['status'] }}</div>
338 {% endfor %}
339 </div>
340 {% endif %}
341 </td>
342 <td class="col_cpu_notes smallgreytext" colspan="2">
343 CPU Model: {{ _ndat['lscpu']['model_name'] }} at {{ _ndat['lscpu']['cpu_mhz'] }}Mhz<br>
344 Virtualization: {{ _ndat['lscpu']['virtualization'] }}
345 </td>
Alex836fac82019-08-22 13:36:16 -0500346 <td class="col_kernel"></td>
347 <td class="col_vcpu"></td>
Alex1839bbf2019-08-22 17:17:21 -0500348 <td class="col_net">
349 <div class="net_group">
350 {% for cpu in _ndat['net_stats'].keys() | sort %}
351 <div class="item net">{{ cpu }}</div>
352 {% for val in _ndat['net_stats'][cpu] %}
353 <div class="item net">{{ val }}</div>
354 {% endfor %}
355 {% endfor %}
356 </div>
357 </td>
Alex836fac82019-08-22 13:36:16 -0500358 <td class="col_ram"></td>
359 <td class="col_disk">
360 <div class="disk_group">
361 {% for dev in _ndat['disk'].keys() | sort %}
362 <div class="item disk">{{ dev }}</div>
363 {% for val in _ndat['disk'][dev]['v'] %}
364 <div class="item disk {{ _ndat['disk'][dev]['f'] }}">{{ val }}</div>
365 {% endfor %}
366 {% endfor %}
367 </div>
368 </td>
Alex41485522019-04-12 17:26:18 -0500369 </tr>
370 {% endfor %}
371 </table>
372 <hr>
373</div>
374{% endmacro %}
375
376{% macro networks_page(networks, id_label) %}
377<div id="{{ id_label }}" class="barcontent">
378 <h5>{{ caller() }}</h5>
379 <hr>
380 <table class="networks">
Alex836fac82019-08-22 13:36:16 -0500381 {% for net in map.keys() %}
382 <tr class="subnet" onclick="toggleClassByID('net_{{ net }}')" id="{{ net }}_net_button">
383 <td>{{ net }}</td>
Alex41485522019-04-12 17:26:18 -0500384 </tr>
Alex836fac82019-08-22 13:36:16 -0500385 <tr class="collapsable" id="net_{{ net }}"><td>
386 <div class="map_grid">
387 {% for node in map[net].keys() | sort %}
388 {% for d in map[net][node] %}
389 <div class="map_item name">{{ node }}</div>
390 <div class="map_item interface {{ d['interface_error'] }}">{{ d['interface'] }}</div>
Alex1839bbf2019-08-22 17:17:21 -0500391 <div class="map_item note"><pre>{{ d['interface_map'] | linebreaks }}</pre></div>
Alex836fac82019-08-22 13:36:16 -0500392 <div class="map_item ipaddr">{{ d['ip_address'] }}</div>
393 <div class="map_item ipaddr_type">{{ d['address_type'] }}</div>
394 <div class="map_item mtu {{ d['mtu_error'] }}">{{ d['rt_mtu'] }}</div>
395 <div class="map_item status {{ d['status_error'] }}">{{ d['status'] }}</div>
396 <div class="map_item gate {{ d['subnet_gateway_error'] }}">{{ d['subnet_gateway'] }}</div>
397 <div class="map_item gate">{{ d['default_gateway'] }}</div>
398 <div class="map_item error_note">{{ d['error_note'] }}</div>
399 {% endfor %}
400 {% endfor %}
401 </div>
402 </td></tr>
403 {% endfor %}
Alex41485522019-04-12 17:26:18 -0500404 </table>
405 <hr>
406</div>
407{% endmacro %}
408
409{% macro services_page(services, id_label) %}
410<div id="{{ id_label }}" class="barcontent">
411 <h5>{{ caller() }}</h5>
412 <hr>
Alex836fac82019-08-22 13:36:16 -0500413 <div class="services">
414 {% for node in nodes.keys() | sort %}
Alex1839bbf2019-08-22 17:17:21 -0500415 <div class="service_node" onclick="toggleClassByID('svc_{{ node }}')" id="svc_{{ node }}_button">
416 <div class="node_name">{{ node }}</div>
417 {% for service in nodes[node]['services'].keys() | sort -%}
418 {% if service in const['services'] %}
419 {% if not nodes[node]['services'][service] %}
420 <div class="service_name fail">{{ service }}</div>
421 {% endif %}
422 {% endif%}
423 {% endfor%}
424 </div>
Alex836fac82019-08-22 13:36:16 -0500425 <div class="collapsable" id="svc_{{ node }}">
426 <div class="service_grid">
427 {% for service in nodes[node]['services'].keys() | sort -%}
Alex1839bbf2019-08-22 17:17:21 -0500428 {% if service in const['services'] %}
Alex836fac82019-08-22 13:36:16 -0500429 {% if nodes[node]['services'][service] %}
Alex1839bbf2019-08-22 17:17:21 -0500430 <div class="service on">{{ service }}</div>
Alex836fac82019-08-22 13:36:16 -0500431 {% else %}
Alex1839bbf2019-08-22 17:17:21 -0500432 <div class="service fail">{{ service }}</div>
433 {% endif %}
434 {% endif%}
435 {% endfor %}
436 <div class="service"># Other services</div>
437 {% for service in nodes[node]['services'].keys() | sort -%}
438 {% if service not in const['services'] %}
439 {% if nodes[node]['services'][service] %}
440 <div class="service on">{{ service }}</div>
441 {% else %}
442 <div class="service off">{{ service }}</div>
443 {% endif %}
Alex836fac82019-08-22 13:36:16 -0500444 {% endif %}
445 {% endfor %}
446 </div>
447 </div>
448 {% endfor %}
449 </div>
450 <hr>
Alex41485522019-04-12 17:26:18 -0500451</div>
452{% endmacro %}
453
454<!-- Cluster nodes page -->
455{% call nodes_page(nodes, "nodes") %}
456 Cluster nodes status and simple meterings
457{% endcall %}
458
459<!-- Cluster nodes page -->
460{% call networks_page(networks, "networks") %}
461 Networks in the cluster
462{% endcall %}
463
464<!-- Cluster nodes page -->
465{% call services_page(services, "services") %}
466 Services status in the cluster
467{% endcall %}
468
Alex Savatieiev9b2f6512019-02-20 18:05:00 -0600469</body>
470</html>