From d3c3d4dabe907ac9b6fc9eb95a6015564ed55d72 Mon Sep 17 00:00:00 2001 From: Julia Kreger Date: Wed, 19 Aug 2020 18:44:39 -0700 Subject: Update the cache if we don't have a root device hint Or at least try to. Some deployments just don't use root device hints, and this is okay. However, other deployments need root device hints, and with fast track mode in ramdisks, we created a situation where the node cache could be updated by a human or software between the time the agent was started, and the deployment was requested. As a result, the agent has been updated to check if we have a hint and if we don't, update the cache from the node lookup endpoint. This is not needed when the inband deploy steps are executed, as the process of updating the steps does force the node cache to be updated. Change-Id: I27201319f31cdc01605a3c5ae9ef4b4218e4a3f6 Story: 2008039 Task: 40701 --- .../tests/unit/extensions/test_iscsi.py | 12 ++-- .../tests/unit/extensions/test_standby.py | 30 ++++++---- ironic_python_agent/tests/unit/test_hardware.py | 70 ++++++++++++++++++++++ 3 files changed, 98 insertions(+), 14 deletions(-) (limited to 'ironic_python_agent/tests') diff --git a/ironic_python_agent/tests/unit/extensions/test_iscsi.py b/ironic_python_agent/tests/unit/extensions/test_iscsi.py index 131ad075..a4678a98 100644 --- a/ironic_python_agent/tests/unit/extensions/test_iscsi.py +++ b/ironic_python_agent/tests/unit/extensions/test_iscsi.py @@ -69,7 +69,8 @@ class TestISCSIExtensionTgt(base.IronicAgentTest): '--op', 'bind', '--tid', '1', '--initiator-address', 'ALL')] mock_execute.assert_has_calls(expected) - mock_dispatch.assert_called_once_with('get_os_install_device') + mock_dispatch.assert_called_once_with('get_os_install_device', + permit_refresh=True) self.assertEqual({'iscsi_target_iqn': self.fake_iqn}, result.command_result) self.assertFalse(mock_destroy.called) @@ -98,7 +99,8 @@ class TestISCSIExtensionTgt(base.IronicAgentTest): '--op', 'bind', '--tid', '1', '--initiator-address', 'ALL')] mock_execute.assert_has_calls(expected) - mock_dispatch.assert_called_once_with('get_os_install_device') + mock_dispatch.assert_called_once_with('get_os_install_device', + permit_refresh=True) self.assertEqual({'iscsi_target_iqn': self.fake_iqn}, result.command_result) @@ -119,7 +121,8 @@ class TestISCSIExtensionTgt(base.IronicAgentTest): '--op', 'show', attempts=10)] mock_execute.assert_has_calls(expected) - mock_dispatch.assert_called_once_with('get_os_install_device') + mock_dispatch.assert_called_once_with('get_os_install_device', + permit_refresh=True) self.assertFalse(mock_destroy.called) @mock.patch.object(iscsi, '_wait_for_tgtd', autospec=True) @@ -138,7 +141,8 @@ class TestISCSIExtensionTgt(base.IronicAgentTest): 'target', '--op', 'new', '--tid', '1', '--targetname', self.fake_iqn)] mock_execute.assert_has_calls(expected) - mock_dispatch.assert_called_once_with('get_os_install_device') + mock_dispatch.assert_called_once_with('get_os_install_device', + permit_refresh=True) def test_start_iscsi_target_fail_command_not_exist(self, mock_execute, mock_dispatch, diff --git a/ironic_python_agent/tests/unit/extensions/test_standby.py b/ironic_python_agent/tests/unit/extensions/test_standby.py index 5d27f6d7..9ca0f244 100644 --- a/ironic_python_agent/tests/unit/extensions/test_standby.py +++ b/ironic_python_agent/tests/unit/extensions/test_standby.py @@ -569,7 +569,8 @@ class TestStandbyExtension(base.IronicAgentTest): async_result.join() download_mock.assert_called_once_with(image_info) write_mock.assert_called_once_with(image_info, 'manager') - dispatch_mock.assert_called_once_with('get_os_install_device') + dispatch_mock.assert_called_once_with('get_os_install_device', + permit_refresh=True) self.assertEqual(image_info['id'], self.agent_extension.cached_image_id) self.assertEqual('SUCCEEDED', async_result.command_status) @@ -595,7 +596,8 @@ class TestStandbyExtension(base.IronicAgentTest): async_result.join() download_mock.assert_called_once_with(image_info) write_mock.assert_called_once_with(image_info, 'manager') - dispatch_mock.assert_called_once_with('get_os_install_device') + dispatch_mock.assert_called_once_with('get_os_install_device', + permit_refresh=True) self.assertEqual(image_info['id'], self.agent_extension.cached_image_id) self.assertEqual('SUCCEEDED', async_result.command_status) @@ -626,7 +628,8 @@ class TestStandbyExtension(base.IronicAgentTest): async_result.join() download_mock.assert_called_once_with(image_info) write_mock.assert_called_once_with(image_info, 'manager') - dispatch_mock.assert_called_once_with('get_os_install_device') + dispatch_mock.assert_called_once_with('get_os_install_device', + permit_refresh=True) self.assertEqual(image_info['id'], self.agent_extension.cached_image_id) self.assertEqual('SUCCEEDED', async_result.command_status) @@ -654,7 +657,8 @@ class TestStandbyExtension(base.IronicAgentTest): async_result.join() self.assertFalse(download_mock.called) self.assertFalse(write_mock.called) - dispatch_mock.assert_called_once_with('get_os_install_device') + dispatch_mock.assert_called_once_with('get_os_install_device', + permit_refresh=True) self.assertEqual(image_info['id'], self.agent_extension.cached_image_id) self.assertEqual('SUCCEEDED', async_result.command_status) @@ -699,7 +703,8 @@ class TestStandbyExtension(base.IronicAgentTest): download_mock.assert_called_once_with(image_info) write_mock.assert_called_once_with(image_info, 'manager') - dispatch_mock.assert_called_once_with('get_os_install_device') + dispatch_mock.assert_called_once_with('get_os_install_device', + permit_refresh=True) configdrive_copy_mock.assert_called_once_with(image_info['node_uuid'], 'manager', 'configdrive_data') @@ -749,7 +754,8 @@ class TestStandbyExtension(base.IronicAgentTest): download_mock.assert_called_once_with(image_info) write_mock.assert_called_once_with(image_info, 'manager') - dispatch_mock.assert_called_once_with('get_os_install_device') + dispatch_mock.assert_called_once_with('get_os_install_device', + permit_refresh=True) self.assertFalse(configdrive_copy_mock.called) self.assertEqual('SUCCEEDED', async_result.command_status) @@ -821,7 +827,8 @@ class TestStandbyExtension(base.IronicAgentTest): download_mock.assert_called_once_with(image_info) write_mock.assert_called_once_with(image_info, 'manager') - dispatch_mock.assert_called_once_with('get_os_install_device') + dispatch_mock.assert_called_once_with('get_os_install_device', + permit_refresh=True) self.assertEqual(0, configdrive_copy_mock.call_count) self.assertEqual('SUCCEEDED', async_result.command_status) @@ -871,7 +878,8 @@ class TestStandbyExtension(base.IronicAgentTest): download_mock.assert_called_once_with(image_info) write_mock.assert_called_once_with(image_info, 'manager') - dispatch_mock.assert_called_once_with('get_os_install_device') + dispatch_mock.assert_called_once_with('get_os_install_device', + permit_refresh=True) self.assertFalse(configdrive_copy_mock.called) self.assertEqual('FAILED', async_result.command_status) @@ -913,7 +921,8 @@ class TestStandbyExtension(base.IronicAgentTest): download_mock.assert_called_once_with(image_info) write_mock.assert_called_once_with(image_info, 'manager') - dispatch_mock.assert_called_once_with('get_os_install_device') + dispatch_mock.assert_called_once_with('get_os_install_device', + permit_refresh=True) configdrive_copy_mock.assert_called_once_with(image_info['node_uuid'], 'manager', 'configdrive_data') @@ -967,7 +976,8 @@ class TestStandbyExtension(base.IronicAgentTest): ) async_result.join() - dispatch_mock.assert_any_call('get_os_install_device') + dispatch_mock.assert_any_call('get_os_install_device', + permit_refresh=True) self.assertFalse(configdrive_copy_mock.called) # Assert we've streamed the image or not diff --git a/ironic_python_agent/tests/unit/test_hardware.py b/ironic_python_agent/tests/unit/test_hardware.py index 813c8769..0ab04b67 100644 --- a/ironic_python_agent/tests/unit/test_hardware.py +++ b/ironic_python_agent/tests/unit/test_hardware.py @@ -1467,6 +1467,46 @@ class TestGenericHardwareManager(base.IronicAgentTest): mock_cached_node.assert_called_once_with() mock_dev.assert_called_once_with() + @mock.patch.object(hardware, 'update_cached_node', autospec=True) + @mock.patch.object(hardware, 'list_all_block_devices', autospec=True) + @mock.patch.object(hardware, 'get_cached_node', autospec=True) + def test_get_os_install_device_no_root_device(self, mock_cached_node, + mock_dev, + mock_update): + mock_cached_node.return_value = {'properties': {}, + 'uuid': 'node1', + 'instance_info': {}} + mock_dev.return_value = [ + hardware.BlockDevice(name='/dev/sda', + model='TinyUSB Drive', + size=3116853504, + rotational=False, + vendor='Super Vendor', + wwn='wwn0', + wwn_with_extension='wwn0ven0', + wwn_vendor_extension='ven0', + serial='serial0'), + hardware.BlockDevice(name='/dev/sdb', + model='magical disk', + size=10737418240, + rotational=True, + vendor='fake-vendor', + wwn='fake-wwn', + wwn_with_extension='fake-wwnven0', + wwn_vendor_extension='ven0', + serial='fake-serial', + by_path='/dev/disk/by-path/1:0:0:0'), + ] + mock_update.return_value = {'properties': {'root_device': + {'name': '/dev/sda'}}, + 'uuid': 'node1', + 'instance_info': {'magic': 'value'}} + self.assertEqual('/dev/sda', + self.hardware.get_os_install_device( + permit_refresh=True)) + self.assertEqual(1, mock_cached_node.call_count) + mock_dev.assert_called_once_with() + def test__get_device_info(self): fileobj = mock.mock_open(read_data='fake-vendor') with mock.patch( @@ -4468,3 +4508,33 @@ class TestListHardwareInfo(base.IronicAgentTest): self.assertEqual(fake_info, hardware.list_hardware_info()) mock_dispatch.assert_called_with('list_hardware_info') self.assertEqual(2, mock_dispatch.call_count) + + +class TestAPIClientSaveAndUse(base.IronicAgentTest): + + def test_save_api_client(self): + hardware.API_CLIENT = None + mock_api_client = mock.Mock() + hardware.save_api_client(mock_api_client, 1, 2) + self.assertEqual(mock_api_client, hardware.API_CLIENT) + + @mock.patch('ironic_python_agent.hardware.dispatch_to_managers', + autospec=True) + @mock.patch.object(hardware, 'get_cached_node', autospec=True) + def test_update_node_cache(self, mock_cached_node, mock_dispatch): + mock_cached_node.return_value = {'uuid': 'node1'} + updated_node = {'uuid': 'node1', 'other': 'key'} + hardware.API_CLIENT = None + mock_api_client = mock.Mock() + hardware.save_api_client(mock_api_client, 1, 2) + mock_api_client.lookup_node.return_value = {'node': updated_node} + self.assertEqual(updated_node, hardware.update_cached_node()) + mock_api_client.lookup_node.assert_called_with( + hardware_info=mock.ANY, + timeout=1, + starting_interval=2, + uuid='node1') + self.assertEqual(updated_node, hardware.NODE) + calls = [mock.call('list_hardware_info'), + mock.call('wait_for_disks')] + mock_dispatch.assert_has_calls(calls) -- cgit v1.2.1