Add feature sets to test with different available feature

* "full" is the default and provides all features
* "minimum" only provides boot settings
* "vmedia" is "minimum" plus virtual media and NICs

Closes-Bug: #2046153
Change-Id: I57cff90b1327104f65264d3fb87dafc89f3be521
This commit is contained in:
Dmitry Tantsur 2023-12-11 17:46:36 +01:00
parent a654a033de
commit 0e18baab40
No known key found for this signature in database
GPG Key ID: 315B2AF9FD216C60
7 changed files with 321 additions and 45 deletions

View File

@ -8,6 +8,19 @@ except that the frontend protocol is Redfish rather than IPMI. The Redfish
commands coming from the client are handled by one or more resource-specific
drivers.
Feature sets
------------
The emulator can be configured with different feature sets to emulate different
hardware. The feature set is supplied either via the
``SUSHY_EMULATOR_FEATURE_SET`` configuration variable or through the
``--feature-set`` command line flag.
Supported feature sets are:
* ``minimum`` - only Systems with Boot settings and no other optional fields.
* ``vmedia`` - ``minimum`` plus Managers, VirtualMedia and EthernetInterfaces.
* ``full`` - all features implemented in the emulator.
Systems resource
----------------

View File

@ -0,0 +1,5 @@
---
features:
- |
Add a configuration options ``SUSHY_EMULATOR_FEATURE_SET`` to define which
resources should be available. See the documentation for more details.

View File

