diff --git a/sushy_oem_idrac/resources/manager/manager.py b/sushy_oem_idrac/resources/manager/manager.py
index 4c4c1a2..e6ef42c 100644
--- a/sushy_oem_idrac/resources/manager/manager.py
+++ b/sushy_oem_idrac/resources/manager/manager.py
@@ -238,8 +238,8 @@ VFDD\
return response
- except (sushy.exceptions.ServerSideError,
- sushy.exceptions.BadRequestError) as exc:
+ except sushy.exceptions.HTTPError as exc:
+
LOG.warning(
'Dell OEM set boot device failed (attempts left '
'%d): %s', attempts, exc)
@@ -247,6 +247,8 @@ VFDD\
errors = exc.body and exc.body.get(
'@Message.ExtendedInfo') or []
+ found = False
+
for error in errors:
message_id = error.get('MessageId')
@@ -254,6 +256,7 @@ VFDD\
error.get('Message', 'Unknown error'))
if constants.IDRAC_CONFIG_PENDING in message_id:
+ found = True
if not rebooted:
LOG.warning(
'Let\'s try to turn it off and on again... '
@@ -264,10 +267,14 @@ VFDD\
break
elif constants.IDRAC_JOB_RUNNING in message_id:
+ found = True
pass
else:
- time.sleep(self.RETRY_DELAY)
+ if found:
+ time.sleep(self.RETRY_DELAY)
+ else:
+ raise
if not attempts:
LOG.error('Too many (%d) retries, bailing '
diff --git a/sushy_oem_idrac/tests/unit/json_samples/error_pending_job.json b/sushy_oem_idrac/tests/unit/json_samples/error_pending_job.json
new file mode 100644
index 0000000..7a61f4d
--- /dev/null
+++ b/sushy_oem_idrac/tests/unit/json_samples/error_pending_job.json
@@ -0,0 +1,18 @@
+{
+ "error": {
+ "@Message.ExtendedInfo": [
+ {
+ "Message": "Unable to perform the import or export operation because there are pending attribute changes or a configuration job is in progress.",
+ "MessageArgs": "[]",
+ "MessageArgs@odata.count": 0,
+ "MessageId": "IDRAC.2.8.LC068",
+ "RelatedProperties": [],
+ "RelatedProperties@odata.count": 0,
+ "Resolution": "Apply or cancel any pending attribute changes. Changes can be applied by creating a targeted configuration job, or the changes can be cancelled by invoking the DeletePendingConfiguration method. If a configuration job is in progress, wait until it is completed before retrying the import or export system configuration operation.",
+ "Severity": "Warning"
+ }
+ ],
+ "code": "IDRAC.2.8.LC068",
+ "message": "Unable to perform the import or export operation because there are pending attribute changes or a configuration job is in progress."
+ }
+}
diff --git a/sushy_oem_idrac/tests/unit/json_samples/error_running_job.json b/sushy_oem_idrac/tests/unit/json_samples/error_running_job.json
new file mode 100644
index 0000000..aa634a8
--- /dev/null
+++ b/sushy_oem_idrac/tests/unit/json_samples/error_running_job.json
@@ -0,0 +1,18 @@
+{
+ "error": {
+ "@Message.ExtendedInfo": [
+ {
+ "Message": "A job operation is already running. Retry the operation after the existing job is completed.",
+ "MessageArgs": "[]",
+ "MessageArgs@odata.count": 0,
+ "MessageId": "IDRAC.2.8.RAC0679",
+ "RelatedProperties": [],
+ "RelatedProperties@odata.count": 0,
+ "Resolution": "Wait until the running job is completed or delete the scheduled job and retry the operation",
+ "Severity": "Warning"
+ }
+ ],
+ "code": "IDRAC.2.8.RAC0679",
+ "message": "Wait until the running job is completed or delete the scheduled job and retry the operation."
+ }
+}
diff --git a/sushy_oem_idrac/tests/unit/json_samples/releasenotes/notes/fix-lc-wait-loop-cebbee222d3dc7c3.yaml b/sushy_oem_idrac/tests/unit/json_samples/releasenotes/notes/fix-lc-wait-loop-cebbee222d3dc7c3.yaml
new file mode 100644
index 0000000..a9bc1a8
--- /dev/null
+++ b/sushy_oem_idrac/tests/unit/json_samples/releasenotes/notes/fix-lc-wait-loop-cebbee222d3dc7c3.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+ - |
+ Resolves the issue where wait for Lifecycle Controller job ends prematurely
+ due to iDRAC BMC raising a different exception type than the code
+ previously expected by using the correct exception class.
diff --git a/sushy_oem_idrac/tests/unit/resources/manager/test_manager.py b/sushy_oem_idrac/tests/unit/resources/manager/test_manager.py
index 350dff2..84fc7a9 100644
--- a/sushy_oem_idrac/tests/unit/resources/manager/test_manager.py
+++ b/sushy_oem_idrac/tests/unit/resources/manager/test_manager.py
@@ -14,10 +14,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+from http import client as http_client
import json
from unittest import mock
from oslotest.base import BaseTestCase
+import requests
import sushy
from sushy.resources.manager import manager
from sushy.taskmonitor import TaskMonitor
@@ -94,6 +96,91 @@ class ManagerTestCase(BaseTestCase):
'#FirstBootDevice">VCD-DVD'
''})
+ @mock.patch('time.sleep', autospec=True)
+ @mock.patch('sushy.resources.oem.common._global_extn_mgrs_by_resource', {})
+ def test_set_virtual_boot_device_cd_running_exc(self, mock_sleep):
+ oem = self.manager.get_oem_extension('Dell')
+
+ with open('sushy_oem_idrac/tests/unit/json_samples/'
+ 'error_running_job.json') as f:
+ response_obj = json.load(f)
+
+ response1 = mock.MagicMock(spec=requests.Response)
+ response1.status_code = http_client.BAD_REQUEST
+ response1.json.return_value = response_obj
+ response1.code = "IDRAC.2.8.LC068"
+
+ response2 = mock.MagicMock(spec=requests.Response)
+ response2.status_code = http_client.OK
+
+ self.conn.post.side_effect = [sushy.exceptions.HTTPError(
+ method='POST', url=self.manager.path, response=response1),
+ response2]
+
+ oem.set_virtual_boot_device(
+ sushy.VIRTUAL_MEDIA_CD, manager=self.manager)
+
+ self.conn.post.assert_called_with(
+ '/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Oem/EID_674_Manager'
+ '.ImportSystemConfiguration',
+ data={'ShareParameters': {'Target': 'ALL'},
+ 'ImportBuffer':
+ ''
+ 'Enabled'
+ 'VCD-DVD'
+ ''})
+
+ @mock.patch('sushy_oem_idrac.utils.reboot_system', autospec=True)
+ @mock.patch('sushy.resources.oem.common._global_extn_mgrs_by_resource', {})
+ def test_set_virtual_boot_device_cd_pending_exc(self, mock_reboot):
+ oem = self.manager.get_oem_extension('Dell')
+
+ with open('sushy_oem_idrac/tests/unit/json_samples/'
+ 'error_pending_job.json') as f:
+ response_obj = json.load(f)
+
+ response1 = mock.MagicMock(spec=requests.Response)
+ response1.status_code = http_client.BAD_REQUEST
+ response1.json.return_value = response_obj
+ response1.code = "IDRAC.2.8.LC068"
+
+ response2 = mock.MagicMock(spec=requests.Response)
+ response2.status_code = http_client.OK
+
+ self.conn.post.side_effect = [sushy.exceptions.HTTPError(
+ method='POST', url=self.manager.path, response=response1),
+ response2]
+
+ oem.set_virtual_boot_device(
+ sushy.VIRTUAL_MEDIA_CD, manager=self.manager)
+
+ self.conn.post.assert_called_with(
+ '/redfish/v1/Managers/iDRAC.Embedded.1/Actions/Oem/EID_674_Manager'
+ '.ImportSystemConfiguration',
+ data={'ShareParameters': {'Target': 'ALL'},
+ 'ImportBuffer':
+ ''
+ 'Enabled'
+ 'VCD-DVD'
+ ''})
+
+ @mock.patch('sushy.resources.oem.common._global_extn_mgrs_by_resource', {})
+ def test_set_virtual_boot_device_cd_other_exc(self):
+ oem = self.manager.get_oem_extension('Dell')
+
+ response = mock.MagicMock(spec=requests.Response)
+ response.status_code = http_client.FORBIDDEN
+
+ self.conn.post.side_effect = sushy.exceptions.HTTPError(
+ method='POST', url=self.manager.path, response=response)
+
+ self.assertRaises(sushy.exceptions.HTTPError,
+ oem.set_virtual_boot_device,
+ sushy.VIRTUAL_MEDIA_CD,
+ manager=self.manager)
+
@mock.patch('sushy.resources.oem.common._global_extn_mgrs_by_resource', {})
def test_get_allowed_export_target_values(self):
oem = self.manager.get_oem_extension('Dell')