From 172ee4fa988dd3964bd6859cb67510f67479647a Mon Sep 17 00:00:00 2001 From: Ana Krivokapic Date: Tue, 3 Mar 2015 14:05:39 +0100 Subject: [PATCH] Add IPMI metrics to node overview page Change-Id: Ibe39b7ba17004d9f6a2ec41eda7942b7ec487971 --- tuskar_ui/infrastructure/nodes/tabs.py | 12 + .../scss/_individual_pages.scss | 4 +- .../_performance_chart_box.html | 4 +- .../templates/infrastructure/_top_5_box.html | 8 + .../infrastructure/_top_5_chart.html | 29 ++ .../infrastructure/nodes/_overview.html | 266 +++++++++--------- tuskar_ui/utils/metering.py | 56 +++- 7 files changed, 233 insertions(+), 146 deletions(-) create mode 100644 tuskar_ui/infrastructure/templates/infrastructure/_top_5_box.html create mode 100644 tuskar_ui/infrastructure/templates/infrastructure/_top_5_chart.html diff --git a/tuskar_ui/infrastructure/nodes/tabs.py b/tuskar_ui/infrastructure/nodes/tabs.py index 1931751d5..1c8def1fc 100644 --- a/tuskar_ui/infrastructure/nodes/tabs.py +++ b/tuskar_ui/infrastructure/nodes/tabs.py @@ -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 diff --git a/tuskar_ui/infrastructure/static/infrastructure/scss/_individual_pages.scss b/tuskar_ui/infrastructure/static/infrastructure/scss/_individual_pages.scss index b94e132f1..33ada733e 100644 --- a/tuskar_ui/infrastructure/static/infrastructure/scss/_individual_pages.scss +++ b/tuskar_ui/infrastructure/static/infrastructure/scss/_individual_pages.scss @@ -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%; } } diff --git a/tuskar_ui/infrastructure/templates/infrastructure/_performance_chart_box.html b/tuskar_ui/infrastructure/templates/infrastructure/_performance_chart_box.html index 7f1fe6237..6c27e91e7 100644 --- a/tuskar_ui/infrastructure/templates/infrastructure/_performance_chart_box.html +++ b/tuskar_ui/infrastructure/templates/infrastructure/_performance_chart_box.html @@ -3,7 +3,7 @@ {% if meter_conf %}
-
+
@@ -81,7 +81,7 @@
{% for meter_label, url_part, y_max in meter_conf %} -
+
{% include "infrastructure/_performance_chart.html" with label=meter_label y_max=y_max url=node_perf_url|add:"?"|add:url_part only %}
{% endfor %} diff --git a/tuskar_ui/infrastructure/templates/infrastructure/_top_5_box.html b/tuskar_ui/infrastructure/templates/infrastructure/_top_5_box.html new file mode 100644 index 000000000..1ac664d79 --- /dev/null +++ b/tuskar_ui/infrastructure/templates/infrastructure/_top_5_box.html @@ -0,0 +1,8 @@ +
+
{% include "infrastructure/_top_5_chart.html" with top_5=top_5.fan%}
+
{% include "infrastructure/_top_5_chart.html" with top_5=top_5.voltage %}
+
{% include "infrastructure/_top_5_chart.html" with top_5=top_5.temperature%}
+
+
+
{% include "infrastructure/_top_5_chart.html" with top_5=top_5.current %}
+
diff --git a/tuskar_ui/infrastructure/templates/infrastructure/_top_5_chart.html b/tuskar_ui/infrastructure/templates/infrastructure/_top_5_chart.html new file mode 100644 index 000000000..76136378f --- /dev/null +++ b/tuskar_ui/infrastructure/templates/infrastructure/_top_5_chart.html @@ -0,0 +1,29 @@ +{% load i18n %} +{% load chart_helpers %} + +

+ {% trans 'Top 5 Nodes' %} ({{ top_5.label }}): +

+{% if top_5.data %} + + {% for d in top_5.data %} + + + + + + {% endfor %} +
+ + {{ d.node_uuid|truncatechars:6 }} + + + {{ d.value}} {{ top_5.unit }} + + {%if d.direction %} + + {% endif %} +
+{% else %} +{% trans 'No data available.' %} +{% endif %} diff --git a/tuskar_ui/infrastructure/templates/infrastructure/nodes/_overview.html b/tuskar_ui/infrastructure/templates/infrastructure/nodes/_overview.html index eca24d97b..377980e2e 100644 --- a/tuskar_ui/infrastructure/templates/infrastructure/nodes/_overview.html +++ b/tuskar_ui/infrastructure/templates/infrastructure/nodes/_overview.html @@ -1,146 +1,142 @@ {% load i18n %} {% load url from future%} -
-
-

{% trans 'Hardware Inventory' %}

- -

- {{ cpus }} {% trans 'CPUs' %} | {{ memory_gb }} {% trans 'GB RAM' %} | {{ local_gb }} {% trans 'GB HDD' %} -

+

{% trans 'Hardware Inventory' %}

+
+ -
-

{% trans 'Nodes Status' %}

-
-
-
-

