diff --git a/tuskar_ui/api/node.py b/tuskar_ui/api/node.py index 1caa376d4..2e445ee4c 100644 --- a/tuskar_ui/api/node.py +++ b/tuskar_ui/api/node.py @@ -589,38 +589,3 @@ class Node(base.APIResourceWrapper): if self.instance_uuid: return _("Provisioned") return _("Free") - - -def filter_nodes(nodes, healthy=None, power_state=None): - """Filters the list of Nodes and returns the filtered list. - - :param nodes: list of tuskar_ui.api.node.Node objects to filter - :type nodes: list - :param healthy: retrieve all Nodes (healthy=None), - only the healthly ones (healthy=True), - or only those in an error state (healthy=False) - :type healthy: None or bool - :param power_state: retrieve all Nodes (power_state=None), - only those that are running (power_state=True), - or only those that are stopped (power_state=False) - :type power_state: None or bool - :return: list of filtered tuskar_ui.api.node.Node objects - :rtype: list - """ - if healthy is not None: - if healthy: - nodes = [node for node in nodes - if node.power_state not in ERROR_STATES] - else: - nodes = [node for node in nodes - if node.power_state in ERROR_STATES] - - if power_state is not None: - if power_state: - nodes = [node for node in nodes - if node.power_state in POWER_ON_STATES] - else: - nodes = [node for node in nodes - if node.power_state not in POWER_ON_STATES] - - return nodes diff --git a/tuskar_ui/infrastructure/nodes/tabs.py b/tuskar_ui/infrastructure/nodes/tabs.py index 159026f2c..b7aeb264f 100644 --- a/tuskar_ui/infrastructure/nodes/tabs.py +++ b/tuskar_ui/infrastructure/nodes/tabs.py @@ -12,6 +12,8 @@ # License for the specific language governing permissions and limitations # under the License. +import itertools + from django.core import urlresolvers from django.utils.translation import ugettext_lazy as _ from horizon import exceptions @@ -21,6 +23,7 @@ from openstack_dashboard.api import base as api_base from tuskar_ui import api from tuskar_ui.infrastructure.nodes import tables from tuskar_ui.utils import metering as metering_utils +from tuskar_ui.utils import utils class OverviewTab(tabs.Tab): @@ -34,34 +37,26 @@ class OverviewTab(tabs.Tab): memory_mb = sum(int(node.memory_mb) for node in nodes if node.memory_mb) local_gb = sum(int(node.local_gb) for node in nodes if node.local_gb) - deployed_nodes = api.node.Node.list(request, associated=True) - free_nodes = api.node.Node.list(request, associated=False) - deployed_nodes_error = api.node.filter_nodes( - deployed_nodes, healthy=False) - deployed_nodes_down = api.node.filter_nodes( - deployed_nodes, power_state=False) - free_nodes_error = api.node.filter_nodes(free_nodes, healthy=False) - free_nodes_down = api.node.filter_nodes(free_nodes, power_state=False) - total_nodes = deployed_nodes + free_nodes - total_nodes_error = deployed_nodes_error + free_nodes_error - total_nodes_down = deployed_nodes_down + free_nodes_down - total_nodes_healthy = api.node.filter_nodes(total_nodes, healthy=True) - total_nodes_up = api.node.filter_nodes(total_nodes, power_state=True) + + nodes_provisioned = api.node.Node.list(request, associated=True) + nodes_free = api.node.Node.list(request, associated=False) + nodes_provisioned_down = utils.filter_items( + nodes_provisioned, power_state__not_in=api.node.POWER_ON_STATES) + nodes_free_down = utils.filter_items( + nodes_free, power_state__not_in=api.node.POWER_ON_STATES) + + nodes_down = itertools.chain(nodes_provisioned_down, nodes_free_down) + nodes_up = utils.filter_items( + nodes, power_state__in=api.node.POWER_ON_STATES) context = { 'cpus': cpus, 'memory_gb': memory_mb / 1024.0, 'local_gb': local_gb, - 'total_nodes_healthy': total_nodes_healthy, - 'total_nodes_up': total_nodes_up, - 'total_nodes_error': total_nodes_error, - 'total_nodes_down': total_nodes_down, - 'deployed_nodes': deployed_nodes, - 'deployed_nodes_error': deployed_nodes_error, - 'deployed_nodes_down': deployed_nodes_down, - 'free_nodes': free_nodes, - 'free_nodes_error': free_nodes_error, - 'free_nodes_down': free_nodes_down, + 'nodes_up_count': utils.length(nodes_up), + 'nodes_down_count': utils.length(nodes_down), + 'nodes_provisioned_count': utils.length(nodes_provisioned), + 'nodes_free_count': utils.length(nodes_free), } if api_base.is_service_enabled(self.request, 'metering'): @@ -99,9 +94,6 @@ class RegisteredTab(tabs.TableTab): nodes = api.node.Node.list(self.request, maintenance=False, _error_redirect=redirect) - if 'errors' in self.request.GET: - return api.node.filter_nodes(nodes, healthy=False) - if nodes: all_resources = api.heat.Resource.list_all_resources(self.request) for node in nodes: diff --git a/tuskar_ui/infrastructure/nodes/templates/nodes/_overview.html b/tuskar_ui/infrastructure/nodes/templates/nodes/_overview.html index 75553ef7f..b62dca048 100644 --- a/tuskar_ui/infrastructure/nodes/templates/nodes/_overview.html +++ b/tuskar_ui/infrastructure/nodes/templates/nodes/_overview.html @@ -24,16 +24,16 @@

