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:
parent
a654a033de
commit
0e18baab40
@ -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
|
commands coming from the client are handled by one or more resource-specific
|
||||||
drivers.
|
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
|
Systems resource
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
5
releasenotes/notes/feature-set-42f2846a17f59424.yaml
Normal file
5
releasenotes/notes/feature-set-42f2846a17f59424.yaml
Normal 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.
|
@ -98,6 +98,18 @@ class Application(flask.Flask):
|
|||||||
if auth_file and not isinstance(self.wsgi_app, RedfishAuthMiddleware):
|
if auth_file and not isinstance(self.wsgi_app, RedfishAuthMiddleware):
|
||||||
self.wsgi_app = RedfishAuthMiddleware(self.wsgi_app, auth_file)
|
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
|
@property
|
||||||
@memoize.memoize()
|
@memoize.memoize()
|
||||||
def systems(self):
|
def systems(self):
|
||||||
@ -203,15 +215,18 @@ def all_exception_handler(message):
|
|||||||
@app.route('/redfish/v1/')
|
@app.route('/redfish/v1/')
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def root_resource():
|
def root_resource():
|
||||||
return flask.render_template('root.json')
|
return app.render_template('root.json')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/redfish/v1/Chassis')
|
@app.route('/redfish/v1/Chassis')
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def chassis_collection_resource():
|
def chassis_collection_resource():
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Chassis")
|
||||||
|
|
||||||
app.logger.debug('Serving chassis list')
|
app.logger.debug('Serving chassis list')
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'chassis_collection.json',
|
'chassis_collection.json',
|
||||||
manager_count=len(app.chassis.chassis),
|
manager_count=len(app.chassis.chassis),
|
||||||
chassis=app.chassis.chassis)
|
chassis=app.chassis.chassis)
|
||||||
@ -220,6 +235,9 @@ def chassis_collection_resource():
|
|||||||
@app.route('/redfish/v1/Chassis/<identity>', methods=['GET', 'PATCH'])
|
@app.route('/redfish/v1/Chassis/<identity>', methods=['GET', 'PATCH'])
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def chassis_resource(identity):
|
def chassis_resource(identity):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Chassis")
|
||||||
|
|
||||||
chassis = app.chassis
|
chassis = app.chassis
|
||||||
|
|
||||||
uuid = chassis.uuid(identity)
|
uuid = chassis.uuid(identity)
|
||||||
@ -241,7 +259,7 @@ def chassis_resource(identity):
|
|||||||
storage = []
|
storage = []
|
||||||
drives = []
|
drives = []
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'chassis.json',
|
'chassis.json',
|
||||||
identity=identity,
|
identity=identity,
|
||||||
name=chassis.name(identity),
|
name=chassis.name(identity),
|
||||||
@ -272,6 +290,9 @@ def chassis_resource(identity):
|
|||||||
@app.route('/redfish/v1/Chassis/<identity>/Thermal', methods=['GET'])
|
@app.route('/redfish/v1/Chassis/<identity>/Thermal', methods=['GET'])
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def thermal_resource(identity):
|
def thermal_resource(identity):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Chassis")
|
||||||
|
|
||||||
chassis = app.chassis
|
chassis = app.chassis
|
||||||
|
|
||||||
uuid = chassis.uuid(identity)
|
uuid = chassis.uuid(identity)
|
||||||
@ -286,7 +307,7 @@ def thermal_resource(identity):
|
|||||||
else:
|
else:
|
||||||
systems = []
|
systems = []
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'thermal.json',
|
'thermal.json',
|
||||||
chassis=identity,
|
chassis=identity,
|
||||||
systems=systems
|
systems=systems
|
||||||
@ -296,9 +317,12 @@ def thermal_resource(identity):
|
|||||||
@app.route('/redfish/v1/Managers')
|
@app.route('/redfish/v1/Managers')
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def manager_collection_resource():
|
def manager_collection_resource():
|
||||||
|
if app.feature_set == "minimum":
|
||||||
|
raise error.FeatureNotAvailable("Managers")
|
||||||
|
|
||||||
app.logger.debug('Serving managers list')
|
app.logger.debug('Serving managers list')
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'manager_collection.json',
|
'manager_collection.json',
|
||||||
manager_count=len(app.managers.managers),
|
manager_count=len(app.managers.managers),
|
||||||
managers=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'])
|
@app.route('/redfish/v1/Managers/<identity>', methods=['GET'])
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def manager_resource(identity):
|
def manager_resource(identity):
|
||||||
|
if app.feature_set == "minimum":
|
||||||
|
raise error.FeatureNotAvailable("Managers")
|
||||||
|
|
||||||
app.logger.debug('Serving resources for manager "%s"', identity)
|
app.logger.debug('Serving resources for manager "%s"', identity)
|
||||||
|
|
||||||
manager = app.managers.get_manager(identity)
|
manager = app.managers.get_manager(identity)
|
||||||
@ -326,22 +353,11 @@ def manager_resource(identity):
|
|||||||
chassis = app.managers.get_managed_chassis(manager)
|
chassis = app.managers.get_managed_chassis(manager)
|
||||||
|
|
||||||
uuid = manager['UUID']
|
uuid = manager['UUID']
|
||||||
return jsonify('Manager', 'v1_3_1', {
|
result = {
|
||||||
"Id": manager['Id'],
|
"Id": manager['Id'],
|
||||||
"Name": manager.get('Name'),
|
"Name": manager.get('Name'),
|
||||||
"UUID": uuid,
|
"UUID": uuid,
|
||||||
"ServiceEntryPointUUID": manager.get('ServiceEntryPointUUID'),
|
|
||||||
"ManagerType": "BMC",
|
"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": {
|
"VirtualMedia": {
|
||||||
"@odata.id": "/redfish/v1/Systems/%s/VirtualMedia" % systems[0],
|
"@odata.id": "/redfish/v1/Systems/%s/VirtualMedia" % systems[0],
|
||||||
},
|
},
|
||||||
@ -356,12 +372,28 @@ def manager_resource(identity):
|
|||||||
{
|
{
|
||||||
"@odata.id": "/redfish/v1/Chassis/%s" % ch
|
"@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')
|
@app.route('/redfish/v1/Systems')
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
@ -371,7 +403,7 @@ def system_collection_resource():
|
|||||||
|
|
||||||
app.logger.debug('Serving systems list')
|
app.logger.debug('Serving systems list')
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'system_collection.json', system_count=len(systems), systems=systems)
|
'system_collection.json', system_count=len(systems), systems=systems)
|
||||||
|
|
||||||
|
|
||||||
@ -390,7 +422,7 @@ def system_resource(identity):
|
|||||||
except error.NotSupportedError:
|
except error.NotSupportedError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'system.json',
|
'system.json',
|
||||||
identity=identity,
|
identity=identity,
|
||||||
name=app.systems.name(identity),
|
name=app.systems.name(identity),
|
||||||
@ -414,6 +446,8 @@ def system_resource(identity):
|
|||||||
if not boot and not indicator_led_state:
|
if not boot and not indicator_led_state:
|
||||||
return ('PATCH only works for Boot and '
|
return ('PATCH only works for Boot and '
|
||||||
'IndicatorLED elements'), 400
|
'IndicatorLED elements'), 400
|
||||||
|
if indicator_led_state and app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("IndicatorLED", code=400)
|
||||||
|
|
||||||
if boot:
|
if boot:
|
||||||
target = boot.get('BootSourceOverrideTarget')
|
target = boot.get('BootSourceOverrideTarget')
|
||||||
@ -492,9 +526,12 @@ def system_resource(identity):
|
|||||||
@api_utils.ensure_instance_access
|
@api_utils.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def ethernet_interfaces_collection(identity):
|
def ethernet_interfaces_collection(identity):
|
||||||
|
if app.feature_set == "minimum":
|
||||||
|
raise error.FeatureNotAvailable("EthernetInterfaces")
|
||||||
|
|
||||||
nics = app.systems.get_nics(identity)
|
nics = app.systems.get_nics(identity)
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'ethernet_interfaces_collection.json', identity=identity,
|
'ethernet_interfaces_collection.json', identity=identity,
|
||||||
nics=nics)
|
nics=nics)
|
||||||
|
|
||||||
@ -504,11 +541,14 @@ def ethernet_interfaces_collection(identity):
|
|||||||
@api_utils.ensure_instance_access
|
@api_utils.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def ethernet_interface(identity, nic_id):
|
def ethernet_interface(identity, nic_id):
|
||||||
|
if app.feature_set == "minimum":
|
||||||
|
raise error.FeatureNotAvailable("EthernetInterfaces")
|
||||||
|
|
||||||
nics = app.systems.get_nics(identity)
|
nics = app.systems.get_nics(identity)
|
||||||
|
|
||||||
for nic in nics:
|
for nic in nics:
|
||||||
if nic['id'] == nic_id:
|
if nic['id'] == nic_id:
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'ethernet_interface.json', identity=identity, nic=nic)
|
'ethernet_interface.json', identity=identity, nic=nic)
|
||||||
|
|
||||||
raise error.NotFound()
|
raise error.NotFound()
|
||||||
@ -519,9 +559,12 @@ def ethernet_interface(identity, nic_id):
|
|||||||
@api_utils.ensure_instance_access
|
@api_utils.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def processors_collection(identity):
|
def processors_collection(identity):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Processors")
|
||||||
|
|
||||||
processors = app.systems.get_processors(identity)
|
processors = app.systems.get_processors(identity)
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'processors_collection.json', identity=identity,
|
'processors_collection.json', identity=identity,
|
||||||
processors=processors)
|
processors=processors)
|
||||||
|
|
||||||
@ -531,11 +574,14 @@ def processors_collection(identity):
|
|||||||
@api_utils.ensure_instance_access
|
@api_utils.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def processor(identity, processor_id):
|
def processor(identity, processor_id):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Processors")
|
||||||
|
|
||||||
processors = app.systems.get_processors(identity)
|
processors = app.systems.get_processors(identity)
|
||||||
|
|
||||||
for proc in processors:
|
for proc in processors:
|
||||||
if proc['id'] == processor_id:
|
if proc['id'] == processor_id:
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'processor.json', identity=identity, processor=proc)
|
'processor.json', identity=identity, processor=proc)
|
||||||
|
|
||||||
raise error.NotFound()
|
raise error.NotFound()
|
||||||
@ -560,11 +606,14 @@ def system_reset_action(identity):
|
|||||||
@api_utils.ensure_instance_access
|
@api_utils.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def bios(identity):
|
def bios(identity):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("BIOS")
|
||||||
|
|
||||||
bios = app.systems.get_bios(identity)
|
bios = app.systems.get_bios(identity)
|
||||||
|
|
||||||
app.logger.debug('Serving BIOS for system "%s"', identity)
|
app.logger.debug('Serving BIOS for system "%s"', identity)
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'bios.json',
|
'bios.json',
|
||||||
identity=identity,
|
identity=identity,
|
||||||
bios_current_attributes=json.dumps(bios, sort_keys=True, indent=6))
|
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.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def bios_settings(identity):
|
def bios_settings(identity):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("BIOS")
|
||||||
|
|
||||||
if flask.request.method == 'GET':
|
if flask.request.method == 'GET':
|
||||||
bios = app.systems.get_bios(identity)
|
bios = app.systems.get_bios(identity)
|
||||||
|
|
||||||
app.logger.debug('Serving BIOS Settings for system "%s"', identity)
|
app.logger.debug('Serving BIOS Settings for system "%s"', identity)
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'bios_settings.json',
|
'bios_settings.json',
|
||||||
identity=identity,
|
identity=identity,
|
||||||
bios_pending_attributes=json.dumps(bios, sort_keys=True, indent=6))
|
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.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def system_reset_bios(identity):
|
def system_reset_bios(identity):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("BIOS")
|
||||||
|
|
||||||
app.systems.reset_bios(identity)
|
app.systems.reset_bios(identity)
|
||||||
|
|
||||||
app.logger.info('BIOS for system "%s" reset', 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.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def secure_boot(identity):
|
def secure_boot(identity):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("SecureBoot")
|
||||||
|
|
||||||
if flask.request.method == 'GET':
|
if flask.request.method == 'GET':
|
||||||
secure = app.systems.get_secure_boot(identity)
|
secure = app.systems.get_secure_boot(identity)
|
||||||
|
|
||||||
app.logger.debug('Serving secure boot for system "%s"', identity)
|
app.logger.debug('Serving secure boot for system "%s"', identity)
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'secure_boot.json',
|
'secure_boot.json',
|
||||||
identity=identity,
|
identity=identity,
|
||||||
secure_boot_enable=secure,
|
secure_boot_enable=secure,
|
||||||
@ -640,10 +696,13 @@ def secure_boot(identity):
|
|||||||
@api_utils.ensure_instance_access
|
@api_utils.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def simple_storage_collection(identity):
|
def simple_storage_collection(identity):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("SimpleStorage")
|
||||||
|
|
||||||
simple_storage_controllers = (
|
simple_storage_controllers = (
|
||||||
app.systems.get_simple_storage_collection(identity))
|
app.systems.get_simple_storage_collection(identity))
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'simple_storage_collection.json', identity=identity,
|
'simple_storage_collection.json', identity=identity,
|
||||||
simple_storage_controllers=simple_storage_controllers)
|
simple_storage_controllers=simple_storage_controllers)
|
||||||
|
|
||||||
@ -653,6 +712,9 @@ def simple_storage_collection(identity):
|
|||||||
@api_utils.ensure_instance_access
|
@api_utils.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def simple_storage(identity, simple_storage_id):
|
def simple_storage(identity, simple_storage_id):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("SimpleStorage")
|
||||||
|
|
||||||
simple_storage_controllers = (
|
simple_storage_controllers = (
|
||||||
app.systems.get_simple_storage_collection(identity))
|
app.systems.get_simple_storage_collection(identity))
|
||||||
try:
|
try:
|
||||||
@ -660,7 +722,7 @@ def simple_storage(identity, simple_storage_id):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
app.logger.debug('"%s" Simple Storage resource was not found')
|
app.logger.debug('"%s" Simple Storage resource was not found')
|
||||||
raise error.NotFound()
|
raise error.NotFound()
|
||||||
return flask.render_template('simple_storage.json', identity=identity,
|
return app.render_template('simple_storage.json', identity=identity,
|
||||||
simple_storage=storage_controller)
|
simple_storage=storage_controller)
|
||||||
|
|
||||||
|
|
||||||
@ -669,11 +731,14 @@ def simple_storage(identity, simple_storage_id):
|
|||||||
@api_utils.ensure_instance_access
|
@api_utils.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def storage_collection(identity):
|
def storage_collection(identity):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Storage")
|
||||||
|
|
||||||
uuid = app.systems.uuid(identity)
|
uuid = app.systems.uuid(identity)
|
||||||
|
|
||||||
storage_col = app.storage.get_storage_col(uuid)
|
storage_col = app.storage.get_storage_col(uuid)
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'storage_collection.json', identity=identity,
|
'storage_collection.json', identity=identity,
|
||||||
storage_col=storage_col)
|
storage_col=storage_col)
|
||||||
|
|
||||||
@ -683,12 +748,15 @@ def storage_collection(identity):
|
|||||||
@api_utils.ensure_instance_access
|
@api_utils.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def storage(identity, storage_id):
|
def storage(identity, storage_id):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Storage")
|
||||||
|
|
||||||
uuid = app.systems.uuid(identity)
|
uuid = app.systems.uuid(identity)
|
||||||
storage_col = app.storage.get_storage_col(uuid)
|
storage_col = app.storage.get_storage_col(uuid)
|
||||||
|
|
||||||
for stg in storage_col:
|
for stg in storage_col:
|
||||||
if stg['Id'] == storage_id:
|
if stg['Id'] == storage_id:
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'storage.json', identity=identity, storage=stg)
|
'storage.json', identity=identity, storage=stg)
|
||||||
|
|
||||||
raise error.NotFound()
|
raise error.NotFound()
|
||||||
@ -699,12 +767,15 @@ def storage(identity, storage_id):
|
|||||||
@api_utils.ensure_instance_access
|
@api_utils.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def drive_resource(identity, stg_id, drv_id):
|
def drive_resource(identity, stg_id, drv_id):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Storage")
|
||||||
|
|
||||||
uuid = app.systems.uuid(identity)
|
uuid = app.systems.uuid(identity)
|
||||||
drives = app.drives.get_drives(uuid, stg_id)
|
drives = app.drives.get_drives(uuid, stg_id)
|
||||||
|
|
||||||
for drv in drives:
|
for drv in drives:
|
||||||
if drv['Id'] == drv_id:
|
if drv['Id'] == drv_id:
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'drive.json', identity=identity, storage_id=stg_id, drive=drv)
|
'drive.json', identity=identity, storage_id=stg_id, drive=drv)
|
||||||
|
|
||||||
raise error.NotFound()
|
raise error.NotFound()
|
||||||
@ -715,6 +786,9 @@ def drive_resource(identity, stg_id, drv_id):
|
|||||||
@api_utils.ensure_instance_access
|
@api_utils.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def volumes_collection(identity, storage_id):
|
def volumes_collection(identity, storage_id):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Storage")
|
||||||
|
|
||||||
uuid = app.systems.uuid(identity)
|
uuid = app.systems.uuid(identity)
|
||||||
|
|
||||||
if flask.request.method == 'GET':
|
if flask.request.method == 'GET':
|
||||||
@ -729,7 +803,7 @@ def volumes_collection(identity, storage_id):
|
|||||||
else:
|
else:
|
||||||
vol_ids.append(vol_id)
|
vol_ids.append(vol_id)
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'volume_collection.json', identity=identity,
|
'volume_collection.json', identity=identity,
|
||||||
storage_id=storage_id, volume_col=vol_ids)
|
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.ensure_instance_access
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def volume(identity, stg_id, vol_id):
|
def volume(identity, stg_id, vol_id):
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Storage")
|
||||||
|
|
||||||
uuid = app.systems.uuid(identity)
|
uuid = app.systems.uuid(identity)
|
||||||
vol_col = app.volumes.get_volumes_col(uuid, stg_id)
|
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:
|
if not vol_id:
|
||||||
app.volumes.delete_volume(uuid, stg_id, vol)
|
app.volumes.delete_volume(uuid, stg_id, vol)
|
||||||
else:
|
else:
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'volume.json', identity=identity, storage_id=stg_id,
|
'volume.json', identity=identity, storage_id=stg_id,
|
||||||
volume=vol)
|
volume=vol)
|
||||||
|
|
||||||
@ -776,44 +853,59 @@ def volume(identity, stg_id, vol_id):
|
|||||||
@app.route('/redfish/v1/Registries')
|
@app.route('/redfish/v1/Registries')
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def registry_file_collection():
|
def registry_file_collection():
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Registries")
|
||||||
|
|
||||||
app.logger.debug('Serving registry file collection')
|
app.logger.debug('Serving registry file collection')
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'registry_file_collection.json')
|
'registry_file_collection.json')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/redfish/v1/Registries/BiosAttributeRegistry.v1_0_0')
|
@app.route('/redfish/v1/Registries/BiosAttributeRegistry.v1_0_0')
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def bios_attribute_registry_file():
|
def bios_attribute_registry_file():
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Registries")
|
||||||
|
|
||||||
app.logger.debug('Serving BIOS attribute registry file')
|
app.logger.debug('Serving BIOS attribute registry file')
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'bios_attribute_registry_file.json')
|
'bios_attribute_registry_file.json')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/redfish/v1/Registries/Messages')
|
@app.route('/redfish/v1/Registries/Messages')
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def message_registry_file():
|
def message_registry_file():
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Registries")
|
||||||
|
|
||||||
app.logger.debug('Serving message registry file')
|
app.logger.debug('Serving message registry file')
|
||||||
|
|
||||||
return flask.render_template(
|
return app.render_template(
|
||||||
'message_registry_file.json')
|
'message_registry_file.json')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/redfish/v1/Systems/Bios/BiosRegistry')
|
@app.route('/redfish/v1/Systems/Bios/BiosRegistry')
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def bios_registry():
|
def bios_registry():
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Registries")
|
||||||
|
|
||||||
app.logger.debug('Serving BIOS registry')
|
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')
|
@app.route('/redfish/v1/Registries/Messages/Registry')
|
||||||
@api_utils.returns_json
|
@api_utils.returns_json
|
||||||
def message_registry():
|
def message_registry():
|
||||||
|
if app.feature_set != "full":
|
||||||
|
raise error.FeatureNotAvailable("Registries")
|
||||||
|
|
||||||
app.logger.debug('Serving message registry')
|
app.logger.debug('Serving message registry')
|
||||||
|
|
||||||
return flask.render_template('message_registry.json')
|
return app.render_template('message_registry.json')
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
@ -843,6 +935,10 @@ def parse_args():
|
|||||||
type=str,
|
type=str,
|
||||||
help='SSL key to use for HTTPS. Can also be set'
|
help='SSL key to use for HTTPS. Can also be set'
|
||||||
'via config variable SUSHY_EMULATOR_SSL_KEY.')
|
'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 = parser.add_mutually_exclusive_group()
|
||||||
backend_group.add_argument('--os-cloud',
|
backend_group.add_argument('--os-cloud',
|
||||||
type=str,
|
type=str,
|
||||||
@ -908,6 +1004,9 @@ def main():
|
|||||||
if args.ssl_key:
|
if args.ssl_key:
|
||||||
app.config['SUSHY_EMULATOR_SSL_KEY'] = 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_context = None
|
||||||
ssl_certificate = app.config.get('SUSHY_EMULATOR_SSL_CERT')
|
ssl_certificate = app.config.get('SUSHY_EMULATOR_SSL_CERT')
|
||||||
ssl_key = app.config.get('SUSHY_EMULATOR_SSL_KEY')
|
ssl_key = app.config.get('SUSHY_EMULATOR_SSL_KEY')
|
||||||
|
@ -4,21 +4,27 @@
|
|||||||
"Name": "Redvirt Service",
|
"Name": "Redvirt Service",
|
||||||
"RedfishVersion": "1.5.0",
|
"RedfishVersion": "1.5.0",
|
||||||
"UUID": "85775665-c110-4b85-8989-e6162170b3ec",
|
"UUID": "85775665-c110-4b85-8989-e6162170b3ec",
|
||||||
|
{% if feature_set == "full" %}
|
||||||
"Chassis": {
|
"Chassis": {
|
||||||
"@odata.id": "/redfish/v1/Chassis"
|
"@odata.id": "/redfish/v1/Chassis"
|
||||||
},
|
},
|
||||||
|
{% endif %}
|
||||||
"Systems": {
|
"Systems": {
|
||||||
"@odata.id": "/redfish/v1/Systems"
|
"@odata.id": "/redfish/v1/Systems"
|
||||||
},
|
},
|
||||||
|
{% if feature_set != "minimum" %}
|
||||||
"Managers": {
|
"Managers": {
|
||||||
"@odata.id": "/redfish/v1/Managers"
|
"@odata.id": "/redfish/v1/Managers"
|
||||||
},
|
},
|
||||||
|
{% endif %}
|
||||||
|
{% if feature_set == "full" %}
|
||||||
"Registries": {
|
"Registries": {
|
||||||
"@odata.id": "/redfish/v1/Registries"
|
"@odata.id": "/redfish/v1/Registries"
|
||||||
},
|
},
|
||||||
"CertificateService": {
|
"CertificateService": {
|
||||||
"@odata.id": "/redfish/v1/CertificateService"
|
"@odata.id": "/redfish/v1/CertificateService"
|
||||||
},
|
},
|
||||||
|
{% endif %}
|
||||||
"@odata.id": "/redfish/v1/",
|
"@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."
|
"@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."
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
"Id": {{ identity|string|tojson }},
|
"Id": {{ identity|string|tojson }},
|
||||||
"Name": {{ name|string|tojson }},
|
"Name": {{ name|string|tojson }},
|
||||||
"UUID": {{ uuid|string|tojson }},
|
"UUID": {{ uuid|string|tojson }},
|
||||||
|
{%- if feature_set == "full" %}
|
||||||
"Manufacturer": "Sushy Emulator",
|
"Manufacturer": "Sushy Emulator",
|
||||||
"Status": {
|
"Status": {
|
||||||
"State": "Enabled",
|
"State": "Enabled",
|
||||||
"Health": "OK",
|
"Health": "OK",
|
||||||
"HealthRollUp": "OK"
|
"HealthRollUp": "OK"
|
||||||
},
|
},
|
||||||
|
{% endif %}
|
||||||
{%- if power_state %}
|
{%- if power_state %}
|
||||||
"PowerState": {{ power_state|string|tojson }},
|
"PowerState": {{ power_state|string|tojson }},
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
@ -40,6 +42,7 @@
|
|||||||
"BootSourceOverrideEnabled": "Continuous"
|
"BootSourceOverrideEnabled": "Continuous"
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
},
|
},
|
||||||
|
{%- if feature_set == "full" %}
|
||||||
"ProcessorSummary": {
|
"ProcessorSummary": {
|
||||||
{%- if total_cpus %}
|
{%- if total_cpus %}
|
||||||
"Count": {{ total_cpus }},
|
"Count": {{ total_cpus }},
|
||||||
@ -70,9 +73,6 @@
|
|||||||
"Memory": {
|
"Memory": {
|
||||||
"@odata.id": {{ "/redfish/v1/Systems/%s/Memory"|format(identity)|tojson }}
|
"@odata.id": {{ "/redfish/v1/Systems/%s/Memory"|format(identity)|tojson }}
|
||||||
},
|
},
|
||||||
"EthernetInterfaces": {
|
|
||||||
"@odata.id": {{ "/redfish/v1/Systems/%s/EthernetInterfaces"|format(identity)|tojson }}
|
|
||||||
},
|
|
||||||
"SecureBoot": {
|
"SecureBoot": {
|
||||||
"@odata.id": {{ "/redfish/v1/Systems/%s/SecureBoot"|format(identity)|tojson }}
|
"@odata.id": {{ "/redfish/v1/Systems/%s/SecureBoot"|format(identity)|tojson }}
|
||||||
},
|
},
|
||||||
@ -85,10 +85,17 @@
|
|||||||
{%- if indicator_led %}
|
{%- if indicator_led %}
|
||||||
"IndicatorLED": {{ indicator_led|string|tojson }},
|
"IndicatorLED": {{ indicator_led|string|tojson }},
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
{%- endif %}
|
||||||
|
{%- if feature_set != "minimum" %}
|
||||||
|
"EthernetInterfaces": {
|
||||||
|
"@odata.id": {{ "/redfish/v1/Systems/%s/EthernetInterfaces"|format(identity)|tojson }}
|
||||||
|
},
|
||||||
"VirtualMedia": {
|
"VirtualMedia": {
|
||||||
"@odata.id": {{ "/redfish/v1/Systems/%s/VirtualMedia"|format(identity)|tojson }}
|
"@odata.id": {{ "/redfish/v1/Systems/%s/VirtualMedia"|format(identity)|tojson }}
|
||||||
},
|
},
|
||||||
|
{%- endif %}
|
||||||
"Links": {
|
"Links": {
|
||||||
|
{%- if feature_set == "full" %}
|
||||||
"Chassis": [
|
"Chassis": [
|
||||||
{%- for chassis_ in chassis %}
|
{%- for chassis_ in chassis %}
|
||||||
{
|
{
|
||||||
@ -96,6 +103,8 @@
|
|||||||
}{% if not loop.last %},{% endif %}
|
}{% if not loop.last %},{% endif %}
|
||||||
{% endfor -%}
|
{% endfor -%}
|
||||||
],
|
],
|
||||||
|
{% endif %}
|
||||||
|
{%- if feature_set != "minimum" %}
|
||||||
"ManagedBy": [
|
"ManagedBy": [
|
||||||
{%- for manager in managers %}
|
{%- for manager in managers %}
|
||||||
{
|
{
|
||||||
@ -103,6 +112,7 @@
|
|||||||
}{% if not loop.last %},{% endif %}
|
}{% if not loop.last %},{% endif %}
|
||||||
{% endfor -%}
|
{% endfor -%}
|
||||||
]
|
]
|
||||||
|
{% endif %}
|
||||||
},
|
},
|
||||||
"Actions": {
|
"Actions": {
|
||||||
"#ComputerSystem.Reset": {
|
"#ComputerSystem.Reset": {
|
||||||
|
@ -45,3 +45,10 @@ class BadRequest(FishyError):
|
|||||||
|
|
||||||
def __init__(self, msg, code=400):
|
def __init__(self, msg, code=400):
|
||||||
super().__init__(msg, code)
|
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)
|
||||||
|
@ -36,6 +36,12 @@ class EmulatorTestCase(base.BaseTestCase):
|
|||||||
|
|
||||||
super(EmulatorTestCase, self).setUp()
|
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):
|
class CommonTestCase(EmulatorTestCase):
|
||||||
|
|
||||||
@ -52,6 +58,22 @@ class CommonTestCase(EmulatorTestCase):
|
|||||||
self.assertEqual(200, response.status_code)
|
self.assertEqual(200, response.status_code)
|
||||||
self.assertEqual('RedvirtService', response.json['Id'])
|
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 = \
|
TEST_PASSWD = \
|
||||||
b"admin:$2y$05$mYl8KMwM94l4LR/sw1teIeA6P2u8gfX16e8wvT7NmGgAM5r9jgLl."
|
b"admin:$2y$05$mYl8KMwM94l4LR/sw1teIeA6P2u8gfX16e8wvT7NmGgAM5r9jgLl."
|
||||||
@ -210,6 +232,33 @@ class ManagersTestCase(EmulatorTestCase):
|
|||||||
response.json['Links']['ManagerForServers'])
|
response.json['Links']['ManagerForServers'])
|
||||||
self.assertEqual([{'@odata.id': '/redfish/v1/Chassis/chassis0'}],
|
self.assertEqual([{'@odata.id': '/redfish/v1/Chassis/chassis0'}],
|
||||||
response.json['Links']['ManagerForChassis'])
|
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):
|
class SystemsTestCase(EmulatorTestCase):
|
||||||
@ -263,6 +312,81 @@ class SystemsTestCase(EmulatorTestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[{'@odata.id': '/redfish/v1/Chassis/chassis0'}],
|
[{'@odata.id': '/redfish/v1/Chassis/chassis0'}],
|
||||||
response.json['Links']['Chassis'])
|
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')
|
@patch_resource('systems')
|
||||||
def test_system_resource_patch(self, systems_mock):
|
def test_system_resource_patch(self, systems_mock):
|
||||||
@ -336,6 +460,18 @@ class SystemsTestCase(EmulatorTestCase):
|
|||||||
json=data)
|
json=data)
|
||||||
self.assertEqual(500, response.status_code)
|
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')
|
@patch_resource('systems')
|
||||||
class BiosTestCase(EmulatorTestCase):
|
class BiosTestCase(EmulatorTestCase):
|
||||||
|
Loading…
Reference in New Issue
Block a user