The Redfish Interface Emulator can emulate a Redfish-based interface statically (GET) or dynamically (POST, PATCH, DELETE)
Copyright 2016-2023 DMTF. All rights reserved.
The Redfish Interface Emulator that can emulator a Redfish interface resources as static or dynamically.
Static emulator is accomplish by copy a Redfish mockup in a ./static directory.
Dynamic emulator is accomplished by creating the Python files. The code for an example resource (EgResource) is available to expedite the creation of dynamic resources. The example is for a collection/member construct, EgResources/{id}.
The Swordfish model has been emulate using this emulator. The repository is available at Swordfish API Emulator. The repository provides a good example of the Python files for dynamic resources.
The program has been verified on 3.5.2 and 3.9.1. Use the packet sets to install the correct packages.
The emulator is structure so it can be ran locally, in a Cloud Foundry, or as a Docker file.
When executing the Emulator locally, the Redfish service appears at port 5000, by default. The Redfish client uses the following URL to access the emulator Redfish server - http://localhost:5000. To run a second instance must a different 'port'. The port number can be changed via the command line parameters or the config.json file.
Several external packages are required for this tool. You may install the prerequisites by running:
pip3 install -r requirements.txt
Edit the emulator-config.json file and set "MODE": "Local", then start the emulator.
python emulator.py
The cloud foundry method has be successful within a company internal cloud foundry service. It has not be attempted on a public cloud foundry service.
The required python packages for a Cloud Foundry environment are listed in the file ./requirements.txt. The file lists the Python package, without the revision. The packages will be installed automatically during invocation.
The cloud foundry makes use of the following files: requirements.txt, runtime.txt, and Profile. So they should exists in the same directory as emulator.py.
Edit the emulator-config.json file and set "MODE": "Cloud", then push the emulator to the foundry.
cf push [foundry-app-name]
The foundry-app-name determines the URL for the Redfish service.
Use one of these actions to pull or build the container:
Pull the container from Docker Hub:
docker pull dmtf/redfish-interface-emulator:latest
Build a container from local source. Make sure to run from the root directory of the code that contains the Dockerfile:
docker build -t dmtf/redfish-interface-emulator:latest .
Build a container from GitHub:
docker build -t dmtf/redfish-interface-emulator:latest https://github.com/DMTF/Redfish-Interface-Emulator.git
This command runs the container with the built-in mockup:
docker run --rm dmtf/redfish-interface-emulator:latest
The behavior of the emulator can be control via command line flags or property values in emulator-config.json.
The emulator is invoked with the following command:
python emulator.py [-h] [-v] [-port PORT] [-debug]
-h -- help (gives syntax and usage)
-v -- verbose
-port -- specifies the port number to use
-debug -- enables debugging (needed to debug flask calls)
The emulator reads the emulator-config.json file to configure its behavior.
{
"MODE": "Local"
"HTTPS": "Disable",
"SPEC": "Redfish",
"STATIC": "Enable",
"TRAYS": [
"./Resources/Systems/1/index.json"
]
"POPULATE": "Emulator"
}
Three sample configuration files are provided:
The emulator supports HTTP and HTTPS connections. HTTPS is enabled by setting the HTTPS property in emulator-config.json.
{
"HTTPS": "Enable",
...
}
When HTTPS is enabled, the emulator looks for the files: server.crt and server.key in the same directory as emulator.py. The certificate file and key file can be self-signed or obtained from a certificate authority.
The emulator can be used to support static mockups. In a static mock, only HTTP GETs will work. Other Redfish simulators support static mockups.
The static mockup is found in the directory ./api_emulator/redfish/static. The emulator comes with a sample Redfish mockup already in the directory. This can be replaced with any mockup folder hierarchy. The Redfish Forum has posted several of their mockups in DSP2043.
Note: If the new mockup has additional resources in the ServiceRoot, then modifications need to be made in static_resource_emulator.py to adds these new resources.
The emulator was designed to support dynamic resources. This requires that Python code exists for each dynamic resource. Resources which are static and dynamic can co-exist in an emulator. This means one can straddle static vs dynamic emulation, with some resources static while others are dynamic.
Dynamic resource implementations which have been implemented are provided in the Appendix.
The following outlines the overall process. More complete documentation is in a Word document in the ./doc directory. To expedite the creation of the API-file and template file, the code generators for both files are described.
A dynamic resource is made by creating a template-file and an API-file for the resource.
Once the files are created, they are placed in the emulator directory structure.
To generate a API file, execute the following command
codegen_api [mockup] [outputdir]
Where
The generated code supports the HTTP GET, PATCH, POST and DELETE commands
If the resource has subordinate resources that need to be instantiated when this resource is instantiated, that code will need to be manually added.
To generate a template file, execute the following command
codegen_template [mockup] [outputdir]
Where
(TODO - add the filename as a command line parameter)
The codegen_template source file contains a dictionary with the names of Redfish collections and their corresponding wildcard. This dictionary needs to be manually updated to the keep in sync with Redfish modeling.
Once a resource is made dynamic, the emulator can either start up with no members in its collections or some initial set of members.
To populate the Redfish model, set the POPULATE property in emulator-config.json.
{
"POPULATE": "Emulator",
. . .
}
Once the emulator has started, it will read the file ./infragen/populate-config.json. This file contains a JSON structure which specifies resources to populate. The following example specifies that 5 Chassis be instantiated and linked to 5 Systems.
{
"POPULATE": {
"Chassis": [
{
"Name": "Compute Chassis",
"Id": "Chassis-{0}",
"Count": 5,
"Links": {
"ComputerSystems": [
{
"Name": "Compute System",
"Id": "System-{0}",
"Count": 1,
"Processors": [
{
"Id": "CPU{0}",
"TotalCores": 12,
"MaxSpeedMHz": 2400,
"Count": 2
}
],
"Memory": [
{
"Id": "DRAM{0}",
"CapacityMiB": 16384,
"MemoryType": "DRAM",
"Count": 4
},
{
"Id": "NVRAM{0}",
"CapacityMiB": 65536,
"MemoryType": "NVDIMM_N",
"Count": 4
}
],
"SimpleStorage": [
{
"Id": "SAS-CTRL{0}",
"Count": 1,
"Devices": {
"CapacityBytes": 549755813888,
"Count": 1
}
}
],
"EthernetInterfaces": [
{
"Id": "NIC-{0}",
"SpeedMbps": 10000,
"Count": 2
}
]
}
]
}
},
The INFRAGEN module is used to populate the Redfish Interface with members (Chassis, Systems, Resource Blocks, Resources Zones, Processors, Memory, etc).
This module is execute by emulator.py once the emulator is up and reads the populate-config.json file.
The tool generate_template.py can be used to help a user with the creation of JSON template according to a specific Redfish schema by guiding the user through the schema and asking for input values. This module runs independently of the populate function and from the emulator itself.
The following is the general command for running unit test.
python unittests.py <SPEC> "<PATH>"
Where
Once the command completes, inspect the log file which is produced, "test-rsa-emulator.log".
The command to test the emulator can executed against the emulator running locally or hosted in the cloud.
Generally, Postman is used to interact with the Redfish interface. However, a web GUI is available for testing the composition service, including the ability to compose and delete systems.
Screenshots of the browser available in /doc/browser-screenshots.pdf
To use, point a brower to the URI http://localhost:5000/browse.html
Run the release.sh
script to publish a new version.
sh release.sh <NewVersion>
Enter the release notes when prompted; an empty line signifies no more notes to add.
The emulator is made dynamic by added python code to emulate a resources RESTful behavior, call the API-file.
Dynamic resources implementations can be found in the Redfish Interface Emulator repository and the SNIA API Emulator repository.
The repository also had the codegen_api code generator for creating an API-file for a resource with some default behaviors. The code generator takes a mockup file as input.
The Redfish Interface Emulator comes with a small set of API-files to demonstrate the code structure. The repository also had the codegen_api code generator for creating an API-file for a resource with some default behaviors. The code generator takes a mockup file as input.
These dynamic resources are available in the Redfish Interface Emulator repository in the api_emulator/redfish directory.
Resource | API-file |
---|---|
./CompositionService | CompositionService_api.py |
./EventService | event_service.py |
./SessionService | |
./SessionService/Sessions/{id} | sessions_api.py |
./Chassis/{id} | Chassis_api.py |
./Chassis/{id}/Thermal | thermal_api.py |
./Chassis/{id}/Power | power_api.py |
./Systems/{id} | ComputerSystem_api.py |
./Systems/{id}/Memory | memory.py |
./Systems/{id}/Processors/{id} | processor.py |
./Systems/{id}/SimpleStorage/{id} | simple_storage.py |
./Managers/{id} | Manager_api.py |
The Swordfish API Emulator added the API-files to emulate the Swordfish schema.
These dynamic resources are available in the SNIA API Emulator repository in the api_emulator/redfish directory.
API-file | Resource |
---|---|
. | serviceroot_api |
./EventService/Subscriptions | Subscriptions.py |
./Chassis/{id} | Chassis_api.py |
./Chassis/{id}/Memory | c_memory |
./Chassis/{id}/Drives/{id} | drives_api.py |
./Chassis/{id}/MediaController | MediaControllers_api.py |
./Chassis/{id}/MediaControllers/{id}/Ports | mc_ports_api.py |
./Chassis/{id}/NetworkAdapters | networkadapaters_api.py |
./Chassis/{id}/NetworkAdapters/{id}/NetworkDeviceFunctions/{id} | networkdevicefunctions_api.py |
./Chassis/{id}/NetworkAdapters/{id}/Ports/{id} | nwports_api.py |
./Systems/{id} | ComputerSystem_api.py |
./Systems/{id}/Storage/{id}/Volumes/{id} | volumes_api |
./Systems/{id}/Storage/{id}/StoragePools/{id} | storagepools_api.py |
./Systems/{id}/Memory/{id} | memory.py |
./Systems/{id}/Memory/{id}/MemoryDomains/{id} | memory_domains_api.py |
./Systems/{id}/Memory/{id}/MemoryDomains/{id}/MemoryChunks/{id} | md_chunks_api.py |
./Fabrics/{id}/Connections/{id} | f_connections.py |
./Fabrics/{id}/EndpointGroups/{id} | f_endpointgroups.py |
./Fabrics/{id}/Endpoints/{id} | f_endpoints.py |
./Fabrics/{id}/Switches/{id} | f_switches.py |
./Fabrics/{id}/Switches/{id}/Ports/{id} | f_switch_ports_api.py |
./Fabrics/{id}/Zones/{id} | f_zones_api.py |
./Fabrics/{id}/FabricAdapters/{id} | fabricadapters.py |
./Fabrics/{id}/FabricAdapters/{id}/Ports/{id} | fa_ports_api.py |
./Storage | storage_api.py |
./Storage/{id}/Controllers/{id} | storagecontrollers_api |
./Storage/{id}/FileSystems | filesystems_api.py |
./Storage/{id}/StorageGroups | storagegroups_api.py |
./StorageSystems/{id} | storagesystems_api.py |
./StorageServices/{id}/ClassesOfService | classofservice_api.py |
./StorageServices/{id}/DataProtectionLoSCapabilities | dataprotectionloscapabilities_api.py |
./StorageServices/{id}/DataSecurityLoSCapabilities | datasecurityloscapabilities_api.py |
./StorageServices/{id}/DataStorageLoSCapabilities | datastorageloscapabilities_api.py |
./StorageServices/{id}/EndpointGroups | EndpointGroups_api.py |
./StorageServices/{id}/Endpoints | Endpoints_api.py |
./StorageServices/{id}/IOConnectivityLoSCapabilities | IOConnectivityLOSCapabilities_api.py |
./StorageServices/{id}/IOPerformanceLoSCapabilities | IOPerformanceLOSCapabilities_api.py |