Add IPMI metrics to node overview page

Change-Id: Ibe39b7ba17004d9f6a2ec41eda7942b7ec487971
This commit is contained in:
Ana Krivokapic 2015-03-03 14:05:39 +01:00 committed by Radomir Dopieralski
parent 10ec89b16e
commit 172ee4fa98
7 changed files with 233 additions and 146 deletions

View File

@ -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

View File

@ -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%;
}
}

View File

@ -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 %}

View File

@ -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>

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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