{% trans 'Free Nodes' %}

-
+
@@ -42,7 +42,7 @@

{% trans 'Power Status' %}

-
+
@@ -129,7 +129,7 @@
- {{ deployed_nodes|length|default:0 }}
+ {{ nodes_provisioned_count }}
{% trans 'Provisioned' %}
{% trans 'Nodes' %}
diff --git a/tuskar_ui/test/api_tests/node_tests.py b/tuskar_ui/test/api_tests/node_tests.py index 691318ef9..af57335f9 100644 --- a/tuskar_ui/test/api_tests/node_tests.py +++ b/tuskar_ui/test/api_tests/node_tests.py @@ -141,17 +141,3 @@ class NodeAPITests(test.APITestCase): node = self.baremetalclient_nodes.first() ret_val = api.node.BareMetalNode(node).addresses self.assertEqual(2, len(ret_val)) - - def test_filter_nodes(self): - nodes = self.baremetalclient_nodes.list() - nodes = [api.node.BareMetalNode(node) for node in nodes] - num_nodes = len(nodes) - - with patch('novaclient.v1_1.contrib.baremetal.' - 'BareMetalNodeManager.list', return_value=nodes): - all_nodes = api.node.filter_nodes(nodes) - healthy_nodes = api.node.filter_nodes(nodes, healthy=True) - defective_nodes = api.node.filter_nodes(nodes, healthy=False) - self.assertEqual(len(all_nodes), num_nodes) - self.assertEqual(len(healthy_nodes), num_nodes - 1) - self.assertEqual(len(defective_nodes), 1) diff --git a/tuskar_ui/test/utils_tests.py b/tuskar_ui/test/utils_tests.py new file mode 100644 index 000000000..f53c1f6b7 --- /dev/null +++ b/tuskar_ui/test/utils_tests.py @@ -0,0 +1,34 @@ +# -*- coding: utf8 -*- +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from tuskar_ui.test import helpers as test +from tuskar_ui.utils import utils + + +class TestItem(object): + def __init__(self, index): + self.index = index + + +class UtilsTests(test.TestCase): + def test_filter_items(self): + items = [TestItem(i) for i in range(7)] + + first = utils.filter_items(items, index=0) + even = utils.filter_items(items, index__in=(0, 2, 4, 6)) + last_two = utils.filter_items(items, index__not_in=range(5)) + + self.assertEqual(utils.length(first), 1) + self.assertEqual(utils.length(even), 4) + self.assertEqual(utils.length(last_two), 2) diff --git a/tuskar_ui/utils/utils.py b/tuskar_ui/utils/utils.py index 45e074732..52f8dc6b9 100644 --- a/tuskar_ui/utils/utils.py +++ b/tuskar_ui/utils/utils.py @@ -34,3 +34,44 @@ def list_to_dict(object_list, key_attribute='id'): :rtype: dict """ return dict((getattr(o, key_attribute), o) for o in object_list) + + +def length(iterator): + """A length function for iterators + + Returns the number of items in the specified iterator. Note that this + function consumes the iterator in the process. + """ + return sum(1 for _item in iterator) + + +def filter_items(items, **kwargs): + """Filters the list of items and returns the filtered list. + + Example usage: + >>> class Item(object): + ... def __init__(self, index): + ... self.index = index + ... def __repr__(self): + ... return '' % self.index + >>> items = [Item(i) for i in range(7)] + >>> list(filter_items(items, index=1)) + [] + >>> list(filter_items(items, index__in=(1, 2, 3))) + [, , ] + >>> list(filter_items(items, index__not_in=(1, 2, 3))) + [, , , ] + """ + for item in items: + for name, value in kwargs.items(): + if name.endswith('__in'): + if getattr(item, name[:-len('__in')]) not in value: + break + elif name.endswith('__not_in'): + if getattr(item, name[:-len('__not_in')]) in value: + break + else: + if getattr(item, name) != value: + break + else: + yield item