Fix volume deletion on newer iDRACs

Fixes 'Unsupported parameter name @Redfish.OperationApplyTime' General
error on iDRAC firmware version 6.00.02.00 or newer when deleting
volumes.
Handles the failure of volume.delete by retrying without operation
apply time. In older iDRAC firmware versions operation apply time was
silently ignored, but now in newer iDRAC firmware versions it is
returning 501 Not Implemented error.

Change-Id: Ia421ff025f1f0bc72252b5441589beb2e53cc25a
This commit is contained in:
Kamlesh Chauvhan 2022-11-17 07:46:29 +00:00 committed by Aija Jauntēva
parent 56efdee0ee
commit 74f95b1dd5
3 changed files with 99 additions and 2 deletions

View File

@ -0,0 +1,4 @@
fixes:
- |
Fixes 'Unsupported parameter name @Redfish.OperationApplyTime' error
on iDRAC firmware version 6.00.02.00 or newer when deleting volumes.

View File

@ -136,8 +136,22 @@ class Volume(base.ResourceBase):
if (payload and payload.get(_OAT_PROP)
== res_cons.ApplyTime.IMMEDIATE.value):
blocking = True
r = self._conn.delete(self._path, data=payload, blocking=blocking,
timeout=timeout)
try:
r = self._conn.delete(self._path, data=payload,
blocking=blocking, timeout=timeout)
except exceptions.ServerSideError as exc:
if (_OAT_PROP in str(exc.message)
and 'SYS029' in str(exc.message)):
LOG.debug('Retry volume delete without %(prop)s for %(path)s '
'because got error: %(err)s',
{'prop': _OAT_PROP,
'path': self._path,
'err': exc})
payload.pop(_OAT_PROP)
r = self._conn.delete(self._path, data=payload,
blocking=blocking, timeout=timeout)
else:
raise exc
return r
def delete(self, payload=None, apply_time=None, timeout=500):

View File

@ -16,6 +16,7 @@ from unittest import mock
from dateutil import parser
import sushy
from sushy import exceptions
from sushy.resources import constants as res_cons
from sushy.resources.system.storage import constants as store_cons
from sushy.resources.system.storage import volume
@ -106,6 +107,84 @@ class VolumeTestCase(base.TestCase):
self.assertEqual(task_mon.task_monitor_uri,
'/redfish/v1/taskmon/4608f7e6')
@mock.patch.object(volume.LOG, 'debug', autospec=True)
def test_delete_retry_on_501_sys029_apply_time(self, mock_debug):
payload = {}
_OAT_PROP = '@Redfish.OperationApplyTime'
payload[_OAT_PROP] = 'Immediate'
target_uri = '/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes/1'
response_info = {"error": {"@Message.ExtendedInfo": [
{'Message': '@Redfish.OperationApplyTime.',
'MessageId': 'IDRAC.2.7.SYS029'}]}}
mock_error = mock.Mock()
mock_error.status_code = 501
mock_error.json.return_value = response_info
mock_success = mock.Mock()
mock_success.status_code = 201
self.conn.delete.side_effect = [exceptions.ServerSideError(
method='DELETE', url=target_uri, response=mock_error),
mock_success]
resource = self.stor_volume.delete(
payload=payload, apply_time=res_cons.ApplyTime.IMMEDIATE)
self.assertIsNone(resource)
self.assertEqual(2, self.stor_volume._conn.delete.call_count)
expected_calls = [
mock.call(self.stor_volume._path, data=payload, blocking=True,
timeout=500),
mock.call(self.stor_volume._path, data={}, blocking=True,
timeout=500)
]
self.stor_volume._conn.delete.assert_has_calls(expected_calls)
mock_debug.assert_called_once()
@mock.patch.object(volume.LOG, 'debug', autospec=True)
def test_delete_retry_on_501_sys029_other(self, mock_debug):
payload = {}
_OAT_PROP = '@Redfish.OperationApplyTime'
payload[_OAT_PROP] = 'Immediate'
target_uri = '/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes/1'
response_info = {"error": {"@Message.ExtendedInfo": [
{'Message': '@Redfish.SomethingElse.',
'MessageId': 'IDRAC.2.7.SYS029'}]}}
mock_error = mock.Mock()
mock_error.status_code = 501
mock_error.json.return_value = response_info
mock_success = mock.Mock()
mock_success.status_code = 201
self.conn.delete.side_effect = [exceptions.ServerSideError(
method='DELETE', url=target_uri, response=mock_error),
mock_success]
self.assertRaises(exceptions.ServerSideError, self.stor_volume.delete,
payload=payload,
apply_time=res_cons.ApplyTime.IMMEDIATE)
self.stor_volume._conn.delete.assert_called_once_with(
self.stor_volume._path, data=payload, blocking=True, timeout=500)
mock_debug.assert_not_called()
@mock.patch.object(volume.LOG, 'debug', autospec=True)
def test_delete_raise_on_501_other(self, mock_debug):
payload = {}
_OAT_PROP = '@Redfish.OperationApplyTime'
payload[_OAT_PROP] = 'Immediate'
target_uri = '/redfish/v1/Systems/437XR1138R2/Storage/1/Volumes/1'
response_info = {"error": {"@Message.ExtendedInfo": [
{'Message': 'Other message.'}]}}
mock_error = mock.Mock()
mock_error.status_code = 501
mock_error.json.return_value = response_info
self.conn.delete.side_effect = [exceptions.ServerSideError(
method='DELETE', url=target_uri, response=mock_error)]
self.assertRaises(exceptions.ServerSideError, self.stor_volume.delete,
payload=payload,
apply_time=res_cons.ApplyTime.IMMEDIATE)
self.stor_volume._conn.delete.assert_called_once_with(
self.stor_volume._path, data=payload, blocking=True, timeout=500)
mock_debug.assert_not_called()
class VolumeCollectionTestCase(base.TestCase):