Merge "Fix missing ETag when patching Redfish resource"
This commit is contained in:
commit
b87bc5448d
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixes missing ETag in PATCH operation against Redfish resources with
|
||||
backward compatibility for Redfish implementation which doesn't work
|
||||
with ETag in header.
|
|
@ -214,9 +214,10 @@ class Chassis(base.ResourceBase):
|
|||
parameter='state', value=state,
|
||||
valid_values=' ,'.join(i.value for i in res_cons.IndicatorLED))
|
||||
|
||||
etag = self._get_etag()
|
||||
data = {'IndicatorLED': state}
|
||||
|
||||
self._conn.patch(self.path, data=data)
|
||||
self._conn.patch(self.path, data=data, etag=etag)
|
||||
self.invalidate()
|
||||
|
||||
@property
|
||||
|
|
|
@ -248,8 +248,10 @@ class VirtualMedia(base.ResourceBase):
|
|||
parameter='verify_certificate', value=verify_certificate,
|
||||
valid_values='boolean (True, False)')
|
||||
|
||||
etag = self._get_etag()
|
||||
self._conn.patch(self.path,
|
||||
data={'VerifyCertificate': verify_certificate})
|
||||
data={'VerifyCertificate': verify_certificate},
|
||||
etag=etag)
|
||||
self.invalidate()
|
||||
|
||||
@property
|
||||
|
|
|
@ -170,7 +170,7 @@ class SettingsField(base.CompositeField):
|
|||
:returns: Response object
|
||||
"""
|
||||
|
||||
return connector.patch(self.resource_uri, data=value)
|
||||
return connector.patch(self.resource_uri, data=value, etag=self._etag)
|
||||
|
||||
@property
|
||||
def resource_uri(self):
|
||||
|
|
|
@ -149,6 +149,10 @@ class Bios(base.ResourceBase):
|
|||
payload = utils.process_apply_time_input(
|
||||
payload, apply_time, maint_window_start_time,
|
||||
maint_window_duration)
|
||||
# NOTE(vanou): To retrieve current ETag value of @Redfish.Settings
|
||||
# but not update cached _pending_settings_resource, because cached
|
||||
# property is only this one and re-cache is not required
|
||||
self.refresh(force=False)
|
||||
self._settings.commit(self._conn,
|
||||
payload)
|
||||
utils.cache_clear(self, force_refresh=False,
|
||||
|
|
|
@ -144,4 +144,6 @@ class SecureBoot(base.ResourceBase):
|
|||
raise exceptions.InvalidParameterValueError(
|
||||
"Expected a boolean for 'enabled', got %r" % enabled)
|
||||
|
||||
self._conn.patch(self.path, data={'SecureBootEnable': enabled})
|
||||
etag = self._get_etag()
|
||||
self._conn.patch(self.path, data={'SecureBootEnable': enabled},
|
||||
etag=etag)
|
||||
|
|
|
@ -97,6 +97,10 @@ class StorageController(base.ResourceBase):
|
|||
payload = utils.process_apply_time_input(
|
||||
payload, apply_time, maint_window_start_time,
|
||||
maint_window_duration)
|
||||
# NOTE(vanou): To retrieve current ETag value of @Redfish.Settings
|
||||
# but not update cached pending_settings, because cached property is
|
||||
# only this one and re-cache this is not required
|
||||
self.refresh(force=False)
|
||||
r = self._settings.commit(self._conn, payload)
|
||||
utils.cache_clear(self, force_refresh=False,
|
||||
only_these=['pending_settings'])
|
||||
|
|
|
@ -102,7 +102,8 @@ class Drive(base.ResourceBase):
|
|||
parameter='state', value=state,
|
||||
valid_values=' ,'.join(i.value for i in res_cons.IndicatorLED))
|
||||
|
||||
etag = self._get_etag()
|
||||
data = {'IndicatorLED': state}
|
||||
|
||||
self._conn.patch(self.path, data=data)
|
||||
self._conn.patch(self.path, data=data, etag=etag)
|
||||
self.invalidate()
|
||||
|
|
|
@ -342,9 +342,10 @@ class System(base.ResourceBase):
|
|||
parameter='state', value=state,
|
||||
valid_values=' ,'.join(i.value for i in res_cons.IndicatorLED))
|
||||
|
||||
etag = self._get_etag()
|
||||
data = {'IndicatorLED': state}
|
||||
|
||||
self._conn.patch(self.path, data=data)
|
||||
self._conn.patch(self.path, data=data, etag=etag)
|
||||
self.invalidate()
|
||||
|
||||
def _get_processor_collection_path(self):
|
||||
|
|
|
@ -34,6 +34,7 @@ class ChassisTestCase(base.TestCase):
|
|||
self.json_doc = json.load(f)
|
||||
|
||||
self.conn.get.return_value.json.return_value = self.json_doc
|
||||
self.conn.get.return_value.headers = {'ETag': 'd37f7bcd528e4d59'}
|
||||
|
||||
self.chassis = chassis.Chassis(self.conn, '/redfish/v1/Chassis/Blade1',
|
||||
redfish_version='1.8.0')
|
||||
|
@ -144,7 +145,8 @@ class ChassisTestCase(base.TestCase):
|
|||
self.chassis.set_indicator_led(sushy.IndicatorLED.BLINKING)
|
||||
self.chassis._conn.patch.assert_called_once_with(
|
||||
'/redfish/v1/Chassis/Blade1',
|
||||
data={'IndicatorLED': 'Blinking'})
|
||||
data={'IndicatorLED': 'Blinking'},
|
||||
etag='d37f7bcd528e4d59')
|
||||
|
||||
invalidate_mock.assert_called_once_with()
|
||||
|
||||
|
|
|
@ -294,13 +294,16 @@ class VirtualMediaTestCase(base.TestCase):
|
|||
self.assertTrue(self.sys_virtual_media._is_stale)
|
||||
|
||||
def test_set_verify_certificate(self):
|
||||
self.conn.get.return_value.headers = {'Allow': 'GET,HEAD',
|
||||
'ETag': '3d7b8a7360bf2941d'}
|
||||
with mock.patch.object(
|
||||
self.sys_virtual_media, 'invalidate',
|
||||
autospec=True) as invalidate_mock:
|
||||
self.sys_virtual_media.set_verify_certificate(True)
|
||||
self.sys_virtual_media._conn.patch.assert_called_once_with(
|
||||
"/redfish/v1/Managers/BMC/VirtualMedia/Floppy1",
|
||||
data={'VerifyCertificate': True})
|
||||
data={'VerifyCertificate': True},
|
||||
etag='3d7b8a7360bf2941d')
|
||||
|
||||
invalidate_mock.assert_called_once_with()
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ class ControllerTestCase(base.TestCase):
|
|||
self.controller.supported_apply_times)
|
||||
|
||||
def test_update(self):
|
||||
self.conn.get.return_value.json.side_effect = [
|
||||
self.json_doc, self.json_doc]
|
||||
mock_response = mock.Mock()
|
||||
mock_response.status_code = http_client.ACCEPTED
|
||||
mock_response.headers = {'Content-Length': 42,
|
||||
|
@ -81,7 +83,8 @@ class ControllerTestCase(base.TestCase):
|
|||
data={'ControllerRates': {'ConsistencyCheckRatePercent': 30},
|
||||
'@Redfish.SettingsApplyTime': {
|
||||
'@odata.type': '#Settings.v1_0_0.PreferredApplyTime',
|
||||
'ApplyTime': 'OnReset'}})
|
||||
'ApplyTime': 'OnReset'}},
|
||||
etag=None)
|
||||
self.assertIsInstance(tm, taskmonitor.TaskMonitor)
|
||||
self.assertEqual('/Task/545', tm.task_monitor_uri)
|
||||
|
||||
|
|
|
@ -83,13 +83,15 @@ class DriveTestCase(base.TestCase):
|
|||
self.assertEqual('3', volumes[1].identity)
|
||||
|
||||
def test_set_indicator_led(self):
|
||||
self.conn.get.return_value.headers = {'ETag': 'a3b01b63f80a4913'}
|
||||
with mock.patch.object(
|
||||
self.stor_drive, 'invalidate',
|
||||
autospec=True) as invalidate_mock:
|
||||
self.stor_drive.set_indicator_led(sushy.IndicatorLED.BLINKING)
|
||||
self.stor_drive._conn.patch.assert_called_once_with(
|
||||
'/redfish/v1/Systems/437XR1138/Storage/1/Drives/'
|
||||
'32ADF365C6C1B7BD', data={'IndicatorLED': 'Blinking'})
|
||||
'32ADF365C6C1B7BD', data={'IndicatorLED': 'Blinking'},
|
||||
etag='a3b01b63f80a4913')
|
||||
|
||||
invalidate_mock.assert_called_once_with()
|
||||
|
||||
|
|
|
@ -119,6 +119,10 @@ class BiosTestCase(base.TestCase):
|
|||
attributes.get('maintenance_window'))
|
||||
|
||||
def test_set_attribute_apply_time(self):
|
||||
self.conn.get.return_value.json.side_effect = [
|
||||
self.bios_json,
|
||||
self.bios_json]
|
||||
|
||||
self.sys_bios.set_attribute(
|
||||
'ProcTurboMode', 'Disabled',
|
||||
res_cons.ApplyTime.IN_MAINTENANCE_WINDOW_ON_RESET,
|
||||
|
@ -131,9 +135,15 @@ class BiosTestCase(base.TestCase):
|
|||
'@odata.type': '#Settings.v1_0_0.PreferredApplyTime',
|
||||
'ApplyTime': 'InMaintenanceWindowOnReset',
|
||||
'MaintenanceWindowStartTime': '2020-09-01T04:30:00',
|
||||
'MaintenanceWindowDurationInSeconds': 600}})
|
||||
'MaintenanceWindowDurationInSeconds': 600}},
|
||||
etag='9234ac83b9700123cc32')
|
||||
|
||||
def test_set_attribute_on_refresh(self):
|
||||
self.conn.get.return_value.json.side_effect = [
|
||||
self.bios_settings_json,
|
||||
self.bios_json,
|
||||
self.bios_settings_json]
|
||||
|
||||
self.conn.get.reset_mock()
|
||||
# make it to instantiate pending attributes
|
||||
self.sys_bios.pending_attributes
|
||||
|
@ -150,6 +160,9 @@ class BiosTestCase(base.TestCase):
|
|||
self.assertTrue(self.conn.get.called)
|
||||
|
||||
def test_set_attributes(self):
|
||||
self.conn.get.return_value.json.side_effect = [
|
||||
self.bios_json]
|
||||
|
||||
self.sys_bios.set_attributes(
|
||||
{'ProcTurboMode': 'Disabled', 'UsbControl': 'UsbDisabled'},
|
||||
res_cons.ApplyTime.AT_MAINTENANCE_WINDOW_START,
|
||||
|
@ -163,9 +176,15 @@ class BiosTestCase(base.TestCase):
|
|||
'@odata.type': '#Settings.v1_0_0.PreferredApplyTime',
|
||||
'ApplyTime': 'AtMaintenanceWindowStart',
|
||||
'MaintenanceWindowStartTime': '2020-09-01T04:30:00',
|
||||
'MaintenanceWindowDurationInSeconds': 600}})
|
||||
'MaintenanceWindowDurationInSeconds': 600}},
|
||||
etag='9234ac83b9700123cc32')
|
||||
|
||||
def test_set_attributes_on_refresh(self):
|
||||
self.conn.get.return_value.json.side_effect = [
|
||||
self.bios_settings_json,
|
||||
self.bios_json,
|
||||
self.bios_settings_json]
|
||||
|
||||
self.conn.get.reset_mock()
|
||||
# make it to instantiate pending attributes
|
||||
self.sys_bios.pending_attributes
|
||||
|
|
|
@ -29,6 +29,7 @@ class SecureBootTestCase(base.TestCase):
|
|||
self.secure_boot_json = json.load(f)
|
||||
|
||||
self.conn.get.return_value.json.return_value = self.secure_boot_json
|
||||
self.conn.get.return_value.headers = {'ETag': 'b26ae716a2c1f39f'}
|
||||
self.secure_boot = secure_boot.SecureBoot(
|
||||
self.conn, '/redfish/v1/Systems/437XR1138R2/SecureBoot',
|
||||
registries={}, redfish_version='1.1.0')
|
||||
|
@ -79,7 +80,8 @@ class SecureBootTestCase(base.TestCase):
|
|||
self.secure_boot.set_enabled(True)
|
||||
self.conn.patch.assert_called_once_with(
|
||||
'/redfish/v1/Systems/437XR1138R2/SecureBoot',
|
||||
data={'SecureBootEnable': True})
|
||||
data={'SecureBootEnable': True},
|
||||
etag='b26ae716a2c1f39f')
|
||||
|
||||
def test_set_enabled_wrong_type(self):
|
||||
self.assertRaises(exceptions.InvalidParameterValueError,
|
||||
|
|
|
@ -46,6 +46,8 @@ class SystemTestCase(base.TestCase):
|
|||
self.sys_inst = system.System(
|
||||
self.conn, '/redfish/v1/Systems/437XR1138R2',
|
||||
redfish_version='1.0.2')
|
||||
self.sys_inst._get_etag = mock.Mock()
|
||||
self.sys_inst._get_etag.return_value = '81802dbf61beb0bd'
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.sys_inst._parse_attributes(self.json_doc)
|
||||
|
@ -283,7 +285,7 @@ class SystemTestCase(base.TestCase):
|
|||
data={'Boot': {'BootSourceOverrideEnabled': 'Continuous',
|
||||
'BootSourceOverrideTarget': 'Pxe',
|
||||
'BootSourceOverrideMode': 'UEFI'}},
|
||||
etag=None)
|
||||
etag='81802dbf61beb0bd')
|
||||
|
||||
def test_set_system_boot_options_no_mode_specified(self):
|
||||
self.sys_inst.set_system_boot_options(
|
||||
|
@ -293,7 +295,7 @@ class SystemTestCase(base.TestCase):
|
|||
'/redfish/v1/Systems/437XR1138R2',
|
||||
data={'Boot': {'BootSourceOverrideEnabled': 'Once',
|
||||
'BootSourceOverrideTarget': 'Hdd'}},
|
||||
etag=None)
|
||||
etag='81802dbf61beb0bd')
|
||||
|
||||
def test_set_system_boot_options_no_target_specified(self):
|
||||
self.sys_inst.set_system_boot_options(
|
||||
|
@ -303,7 +305,7 @@ class SystemTestCase(base.TestCase):
|
|||
'/redfish/v1/Systems/437XR1138R2',
|
||||
data={'Boot': {'BootSourceOverrideEnabled': 'Continuous',
|
||||
'BootSourceOverrideMode': 'UEFI'}},
|
||||
etag=None)
|
||||
etag='81802dbf61beb0bd')
|
||||
|
||||
def test_set_system_boot_options_no_freq_specified(self):
|
||||
self.sys_inst.set_system_boot_options(
|
||||
|
@ -313,7 +315,7 @@ class SystemTestCase(base.TestCase):
|
|||
'/redfish/v1/Systems/437XR1138R2',
|
||||
data={'Boot': {'BootSourceOverrideTarget': 'Pxe',
|
||||
'BootSourceOverrideMode': 'UEFI'}},
|
||||
etag=None)
|
||||
etag='81802dbf61beb0bd')
|
||||
|
||||
def test_set_system_boot_options_nothing_specified(self):
|
||||
self.sys_inst.set_system_boot_options()
|
||||
|
@ -348,7 +350,7 @@ class SystemTestCase(base.TestCase):
|
|||
'/redfish/v1/Systems/437XR1138R2',
|
||||
data={'Boot': {'BootSourceOverrideEnabled': 'Once',
|
||||
'BootSourceOverrideTarget': 'UsbCd'}},
|
||||
etag=None)
|
||||
etag='81802dbf61beb0bd')
|
||||
|
||||
def test_set_system_boot_options_supermicro_no_usb_cd_boot(self):
|
||||
|
||||
|
@ -361,7 +363,7 @@ class SystemTestCase(base.TestCase):
|
|||
'/redfish/v1/Systems/437XR1138R2',
|
||||
data={'Boot': {'BootSourceOverrideEnabled': 'Once',
|
||||
'BootSourceOverrideTarget': 'Cd'}},
|
||||
etag=None)
|
||||
etag='81802dbf61beb0bd')
|
||||
|
||||
def test_set_system_boot_options_settings_resource_nokia(self):
|
||||
with open('sushy/tests/unit/json_samples/settings-nokia.json') as f:
|
||||
|
@ -487,10 +489,10 @@ class SystemTestCase(base.TestCase):
|
|||
data={'Boot': {'BootSourceOverrideEnabled': 'Continuous',
|
||||
'BootSourceOverrideTarget': 'Pxe',
|
||||
'BootSourceOverrideMode': 'UEFI'}},
|
||||
etag=None)
|
||||
etag='81802dbf61beb0bd')
|
||||
|
||||
def test_set_system_boot_source_with_etag(self):
|
||||
self.conn.get.return_value.headers = {'ETag': '"3d7b838291941d"'}
|
||||
self.conn.get.return_value.headers = {'ETag': '"81802dbf61beb0bd"'}
|
||||
self.sys_inst.set_system_boot_source(
|
||||
sushy.BOOT_SOURCE_TARGET_PXE,
|
||||
enabled=sushy.BOOT_SOURCE_ENABLED_CONTINUOUS,
|
||||
|
@ -500,7 +502,7 @@ class SystemTestCase(base.TestCase):
|
|||
data={'Boot': {'BootSourceOverrideEnabled': 'Continuous',
|
||||
'BootSourceOverrideTarget': 'Pxe',
|
||||
'BootSourceOverrideMode': 'UEFI'}},
|
||||
etag='"3d7b838291941d"')
|
||||
etag="81802dbf61beb0bd")
|
||||
|
||||
def test_set_system_boot_source_no_mode_specified(self):
|
||||
self.sys_inst.set_system_boot_source(
|
||||
|
@ -510,7 +512,7 @@ class SystemTestCase(base.TestCase):
|
|||
'/redfish/v1/Systems/437XR1138R2',
|
||||
data={'Boot': {'BootSourceOverrideEnabled': 'Once',
|
||||
'BootSourceOverrideTarget': 'Hdd'}},
|
||||
etag=None)
|
||||
etag='81802dbf61beb0bd')
|
||||
|
||||
def test_set_system_boot_source_invalid_target(self):
|
||||
self.assertRaises(exceptions.InvalidParameterValueError,
|
||||
|
@ -533,7 +535,8 @@ class SystemTestCase(base.TestCase):
|
|||
self.sys_inst.set_indicator_led(sushy.IndicatorLED.BLINKING)
|
||||
self.sys_inst._conn.patch.assert_called_once_with(
|
||||
'/redfish/v1/Systems/437XR1138R2',
|
||||
data={'IndicatorLED': 'Blinking'})
|
||||
data={'IndicatorLED': 'Blinking'},
|
||||
etag='81802dbf61beb0bd')
|
||||
|
||||
invalidate_mock.assert_called_once_with()
|
||||
|
||||
|
|
|
@ -78,7 +78,8 @@ class SettingsFieldTestCase(base.TestCase):
|
|||
instance.commit(conn, {'Attributes': {'key': 'value'}})
|
||||
conn.patch.assert_called_once_with(
|
||||
'/redfish/v1/Systems/437XR1138R2/BIOS/Settings',
|
||||
data={'Attributes': {'key': 'value'}})
|
||||
data={'Attributes': {'key': 'value'}},
|
||||
etag='9234ac83b9700123cc32')
|
||||
|
||||
def test_get_status_failure(self):
|
||||
instance = self.settings._load(self.json, mock.Mock())
|
||||
|
|
Loading…
Reference in New Issue