From 5de0ccccd69258b930ed8ab7b91ca3a1aad705c1 Mon Sep 17 00:00:00 2001 From: Xavier Date: Wed, 9 Aug 2017 01:55:29 -0300 Subject: [PATCH] Fix persistent information when getting boot device This patches fixes the get_boot_device methods for oneview drivers to consider onetime boot option on the machine's iLO. If onetime boot is set to 'Once' on iLO, the method will return persistent as False (not persistent), True otherwise (persistent). Change-Id: Iae837a304003cb6c17d5c40d039469b418c97421 Closes-Bug: #1706725 --- ironic/drivers/modules/oneview/management.py | 32 +++++++- .../modules/oneview/test_management.py | 78 ++++++++++++++++--- ...evice-not-persistent-5d6acffac3b287f7.yaml | 6 ++ 3 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 releasenotes/notes/fix-get-boot-device-not-persistent-5d6acffac3b287f7.yaml diff --git a/ironic/drivers/modules/oneview/management.py b/ironic/drivers/modules/oneview/management.py index b7b18c8cae..5984b906a3 100644 --- a/ironic/drivers/modules/oneview/management.py +++ b/ironic/drivers/modules/oneview/management.py @@ -49,6 +49,10 @@ BOOT_DEVICE_MAP_ILO = { BOOT_DEVICE_MAP_ILO_REV = { v: k for k, v in BOOT_DEVICE_MAP_ILO.items()} +ILO_SYSTEM_PATH = "/rest/v1/Systems/1" + +ILO_REQUEST_HEADERS = {"Content-Type": "application/json"} + def set_onetime_boot(task): """Set onetime boot to server hardware. @@ -69,15 +73,35 @@ def set_onetime_boot(task): server_hardware = task.node.driver_info.get('server_hardware_uri') ilo_client = common.get_ilorest_client(client, server_hardware) boot_device = BOOT_DEVICE_MAP_ILO.get(boot_device) - path = '/rest/v1/Systems/1' body = { "Boot": { "BootSourceOverrideTarget": boot_device, "BootSourceOverrideEnabled": "Once" } } - headers = {"Content-Type": "application/json"} - ilo_client.patch(path=path, body=body, headers=headers) + ilo_client.patch(path=ILO_SYSTEM_PATH, body=body, + headers=ILO_REQUEST_HEADERS) + + +def _is_onetime_boot(task): + """Check onetime boot from server hardware. + + Check if the onetime boot option of an OneView server hardware + is set to 'Once' in iLO. + + :param task: a task from TaskManager. + :returns: Boolean value. True if onetime boot is 'Once' + False otherwise. + + """ + client = common.get_hponeview_client() + server_hardware = task.node.driver_info.get('server_hardware_uri') + ilo_client = common.get_ilorest_client(client, server_hardware) + response = ilo_client.get(path=ILO_SYSTEM_PATH, + headers=ILO_REQUEST_HEADERS) + boot = response.dict.get('Boot') + onetime_boot = boot.get('BootSourceOverrideEnabled') + return onetime_boot == 'Once' def set_boot_device(task): @@ -269,7 +293,7 @@ class OneViewManagement(base.ManagementInterface): boot_device = { 'boot_device': BOOT_DEVICE_MAP_ONEVIEW_REV.get(primary_device), - 'persistent': True, + 'persistent': not _is_onetime_boot(task) } return boot_device diff --git a/ironic/tests/unit/drivers/modules/oneview/test_management.py b/ironic/tests/unit/drivers/modules/oneview/test_management.py index a8be001ed4..9b0054faea 100644 --- a/ironic/tests/unit/drivers/modules/oneview/test_management.py +++ b/ironic/tests/unit/drivers/modules/oneview/test_management.py @@ -82,14 +82,12 @@ class OneViewManagementDriverFunctionsTestCase(db_base.DbTestCase): client.server_profiles.get.return_value = server_profile boot_device_map_ilo = management.BOOT_DEVICE_MAP_ILO boot_device = boot_device_map_ilo.get(boot_devices.PXE) - path = '/rest/v1/Systems/1' body = { "Boot": { "BootSourceOverrideTarget": boot_device, "BootSourceOverrideEnabled": "Once" } } - headers = {"Content-Type": "application/json"} with task_manager.acquire(self.context, self.node.uuid) as task: driver_info = task.node.driver_info profile_uri = driver_info.get('applied_server_profile_uri') @@ -103,7 +101,10 @@ class OneViewManagementDriverFunctionsTestCase(db_base.DbTestCase): update.assert_called_once_with(server_profile, profile_uri) patch = ilo_client.patch patch.assert_called_once_with( - path=path, body=body, headers=headers) + path=management.ILO_SYSTEM_PATH, + body=body, + headers=management.ILO_REQUEST_HEADERS + ) driver_internal_info = task.node.driver_internal_info self.assertNotIn('next_boot_device', driver_internal_info) @@ -158,14 +159,12 @@ class OneViewManagementDriverFunctionsTestCase(db_base.DbTestCase): self, mock_iloclient, mock_get_ov_client): ilo_client = mock_iloclient() boot_device = management.BOOT_DEVICE_MAP_ILO.get(boot_devices.DISK) - path = '/rest/v1/Systems/1' body = { "Boot": { "BootSourceOverrideTarget": boot_device, "BootSourceOverrideEnabled": "Once" } } - headers = {"Content-Type": "application/json"} with task_manager.acquire(self.context, self.node.uuid) as task: driver_internal_info = task.node.driver_internal_info next_boot_device = {'boot_device': 'disk', 'persistent': False} @@ -174,7 +173,48 @@ class OneViewManagementDriverFunctionsTestCase(db_base.DbTestCase): management.set_onetime_boot(task) self.assertTrue(mock_iloclient.called) ilo_client.patch.assert_called_with( - path=path, body=body, headers=headers) + path=management.ILO_SYSTEM_PATH, + body=body, + headers=management.ILO_REQUEST_HEADERS + ) + + @mock.patch.object(common, 'get_ilorest_client') + def test__is_onetime_boot_true( + self, mock_iloclient, mock_get_ov_client): + + class RestResponse(object): + @property + def dict(self): + return {'Boot': {'BootSourceOverrideEnabled': "Once"}} + + ilo_client = mock_iloclient() + ilo_client.get.return_value = RestResponse() + with task_manager.acquire(self.context, self.node.uuid) as task: + self.assertTrue(management._is_onetime_boot(task)) + self.assertTrue(mock_iloclient.called) + ilo_client.get.assert_called_with( + path=management.ILO_SYSTEM_PATH, + headers=management.ILO_REQUEST_HEADERS + ) + + @mock.patch.object(common, 'get_ilorest_client') + def test__is_onetime_boot_false( + self, mock_iloclient, mock_get_ov_client): + + class RestResponse(object): + @property + def dict(self): + return {'Boot': {'BootSourceOverrideEnabled': "Disabled"}} + + ilo_client = mock_iloclient() + ilo_client.get.return_value = RestResponse() + with task_manager.acquire(self.context, self.node.uuid) as task: + self.assertFalse(management._is_onetime_boot(task)) + self.assertTrue(mock_iloclient.called) + ilo_client.get.assert_called_with( + path=management.ILO_SYSTEM_PATH, + headers=management.ILO_REQUEST_HEADERS + ) @mock.patch.object(common, 'get_hponeview_client') @@ -275,8 +315,11 @@ class OneViewManagementDriverTestCase(db_base.DbTestCase): task.driver.management.get_supported_boot_devices(task), ) - def test_get_boot_device(self, mock_get_ov_client): + @mock.patch.object(common, 'get_ilorest_client') + def test_get_boot_device( + self, mock_ilo_client, mock_get_ov_client): client = mock_get_ov_client() + ilo_client = mock_ilo_client() self.driver.management.client = client device_mapping = management.BOOT_DEVICE_MAP_ONEVIEW.items() with task_manager.acquire(self.context, self.node.uuid) as task: @@ -289,10 +332,14 @@ class OneViewManagementDriverTestCase(db_base.DbTestCase): response = self.driver.management.get_boot_device(task) self.assertEqual(expected, response) self.assertTrue(client.server_profiles.get.called) + self.assertTrue(client.server_profiles.get.called) + self.assertTrue(ilo_client.get.called) + @mock.patch.object(common, 'get_ilorest_client') def test_get_boot_device_from_next_boot_device( - self, mock_get_ov_client): + self, mock_ilo_client, mock_get_ov_client): client = mock_get_ov_client() + ilo_client = mock_ilo_client() self.driver.management.client = client with task_manager.acquire(self.context, self.node.uuid) as task: @@ -307,10 +354,14 @@ class OneViewManagementDriverTestCase(db_base.DbTestCase): } response = self.driver.management.get_boot_device(task) self.assertEqual(expected_response, response) - self.assertFalse(client.get_boot_order.called) + self.assertFalse(client.get_boot_order.called) + self.assertFalse(ilo_client.get.called) - def test_get_boot_device_fail(self, mock_get_ov_client): + @mock.patch.object(common, 'get_ilorest_client') + def test_get_boot_device_fail( + self, mock_ilo_client, mock_get_ov_client): client = mock_get_ov_client() + ilo_client = mock_ilo_client() self.driver.management.client = client exc = client_exception.HPOneViewException() client.server_profiles.get.side_effect = exc @@ -321,9 +372,13 @@ class OneViewManagementDriverTestCase(db_base.DbTestCase): task ) self.assertTrue(client.server_profiles.get.called) + self.assertFalse(ilo_client.get.called) - def test_get_boot_device_unknown_device(self, mock_get_ov_client): + @mock.patch.object(common, 'get_ilorest_client') + def test_get_boot_device_unknown_device( + self, mock_ilo_client, mock_get_ov_client): client = mock_get_ov_client() + ilo_client = mock_ilo_client() order = ['Eggs', 'Bacon'] profile = {'boot': {'order': order}} client.server_profiles.get.return_value = profile @@ -334,6 +389,7 @@ class OneViewManagementDriverTestCase(db_base.DbTestCase): task.driver.management.get_boot_device, task ) + self.assertFalse(ilo_client.get.called) def test_get_sensors_data_not_implemented(self, mock_get_ov_client): with task_manager.acquire(self.context, self.node.uuid) as task: diff --git a/releasenotes/notes/fix-get-boot-device-not-persistent-5d6acffac3b287f7.yaml b/releasenotes/notes/fix-get-boot-device-not-persistent-5d6acffac3b287f7.yaml new file mode 100644 index 0000000000..2bd971c50e --- /dev/null +++ b/releasenotes/notes/fix-get-boot-device-not-persistent-5d6acffac3b287f7.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixes ``get_boot_device`` method from oneview drivers' management interface. + Now the method returns the persistent boot option correctly, based on the + iLO information of the node.