Add IPMI metrics to node overview page
Change-Id: Ibe39b7ba17004d9f6a2ec41eda7942b7ec487971
This commit is contained in:
parent
10ec89b16e
commit
172ee4fa98
@ -142,6 +142,18 @@ class OverviewTab(tabs.Tab):
|
||||
'100'),
|
||||
)
|
||||
|
||||
# TODO(akrivoka): Ajaxize these calls so that they don't hold up the
|
||||
# whole page load
|
||||
context['top_5'] = {
|
||||
'fan': metering_utils.get_top_5(request, 'hardware.ipmi.fan'),
|
||||
'voltage': metering_utils.get_top_5(
|
||||
request, 'hardware.ipmi.voltage'),
|
||||
'temperature': metering_utils.get_top_5(
|
||||
request, 'hardware.ipmi.temperature'),
|
||||
'current': metering_utils.get_top_5(
|
||||
request, 'hardware.ipmi.current'),
|
||||
}
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
@ -139,8 +139,10 @@ $link-color: #428bca;
|
||||
|
||||
.nodes {
|
||||
.widget-info {
|
||||
padding: 0 30px 0 30px;
|
||||
text-align: center;
|
||||
span {
|
||||
font-size: 200%;
|
||||
font-size: 300%;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
{% if meter_conf %}
|
||||
<div class="nodes">
|
||||
<div id="ceilometer-stats" class="clearfix">
|
||||
<div id="ceilometer-stats">
|
||||
<form class="form-inline performance_charts" id="linechart_general_form">
|
||||
<div class="pull-right">
|
||||
<div class="form-group">
|
||||
@ -81,7 +81,7 @@
|
||||
|
||||
<div id="node-charts" class="nodes row">
|
||||
{% for meter_label, url_part, y_max in meter_conf %}
|
||||
<div class="col-lg-{{col_size}}">
|
||||
<div class="col-xs-{{col_size}}">
|
||||
{% include "infrastructure/_performance_chart.html" with label=meter_label y_max=y_max url=node_perf_url|add:"?"|add:url_part only %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
@ -0,0 +1,8 @@
|
||||
<div class="row">
|
||||
<div class="col-xs-2 col-xs-offset-3">{% include "infrastructure/_top_5_chart.html" with top_5=top_5.fan%}</div>
|
||||
<div class="col-xs-2">{% include "infrastructure/_top_5_chart.html" with top_5=top_5.voltage %}</div>
|
||||
<div class="col-xs-2">{% include "infrastructure/_top_5_chart.html" with top_5=top_5.temperature%}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-2 col-xs-offset-3">{% include "infrastructure/_top_5_chart.html" with top_5=top_5.current %}</div>
|
||||
</div>
|
@ -0,0 +1,29 @@
|
||||
{% load i18n %}
|
||||
{% load chart_helpers %}
|
||||
|
||||
<h4>
|
||||
{% trans 'Top 5 Nodes' %} ({{ top_5.label }}):
|
||||
</h4>
|
||||
{% if top_5.data %}
|
||||
<table width="100%">
|
||||
{% for d in top_5.data %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url 'horizon:infrastructure:nodes:detail' d.node_uuid %}">
|
||||
{{ d.node_uuid|truncatechars:6 }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ d.value}} {{ top_5.unit }}
|
||||
</td>
|
||||
<td>
|
||||
{%if d.direction %}
|
||||
<i class="fa fa-arrow-{{d.direction}}"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
{% trans 'No data available.' %}
|
||||
{% endif %}
|
@ -1,146 +1,142 @@
|
||||
{% load i18n %}
|
||||
{% load url from future%}
|
||||
|
||||
|
||||
<div class="nodes row">
|
||||
<div class="col-xs-4">
|
||||
<div class="widget">
|
||||
<h3>{% trans 'Hardware Inventory' %}</h3>
|
||||
<div class="widget-info">
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__all">
|
||||
<span class="info">{{ nodes_all_count }} {% trans 'nodes' %}</span>
|
||||
</a>
|
||||
</div>
|
||||
<p>
|
||||
{{ cpus }} {% trans 'CPUs' %} | {{ memory_gb }} {% trans 'GB RAM' %} | {{ local_gb }} {% trans 'GB HDD' %}
|
||||
</p>
|
||||
<h3>{% trans 'Hardware Inventory' %}</h3>
|
||||
<hr>
|
||||
<div class="widget-info pull-left">
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__all">
|
||||
<span class="info">{{ nodes_all_count }}</span>
|
||||
<p>{% trans 'Nodes' %}</p>
|
||||
</a>
|
||||
</div>
|
||||
<div class="widget">
|
||||
<h3>{% trans 'Nodes Status' %}</h3>
|
||||
<div class="d3_pie_chart_distribution" data-used="{{ nodes_status_data }}"></div>
|
||||
</div>
|
||||
<div class="widget">
|
||||
<h3>{% trans 'Power Status' %}</h3>
|
||||
<div class="d3_pie_chart_distribution" data-used="Running={{ nodes_up_count }}|Stopped={{ nodes_down_count }}"></div>
|
||||
<div>
|
||||
<p>{{ cpus }} {% trans 'CPU cores' %}</p>
|
||||
<p>{{ memory_gb|floatformat:"0" }} {% trans 'GB of memory' %}</p>
|
||||
<p>{{ local_gb|floatformat:"0" }} {% trans 'GB of storage' %}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8">
|
||||
<div class="nodes row">
|
||||
<div class="col-xs-12">
|
||||
<h3>{% trans "Provisioned nodes" %}</h3>
|
||||
<div class="widget-info">
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__provisioned">
|
||||
<span class="info">{{ nodes_provisioned_count }} {% trans 'provisioned nodes' %}</span>
|
||||
</a>
|
||||
</div>
|
||||
{% if nodes_provisioning_count %}
|
||||
<div class="widget-info">
|
||||
<i class="fa fa-spinner fa-spin text-info"></i><a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__registered">
|
||||
{% blocktrans count nodes_provisioning_count as counter %}
|
||||
{{ counter }} node
|
||||
{% plural %}
|
||||
{{ counter }} nodes
|
||||
{% endblocktrans %}
|
||||
</a>
|
||||
{% blocktrans count nodes_provisioning_count as counter %}
|
||||
is being provisioned
|
||||
{% plural %}
|
||||
are being provisioned
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if nodes_deleting_count %}
|
||||
<div class="widget-info">
|
||||
<i class="fa fa-spinner fa-spin text-info"></i><a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__registered">
|
||||
{% blocktrans count nodes_deleting_count as counter %}
|
||||
{{ counter }} node
|
||||
{% plural %}
|
||||
{{ counter }} nodes
|
||||
{% endblocktrans %}
|
||||
</a>
|
||||
{% blocktrans count nodes_deleting_count as counter %}
|
||||
is being deleted
|
||||
{% plural %}
|
||||
are being deleted
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if nodes_error_count %}
|
||||
<div class="widget-info">
|
||||
<i class="fa fa-exclamation-circle text-info"></i><a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__registered">
|
||||
{% blocktrans count nodes_error_count as counter %}
|
||||
{{ counter }} node
|
||||
{% plural %}
|
||||
{{ counter }} nodes
|
||||
{% endblocktrans %}
|
||||
</a>
|
||||
{% blocktrans count nodes_error_count as counter %}
|
||||
{{ counter }} failed
|
||||
{% plural %}
|
||||
{{ counter }} failed
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% url 'horizon:infrastructure:nodes:nodes_performance' as node_perf_url %}
|
||||
{% include "infrastructure/_performance_chart_box.html" with meter_conf=meter_conf node_perf_url=node_perf_url col_size=4 %}
|
||||
{% if nodes_on_discovery_count or nodes_discovered_count or nodes_discovery_failed_count %}
|
||||
<div class="nodes row">
|
||||
<div class="col-xs-12">
|
||||
<h3>{% trans "Nodes Discovery" %}</h3>
|
||||
{% if nodes_discovered_count %}
|
||||
<div class="widget-info">
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__maintenance">
|
||||
<span class="info">
|
||||
{% blocktrans count nodes_discovered_count as counter %}
|
||||
{{ counter }} discovered node
|
||||
{% plural %}
|
||||
{{ counter }} discovered nodes
|
||||
{% endblocktrans %}
|
||||
</span>
|
||||
</a>({% blocktrans count nodes_discovered_count as counter %}
|
||||
{{ counter }} waiting for activation
|
||||
{% plural %}
|
||||
{{ counter }} waiting for activation
|
||||
{% endblocktrans %})
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if nodes_on_discovery_count %}
|
||||
<div class="widget-info">
|
||||
<i class="fa fa-spinner fa-spin text-info"></i><a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__maintenance">
|
||||
{% blocktrans count nodes_on_discovery_count as counter %}
|
||||
{{ counter }} node
|
||||
{% plural %}
|
||||
{{ counter }} nodes
|
||||
{% endblocktrans %}
|
||||
</a>
|
||||
{% blocktrans count nodes_on_discovery_count as counter %}
|
||||
is being discovered
|
||||
{% plural %}
|
||||
are being discovered
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if nodes_discovery_failed_count %}
|
||||
<div class="widget-info">
|
||||
<i class="fa fa-exclamation-circle text-danger"></i><a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__maintenance">
|
||||
{% blocktrans count nodes_discovery_failed_count as counter %}
|
||||
{{ counter }} node
|
||||
{% plural %}
|
||||
{{ counter }} nodes
|
||||
{% endblocktrans %}
|
||||
</a>
|
||||
{% blocktrans count nodes_discovery_failed_count as counter %}
|
||||
discovery failed
|
||||
{% plural %}
|
||||
discovery failed
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-xs-4">
|
||||
<h3>{% trans 'Nodes Status' %}</h3>
|
||||
<hr>
|
||||
<div class="d3_pie_chart_distribution" data-used="{{ nodes_status_data }}"></div>
|
||||
</div>
|
||||
<div class="col-xs-4">
|
||||
<h3>{% trans 'Power Status' %}</h3>
|
||||
<hr>
|
||||
<div class="d3_pie_chart_distribution" data-used="Running={{ nodes_up_count }}|Stopped={{ nodes_down_count }}"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>{% trans "Provisioned nodes" %}</h3>
|
||||
<hr>
|
||||
<div class="nodes row">
|
||||
<div class="col-xs-3">
|
||||
<div class="widget-info pull-left">
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__provisioned">
|
||||
<span class="info">{{ nodes_provisioned_count }}</span>
|
||||
<p>{% trans 'Provisioned' %}</p><p>{% trans 'Nodes' %}</p>
|
||||
</a>
|
||||
{% if nodes_provisioning_count %}
|
||||
<div class="widget-info">
|
||||
<i class="fa fa-spinner fa-spin text-info"></i>
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__all">
|
||||
{% blocktrans count nodes_provisioning_count as counter %}
|
||||
{{ counter }} node
|
||||
{% plural %}
|
||||
{{ counter }} nodes
|
||||
{% endblocktrans %}
|
||||
</a>
|
||||
{% blocktrans count nodes_provisioning_count as counter %}
|
||||
is being provisioned
|
||||
{% plural %}
|
||||
are being provisioned
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if nodes_deleting_count %}
|
||||
<div class="widget-info">
|
||||
<i class="fa fa-spinner fa-spin text-info"></i>
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__all">
|
||||
{% blocktrans count nodes_deleting_count as counter %}
|
||||
{{ counter }} node
|
||||
{% plural %}
|
||||
{{ counter }} nodes
|
||||
{% endblocktrans %}
|
||||
</a>
|
||||
{% blocktrans count nodes_deleting_count as counter %}
|
||||
is being deleted
|
||||
{% plural %}
|
||||
are being deleted
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if nodes_error_count %}
|
||||
<div class="widget-info">
|
||||
<i class="fa fa-exclamation-circle text-info"></i>
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__all">
|
||||
{% blocktrans count nodes_error_count as counter %}
|
||||
{{ counter }} node
|
||||
{% plural %}
|
||||
{{ counter }} nodes
|
||||
{% endblocktrans %}
|
||||
</a>
|
||||
{% trans 'failed' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{% url 'horizon:infrastructure:nodes:nodes_performance' as node_perf_url %}
|
||||
{% include "infrastructure/_performance_chart_box.html" with meter_conf=meter_conf node_perf_url=node_perf_url col_size=2 %}
|
||||
</div>
|
||||
</div>
|
||||
{% include "infrastructure/_top_5_box.html" %}
|
||||
{% if nodes_on_discovery_count or nodes_discovered_count or nodes_discovery_failed_count %}
|
||||
<h3>{% trans "Nodes Discovery" %}</h3>
|
||||
<hr>
|
||||
<div class="nodes row">
|
||||
<div class="col-xs-3">
|
||||
<div class="widget-info pull-left">
|
||||
{% if nodes_discovered_count %}
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__maintenance">
|
||||
<span class="info">{{ nodes_discovered_count }}</span>
|
||||
<p>{% trans 'Discovered' %}</p><p>{% trans 'Nodes' %}</p>
|
||||
</a>
|
||||
({{ nodes_discovered_count }} {% trans 'waiting for activation' %})
|
||||
{% endif %}
|
||||
{% if nodes_on_discovery_count %}
|
||||
<div class="widget-info">
|
||||
<i class="fa fa-spinner fa-spin text-info"></i>
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__maintenance">
|
||||
{% blocktrans count nodes_on_discovery_count as counter %}
|
||||
{{ counter }} node
|
||||
{% plural %}
|
||||
{{ counter }} nodes
|
||||
{% endblocktrans %}
|
||||
</a>
|
||||
{% blocktrans count nodes_on_discovery_count as counter %}
|
||||
is being discovered
|
||||
{% plural %}
|
||||
are being discovered
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if nodes_discovery_failed_count %}
|
||||
<div class="widget-info">
|
||||
<i class="fa fa-exclamation-circle text-danger"></i>
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__maintenance">
|
||||
{% blocktrans count nodes_discovery_failed_count as counter %}
|
||||
{{ counter }} node
|
||||
{% plural %}
|
||||
{{ counter }} nodes
|
||||
{% endblocktrans %}
|
||||
</a>
|
||||
{% trans 'discovery failed' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -60,6 +60,10 @@ LABELS = {
|
||||
'hardware.network.ip.outgoing.datagrams': _("IP out requests"),
|
||||
'hardware.network.ip.incoming.datagrams': _("IP in requests"),
|
||||
'hardware.memory.swap.util': _("Swap utilization"),
|
||||
'hardware.ipmi.fan': _("Fan Speed"),
|
||||
'hardware.ipmi.voltage': _("Votage"),
|
||||
'hardware.ipmi.temperature': _("Temperature"),
|
||||
'hardware.ipmi.current': _("Current")
|
||||
}
|
||||
|
||||
|
||||
@ -116,6 +120,18 @@ def get_meter_name(meter):
|
||||
return meter.replace('.', '_')
|
||||
|
||||
|
||||
def get_meter_list_and_unit(request, meter):
|
||||
try:
|
||||
meter_list = [m for m in ceilometer.meter_list(request)
|
||||
if m.name == meter]
|
||||
unit = meter_list[0].unit
|
||||
except Exception:
|
||||
meter_list = []
|
||||
unit = ''
|
||||
|
||||
return meter_list, unit
|
||||
|
||||
|
||||
def get_meters(meters):
|
||||
return [(m, get_meter_name(m)) for m in meters]
|
||||
|
||||
@ -165,14 +181,7 @@ def get_nodes_stats(request, node_uuid, instance_uuid, meter,
|
||||
date_options=None, date_from=None, date_to=None,
|
||||
stats_attr=None, barchart=None, group_by=None):
|
||||
series = []
|
||||
|
||||
try:
|
||||
meter_list = [m for m in ceilometer.meter_list(request)
|
||||
if m.name == meter]
|
||||
unit = meter_list[0].unit
|
||||
except Exception:
|
||||
meter_list = []
|
||||
unit = ''
|
||||
meter_list, unit = get_meter_list_and_unit(request, meter)
|
||||
|
||||
if instance_uuid:
|
||||
if 'ipmi' in meter:
|
||||
@ -252,3 +261,34 @@ def get_nodes_stats(request, node_uuid, instance_uuid, meter,
|
||||
date_to)
|
||||
|
||||
return json_output
|
||||
|
||||
|
||||
def get_top_5(request, meter):
|
||||
ceilometer_usage = ceilometer.CeilometerUsage(request)
|
||||
meter_list, unit = get_meter_list_and_unit(request, meter)
|
||||
top_5 = {'unit': unit, 'label': LABELS.get(meter, meter)}
|
||||
data = []
|
||||
|
||||
for m in meter_list:
|
||||
query = [{'field': 'resource_id', 'op': 'eq', 'value': m.resource_id}]
|
||||
resource = ceilometer_usage.resources_with_statistics(query, [m.name],
|
||||
period=600)[0]
|
||||
node_uuid = resource.metadata['node']
|
||||
old_value, value = resource.get_meter(get_meter_name(m.name))[-2:]
|
||||
old_value, value = old_value.max, value.max
|
||||
|
||||
if value > old_value:
|
||||
direction = 'up'
|
||||
elif value < old_value:
|
||||
direction = 'down'
|
||||
else:
|
||||
direction = None
|
||||
|
||||
data.append({
|
||||
'node_uuid': node_uuid,
|
||||
'value': value,
|
||||
'direction': direction
|
||||
})
|
||||
|
||||
top_5['data'] = sorted(data, key=lambda d: d['value'], reverse=True)[:5]
|
||||
return top_5
|
||||
|
Loading…
x
Reference in New Issue
Block a user