From 8a77093c01eb5c1393ae43e56c5f48bdb01a5247 Mon Sep 17 00:00:00 2001 From: Tzu-Mainn Chen Date: Fri, 24 Oct 2014 19:50:02 +0000 Subject: [PATCH] Re-factor nodes index tables Tabs are now: 'All', 'Provisioned', 'Free', 'Maintenance'. Change-Id: Ia8d26c6aa4b4d7dc9ac78f25aa6ab9477b2f0781 --- tuskar_ui/api/node.py | 32 ++++- tuskar_ui/infrastructure/nodes/tables.py | 104 +++++++++----- tuskar_ui/infrastructure/nodes/tabs.py | 129 +++++++++++++----- .../nodes/templates/nodes/_overview.html | 4 +- tuskar_ui/infrastructure/nodes/tests.py | 112 ++++++++------- tuskar_ui/infrastructure/nodes/views.py | 2 +- tuskar_ui/infrastructure/roles/tables.py | 2 +- tuskar_ui/test/test_data/node_data.py | 15 ++ 8 files changed, 269 insertions(+), 131 deletions(-) diff --git a/tuskar_ui/api/node.py b/tuskar_ui/api/node.py index dfd8cde87..d5b04fc44 100644 --- a/tuskar_ui/api/node.py +++ b/tuskar_ui/api/node.py @@ -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') diff --git a/tuskar_ui/infrastructure/nodes/tables.py b/tuskar_ui/infrastructure/nodes/tables.py index 07f7f60d2..b32e07089 100644 --- a/tuskar_ui/infrastructure/nodes/tables.py +++ b/tuskar_ui/infrastructure/nodes/tables.py @@ -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 diff --git a/tuskar_ui/infrastructure/nodes/tabs.py b/tuskar_ui/infrastructure/nodes/tabs.py index 40b2b1117..f0b9b21bc 100644 --- a/tuskar_ui/infrastructure/nodes/tabs.py +++ b/tuskar_ui/infrastructure/nodes/tabs.py @@ -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" diff --git a/tuskar_ui/infrastructure/nodes/templates/nodes/_overview.html b/tuskar_ui/infrastructure/nodes/templates/nodes/_overview.html index 282250e3b..efaf86957 100644 --- a/tuskar_ui/infrastructure/nodes/templates/nodes/_overview.html +++ b/tuskar_ui/infrastructure/nodes/templates/nodes/_overview.html @@ -7,7 +7,7 @@

{% trans 'Hardware Inventory' %}

@@ -29,7 +29,7 @@

{% trans "Provisioned nodes" %}

diff --git a/tuskar_ui/infrastructure/nodes/tests.py b/tuskar_ui/infrastructure/nodes/tests.py index 5725f9bb6..9c61de5c0 100644 --- a/tuskar_ui/infrastructure/nodes/tests.py +++ b/tuskar_ui/infrastructure/nodes/tests.py @@ -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]) diff --git a/tuskar_ui/infrastructure/nodes/views.py b/tuskar_ui/infrastructure/nodes/views.py index dd73b2baa..8267e5d3a 100644 --- a/tuskar_ui/infrastructure/nodes/views.py +++ b/tuskar_ui/infrastructure/nodes/views.py @@ -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} diff --git a/tuskar_ui/infrastructure/roles/tables.py b/tuskar_ui/infrastructure/roles/tables.py index 4c899470c..da39a0c30 100644 --- a/tuskar_ui/infrastructure/roles/tables.py +++ b/tuskar_ui/infrastructure/roles/tables.py @@ -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" diff --git a/tuskar_ui/test/test_data/node_data.py b/tuskar_ui/test/test_data/node_data.py index bb36a83f4..a73519e12 100644 --- a/tuskar_ui/test/test_data/node_data.py +++ b/tuskar_ui/test/test_data/node_data.py @@ -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)