Adding provision state of Ironic
Adding provision state and extra to API of Nodes. Showing provision state stats in overview page. Change-Id: Ic49f5e34c01ead0f7fc43cf1c073e1463105125c
This commit is contained in:
parent
4a8736cf07
commit
a0f9ee338f
@ -32,6 +32,7 @@ from tuskar_ui.utils import utils
|
||||
ERROR_STATES = set(['deploy failed', 'error'])
|
||||
POWER_ON_STATES = set(['on', 'power on'])
|
||||
|
||||
# TODO(tzumainn) this states doesn't seems to be correct, please fix this
|
||||
# overall state of the node; not power states
|
||||
DISCOVERING_STATE = 'discovering'
|
||||
DISCOVERED_STATE = 'discovered'
|
||||
@ -39,6 +40,13 @@ PROVISIONED_STATE = 'provisioned'
|
||||
PROVISIONING_FAILED_STATE = 'provisioning failed'
|
||||
PROVISIONING_STATE = 'provisioning'
|
||||
FREE_STATE = 'free'
|
||||
# TODO(tzumain) the below should be correct
|
||||
PROVISION_STATE_FREE = ['deleted', None]
|
||||
PROVISION_STATE_PROVISIONED = ['active']
|
||||
PROVISION_STATE_PROVISIONING = [
|
||||
'deploying', 'wait call-back', 'rebuild', 'deploy complete']
|
||||
PROVISION_STATE_DELETING = ['deleting']
|
||||
PROVISION_STATE_ERROR = ['error', 'deploy failed']
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -490,6 +498,16 @@ class BareMetalNode(base.APIResourceWrapper):
|
||||
return [interface["address"] for interface in
|
||||
self.interfaces]
|
||||
|
||||
@cached_property
|
||||
def extra(self):
|
||||
"""Ironic compatibility parameter."""
|
||||
return {}
|
||||
|
||||
@cached_property
|
||||
def provision_state(self):
|
||||
"""Ironic compatibility parameter."""
|
||||
return None
|
||||
|
||||
|
||||
class NodeClient(object):
|
||||
|
||||
@ -507,7 +525,8 @@ class NodeClient(object):
|
||||
class Node(base.APIResourceWrapper):
|
||||
_attrs = ('id', 'uuid', 'instance_uuid', 'driver', 'driver_info', 'state',
|
||||
'power_state', 'target_power_state', 'addresses', 'maintenance',
|
||||
'cpus', 'memory_mb', 'local_gb', 'cpu_arch')
|
||||
'cpus', 'memory_mb', 'local_gb', 'cpu_arch', 'extra',
|
||||
'provision_state')
|
||||
|
||||
def __init__(self, apiresource, request=None, **kwargs):
|
||||
"""Initialize a Node
|
||||
|
@ -40,23 +40,31 @@ class OverviewTab(tabs.Tab):
|
||||
node.memory_mb)
|
||||
local_gb = sum(int(node.local_gb) for node in nodes if node.local_gb)
|
||||
|
||||
nodes_provisioned = api.node.Node.list(request, associated=True)
|
||||
nodes_free = api.node.Node.list(request, associated=False)
|
||||
nodes_all_count = (utils.length(nodes_provisioned) +
|
||||
utils.length(nodes_free))
|
||||
nodes_provisioned = set(utils.filter_items(
|
||||
nodes, provision_state__in=api.node.PROVISION_STATE_PROVISIONED))
|
||||
nodes_free = set(utils.filter_items(
|
||||
nodes, provision_state__in=api.node.PROVISION_STATE_FREE))
|
||||
nodes_deleting = set(utils.filter_items(
|
||||
nodes, provision_state__in=api.node.PROVISION_STATE_DELETING))
|
||||
nodes_error = set(utils.filter_items(
|
||||
nodes, provision_state__in=api.node.PROVISION_STATE_ERROR))
|
||||
|
||||
nodes_provisioned_maintenance = list(utils.filter_items(
|
||||
nodes_provisioned_maintenance = set(utils.filter_items(
|
||||
nodes_provisioned, maintenance=True))
|
||||
nodes_provisioned_not_maintenance = list(
|
||||
set(nodes_provisioned) - set(nodes_provisioned_maintenance))
|
||||
nodes_provisioned_not_maintenance = (
|
||||
nodes_provisioned - nodes_provisioned_maintenance)
|
||||
|
||||
nodes_free_maintenance = list(utils.filter_items(
|
||||
nodes_provisioning = set(utils.filter_items(
|
||||
nodes,
|
||||
provision_state__in=api.node.PROVISION_STATE_PROVISIONING))
|
||||
|
||||
nodes_free_maintenance = set(utils.filter_items(
|
||||
nodes_free, maintenance=True))
|
||||
nodes_free_not_maintenance = list(
|
||||
set(nodes_free) - set(nodes_free_maintenance))
|
||||
nodes_free_not_maintenance = (
|
||||
nodes_free - nodes_free_maintenance)
|
||||
|
||||
nodes_maintenance = (
|
||||
nodes_provisioned_maintenance + nodes_free_maintenance)
|
||||
nodes_provisioned_maintenance | nodes_free_maintenance)
|
||||
|
||||
nodes_provisioned_down = utils.filter_items(
|
||||
nodes_provisioned, power_state__not_in=api.node.POWER_ON_STATES)
|
||||
@ -67,18 +75,42 @@ class OverviewTab(tabs.Tab):
|
||||
nodes_up = utils.filter_items(
|
||||
nodes, power_state__in=api.node.POWER_ON_STATES)
|
||||
|
||||
nodes_free_count = len(nodes_free_not_maintenance)
|
||||
nodes_provisioned_count = len(
|
||||
nodes_provisioned_not_maintenance)
|
||||
nodes_provisioning_count = len(nodes_provisioning)
|
||||
nodes_maintenance_count = len(nodes_maintenance)
|
||||
nodes_deleting_count = len(nodes_deleting)
|
||||
nodes_error_count = len(nodes_error)
|
||||
|
||||
context = {
|
||||
'cpus': cpus,
|
||||
'memory_gb': memory_mb / 1024.0,
|
||||
'local_gb': local_gb,
|
||||
'nodes_up_count': utils.length(nodes_up),
|
||||
'nodes_down_count': utils.length(nodes_down),
|
||||
'nodes_provisioned_count': utils.length(
|
||||
nodes_provisioned_not_maintenance),
|
||||
'nodes_free_count': utils.length(nodes_free_not_maintenance),
|
||||
'nodes_maintenance_count': utils.length(nodes_maintenance),
|
||||
'nodes_all_count': nodes_all_count
|
||||
'nodes_provisioned_count': nodes_provisioned_count,
|
||||
'nodes_provisioning_count': nodes_provisioning_count,
|
||||
'nodes_free_count': nodes_free_count,
|
||||
'nodes_deleting_count': nodes_deleting_count,
|
||||
'nodes_error_count': nodes_error_count,
|
||||
'nodes_maintenance_count': nodes_maintenance_count,
|
||||
'nodes_all_count': len(nodes),
|
||||
'nodes_status_data':
|
||||
'Provisioned={0}|Free={1}|Maintenance={2}'.format(
|
||||
nodes_provisioned_count, nodes_free_count,
|
||||
nodes_maintenance_count)
|
||||
}
|
||||
# additional node status pie chart data, showing only if it appears
|
||||
if nodes_provisioning_count:
|
||||
context['nodes_status_data'] += '|Provisioning={0}'.format(
|
||||
nodes_provisioning_count)
|
||||
if nodes_deleting_count:
|
||||
context['nodes_status_data'] += '|Deleting={0}'.format(
|
||||
nodes_deleting_count)
|
||||
if nodes_error_count:
|
||||
context['nodes_status_data'] += '|Error={0}'.format(
|
||||
nodes_error_count)
|
||||
|
||||
if api_base.is_service_enabled(self.request, 'metering'):
|
||||
context['meter_conf'] = (
|
||||
|
@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<div class="widget">
|
||||
<h3>{% trans 'Nodes Status' %}</h3>
|
||||
<div class="d3_pie_chart_distribution" data-used="Provisioned={{ nodes_provisioned_count }}|Free={{ nodes_free_count }}|Maintenance={{ nodes_maintenance_count }}"></div>
|
||||
<div class="d3_pie_chart_distribution" data-used="{{ nodes_status_data }}"></div>
|
||||
</div>
|
||||
<div class="widget">
|
||||
<h3>{% trans 'Power Status' %}</h3>
|
||||
@ -33,6 +33,54 @@
|
||||
<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 %}
|
||||
|
@ -54,8 +54,7 @@ class NodesTests(test.BaseAdminViewTests, helpers.APITestCase):
|
||||
'list.return_value': [],
|
||||
}) as mock:
|
||||
res = self.client.get(INDEX_URL)
|
||||
# FIXME(lsmola) optimize, this should call 1 time, what the hell
|
||||
self.assertEqual(mock.list.call_count, 7)
|
||||
self.assertEqual(mock.list.call_count, 5)
|
||||
|
||||
self.assertTemplateUsed(
|
||||
res, 'infrastructure/nodes/index.html')
|
||||
@ -76,8 +75,7 @@ class NodesTests(test.BaseAdminViewTests, helpers.APITestCase):
|
||||
'list.return_value': nodes,
|
||||
}) as Node:
|
||||
res = self.client.get(INDEX_URL + '?tab=nodes__' + tab_name)
|
||||
# FIXME(lsmola) horrible count, optimize
|
||||
self.assertEqual(Node.list.call_count, 7)
|
||||
self.assertEqual(Node.list.call_count, 5)
|
||||
|
||||
self.assertTemplateUsed(
|
||||
res, 'infrastructure/nodes/index.html')
|
||||
@ -104,7 +102,7 @@ class NodesTests(test.BaseAdminViewTests, helpers.APITestCase):
|
||||
'list.side_effect': self._raise_tuskar_exception,
|
||||
}) as mock:
|
||||
res = self.client.get(INDEX_URL + '?tab=nodes__' + tab_name)
|
||||
self.assertEqual(mock.list.call_count, 4)
|
||||
self.assertEqual(mock.list.call_count, 2)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
|
@ -137,6 +137,7 @@ def data(TEST):
|
||||
'provision_state': 'active',
|
||||
'maintenance': None,
|
||||
'newly_discovered': None,
|
||||
'provision_state': 'active',
|
||||
'extra': {}
|
||||
})
|
||||
node_2 = node.Node(
|
||||
@ -162,6 +163,7 @@ def data(TEST):
|
||||
'provision_state': 'active',
|
||||
'maintenance': None,
|
||||
'newly_discovered': None,
|
||||
'provision_state': 'active',
|
||||
'extra': {}
|
||||
})
|
||||
node_3 = node.Node(
|
||||
@ -187,6 +189,7 @@ def data(TEST):
|
||||
'provision_state': 'active',
|
||||
'maintenance': None,
|
||||
'newly_discovered': None,
|
||||
'provision_state': 'deploying',
|
||||
'extra': {}
|
||||
})
|
||||
node_4 = node.Node(
|
||||
@ -212,6 +215,7 @@ def data(TEST):
|
||||
'provision_state': 'active',
|
||||
'maintenance': None,
|
||||
'newly_discovered': None,
|
||||
'provision_state': 'deploying',
|
||||
'extra': {}
|
||||
})
|
||||
node_5 = node.Node(
|
||||
@ -237,6 +241,7 @@ def data(TEST):
|
||||
'provision_state': 'error',
|
||||
'maintenance': None,
|
||||
'newly_discovered': None,
|
||||
'provision_state': 'deploying',
|
||||
'extra': {}
|
||||
})
|
||||
node_6 = node.Node(
|
||||
@ -262,6 +267,7 @@ def data(TEST):
|
||||
'provision_state': 'active',
|
||||
'maintenance': None,
|
||||
'newly_discovered': None,
|
||||
'provision_state': 'active',
|
||||
'extra': {}
|
||||
})
|
||||
node_7 = node.Node(
|
||||
@ -286,6 +292,7 @@ def data(TEST):
|
||||
'target_power_state': 'on',
|
||||
'maintenance': True,
|
||||
'newly_discovered': None,
|
||||
'provision_state': 'deploying',
|
||||
'extra': {}
|
||||
})
|
||||
node_8 = node.Node(
|
||||
@ -310,6 +317,7 @@ def data(TEST):
|
||||
'target_power_state': 'on',
|
||||
'maintenance': True,
|
||||
'newly_discovered': True,
|
||||
'provision_state': 'active',
|
||||
'extra': {}
|
||||
})
|
||||
node_9 = node.Node(
|
||||
@ -334,6 +342,7 @@ def data(TEST):
|
||||
'target_power_state': 'on',
|
||||
'maintenance': True,
|
||||
'newly_discovered': True,
|
||||
'provision_state': 'active',
|
||||
'extra': {}
|
||||
})
|
||||
TEST.ironicclient_nodes.add(node_1, node_2, node_3, node_4, node_5, node_6,
|
||||
|
Loading…
Reference in New Issue
Block a user