@ -98,6 +98,18 @@ class Application(flask.Flask):
if auth_file and not isinstance(self.wsgi_app, RedfishAuthMiddleware):
self.wsgi_app = RedfishAuthMiddleware(self.wsgi_app, auth_file)
feature_set = self.config.get('SUSHY_EMULATOR_FEATURE_SET', 'full')
if feature_set not in ('full', 'vmedia', 'minimum'):
raise RuntimeError(f"Invalid feature set {self.feature_set}")
@property
def feature_set(self):
return self.config.get('SUSHY_EMULATOR_FEATURE_SET', 'full')
def render_template(self, template_name, /, **params):
params.setdefault('feature_set', self.feature_set)
return flask.render_template(template_name, **params)
@property
@memoize.memoize()
def systems(self):
@ -203,15 +215,18 @@ def all_exception_handler(message):
@app.route('/redfish/v1/')
@api_utils.returns_json
def root_resource():
return flask.render_template('root.json')
return app.render_template('root.json')
@app.route('/redfish/v1/Chassis')
@api_utils.returns_json
def chassis_collection_resource():
if app.feature_set != "full":
raise error.FeatureNotAvailable("Chassis")
app.logger.debug('Serving chassis list')
return flask.render_template(
return app.render_template(
'chassis_collection.json',
manager_count=len(app.chassis.chassis),
chassis=app.chassis.chassis)
@ -220,6 +235,9 @@ def chassis_collection_resource():
@app.route('/redfish/v1/Chassis/<identity>', methods=['GET', 'PATCH'])
@api_utils.returns_json
def chassis_resource(identity):
if app.feature_set != "full":
raise error.FeatureNotAvailable("Chassis")
chassis = app.chassis
uuid = chassis.uuid(identity)
@ -241,7 +259,7 @@ def chassis_resource(identity):
storage = []
drives = []
return flask.render_template(
return app.render_template(
'chassis.json',
identity=identity,
name=chassis.name(identity),
@ -272,6 +290,9 @@ def chassis_resource(identity):
@app.route('/redfish/v1/Chassis/<identity>/Thermal', methods=['GET'])
@api_utils.returns_json
def thermal_resource(identity):
if app.feature_set != "full":
raise error.FeatureNotAvailable("Chassis")
chassis = app.chassis
uuid = chassis.uuid(identity)
@ -286,7 +307,7 @@ def thermal_resource(identity):
else:
systems = []
return flask.render_template(
return app.render_template(
'thermal.json',
chassis=identity,
systems=systems
@ -296,9 +317,12 @@ def thermal_resource(identity):
@app.route('/redfish/v1/Managers')
@api_utils.returns_json
def manager_collection_resource():
if app.feature_set == "minimum":
raise error.FeatureNotAvailable("Managers")
app.logger.debug('Serving managers list')
return flask.render_template(
return app.render_template(
'manager_collection.json',
manager_count=len(app.managers.managers),
managers=app.managers.managers)
@ -319,6 +343,9 @@ def jsonify(obj_type, obj_version, obj):
@app.route('/redfish/v1/Managers/<identity>', methods=['GET'])
@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)
@ -326,22 +353,11 @@ def manager_resource(identity):
chassis = app.managers.get_managed_chassis(manager)
uuid = manager['UUID']
return jsonify('Manager', 'v1_3_1', {
result = {
"Id": manager['Id'],
"Name": manager.get('Name'),
"UUID": uuid,
"ServiceEntryPointUUID": manager.get('ServiceEntryPointUUID'),
"ManagerType": "BMC",
"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",
"VirtualMedia": {
"@odata.id": "/redfish/v1/Systems/%s/VirtualMedia" % systems[0],
},
@ -356,11 +372,27 @@ def manager_resource(identity):
{
"@odata.id": "/redfish/v1/Chassis/%s" % ch
}
for ch in chassis
for ch in chassis if app.feature_set == "full"
]
},
"@odata.id": "/redfish/v1/Managers/%s" % uuid
})
"@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)
@app.route('/redfish/v1/Systems')
@ -371,7 +403,7 @@ def system_collection_resource():
app.logger.debug('Serving systems list')
return flask.render_template(
return app.render_template(
'system_collection.json', system_count=len(systems), systems=systems)
@ -390,7 +422,7 @@ def system_resource(identity):
except error.NotSupportedError:
return None
return flask.render_template(
return app.render_template(
'system.json',
identity=identity,
name=app.systems.name(identity),
@ -414,6 +446,8 @@ def system_resource(identity):
if not boot and not indicator_led_state:
return ('PATCH only works for Boot and '
'IndicatorLED elements'), 400
if indicator_led_state and app.feature_set != "full":
raise error.FeatureNotAvailable("IndicatorLED", code=400)
if boot:
target = boot.get('BootSourceOverrideTarget')
@ -492,9 +526,12 @@ def system_resource(identity):
@api_utils.ensure_instance_access
@api_utils.returns_json
def ethernet_interfaces_collection(identity):
if app.feature_set == "minimum":
raise error.FeatureNotAvailable("EthernetInterfaces")
nics = app.systems.get_nics(identity)
return flask.render_template(
return app.render_template(
'ethernet_interfaces_collection.json', identity=identity,
nics=nics)
@ -504,11 +541,14 @@ def ethernet_interfaces_collection(identity):
@api_utils.ensure_instance_access
@api_utils.returns_json
def ethernet_interface(identity, nic_id):
if app.feature_set == "minimum":
raise error.FeatureNotAvailable("EthernetInterfaces")
nics = app.systems.get_nics(identity)
for nic in nics:
if nic['id'] == nic_id:
return flask.render_template(
return app.render_template(
'ethernet_interface.json', identity=identity, nic=nic)
raise error.NotFound()
@ -519,9 +559,12 @@ def ethernet_interface(identity, nic_id):
@api_utils.ensure_instance_access
@api_utils.returns_json
def processors_collection(identity):
if app.feature_set != "full":
raise error.FeatureNotAvailable("Processors")
processors = app.systems.get_processors(identity)
return flask.render_template(
return app.render_template(
'processors_collection.json', identity=identity,
processors=processors)
@ -531,11 +574,14 @@ def processors_collection(identity):
@api_utils.ensure_instance_access
@api_utils.returns_json
def processor(identity, processor_id):
if app.feature_set != "full":
raise error.FeatureNotAvailable("Processors")
processors = app.systems.get_processors(identity)
for proc in processors:
if proc['id'] == processor_id:
return flask.render_template(
return app.render_template(
'processor.json', identity=identity, processor=proc)
raise error.NotFound()
@ -560,11 +606,14 @@ def system_reset_action(identity):
@api_utils.ensure_instance_access
@api_utils.returns_json
def bios(identity):
if app.feature_set != "full":
raise error.FeatureNotAvailable("BIOS")
bios = app.systems.get_bios(identity)
app.logger.debug('Serving BIOS for system "%s"', identity)
return flask.render_template(
return app.render_template(
'bios.json',
identity=identity,
bios_current_attributes=json.dumps(bios, sort_keys=True, indent=6))
@ -575,13 +624,15 @@ def bios(identity):
@api_utils.ensure_instance_access
@api_utils.returns_json
def bios_settings(identity):
if app.feature_set != "full":
raise error.FeatureNotAvailable("BIOS")
if flask.request.method == 'GET':
bios = app.systems.get_bios(identity)
app.logger.debug('Serving BIOS Settings for system "%s"', identity)
return flask.render_template(
return app.render_template(
'bios_settings.json',
identity=identity,
bios_pending_attributes=json.dumps(bios, sort_keys=True, indent=6))
@ -601,6 +652,9 @@ def bios_settings(identity):
@api_utils.ensure_instance_access
@api_utils.returns_json
def system_reset_bios(identity):
if app.feature_set != "full":
raise error.FeatureNotAvailable("BIOS")
app.systems.reset_bios(identity)
app.logger.info('BIOS for system "%s" reset', identity)
@ -613,13 +667,15 @@ def system_reset_bios(identity):
@api_utils.ensure_instance_access
@api_utils.returns_json
def secure_boot(identity):
if app.feature_set != "full":
raise error.FeatureNotAvailable("SecureBoot")
if flask.request.method == 'GET':
secure = app.systems.get_secure_boot(identity)
app.logger.debug('Serving secure boot for system "%s"', identity)
return flask.render_template(
return app.render_template(
'secure_boot.json',
identity=identity,
secure_boot_enable=secure,
@ -640,10 +696,13 @@ def secure_boot(identity):
@api_utils.ensure_instance_access
@api_utils.returns_json
def simple_storage_collection(identity):
if app.feature_set != "full":
raise error.FeatureNotAvailable("SimpleStorage")
simple_storage_controllers = (
app.systems.get_simple_storage_collection(identity))
return flask.render_template(
return app.render_template(
'simple_storage_collection.json', identity=identity,
simple_storage_controllers=simple_storage_controllers)
@ -653,6 +712,9 @@ def simple_storage_collection(identity):
@api_utils.ensure_instance_access
@api_utils.returns_json
def simple_storage(identity, simple_storage_id):
if app.feature_set != "full":
raise error.FeatureNotAvailable("SimpleStorage")
simple_storage_controllers = (
app.systems.get_simple_storage_collection(identity))
try:
@ -660,8 +722,8 @@ def simple_storage(identity, simple_storage_id):
except KeyError:
app.logger.debug('"%s" Simple Storage resource was not found')
raise error.NotFound()
return flask.render_template('simple_storage.json', identity=identity,
simple_storage=storage_controller)
return app.render_template('simple_storage.json', identity=identity,
simple_storage=storage_controller)
@app.route('/redfish/v1/Systems/<identity>/Storage',
@ -669,11 +731,14 @@ def simple_storage(identity, simple_storage_id):
@api_utils.ensure_instance_access
@api_utils.returns_json
def storage_collection(identity):
if app.feature_set != "full":
raise error.FeatureNotAvailable("Storage")
uuid = app.systems.uuid(identity)
storage_col = app.storage.get_storage_col(uuid)
return flask.render_template(
return app.render_template(
'storage_collection.json', identity=identity,
storage_col=storage_col)
@ -683,12 +748,15 @@ def storage_collection(identity):
@api_utils.ensure_instance_access
@api_utils.returns_json
def storage(identity, storage_id):
if app.feature_set != "full":
raise error.FeatureNotAvailable("Storage")
uuid = app.systems.uuid(identity)
storage_col = app.storage.get_storage_col(uuid)
for stg in storage_col:
if stg['Id'] == storage_id:
return flask.render_template(
return app.render_template(
'storage.json', identity=identity, storage=stg)
raise error.NotFound()
@ -699,12 +767,15 @@ def storage(identity, storage_id):
@api_utils.ensure_instance_access
@api_utils.returns_json
def drive_resource(identity, stg_id, drv_id):
if app.feature_set != "full":
raise error.FeatureNotAvailable("Storage")
uuid = app.systems.uuid(identity)
drives = app.drives.get_drives(uuid, stg_id)
for drv in drives:
if drv['Id'] == drv_id:
return flask.render_template(
return app.render_template(
'drive.json', identity=identity, storage_id=stg_id, drive=drv)
raise error.NotFound()
@ -715,6 +786,9 @@ def drive_resource(identity, stg_id, drv_id):
@api_utils.ensure_instance_access
@api_utils.returns_json
def volumes_collection(identity, storage_id):
if app.feature_set != "full":
raise error.FeatureNotAvailable("Storage")
uuid = app.systems.uuid(identity)
if flask.request.method == 'GET':
@ -729,7 +803,7 @@ def volumes_collection(identity, storage_id):
else:
vol_ids.append(vol_id)
return flask.render_template(
return app.render_template(
'volume_collection.json', identity=identity,
storage_id=storage_id, volume_col=vol_ids)
@ -757,6 +831,9 @@ def volumes_collection(identity, storage_id):
@api_utils.ensure_instance_access
@api_utils.returns_json
def volume(identity, stg_id, vol_id):
if app.feature_set != "full":
raise error.FeatureNotAvailable("Storage")
uuid = app.systems.uuid(identity)
vol_col = app.volumes.get_volumes_col(uuid, stg_id)
@ -766,7 +843,7 @@ def volume(identity, stg_id, vol_id):
if not vol_id:
app.volumes.delete_volume(uuid, stg_id, vol)
else:
return flask.render_template(
return app.render_template(
'volume.json', identity=identity, storage_id=stg_id,
volume=vol)
@ -776,44 +853,59 @@ def volume(identity, stg_id, vol_id):
@app.route('/redfish/v1/Registries')
@api_utils.returns_json
def registry_file_collection():
if app.feature_set != "full":
raise error.FeatureNotAvailable("Registries")
app.logger.debug('Serving registry file collection')
return flask.render_template(
return app.render_template(
'registry_file_collection.json')
@app.route('/redfish/v1/Registries/BiosAttributeRegistry.v1_0_0')
@api_utils.returns_json
def bios_attribute_registry_file():
if app.feature_set != "full":
raise error.FeatureNotAvailable("Registries")
app.logger.debug('Serving BIOS attribute registry file')
return flask.render_template(
return app.render_template(
'bios_attribute_registry_file.json')
@app.route('/redfish/v1/Registries/Messages')
@api_utils.returns_json
def message_registry_file():
if app.feature_set != "full":
raise error.FeatureNotAvailable("Registries")
app.logger.debug('Serving message registry file')
return flask.render_template(
return app.render_template(
'message_registry_file.json')
@app.route('/redfish/v1/Systems/Bios/BiosRegistry')
@api_utils.returns_json
def bios_registry():
if app.feature_set != "full":
raise error.FeatureNotAvailable("Registries")
app.logger.debug('Serving BIOS registry')
return flask.render_template('bios_registry.json')
return app.render_template('bios_registry.json')
@app.route('/redfish/v1/Registries/Messages/Registry')
@api_utils.returns_json
def message_registry():
if app.feature_set != "full":
raise error.FeatureNotAvailable("Registries")
app.logger.debug('Serving message registry')
return flask.render_template('message_registry.json')
return app.render_template('message_registry.json')
def parse_args():
@ -843,6 +935,10 @@ def parse_args():
type=str,
help='SSL key to use for HTTPS. Can also be set'
'via config variable SUSHY_EMULATOR_SSL_KEY.')
parser.add_argument('--feature-set',
type=str, choices=['full', 'vmedia', 'minimum'],
help='Feature set to provide. Can also be set'
'via config variable SUSHY_EMULATOR_FEATURE_SET.')
backend_group = parser.add_mutually_exclusive_group()
backend_group.add_argument('--os-cloud',
type=str,
@ -908,6 +1004,9 @@ def main():
if args.ssl_key:
app.config['SUSHY_EMULATOR_SSL_KEY'] = args.ssl_key
if args.feature_set:
app.config['SUSHY_EMULATOR_FEATURE_SET'] = args.feature_set
ssl_context = None
ssl_certificate = app.config.get('SUSHY_EMULATOR_SSL_CERT')
ssl_key = app.config.get('SUSHY_EMULATOR_SSL_KEY')

View File

@ -4,21 +4,27 @@
"Name": "Redvirt Service",
"RedfishVersion": "1.5.0",
"UUID": "85775665-c110-4b85-8989-e6162170b3ec",
{% if feature_set == "full" %}
"Chassis": {
"@odata.id": "/redfish/v1/Chassis"
},
{% endif %}
"Systems": {
"@odata.id": "/redfish/v1/Systems"
},
{% if feature_set != "minimum" %}
"Managers": {
"@odata.id": "/redfish/v1/Managers"
},
{% endif %}
{% if feature_set == "full" %}
"Registries": {
"@odata.id": "/redfish/v1/Registries"
},
"CertificateService": {
"@odata.id": "/redfish/v1/CertificateService"
},
{% endif %}
"@odata.id": "/redfish/v1/",
"@Redfish.Copyright": "Copyright 2014-2016 Distributed Management Task Force, Inc. (DMTF). For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright."
}

View File

@ -3,12 +3,14 @@
"Id": {{ identity|string|tojson }},
"Name": {{ name|string|tojson }},
"UUID": {{ uuid|string|tojson }},
{%- if feature_set == "full" %}
"Manufacturer": "Sushy Emulator",
"Status": {
"State": "Enabled",
"Health": "OK",
"HealthRollUp": "OK"
},
{% endif %}
{%- if power_state %}
"PowerState": {{ power_state|string|tojson }},
{%- endif %}
@ -40,6 +42,7 @@
"BootSourceOverrideEnabled": "Continuous"
{%- endif %}
},
{%- if feature_set == "full" %}
"ProcessorSummary": {
{%- if total_cpus %}
"Count": {{ total_cpus }},
@ -70,9 +73,6 @@
"Memory": {
"@odata.id": {{ "/redfish/v1/Systems/%s/Memory"|format(identity)|tojson }}
},
"EthernetInterfaces": {
"@odata.id": {{ "/redfish/v1/Systems/%s/EthernetInterfaces"|format(identity)|tojson }}
},
"SecureBoot": {
"@odata.id": {{ "/redfish/v1/Systems/%s/SecureBoot"|format(identity)|tojson }}
},
@ -85,10 +85,17 @@
{%- if indicator_led %}
"IndicatorLED": {{ indicator_led|string|tojson }},
{%- endif %}
{%- endif %}
{%- if feature_set != "minimum" %}
"EthernetInterfaces": {
"@odata.id": {{ "/redfish/v1/Systems/%s/EthernetInterfaces"|format(identity)|tojson }}
},
"VirtualMedia": {
"@odata.id": {{ "/redfish/v1/Systems/%s/VirtualMedia"|format(identity)|tojson }}
},
{%- endif %}
"Links": {
{%- if feature_set == "full" %}
"Chassis": [
{%- for chassis_ in chassis %}
{
@ -96,6 +103,8 @@
}{% if not loop.last %},{% endif %}
{% endfor -%}
],
{% endif %}
{%- if feature_set != "minimum" %}
"ManagedBy": [
{%- for manager in managers %}
{
@ -103,6 +112,7 @@
}{% if not loop.last %},{% endif %}
{% endfor -%}
]
{% endif %}
},
"Actions": {
"#ComputerSystem.Reset": {

View File

@ -45,3 +45,10 @@ class BadRequest(FishyError):
def __init__(self, msg, code=400):
super().__init__(msg, code)
class FeatureNotAvailable(NotFound):
"""Feature is not available."""
def __init__(self, feature, code=404):
super().__init__(f"Feature {feature} not available", code=code)

View File

@ -36,6 +36,12 @@ class EmulatorTestCase(base.BaseTestCase):
super(EmulatorTestCase, self).setUp()
def set_feature_set(self, new_feature_set):
main.app.config['SUSHY_EMULATOR_FEATURE_SET'] = new_feature_set
self.addCleanup(
lambda: main.app.config.pop('SUSHY_EMULATOR_FEATURE_SET', None)
)
class CommonTestCase(EmulatorTestCase):
@ -52,6 +58,22 @@ class CommonTestCase(EmulatorTestCase):
self.assertEqual(200, response.status_code)
self.assertEqual('RedvirtService', response.json['Id'])
def test_root_resource_only_vmedia(self):
self.set_feature_set("vmedia")
response = self.app.get('/redfish/v1/')
self.assertEqual(200, response.status_code)
self.assertEqual(
{'Id', 'Name', 'RedfishVersion', 'UUID', 'Systems', 'Managers'},
{x for x in response.json if not x.startswith('@')})
def test_root_resource_minimum(self):
self.set_feature_set("minimum")
response = self.app.get('/redfish/v1/')
self.assertEqual(200, response.status_code)
self.assertEqual(
{'Id', 'Name', 'RedfishVersion', 'UUID', 'Systems'},
{x for x in response.json if not x.startswith('@')})
TEST_PASSWD = \
b"admin:$2y$05$mYl8KMwM94l4LR/sw1teIeA6P2u8gfX16e8wvT7NmGgAM5r9jgLl."
@ -210,6 +232,33 @@ class ManagersTestCase(EmulatorTestCase):
response.json['Links']['ManagerForServers'])
self.assertEqual([{'@odata.id': '/redfish/v1/Chassis/chassis0'}],
response.json['Links']['ManagerForChassis'])
self.assertEqual({'@odata.id': '/redfish/v1/Systems/xxx/VirtualMedia'},
response.json['VirtualMedia'])
@patch_resource('managers')
def test_manager_resource_get_reduced_feature_set(self, managers_mock):
self.set_feature_set("vmedia")
managers_mock = managers_mock.return_value
managers_mock.managers = ['xxxx-yyyy-zzzz']
managers_mock.get_manager.return_value = {
'UUID': 'xxxx-yyyy-zzzz',
'Name': 'name',
'Id': 'xxxx-yyyy-zzzz',
}
managers_mock.get_managed_systems.return_value = ['xxx']
managers_mock.get_managed_chassis.return_value = ['chassis0']
response = self.app.get('/redfish/v1/Managers/xxxx-yyyy-zzzz')
self.assertEqual(200, response.status_code, response.json)
self.assertEqual('xxxx-yyyy-zzzz', response.json['Id'])
self.assertEqual('xxxx-yyyy-zzzz', response.json['UUID'])
self.assertNotIn('ServiceEntryPointUUID', response.json)
self.assertEqual([{'@odata.id': '/redfish/v1/Systems/xxx'}],
response.json['Links']['ManagerForServers'])
self.assertNotIn('Chassis', response.json['Links'])
self.assertEqual({'@odata.id': '/redfish/v1/Systems/xxx/VirtualMedia'},
response.json['VirtualMedia'])
class SystemsTestCase(EmulatorTestCase):
@ -263,6 +312,81 @@ class SystemsTestCase(EmulatorTestCase):
self.assertEqual(
[{'@odata.id': '/redfish/v1/Chassis/chassis0'}],
response.json['Links']['Chassis'])
self.assertEqual(
{'@odata.id': '/redfish/v1/Systems/xxxx-yyyy-zzzz/VirtualMedia'},
response.json['VirtualMedia'])
@patch_resource('indicators')
@patch_resource('chassis')
@patch_resource('managers')
@patch_resource('systems')
def test_system_resource_get_reduced_feature_set(
self, systems_mock, managers_mock, chassis_mock, indicators_mock):
self.set_feature_set("vmedia")
systems_mock = systems_mock.return_value
systems_mock.uuid.return_value = 'zzzz-yyyy-xxxx'
systems_mock.get_power_state.return_value = 'On'
systems_mock.get_boot_device.return_value = 'Cd'
systems_mock.get_boot_mode.return_value = 'Legacy'
managers_mock.return_value.get_managers_for_system.return_value = [
'aaaa-bbbb-cccc']
response = self.app.get('/redfish/v1/Systems/xxxx-yyyy-zzzz')
self.assertEqual(200, response.status_code)
self.assertEqual('xxxx-yyyy-zzzz', response.json['Id'])
self.assertEqual('zzzz-yyyy-xxxx', response.json['UUID'])
self.assertEqual('On', response.json['PowerState'])
self.assertNotIn('IndicatorLED', response.json)
self.assertNotIn('MemorySummary', response.json)
self.assertNotIn('ProcessorSummary', response.json)
self.assertNotIn('BiosVersion', response.json)
self.assertNotIn('Bios', response.json)
self.assertEqual(
'Cd', response.json['Boot']['BootSourceOverrideTarget'])
self.assertEqual(
'Legacy', response.json['Boot']['BootSourceOverrideMode'])
self.assertEqual(
[{'@odata.id': '/redfish/v1/Managers/aaaa-bbbb-cccc'}],
response.json['Links']['ManagedBy'])
self.assertNotIn('Chassis', response.json['Links'])
self.assertEqual(
{'@odata.id': '/redfish/v1/Systems/xxxx-yyyy-zzzz/VirtualMedia'},
response.json['VirtualMedia'])
@patch_resource('indicators')
@patch_resource('chassis')
@patch_resource('managers')
@patch_resource('systems')
def test_system_resource_get_minimum_feature_set(
self, systems_mock, managers_mock, chassis_mock, indicators_mock):
self.set_feature_set("minimum")
systems_mock = systems_mock.return_value
systems_mock.uuid.return_value = 'zzzz-yyyy-xxxx'
systems_mock.get_power_state.return_value = 'On'
systems_mock.get_boot_device.return_value = 'Cd'
systems_mock.get_boot_mode.return_value = 'Legacy'
managers_mock.return_value.get_managers_for_system.return_value = [
'aaaa-bbbb-cccc']
response = self.app.get('/redfish/v1/Systems/xxxx-yyyy-zzzz')
self.assertEqual(200, response.status_code)
self.assertEqual('xxxx-yyyy-zzzz', response.json['Id'])
self.assertEqual('zzzz-yyyy-xxxx', response.json['UUID'])
self.assertEqual('On', response.json['PowerState'])
self.assertNotIn('IndicatorLED', response.json)
self.assertNotIn('MemorySummary', response.json)
self.assertNotIn('ProcessorSummary', response.json)
self.assertNotIn('BiosVersion', response.json)
self.assertNotIn('Bios', response.json)
self.assertEqual(
'Cd', response.json['Boot']['BootSourceOverrideTarget'])
self.assertEqual(
'Legacy', response.json['Boot']['BootSourceOverrideMode'])
self.assertNotIn('ManagedBy', response.json['Links'])
self.assertNotIn('Chassis', response.json['Links'])
self.assertNotIn('VirtualMedia', response.json)
@patch_resource('systems')
def test_system_resource_patch(self, systems_mock):
@ -336,6 +460,18 @@ class SystemsTestCase(EmulatorTestCase):
json=data)
self.assertEqual(500, response.status_code)
@patch_resource('indicators')
@patch_resource('systems')
def test_system_indicator_reduced_feature_set(self, systems_mock,
indicators_mock):
self.set_feature_set("vmedia")
systems_mock.return_value.uuid.return_value = self.uuid
data = {'IndicatorLED': 'Off'}
response = self.app.patch('/redfish/v1/Systems/xxxx-yyyy-zzzz',
json=data)
self.assertEqual(400, response.status_code)
@patch_resource('systems')
class BiosTestCase(EmulatorTestCase):