Re-factor nodes index tables
Tabs are now: 'All', 'Provisioned', 'Free', 'Maintenance'. Change-Id: Ia8d26c6aa4b4d7dc9ac78f25aa6ab9477b2f0781
This commit is contained in:
parent
e67223b693
commit
8a77093c01
@ -28,9 +28,18 @@ from tuskar_ui.handle_errors import handle_errors # noqa
|
||||
from tuskar_ui.utils import utils
|
||||
|
||||
|
||||
# power states
|
||||
ERROR_STATES = set(['deploy failed', 'error'])
|
||||
POWER_ON_STATES = set(['on', 'power on'])
|
||||
|
||||
# overall state of the node; not power states
|
||||
DISCOVERING_STATE = 'discovering'
|
||||
DISCOVERED_STATE = 'discovered'
|
||||
PROVISIONED_STATE = 'provisioned'
|
||||
PROVISIONING_FAILED_STATE = 'provisioning failed'
|
||||
PROVISIONING_STATE = 'provisioning'
|
||||
FREE_STATE = 'free'
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -67,7 +76,7 @@ def image_get(request, image_id):
|
||||
class IronicNode(base.APIResourceWrapper):
|
||||
_attrs = ('id', 'uuid', 'instance_uuid', 'driver', 'driver_info',
|
||||
'properties', 'power_state', 'target_power_state',
|
||||
'maintenance')
|
||||
'provision_state', 'maintenance', 'extra')
|
||||
|
||||
def __init__(self, apiresource, request=None):
|
||||
super(IronicNode, self).__init__(apiresource)
|
||||
@ -286,6 +295,21 @@ class IronicNode(base.APIResourceWrapper):
|
||||
def cpu_arch(self):
|
||||
return self.properties.get('cpu_arch', None)
|
||||
|
||||
@cached_property
|
||||
def state(self):
|
||||
if self.maintenance:
|
||||
if self.extra.get('on_discovery', 'false') == 'true':
|
||||
return DISCOVERING_STATE
|
||||
return DISCOVERED_STATE
|
||||
else:
|
||||
if self.instance_uuid:
|
||||
if self.provision_state == 'active':
|
||||
return PROVISIONED_STATE
|
||||
if self.provision_state in ('deploy failed', 'error'):
|
||||
return PROVISIONING_FAILED_STATE
|
||||
return PROVISIONING_STATE
|
||||
return FREE_STATE
|
||||
|
||||
|
||||
class BareMetalNode(base.APIResourceWrapper):
|
||||
_attrs = ('id', 'uuid', 'instance_uuid', 'memory_mb', 'cpus', 'local_gb',
|
||||
@ -421,6 +445,10 @@ class BareMetalNode(base.APIResourceWrapper):
|
||||
}
|
||||
return task_state_dict.get(self.task_state, 'off')
|
||||
|
||||
@cached_property
|
||||
def state(self):
|
||||
return self.power_state
|
||||
|
||||
@cached_property
|
||||
def target_power_state(self):
|
||||
return None
|
||||
@ -477,7 +505,7 @@ class NodeClient(object):
|
||||
|
||||
|
||||
class Node(base.APIResourceWrapper):
|
||||
_attrs = ('id', 'uuid', 'instance_uuid', 'driver', 'driver_info',
|
||||
_attrs = ('id', 'uuid', 'instance_uuid', 'driver', 'driver_info', 'state',
|
||||
'power_state', 'target_power_state', 'addresses', 'maintenance',
|
||||
'cpus', 'memory_mb', 'local_gb', 'cpu_arch')
|
||||
|
||||
|
@ -136,24 +136,41 @@ def get_power_state_with_transition(node):
|
||||
return node.power_state
|
||||
|
||||
|
||||
class RegisteredNodesTable(tables.DataTable):
|
||||
def get_state_string(node):
|
||||
state_dict = {
|
||||
api.node.DISCOVERING_STATE: _('Discovering'),
|
||||
api.node.DISCOVERED_STATE: _('Discovered'),
|
||||
api.node.PROVISIONED_STATE: _('Provisioned'),
|
||||
api.node.PROVISIONING_FAILED_STATE: _('Provisioning Failed'),
|
||||
api.node.PROVISIONING_STATE: _('Provisioning'),
|
||||
api.node.FREE_STATE: _('Free'),
|
||||
}
|
||||
|
||||
node_state = node.state
|
||||
return state_dict.get(node_state, node_state)
|
||||
|
||||
|
||||
class BaseNodesTable(tables.DataTable):
|
||||
node = tables.Column('uuid',
|
||||
link="horizon:infrastructure:nodes:detail",
|
||||
verbose_name=_("Node Name"))
|
||||
instance_ip = tables.Column(lambda n:
|
||||
n.ip_address if n.instance else '-',
|
||||
verbose_name=_("Instance IP"))
|
||||
provisioning_status = tables.Column('provisioning_status',
|
||||
verbose_name=_("Provisioned"))
|
||||
role_name = tables.Column('role_name',
|
||||
link=get_role_link,
|
||||
verbose_name=_("Deployment Role"))
|
||||
power_state = tables.Column(get_power_state_with_transition,
|
||||
verbose_name=_("Power"))
|
||||
cpus = tables.Column('cpus',
|
||||
verbose_name=_("CPU (cores)"))
|
||||
memory_mb = tables.Column('memory_mb',
|
||||
verbose_name=_("Memory (MB)"))
|
||||
local_gb = tables.Column('local_gb',
|
||||
verbose_name=_("Disk (GB)"))
|
||||
power_status = tables.Column(get_power_state_with_transition,
|
||||
verbose_name=_("Power Status"))
|
||||
state = tables.Column(get_state_string,
|
||||
verbose_name=_("Status"))
|
||||
|
||||
class Meta:
|
||||
name = "nodes_table"
|
||||
verbose_name = _("Registered Nodes")
|
||||
verbose_name = _("Nodes")
|
||||
table_actions = (NodeFilterAction, SetPowerStateOn, SetPowerStateOff,
|
||||
DeleteNode)
|
||||
row_actions = (SetPowerStateOn, SetPowerStateOff, DeleteNode)
|
||||
@ -166,32 +183,51 @@ class RegisteredNodesTable(tables.DataTable):
|
||||
return datum.uuid
|
||||
|
||||
|
||||
class MaintenanceNodesTable(tables.DataTable):
|
||||
node = tables.Column('uuid',
|
||||
link="horizon:infrastructure:nodes:detail",
|
||||
verbose_name=_("Node Name"))
|
||||
cpu_arch = tables.Column('cpu_arch',
|
||||
verbose_name=_("Arch."))
|
||||
cpus = tables.Column('cpus',
|
||||
verbose_name=_("CPU (cores)"))
|
||||
memory_mb = tables.Column('memory_mb',
|
||||
verbose_name=_("Memory (MB)"))
|
||||
local_gb = tables.Column('local_gb',
|
||||
verbose_name=_("Disk (GB)"))
|
||||
driver = tables.Column('driver',
|
||||
verbose_name=_("Driver"))
|
||||
nics = tables.Column(lambda n: len(n.addresses),
|
||||
verbose_name=_("NICs"))
|
||||
class AllNodesTable(BaseNodesTable):
|
||||
|
||||
class Meta:
|
||||
name = "all_nodes_table"
|
||||
verbose_name = _("All")
|
||||
columns = ('node', 'cpus', 'memory_mb', 'local_gb', 'power_status',
|
||||
'state')
|
||||
table_actions = (NodeFilterAction, SetPowerStateOn, SetPowerStateOff,
|
||||
DeleteNode)
|
||||
row_actions = (SetPowerStateOn, SetPowerStateOff, DeleteNode)
|
||||
template = "horizon/common/_enhanced_data_table.html"
|
||||
|
||||
|
||||
class ProvisionedNodesTable(BaseNodesTable):
|
||||
|
||||
class Meta:
|
||||
name = "provisioned_nodes_table"
|
||||
verbose_name = _("Provisioned")
|
||||
table_actions = (NodeFilterAction, SetPowerStateOn, SetPowerStateOff,
|
||||
DeleteNode)
|
||||
row_actions = (SetPowerStateOn, SetPowerStateOff, DeleteNode)
|
||||
template = "horizon/common/_enhanced_data_table.html"
|
||||
|
||||
|
||||
class FreeNodesTable(BaseNodesTable):
|
||||
|
||||
class Meta:
|
||||
name = "free_nodes_table"
|
||||
verbose_name = _("Free")
|
||||
columns = ('node', 'cpus', 'memory_mb', 'local_gb', 'power_status')
|
||||
table_actions = (NodeFilterAction, SetPowerStateOn, SetPowerStateOff,
|
||||
DeleteNode)
|
||||
row_actions = (SetPowerStateOn, SetPowerStateOff, DeleteNode,)
|
||||
template = "horizon/common/_enhanced_data_table.html"
|
||||
|
||||
|
||||
class MaintenanceNodesTable(BaseNodesTable):
|
||||
|
||||
class Meta:
|
||||
name = "maintenance_nodes_table"
|
||||
verbose_name = _("Nodes (Maintenance)")
|
||||
table_actions = (NodeFilterAction, ActivateNode, DeleteNode)
|
||||
row_actions = (ActivateNode, DeleteNode,)
|
||||
verbose_name = _("Maintenance")
|
||||
columns = ('node', 'cpus', 'memory_mb', 'local_gb', 'power_status',
|
||||
'state')
|
||||
table_actions = (NodeFilterAction, ActivateNode, SetPowerStateOn,
|
||||
SetPowerStateOff, DeleteNode)
|
||||
row_actions = (ActivateNode, SetPowerStateOn, SetPowerStateOff,
|
||||
DeleteNode)
|
||||
template = "horizon/common/_enhanced_data_table.html"
|
||||
|
||||
def get_object_id(self, datum):
|
||||
return datum.uuid
|
||||
|
||||
def get_object_display(self, datum):
|
||||
return datum.uuid
|
||||
|
@ -81,38 +81,28 @@ class OverviewTab(tabs.Tab):
|
||||
return context
|
||||
|
||||
|
||||
class RegisteredTab(tabs.TableTab):
|
||||
table_classes = (tables.RegisteredNodesTable,)
|
||||
name = _("Registered")
|
||||
slug = "registered"
|
||||
class BaseTab(tabs.TableTab):
|
||||
table_classes = (tables.BaseNodesTable,)
|
||||
name = _("Nodes")
|
||||
slug = "nodes"
|
||||
template_name = "horizon/common/_detail_table.html"
|
||||
|
||||
def __init__(self, tab_group, request):
|
||||
super(RegisteredTab, self).__init__(tab_group, request)
|
||||
|
||||
def get_items_count(self):
|
||||
return len(self._nodes)
|
||||
super(BaseTab, self).__init__(tab_group, request)
|
||||
|
||||
@cached_property
|
||||
def _nodes(self):
|
||||
redirect = urlresolvers.reverse('horizon:infrastructure:nodes:index')
|
||||
return []
|
||||
|
||||
if 'provisioned' in self.request.GET:
|
||||
associated = True
|
||||
elif 'free' in self.request.GET:
|
||||
associated = False
|
||||
else:
|
||||
associated = None
|
||||
|
||||
return api.node.Node.list(self.request, associated=associated,
|
||||
maintenance=False, _error_redirect=redirect)
|
||||
def get_items_count(self):
|
||||
return len(self._nodes)
|
||||
|
||||
@cached_property
|
||||
def _nodes_info(self):
|
||||
page_size = functions.get_page_size(self.request)
|
||||
|
||||
prev_marker = self.request.GET.get(
|
||||
tables.RegisteredNodesTable._meta.prev_pagination_param, None)
|
||||
self.table_classes[0]._meta.prev_pagination_param, None)
|
||||
|
||||
if prev_marker is not None:
|
||||
sort_dir = 'asc'
|
||||
@ -120,7 +110,7 @@ class RegisteredTab(tabs.TableTab):
|
||||
else:
|
||||
sort_dir = 'desc'
|
||||
marker = self.request.GET.get(
|
||||
tables.RegisteredNodesTable._meta.pagination_param, None)
|
||||
self.table_classes[0]._meta.pagination_param, None)
|
||||
|
||||
nodes = self._nodes
|
||||
|
||||
@ -141,7 +131,59 @@ class RegisteredTab(tabs.TableTab):
|
||||
more = len(nodes) > end
|
||||
return nodes[start:end], prev, more
|
||||
|
||||
def get_nodes_table_data(self):
|
||||
def get_base_nodes_table_data(self):
|
||||
nodes, prev, more = self._nodes_info
|
||||
|
||||
if 'errors' in self.request.GET:
|
||||
return api.node.filter_nodes(nodes, healthy=False)
|
||||
|
||||
return nodes
|
||||
|
||||
def has_prev_data(self, table):
|
||||
return self._nodes_info[1]
|
||||
|
||||
def has_more_data(self, table):
|
||||
return self._nodes_info[2]
|
||||
|
||||
|
||||
class AllTab(BaseTab):
|
||||
table_classes = (tables.AllNodesTable,)
|
||||
name = _("All")
|
||||
slug = "all"
|
||||
|
||||
def __init__(self, tab_group, request):
|
||||
super(AllTab, self).__init__(tab_group, request)
|
||||
|
||||
@cached_property
|
||||
def _nodes(self):
|
||||
redirect = urlresolvers.reverse('horizon:infrastructure:nodes:index')
|
||||
|
||||
return api.node.Node.list(self.request, _error_redirect=redirect)
|
||||
|
||||
def get_all_nodes_table_data(self):
|
||||
nodes, prev, more = self._nodes_info
|
||||
|
||||
if 'errors' in self.request.GET:
|
||||
return api.node.filter_nodes(nodes, healthy=False)
|
||||
|
||||
return nodes
|
||||
|
||||
|
||||
class ProvisionedTab(BaseTab):
|
||||
table_classes = (tables.ProvisionedNodesTable,)
|
||||
name = _("Provisioned")
|
||||
slug = "provisioned"
|
||||
|
||||
def __init__(self, tab_group, request):
|
||||
super(ProvisionedTab, self).__init__(tab_group, request)
|
||||
|
||||
@cached_property
|
||||
def _nodes(self):
|
||||
redirect = urlresolvers.reverse('horizon:infrastructure:nodes:index')
|
||||
return api.node.Node.list(self.request, associated=True,
|
||||
maintenance=False, _error_redirect=redirect)
|
||||
|
||||
def get_provisioned_nodes_table_data(self):
|
||||
nodes, prev, more = self._nodes_info
|
||||
|
||||
if 'errors' in self.request.GET:
|
||||
@ -161,27 +203,46 @@ class RegisteredTab(tabs.TableTab):
|
||||
|
||||
return nodes
|
||||
|
||||
def has_prev_data(self, table):
|
||||
return self._nodes_info[1]
|
||||
|
||||
def has_more_data(self, table):
|
||||
return self._nodes_info[2]
|
||||
class FreeTab(BaseTab):
|
||||
table_classes = (tables.FreeNodesTable,)
|
||||
name = _("Free")
|
||||
slug = "free"
|
||||
|
||||
def __init__(self, tab_group, request):
|
||||
super(FreeTab, self).__init__(tab_group, request)
|
||||
|
||||
@cached_property
|
||||
def _nodes(self):
|
||||
redirect = urlresolvers.reverse('horizon:infrastructure:nodes:index')
|
||||
return api.node.Node.list(self.request, associated=False,
|
||||
maintenance=False, _error_redirect=redirect)
|
||||
|
||||
def get_free_nodes_table_data(self):
|
||||
nodes, prev, more = self._nodes_info
|
||||
|
||||
if 'errors' in self.request.GET:
|
||||
return api.node.filter_nodes(nodes, healthy=False)
|
||||
|
||||
return nodes
|
||||
|
||||
|
||||
class MaintenanceTab(tabs.TableTab):
|
||||
class MaintenanceTab(BaseTab):
|
||||
table_classes = (tables.MaintenanceNodesTable,)
|
||||
name = _("Maintenance")
|
||||
slug = "maintenance"
|
||||
template_name = "horizon/common/_detail_table.html"
|
||||
|
||||
def get_items_count(self):
|
||||
return len(self.get_maintenance_nodes_table_data())
|
||||
def __init__(self, tab_group, request):
|
||||
super(MaintenanceTab, self).__init__(tab_group, request)
|
||||
|
||||
@cached_property
|
||||
def _nodes(self):
|
||||
redirect = urlresolvers.reverse('horizon:infrastructure:nodes:index')
|
||||
return api.node.Node.list(self.request, maintenance=True,
|
||||
_error_redirect=redirect)
|
||||
|
||||
def get_maintenance_nodes_table_data(self):
|
||||
redirect = urlresolvers.reverse('horizon:infrastructure:nodes:index')
|
||||
nodes = api.node.Node.list(self.request, maintenance=True,
|
||||
_error_redirect=redirect)
|
||||
return nodes
|
||||
return self._nodes
|
||||
|
||||
|
||||
class DetailOverviewTab(tabs.Tab):
|
||||
@ -226,7 +287,7 @@ class DetailOverviewTab(tabs.Tab):
|
||||
|
||||
class NodeTabs(tabs.TabGroup):
|
||||
slug = "nodes"
|
||||
tabs = (OverviewTab, RegisteredTab)
|
||||
tabs = (OverviewTab, AllTab, ProvisionedTab, FreeTab, MaintenanceTab,)
|
||||
sticky = True
|
||||
template_name = "horizon/common/_items_count_tab_group.html"
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div class="widget">
|
||||
<h3>{% trans 'Hardware Inventory' %}</h3>
|
||||
<div class="widget-info">
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__registered">
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__all">
|
||||
<span class="info">{{ nodes_all_count }} {% trans 'nodes' %}</span>
|
||||
</a>
|
||||
</div>
|
||||
@ -29,7 +29,7 @@
|
||||
<div class="col-xs-12">
|
||||
<h3>{% trans "Provisioned nodes" %}</h3>
|
||||
<div class="widget-info">
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__registered&provisioned">
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__provisioned">
|
||||
<span class="info">{{ nodes_provisioned_count }} {% trans 'provisioned nodes' %}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -55,73 +55,71 @@ class NodesTests(test.BaseAdminViewTests, helpers.APITestCase):
|
||||
}) 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, 4)
|
||||
self.assertEqual(mock.list.call_count, 7)
|
||||
|
||||
self.assertTemplateUsed(
|
||||
res, 'infrastructure/nodes/index.html')
|
||||
self.assertTemplateUsed(res, 'infrastructure/nodes/_overview.html')
|
||||
|
||||
def test_registered_nodes(self):
|
||||
registered_nodes = [api.node.Node(api.node.IronicNode(node))
|
||||
for node in self.ironicclient_nodes.list()]
|
||||
roles = [api.tuskar.Role(r)
|
||||
for r in TEST_DATA.tuskarclient_roles.list()]
|
||||
instance = TEST_DATA.novaclient_servers.first()
|
||||
image = TEST_DATA.glanceclient_images.first()
|
||||
def _test_index_tab(self, tab_name):
|
||||
nodes = [api.node.Node(api.node.IronicNode(node))
|
||||
for node in self.ironicclient_nodes.list()]
|
||||
|
||||
# TODO(akrivoka): this should be placed in the test data, but currently
|
||||
# that's not possible due to the drawbacks in the Node architecture.
|
||||
# We should rework the entire api/node.py and fix this problem.
|
||||
for node in registered_nodes:
|
||||
for node in nodes:
|
||||
node.ip_address = '1.1.1.1'
|
||||
|
||||
with contextlib.nested(
|
||||
patch('tuskar_ui.api.tuskar.Role', **{
|
||||
'spec_set': ['list', 'name'],
|
||||
'list.return_value': roles,
|
||||
}),
|
||||
patch('tuskar_ui.api.node.Node', **{
|
||||
'spec_set': ['list'],
|
||||
'list.return_value': registered_nodes,
|
||||
}),
|
||||
patch('tuskar_ui.api.node.nova', **{
|
||||
'spec_set': ['server_get', 'server_list'],
|
||||
'server_get.return_value': instance,
|
||||
'server_list.return_value': ([instance], False),
|
||||
}),
|
||||
patch('tuskar_ui.api.node.glance', **{
|
||||
'spec_set': ['image_get'],
|
||||
'image_get.return_value': image,
|
||||
}),
|
||||
patch('tuskar_ui.api.heat.Resource', **{
|
||||
'spec_set': ['get_by_node', 'list_all_resources'],
|
||||
'get_by_node.side_effect': (
|
||||
self._raise_horizon_exception_not_found),
|
||||
'list_all_resources.return_value': [],
|
||||
}),
|
||||
) as (_Role, Node, _nova, _glance, _resource):
|
||||
res = self.client.get(INDEX_URL + '?tab=nodes__registered')
|
||||
with patch('tuskar_ui.api.node.Node', **{
|
||||
'spec_set': ['list'],
|
||||
'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, 4)
|
||||
self.assertEqual(Node.list.call_count, 7)
|
||||
|
||||
self.assertTemplateUsed(
|
||||
res, 'infrastructure/nodes/index.html')
|
||||
self.assertTemplateUsed(res, 'horizon/common/_detail_table.html')
|
||||
self.assertItemsEqual(res.context['nodes_table_table'].data,
|
||||
registered_nodes)
|
||||
self.assertItemsEqual(
|
||||
res.context[tab_name + '_nodes_table_table'].data,
|
||||
nodes)
|
||||
|
||||
def test_registered_nodes_list_exception(self):
|
||||
instance = TEST_DATA.novaclient_servers.first()
|
||||
def test_all_nodes(self):
|
||||
self._test_index_tab('all')
|
||||
|
||||
def test_provisioned_nodes(self):
|
||||
self._test_index_tab('provisioned')
|
||||
|
||||
def test_free_nodes(self):
|
||||
self._test_index_tab('free')
|
||||
|
||||
def test_maintenance_nodes(self):
|
||||
self._test_index_tab('maintenance')
|
||||
|
||||
def _test_index_tab_list_exception(self, tab_name):
|
||||
with patch('tuskar_ui.api.node.Node', **{
|
||||
'spec_set': ['list', 'instance'],
|
||||
'instance': instance,
|
||||
'spec_set': ['list'],
|
||||
'list.side_effect': self._raise_tuskar_exception,
|
||||
}) as mock:
|
||||
res = self.client.get(INDEX_URL + '?tab=nodes__registered')
|
||||
res = self.client.get(INDEX_URL + '?tab=nodes__' + tab_name)
|
||||
self.assertEqual(mock.list.call_count, 4)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_all_nodes_list_exception(self):
|
||||
self._test_index_tab_list_exception('all')
|
||||
|
||||
def test_provisioned_nodes_list_exception(self):
|
||||
self._test_index_tab_list_exception('provisioned')
|
||||
|
||||
def test_free_nodes_list_exception(self):
|
||||
self._test_index_tab_list_exception('free')
|
||||
|
||||
def test_maintenance_nodes_list_exception(self):
|
||||
self._test_index_tab_list_exception('maintenance')
|
||||
|
||||
def test_register_get(self):
|
||||
res = self.client.get(REGISTER_URL)
|
||||
self.assertTemplateUsed(
|
||||
@ -280,14 +278,14 @@ class NodesTests(test.BaseAdminViewTests, helpers.APITestCase):
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_node_set_power_on(self):
|
||||
registered_nodes = [api.node.Node(api.node.IronicNode(node))
|
||||
for node in self.ironicclient_nodes.list()]
|
||||
node = registered_nodes[6]
|
||||
all_nodes = [api.node.Node(api.node.IronicNode(node))
|
||||
for node in self.ironicclient_nodes.list()]
|
||||
node = all_nodes[6]
|
||||
roles = [api.tuskar.Role(r)
|
||||
for r in TEST_DATA.tuskarclient_roles.list()]
|
||||
instance = TEST_DATA.novaclient_servers.first()
|
||||
image = TEST_DATA.glanceclient_images.first()
|
||||
data = {'action': "nodes_table__set_power_state_on__{0}".format(
|
||||
data = {'action': "all_nodes_table__set_power_state_on__{0}".format(
|
||||
node.uuid)}
|
||||
|
||||
with contextlib.nested(
|
||||
@ -297,7 +295,7 @@ class NodesTests(test.BaseAdminViewTests, helpers.APITestCase):
|
||||
}),
|
||||
patch('tuskar_ui.api.node.Node', **{
|
||||
'spec_set': ['list', 'set_power_state'],
|
||||
'list.return_value': registered_nodes,
|
||||
'list.return_value': all_nodes,
|
||||
'set_power_state.return_value': node,
|
||||
}),
|
||||
patch('tuskar_ui.api.tuskar.Role', **{
|
||||
@ -321,21 +319,21 @@ class NodesTests(test.BaseAdminViewTests, helpers.APITestCase):
|
||||
}),
|
||||
) as (mock_node_client, mock_node, mock_role, mock_nova, mock_glance,
|
||||
mock_resource):
|
||||
res = self.client.post(INDEX_URL + '?tab=nodes__registered', data)
|
||||
res = self.client.post(INDEX_URL + '?tab=nodes__all', data)
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertEqual(mock_node.set_power_state.call_count, 1)
|
||||
self.assertRedirectsNoFollow(res,
|
||||
INDEX_URL + '?tab=nodes__registered')
|
||||
INDEX_URL + '?tab=nodes__all')
|
||||
|
||||
def test_node_set_power_off(self):
|
||||
registered_nodes = [api.node.Node(api.node.IronicNode(node))
|
||||
for node in self.ironicclient_nodes.list()]
|
||||
node = registered_nodes[8]
|
||||
all_nodes = [api.node.Node(api.node.IronicNode(node))
|
||||
for node in self.ironicclient_nodes.list()]
|
||||
node = all_nodes[8]
|
||||
roles = [api.tuskar.Role(r)
|
||||
for r in TEST_DATA.tuskarclient_roles.list()]
|
||||
instance = TEST_DATA.novaclient_servers.first()
|
||||
image = TEST_DATA.glanceclient_images.first()
|
||||
data = {'action': "nodes_table__set_power_state_off__{0}".format(
|
||||
data = {'action': "all_nodes_table__set_power_state_off__{0}".format(
|
||||
node.uuid)}
|
||||
|
||||
with contextlib.nested(
|
||||
@ -345,7 +343,7 @@ class NodesTests(test.BaseAdminViewTests, helpers.APITestCase):
|
||||
}),
|
||||
patch('tuskar_ui.api.node.Node', **{
|
||||
'spec_set': ['list', 'set_power_state'],
|
||||
'list.return_value': registered_nodes,
|
||||
'list.return_value': all_nodes,
|
||||
'set_power_state.return_value': node,
|
||||
}),
|
||||
patch('tuskar_ui.api.tuskar.Role', **{
|
||||
@ -369,11 +367,11 @@ class NodesTests(test.BaseAdminViewTests, helpers.APITestCase):
|
||||
}),
|
||||
) as (mock_node_client, mock_node, mock_role, mock_nova, mock_glance,
|
||||
mock_resource):
|
||||
res = self.client.post(INDEX_URL + '?tab=nodes__registered', data)
|
||||
res = self.client.post(INDEX_URL + '?tab=nodes__all', data)
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertEqual(mock_node.set_power_state.call_count, 1)
|
||||
self.assertRedirectsNoFollow(res,
|
||||
INDEX_URL + '?tab=nodes__registered')
|
||||
INDEX_URL + '?tab=nodes__all')
|
||||
|
||||
def test_performance(self):
|
||||
node = api.node.Node(self.ironicclient_nodes.list()[0])
|
||||
|
@ -110,7 +110,7 @@ class DetailView(horizon_tabs.TabView):
|
||||
if node.maintenance:
|
||||
table = tables.MaintenanceNodesTable(self.request)
|
||||
else:
|
||||
table = tables.RegisteredNodesTable(self.request)
|
||||
table = tables.ProvisionedNodesTable(self.request)
|
||||
|
||||
context['node'] = node
|
||||
context['title'] = _("Node: %(uuid)s") % {'uuid': node.uuid}
|
||||
|
@ -55,7 +55,7 @@ class RolesTable(tables.DataTable):
|
||||
template = "horizon/common/_enhanced_data_table.html"
|
||||
|
||||
|
||||
class NodeTable(nodes_tables.RegisteredNodesTable):
|
||||
class NodeTable(nodes_tables.ProvisionedNodesTable):
|
||||
|
||||
class Meta:
|
||||
name = "nodetable"
|
||||
|
@ -134,8 +134,10 @@ def data(TEST):
|
||||
},
|
||||
'power_state': 'on',
|
||||
'target_power_state': 'on',
|
||||
'provision_state': 'active',
|
||||
'maintenance': None,
|
||||
'newly_discovered': None,
|
||||
'extra': {}
|
||||
})
|
||||
node_2 = node.Node(
|
||||
node.NodeManager(None),
|
||||
@ -157,8 +159,10 @@ def data(TEST):
|
||||
},
|
||||
'power_state': 'on',
|
||||
'target_power_state': 'on',
|
||||
'provision_state': 'active',
|
||||
'maintenance': None,
|
||||
'newly_discovered': None,
|
||||
'extra': {}
|
||||
})
|
||||
node_3 = node.Node(
|
||||
node.NodeManager(None),
|
||||
@ -180,8 +184,10 @@ def data(TEST):
|
||||
},
|
||||
'power_state': 'rebooting',
|
||||
'target_power_state': 'on',
|
||||
'provision_state': 'active',
|
||||
'maintenance': None,
|
||||
'newly_discovered': None,
|
||||
'extra': {}
|
||||
})
|
||||
node_4 = node.Node(
|
||||
node.NodeManager(None),
|
||||
@ -203,8 +209,10 @@ def data(TEST):
|
||||
},
|
||||
'power_state': 'on',
|
||||
'target_power_state': 'on',
|
||||
'provision_state': 'active',
|
||||
'maintenance': None,
|
||||
'newly_discovered': None,
|
||||
'extra': {}
|
||||
})
|
||||
node_5 = node.Node(
|
||||
node.NodeManager(None),
|
||||
@ -226,8 +234,10 @@ def data(TEST):
|
||||
},
|
||||
'power_state': 'error',
|
||||
'target_power_state': 'on',
|
||||
'provision_state': 'error',
|
||||
'maintenance': None,
|
||||
'newly_discovered': None,
|
||||
'extra': {}
|
||||
})
|
||||
node_6 = node.Node(
|
||||
node.NodeManager(None),
|
||||
@ -249,8 +259,10 @@ def data(TEST):
|
||||
},
|
||||
'power_state': 'on',
|
||||
'target_power_state': 'on',
|
||||
'provision_state': 'active',
|
||||
'maintenance': None,
|
||||
'newly_discovered': None,
|
||||
'extra': {}
|
||||
})
|
||||
node_7 = node.Node(
|
||||
node.NodeManager(None),
|
||||
@ -274,6 +286,7 @@ def data(TEST):
|
||||
'target_power_state': 'on',
|
||||
'maintenance': True,
|
||||
'newly_discovered': None,
|
||||
'extra': {}
|
||||
})
|
||||
node_8 = node.Node(
|
||||
node.NodeManager(None),
|
||||
@ -297,6 +310,7 @@ def data(TEST):
|
||||
'target_power_state': 'on',
|
||||
'maintenance': True,
|
||||
'newly_discovered': True,
|
||||
'extra': {}
|
||||
})
|
||||
node_9 = node.Node(
|
||||
node.NodeManager(None),
|
||||
@ -320,6 +334,7 @@ def data(TEST):
|
||||
'target_power_state': 'on',
|
||||
'maintenance': True,
|
||||
'newly_discovered': True,
|
||||
'extra': {}
|
||||
})
|
||||
TEST.ironicclient_nodes.add(node_1, node_2, node_3, node_4, node_5, node_6,
|
||||
node_7, node_8, node_9)
|
||||
|
Loading…
x
Reference in New Issue
Block a user