blob: c26a115a70925c8643db9a980fc0bea65201be0c [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Nodes and Networks report</title>
{% include 'common_styles.j2' %}
{% include 'common_scripts.j2' %}
<style>
table.cluster_nodes {
width: 90%;
margin-left: 5%;
margin-right: 5%;
}
/* Node rows*/
.node {
font-family: "LaoSangamMN", Monaco, monospace;
font-size: 0.8em;
display: inline-block;
background-color: white;
}
.collapsable {
font-family: "LaoSangamMN", Monaco, monospace;
font-size: 0.8em;
display: none;
background-color: white;
visibility: hidden;
}
.collapsable.in {
visibility: visible;
display: inline-block;
}
div.services > .collapsable.in {
display: table-row;
}
tr.node > td, tr.collapsable > td {
display: block;
float: left;
padding: 1px;
margin: 2px;
}
td > .disk_group {
display: grid;
grid-template-columns: auto auto auto auto auto;
padding-left: 0px;
padding-right: 0px;
margin: 1px;
}
td > .ram_group {
display: grid;
grid-template-columns: auto auto auto auto;
padding-left: 0px;
padding-right: 0px;
margin: 1px;
}
td > .vcpu_group {
display: grid;
grid-template-columns: auto;
padding-left: 0px;
padding-right: 0px;
margin: 1px;
}
.item {
display: inline-grid;
border-width: 1px;
border-style: solid;
margin: 1px 1px 1px 1px;
padding: 0px 1px 0px 1px;
}
.status_none { border-radius: 10px; width: 8px; }
.status_up { border-radius: 10px; width: 8px; background-color: #393; color: #393; }
.status_down { border-radius: 10px; width: 8px; background-color: #933; color: #933; }
.head { height: 18px; }
.col_name { width: 250px; }
.col_role { width: 150px; }
.col_vendor { width: 100px; }
.col_release { width: 100px; }
.col_kernel { min-width: 100px; }
.col_vcpu { min-width: 40px; }
.col_ram { min-width: 150px; }
.col_disk { min-width: 200px; }
.col_notes { width: 618px; }
.meters {
display: inline-block;
margin: 1px;
}
.meters > .meter {
display: block;
float: left;
border-width: 1px;
border-style: solid;
margin: 0px 1px 0px 1px;
padding: 0px 1px 0px 1px;
}
.meters > .ok, .disk_group > .ok, .ram_group > .ok{
border-color: #80a080;
background-color: #efe;
}
.meters > .warn, .disk_group > .warn, .ram_group > .warn {
border-color: #d3a200;
background-color: rgb(255, 216, 133);
}
.meters > .fail, .disk_group > .fail, .ram_group > .fail {
border-color: #bb0000;
background-color: rgb(250, 135, 135);
}
.cpu { border-color: #a0c0a0; background-color: rgb(252, 248, 248); }
.ram { border-color: #c0c0a0; background-color: rgb(255, 255, 251); }
.disk { border-color: #cedfdf; background-color: rgb(237, 241, 243); }
.map_grid {
display: grid;
grid-template-columns: auto auto auto auto auto auto auto auto auto auto;
grid-column-gap: 20px;
padding-left: 0px;
padding-right: 0px;
margin: 1px;
margin-left: 20px;
}
.map_item {
display: inline-grid;
border-width: 0px;
border-style: solid;
margin: 1px 1px 1px 1px;
padding: 0px 1px 0px 1px;
}
.map_grid > .ok {
color: #80a080;
}
.map_grid > .warn {
color: #d3a200;
}
.map_grid > .fail {
color: #bb0000;
}
.services {
font-family: "LaoSangamMN", Monaco, monospace;
font-size: 1.1em;
background-color: white;
}
.service_node {
background-color: #ddd;
margin-bottom: 2px;
}
.service_grid {
display: grid;
grid-template-columns: repeat(8, auto);
grid-template-rows: repeat(10, auto);
grid-auto-flow: column;
grid-column-gap: 20px;
padding-left: 0px;
padding-right: 0px;
margin: 1px;
margin-left: 20px;
}
.service {
display: inline-grid;
text-align: center;
border-width: 0px;
border-style: solid;
margin: 1px 1px 1px 1px;
padding: 0px 1px 0px 1px;
min-width: 150px;
border-radius: 10px;
}
.service_grid > .on {
background-color: #8c8;
}
.service_grid > .off {
background-color: #9aa;
}
.service_grid > .fail {
background-color: rgb(250, 135, 135);
}
</style>
</head>
<body onload="init()">
<div class="header">
<div class="label">OpenStack release:</div>
<div class="text">{{ openstack_release }}</div>
<div class="label">MCP Version:</div>
<div class="text">{{ mcp_release }}</div>
<div class="label">RAM % Warning/Critical:</div>
<div class="text">{{ const['ram_warn'] }}/{{ const['ram_critical'] }}</div>
<div class="label">Disk % Warning/Critical:</div>
<div class="text">{{ const['disk_warn'] }}/{{ const['disk_critical'] }}</div>
<div class="label date">generated on: {{ gen_date }}</div>
</div>
<div class="bar">
<button class="bar-item" onclick="openBar(event, 'nodes')">Nodes</button>
<button class="bar-item" onclick="openBar(event, 'networks')">Networks</button>
<button class="bar-item" onclick="openBar(event, 'services')">Other</button>
</div>
{% macro nodes_page(nodes, id_label) %}
<div id="{{ id_label }}" class="barcontent">
<h5>{{ caller() }}</h5>
<hr>
<table class="cluster_nodes">
<tr class="node">
<td class="status_none"></td>
<td class="head col_name">Name</td>
<td class="head col_role">Role</td>
<td class="head col_vendor">Virtual</td>
<td class="head col_release">Linux</td>
<td class="head col_kernel">Kernel</td>
<td class="head col_vcpu">
<div class="meters vcpu">
<div class="meter cpu">vCPU</div>
</div>
</td>
<td class="head col_ram">
<div class="meters">
<div class="meter ram">Total</div>
<div class="meter ram">Used</div>
<div class="meter ram">Free</div>
<div class="meter ram">Available</div>
</div>
</td>
<td class="head col_disk">
<div class="meters">
<div class="meter disk">device</div>
<div class="meter disk">total</div>
<div class="meter disk">used</div>
<div class="meter disk">free</div>
<div class="meter disk">percent</div>
</div>
</td>
</tr>
{% for node in nodes.keys() | sort %}
{% set _ndat = nodes[node] %}
<tr class="node" onclick="toggleClassByID('info_{{ node }}')" id='info_{{ node }}_button'>
<td class="status_{{ _ndat['status'] | node_status_class }}">.</td>
<td class="head col_name">{{ node }}</td>
<td class="head col_role">{{ _ndat['role'] }}</td>
<td class="head col_vendor">{{ _ndat['virt_vendor'] }}/{{ _ndat['virt_mode'] }}/{{ _ndat['virt_type'] }}</td>
<td class="head col_release">{{ _ndat['linux_arch'] }}/{{ _ndat['linux_codename'] }}</td>
<td class="head col_kernel">{{ _ndat['kernel'] }}</td>
<td class="head col_vcpu">
<div class="meters vcpu">
<div class="meter cpu">{{ _ndat['cpus'] }}</div>
</div>
</td>
<td class="head col_ram">
<div class="ram_group">
<div class="item ram">{{ _ndat['ram_total'] }}</div>
<div class="item ram">{{ _ndat['ram_used'] }}</div>
<div class="item ram">{{ _ndat['ram_free'] }}</div>
<div class="item ram {{ _ndat['ram_status'] }}">{{ _ndat['ram_available'] }}</div>
</div>
</td>
<td class="head col_disk">
<div class="disk_group">
<div class="item disk">{{ _ndat['disk_max_dev'] }}</div>
{% for val in _ndat['disk'][_ndat['disk_max_dev']]['v'] %}
<div class="item disk {{ _ndat['disk'][_ndat['disk_max_dev']]['f'] }}">{{ val }}</div>
{% endfor %}
</div>
</td>
</tr>
<tr class="collapsable" id="info_{{ node }}">
<td class="status_none"></td>
<td class="col_notes" colspan="4">.</td>
<td class="col_kernel"></td>
<td class="col_vcpu"></td>
<td class="col_ram"></td>
<td class="col_disk">
<div class="disk_group">
{% for dev in _ndat['disk'].keys() | sort %}
<div class="item disk">{{ dev }}</div>
{% for val in _ndat['disk'][dev]['v'] %}
<div class="item disk {{ _ndat['disk'][dev]['f'] }}">{{ val }}</div>
{% endfor %}
{% endfor %}
</div>
</td>
</tr>
{% endfor %}
</table>
<hr>
</div>
{% endmacro %}
{% macro networks_page(networks, id_label) %}
<div id="{{ id_label }}" class="barcontent">
<h5>{{ caller() }}</h5>
<hr>
<table class="networks">
{% for net in map.keys() %}
<tr class="subnet" onclick="toggleClassByID('net_{{ net }}')" id="{{ net }}_net_button">
<td>{{ net }}</td>
</tr>
<tr class="collapsable" id="net_{{ net }}"><td>
<div class="map_grid">
{% for node in map[net].keys() | sort %}
{% for d in map[net][node] %}
<div class="map_item name">{{ node }}</div>
<div class="map_item interface {{ d['interface_error'] }}">{{ d['interface'] }}</div>
<div class="map_item note">{{ d['interface_note'] }}</div>
<div class="map_item ipaddr">{{ d['ip_address'] }}</div>
<div class="map_item ipaddr_type">{{ d['address_type'] }}</div>
<div class="map_item mtu {{ d['mtu_error'] }}">{{ d['rt_mtu'] }}</div>
<div class="map_item status {{ d['status_error'] }}">{{ d['status'] }}</div>
<div class="map_item gate {{ d['subnet_gateway_error'] }}">{{ d['subnet_gateway'] }}</div>
<div class="map_item gate">{{ d['default_gateway'] }}</div>
<div class="map_item error_note">{{ d['error_note'] }}</div>
{% endfor %}
{% endfor %}
</div>
</td></tr>
{% endfor %}
</table>
<hr>
</div>
{% endmacro %}
{% macro services_page(services, id_label) %}
<div id="{{ id_label }}" class="barcontent">
<h5>{{ caller() }}</h5>
<hr>
<div class="services">
{% for node in nodes.keys() | sort %}
<div class="service_node" onclick="toggleClassByID('svc_{{ node }}')" id="svc_{{ node }}_button">{{ node }}</div>
<div class="collapsable" id="svc_{{ node }}">
<div class="service_grid">
{% for service in nodes[node]['services'].keys() | sort -%}
{% if nodes[node]['services'][service] %}
<div class="service name on">{{ service }}</div>
{% else %}
<div class="service name off">{{ service }}</div>
{% endif %}
{% endfor %}
</div>
</div>
{% endfor %}
</div>
<hr>
</div>
{% endmacro %}
<!-- Cluster nodes page -->
{% call nodes_page(nodes, "nodes") %}
Cluster nodes status and simple meterings
{% endcall %}
<!-- Cluster nodes page -->
{% call networks_page(networks, "networks") %}
Networks in the cluster
{% endcall %}
<!-- Cluster nodes page -->
{% call services_page(services, "services") %}
Services status in the cluster
{% endcall %}
</body>
</html>