summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAna Krivokapic <akrivoka@redhat.com>2014-10-06 12:59:10 +0200
committerAna Krivokapic <akrivoka@redhat.com>2014-10-06 16:36:13 +0200
commitfc0a6f77bcd3a42ec17d166046127edd9f663245 (patch)
treee81c07e0cecbba13529465f96d302be2237b9553
parent493d6c06d949b4bd664c2f1f176ae0b152f7a9dd (diff)
downloadtuskar-ui-fc0a6f77bcd3a42ec17d166046127edd9f663245.tar.gz
Add a generic function for filtering API objects
Replace the filter_nodes() function with a more generic solution. We can now filter a list of generic API object, by any attribute. Change-Id: I76f8226df5123a8038220658cb340b67461024b4
-rw-r--r--tuskar_ui/api/node.py35
-rw-r--r--tuskar_ui/infrastructure/nodes/tabs.py44
-rw-r--r--tuskar_ui/infrastructure/nodes/templates/nodes/_overview.html10
-rw-r--r--tuskar_ui/test/api_tests/node_tests.py14
-rw-r--r--tuskar_ui/test/utils_tests.py34
-rw-r--r--tuskar_ui/utils/utils.py41
6 files changed, 98 insertions, 80 deletions
diff --git a/tuskar_ui/api/node.py b/tuskar_ui/api/node.py
index 1caa376d..2e445ee4 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 159026f2..b7aeb264 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 75553ef7..b62dca04 100644
--- a/tuskar_ui/infrastructure/nodes/templates/nodes/_overview.html
+++ b/tuskar_ui/infrastructure/nodes/templates/nodes/_overview.html
@@ -24,16 +24,16 @@
<div class="col-xs-4">
<div class="widget">
<h3>{% trans 'Free Nodes' %}</h3>
- <div class="d3_pie_chart_distribution" data-used="Deployed={{ deployed_nodes|length }}|Free={{ free_nodes|length }}"></div>
+ <div class="d3_pie_chart_distribution" data-used="Provisioned={{ nodes_provisioned_count }}|Free={{ nodes_free_count }}"></div>
<div class="widget-info">
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__registered">
- <span class="info">{{ free_nodes|length|default:0 }}</span>
+ <span class="info">{{ nodes_free_count }}</span>
{% trans 'Free Nodes' %}
</a>
</div>
<div class="widget-info">
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__registered">
- <span class="info">{{ deployed_nodes|length|default:0 }}</span>
+ <span class="info">{{ nodes_provisioned_count }}</span>
{% trans 'Provisioned Nodes' %}
</a>
</div>
@@ -42,7 +42,7 @@
<div class="col-xs-4">
<div class="widget">
<h2>{% trans 'Power Status' %}</h2>
- <div class="d3_pie_chart_distribution" data-used="Running={{ total_nodes_up|length }}|Stopped={{ total_nodes_down|length }}"></div>
+ <div class="d3_pie_chart_distribution" data-used="Running={{ nodes_up_count }}|Stopped={{ nodes_down_count }}"></div>
</div>
</div>
</div>
@@ -129,7 +129,7 @@
<div class="col-lg-1">
<div class="widget-info">
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__registered">
- <span class="info">{{ deployed_nodes|length|default:0 }}</span><br>
+ <span class="info">{{ nodes_provisioned_count }}</span><br>
{% trans 'Provisioned' %}<br>
{% trans 'Nodes' %}<br>
</a>
diff --git a/tuskar_ui/test/api_tests/node_tests.py b/tuskar_ui/test/api_tests/node_tests.py
index 691318ef..af57335f 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 00000000..f53c1f6b
--- /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 45e07473..52f8dc6b 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 '<Item index=%d>' % self.index
+ >>> items = [Item(i) for i in range(7)]
+ >>> list(filter_items(items, index=1))
+ [<Item index=1>]
+ >>> list(filter_items(items, index__in=(1, 2, 3)))
+ [<Item index=1>, <Item index=2>, <Item index=3>]
+ >>> list(filter_items(items, index__not_in=(1, 2, 3)))
+ [<Item index=0>, <Item index=4>, <Item index=5>, <Item index=6>]
+ """
+ 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