{% trans 'Power Status' %}

-
+
+

{{ cpus }} {% trans 'CPU cores' %}

+

{{ memory_gb|floatformat:"0" }} {% trans 'GB of memory' %}

+

{{ local_gb|floatformat:"0" }} {% trans 'GB of storage' %}

-
-
-
-

{% trans "Provisioned nodes" %}

- - {% if nodes_provisioning_count %} -
- - {% blocktrans count nodes_provisioning_count as counter %} - {{ counter }} node - {% plural %} - {{ counter }} nodes - {% endblocktrans %} - - {% blocktrans count nodes_provisioning_count as counter %} - is being provisioned - {% plural %} - are being provisioned - {% endblocktrans %} -
- {% endif %} - {% if nodes_deleting_count %} -
- - {% blocktrans count nodes_deleting_count as counter %} - {{ counter }} node - {% plural %} - {{ counter }} nodes - {% endblocktrans %} - - {% blocktrans count nodes_deleting_count as counter %} - is being deleted - {% plural %} - are being deleted - {% endblocktrans %} -
- {% endif %} - {% if nodes_error_count %} -
- - {% blocktrans count nodes_error_count as counter %} - {{ counter }} node - {% plural %} - {{ counter }} nodes - {% endblocktrans %} - - {% blocktrans count nodes_error_count as counter %} - {{ counter }} failed - {% plural %} - {{ counter }} failed - {% endblocktrans %} -
- {% endif %} -
-
- {% 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 %} -
-
-

{% trans "Nodes Discovery" %}

- {% if nodes_discovered_count %} -
- - - {% blocktrans count nodes_discovered_count as counter %} - {{ counter }} discovered node - {% plural %} - {{ counter }} discovered nodes - {% endblocktrans %} - - ({% blocktrans count nodes_discovered_count as counter %} - {{ counter }} waiting for activation - {% plural %} - {{ counter }} waiting for activation - {% endblocktrans %}) -
- {% endif %} - {% if nodes_on_discovery_count %} -
- - {% blocktrans count nodes_on_discovery_count as counter %} - {{ counter }} node - {% plural %} - {{ counter }} nodes - {% endblocktrans %} - - {% blocktrans count nodes_on_discovery_count as counter %} - is being discovered - {% plural %} - are being discovered - {% endblocktrans %} -
- {% endif %} - {% if nodes_discovery_failed_count %} -
- - {% blocktrans count nodes_discovery_failed_count as counter %} - {{ counter }} node - {% plural %} - {{ counter }} nodes - {% endblocktrans %} - - {% blocktrans count nodes_discovery_failed_count as counter %} - discovery failed - {% plural %} - discovery failed - {% endblocktrans %} -
- {% endif %} -
-
- {% endif %} +
+

{% trans 'Nodes Status' %}

+
+
+
+
+

{% trans 'Power Status' %}

+
+
+

{% trans "Provisioned nodes" %}

+
+
+
+
+ + {{ nodes_provisioned_count }} +

{% trans 'Provisioned' %}

{% trans 'Nodes' %}

+
+ {% if nodes_provisioning_count %} +
+ + + {% blocktrans count nodes_provisioning_count as counter %} + {{ counter }} node + {% plural %} + {{ counter }} nodes + {% endblocktrans %} + + {% blocktrans count nodes_provisioning_count as counter %} + is being provisioned + {% plural %} + are being provisioned + {% endblocktrans %} +
+ {% endif %} + {% if nodes_deleting_count %} +
+ + + {% blocktrans count nodes_deleting_count as counter %} + {{ counter }} node + {% plural %} + {{ counter }} nodes + {% endblocktrans %} + + {% blocktrans count nodes_deleting_count as counter %} + is being deleted + {% plural %} + are being deleted + {% endblocktrans %} +
+ {% endif %} + {% if nodes_error_count %} + + {% endif %} +
+
+
+ {% 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 %} +
+
+{% include "infrastructure/_top_5_box.html" %} +{% if nodes_on_discovery_count or nodes_discovered_count or nodes_discovery_failed_count %} +

{% trans "Nodes Discovery" %}

+
+
+
+
+ {% if nodes_discovered_count %} + + {{ nodes_discovered_count }} +

{% trans 'Discovered' %}

{% trans 'Nodes' %}

+
+ ({{ nodes_discovered_count }} {% trans 'waiting for activation' %}) + {% endif %} + {% if nodes_on_discovery_count %} +
+ + + {% blocktrans count nodes_on_discovery_count as counter %} + {{ counter }} node + {% plural %} + {{ counter }} nodes + {% endblocktrans %} + + {% blocktrans count nodes_on_discovery_count as counter %} + is being discovered + {% plural %} + are being discovered + {% endblocktrans %} +
+ {% endif %} + {% if nodes_discovery_failed_count %} + + {% endif %} +
+
+
+{% endif %} diff --git a/tuskar_ui/utils/metering.py b/tuskar_ui/utils/metering.py index 0dae4da3f..1374a9735 100644 --- a/tuskar_ui/utils/metering.py +++ b/tuskar_ui/utils/metering.py @@ -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