Merge "Add PATCH support for Redfish DateTime fields in Manager resource"
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adds PATCH support for the Redfish Manager resource's ``DateTime`` and
|
||||
``DateTimeLocalOffset`` fields in the dynamic emulator. Implements
|
||||
``get_datetime`` and ``set_datetime`` methods in the fake driver and
|
||||
adds test support for mocking datetime values. Disables cache reset
|
||||
to persist updates across requests.
|
||||
|
||||
@@ -85,10 +85,6 @@ class Application(flask.Flask):
|
||||
# This is needed for WSGI since it cannot process argv
|
||||
self.configure(config_file=os.environ.get('SUSHY_EMULATOR_CONFIG'))
|
||||
|
||||
@self.before_request
|
||||
def reset_cache():
|
||||
self._cache = {}
|
||||
|
||||
def configure(self, config_file=None, extra_config=None):
|
||||
if config_file:
|
||||
self.config.from_pyfile(os.path.abspath(config_file))
|
||||
@@ -346,59 +342,79 @@ def jsonify(obj_type, obj_version, obj):
|
||||
return flask.jsonify(obj)
|
||||
|
||||
|
||||
@app.route('/redfish/v1/Managers/<identity>', methods=['GET'])
|
||||
@app.route('/redfish/v1/Managers/<identity>', methods=['GET', 'PATCH'])
|
||||
@api_utils.returns_json
|
||||
def manager_resource(identity):
|
||||
if app.feature_set == "minimum":
|
||||
raise error.FeatureNotAvailable("Managers")
|
||||
|
||||
app.logger.debug('Serving resources for manager "%s"', identity)
|
||||
|
||||
manager = app.managers.get_manager(identity)
|
||||
systems = app.managers.get_managed_systems(manager)
|
||||
chassis = app.managers.get_managed_chassis(manager)
|
||||
|
||||
uuid = manager['UUID']
|
||||
result = {
|
||||
"Id": manager['Id'],
|
||||
"Name": manager.get('Name'),
|
||||
"UUID": uuid,
|
||||
"ManagerType": "BMC",
|
||||
"VirtualMedia": {
|
||||
"@odata.id": "/redfish/v1/Systems/%s/VirtualMedia" % systems[0],
|
||||
},
|
||||
"Links": {
|
||||
"ManagerForServers": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Systems/%s" % system
|
||||
}
|
||||
for system in systems
|
||||
],
|
||||
"ManagerForChassis": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/%s" % ch
|
||||
}
|
||||
for ch in chassis if app.feature_set == "full"
|
||||
]
|
||||
},
|
||||
"@odata.id": "/redfish/v1/Managers/%s" % uuid,
|
||||
}
|
||||
if app.feature_set == "full":
|
||||
result.update({
|
||||
"ServiceEntryPointUUID": manager.get('ServiceEntryPointUUID'),
|
||||
"Description": "Contoso BMC",
|
||||
"Model": "Joo Janta 200",
|
||||
"DateTime": datetime.now().strftime('%Y-%M-%dT%H:%M:%S+00:00'),
|
||||
"DateTimeLocalOffset": "+00:00",
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"PowerState": "On",
|
||||
"FirmwareVersion": "1.00",
|
||||
})
|
||||
|
||||
return jsonify('Manager', 'v1_3_1', result)
|
||||
if flask.request.method == "GET":
|
||||
app.logger.debug('Serving resources for manager "%s"', identity)
|
||||
|
||||
result = {
|
||||
"Id": manager['Id'],
|
||||
"Name": manager.get('Name'),
|
||||
"UUID": uuid,
|
||||
"ManagerType": "BMC",
|
||||
"VirtualMedia": {
|
||||
"@odata.id": "/redfish/v1/Systems/%s/VirtualMedia" % systems[0]
|
||||
},
|
||||
"Links": {
|
||||
"ManagerForServers": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Systems/%s" % system
|
||||
}
|
||||
for system in systems
|
||||
],
|
||||
"ManagerForChassis": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Chassis/%s" % ch
|
||||
}
|
||||
for ch in chassis if app.feature_set == "full"
|
||||
]
|
||||
},
|
||||
"@odata.id": "/redfish/v1/Managers/%s" % uuid,
|
||||
}
|
||||
|
||||
if app.feature_set == "full":
|
||||
dt_info = app.managers.get_datetime()
|
||||
result.update({
|
||||
"ServiceEntryPointUUID": manager.get('ServiceEntryPointUUID'),
|
||||
"Description": "Contoso BMC",
|
||||
"Model": "Joo Janta 200",
|
||||
"DateTime": dt_info.get(
|
||||
"DateTime",
|
||||
datetime.now().strftime('%Y-%m-%dT%H:%M:%S+00:00')),
|
||||
"DateTimeLocalOffset": dt_info.get(
|
||||
"DateTimeLocalOffset", "+00:00"),
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"PowerState": "On",
|
||||
"FirmwareVersion": "1.00",
|
||||
})
|
||||
return jsonify('Manager', 'v1_3_1', result)
|
||||
|
||||
elif flask.request.method == "PATCH":
|
||||
if app.feature_set != "full":
|
||||
raise error.MethodNotAllowed("PATCH not supported in minimum mode")
|
||||
|
||||
data = flask.request.get_json(force=True)
|
||||
new_datetime = data.get("DateTime")
|
||||
new_offset = data.get("DateTimeLocalOffset")
|
||||
|
||||
app.managers.set_datetime(new_datetime, new_offset)
|
||||
|
||||
app.logger.debug("Updated DateTime for manager %s", identity)
|
||||
|
||||
return '', 204
|
||||
|
||||
|
||||
@app.route('/redfish/v1/Systems')
|
||||
|
||||
@@ -21,6 +21,8 @@ class FakeDriver(base.DriverBase):
|
||||
super().__init__(config, logger)
|
||||
self._systems = systems
|
||||
self._chassis = chassis
|
||||
self._datetime = None
|
||||
self._datetimelocaloffset = None
|
||||
|
||||
def get_manager(self, identity):
|
||||
"""Get a manager by its identity
|
||||
@@ -42,10 +44,36 @@ class FakeDriver(base.DriverBase):
|
||||
result = {'Id': system_uuid,
|
||||
'UUID': system_uuid,
|
||||
'Name': '%s-Manager' % system_name}
|
||||
self._logger.debug('Found manager %(mgr)s by UUID %(id)s',
|
||||
{'mgr': result, 'id': identity})
|
||||
|
||||
self._logger.debug(
|
||||
'Found manager %(mgr)s by UUID %(id)s',
|
||||
{'mgr': result, 'id': identity}
|
||||
)
|
||||
return result
|
||||
|
||||
def set_datetime(self, datetime_value, datetimelocaloffset_value):
|
||||
"""Set the datetime and offset information for a manager
|
||||
|
||||
:param datetime_value: The datetime string to set
|
||||
:param datetimelocaloffset_value:
|
||||
The time zone offset to set (e.g., "+00:00")
|
||||
"""
|
||||
self._datetime = datetime_value
|
||||
self._datetimelocaloffset = datetimelocaloffset_value
|
||||
|
||||
def get_datetime(self):
|
||||
"""Retrieve the datetime and offset information for a manager
|
||||
|
||||
:returns: A dictionary with 'DateTime' and 'DateTimeLocalOffset' keys,
|
||||
or an empty dict if no values are set
|
||||
"""
|
||||
if self._datetime and self._datetimelocaloffset:
|
||||
return {
|
||||
'DateTime': self._datetime,
|
||||
'DateTimeLocalOffset': self._datetimelocaloffset
|
||||
}
|
||||
return {}
|
||||
|
||||
@property
|
||||
def driver(self):
|
||||
"""Return human-friendly driver information
|
||||
|
||||
@@ -36,6 +36,9 @@ class FakeDriverTestCase(base.BaseTestCase):
|
||||
self.test_driver = managers.FakeDriver({}, mock.Mock(),
|
||||
self.systems, self.chassis)
|
||||
|
||||
self.datetime_value = "2025-06-11T12:00:00+00:00"
|
||||
self.datetimelocaloffset_value = "+00:00"
|
||||
|
||||
def test_get_manager_not_found(self):
|
||||
self.systems.uuid.side_effect = error.FishyError('boom')
|
||||
self.assertRaises(
|
||||
@@ -52,3 +55,24 @@ class FakeDriverTestCase(base.BaseTestCase):
|
||||
def test_managed_systems(self):
|
||||
self.assertEqual(
|
||||
['xxx'], self.test_driver.get_managed_systems(self.manager))
|
||||
|
||||
def test_set_datetime(self):
|
||||
self.test_driver.set_datetime(self.datetime_value,
|
||||
self.datetimelocaloffset_value)
|
||||
self.assertEqual(self.test_driver._datetime, self.datetime_value)
|
||||
self.assertEqual(self.test_driver._datetimelocaloffset,
|
||||
self.datetimelocaloffset_value)
|
||||
|
||||
def test_get_datetime_returns_expected_dict(self):
|
||||
self.test_driver.set_datetime(self.datetime_value,
|
||||
self.datetimelocaloffset_value)
|
||||
result = self.test_driver.get_datetime()
|
||||
expected = {
|
||||
"DateTime": self.datetime_value,
|
||||
"DateTimeLocalOffset": self.datetimelocaloffset_value
|
||||
}
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
def test_get_datetime_returns_empty_dict_when_not_set(self):
|
||||
result = self.test_driver.get_datetime()
|
||||
self.assertEqual(result, {})
|
||||
|
||||
@@ -221,6 +221,9 @@ class ManagersTestCase(EmulatorTestCase):
|
||||
}
|
||||
managers_mock.get_managed_systems.return_value = ['xxx']
|
||||
managers_mock.get_managed_chassis.return_value = ['chassis0']
|
||||
managers_mock.get_datetime.return_value = {
|
||||
"DateTime": "2025-06-02T12:00:00+00:00",
|
||||
"DateTimeLocalOffset": "+00:00"}
|
||||
|
||||
response = self.app.get('/redfish/v1/Managers/xxxx-yyyy-zzzz')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user