SNIA / Swordfish-API-Emulator

The Swordfish API Emulator can emulate a Swordfish-based system statically or dynamically. Starting from an initial state described by mock-ups, the emulator can be used to emulate a Swordfish system responding to create/modify/delete operations in order to allow developers to model new Swordfish functionality, test clients, demonstrate Swordfish and other similar functions.
Other
22 stars 20 forks source link

Emulator response /redfish/v1/Systems models mismatch #131

Closed commonism closed 5 months ago

commonism commented 5 months ago

Hi,

I'm with https://github.com/commonism/aiopenapi3_redfish and I tried using https://github.com/DMTF/Redfish-Interface-Emulator for unit testing and ended up with Swordfish-API-Emulator.

I have found multiple issues with the data returned by the emulator, I'll show how to reproduce and how I mangle the data using aiopenapi3 plugins.

/redfish/v1/ - Systems missing in ServiceRoot

curl -s -u Administrator:Password --header "Accept: application/json" -H "Content-Type: application/json" -k https://127.0.0.1:5000/redfish/v1/ | grep Systems

/redfish/v1/Systems - malformed data

curl -q -u Administrator:Password --header "Accept: application/json" -H "Content-Type: application/json" -k https://127.0.0.1:5000/redfish/v1/Systems
{
    "@odata.context": "/redfish/v1/$metadata#Systems",
    "@odata.id": "/redfish/v1/Systems",
    "@odata.type": "#ComputerSystemCollection.ComputerSystemCollection",
    "Name": "Computer System Collection",
    "Links": {
        "Members@odata.count": 2,
        "Members": [
            {
                "@odata.id": "/redfish/v1/Systems/1"
            },
            {
                "@odata.id": "/redfish/v1/Systems/2"
            }
        ]
    }
}

not a Collection

the data returned is supposed to be a Collection, there is a collection but it's embedded in Links

        for k,v in ctx.parsed["Links"].items():
            ctx.parsed[k] = v
        del ctx.parsed["Links"]

System 2 does not exist

Accessing will error

curl -q -u Administrator:Password --header "Accept: application/json" -H "Content-Type: application/json" -k https://127.0.0.1:5000/redfish/v1/Systems/2
{
    "error": "Unable to read file because of the following error::[Errno 2] No such file or directory: 'Resources/Systems/2/index.json'"
}

fix

        # the second ComputerSystem does not exist
        del ctx.parsed["Members"][1]

/redfish/v1/Systems/1 returns malformed data

There is multiple issues here …

curl -q -u Administrator:Password --header "Accept: application/json" -H "Content-Type: application/json" -k https://127.0.0.1:5000/redfish/v1/Systems/1

using Processors instead of ProcessorsSummary

    "Processors": {
        "Count": 8,
        "Model": "Multi-Core Intel(R) Xeon(R) processor 7xxx Series",
        "Status": {
            "State": "Enabled",
            "Health": "OK",
            "HealthRollUp": "OK"
        }
    },

fix

            ctx.parsed["ProcessorSummary"] = ctx.parsed["Processors"]
            del ctx.parsed["Processors"]

using Memory instead of MemorySummary

    "Memory": {
        "TotalSystemMemoryGB": 16,
        "Status": {
            "State": "Enabled",
            "Health": "OK",
            "HealthRollUp": "OK"
        }
    },

fix

            ctx.parsed["MemorySummary"] = ctx.parsed["Memory"]
            del ctx.parsed["Memory"]

case HealthRollup

    "Status": {
        "State": "Enabled",
        "Health": "OK",
        "HealthRollUp": "OK"
    },

fix

            # it's HealthRollup
            for i in ["MemorySummary","ProcessorSummary"]:
                ctx.parsed[i]["Status"]["HealthRollup"] = ctx.parsed[i]["Status"]["HealthRollUp"]
                del ctx.parsed[i]["Status"]["HealthRollUp"]

            ctx.parsed["Status"]["HealthRollup"] = ctx.parsed["Status"]["HealthRollUp"]
            del ctx.parsed["Status"]["HealthRollUp"]

missing i in GiB

    "Memory": {
        "TotalSystemMemoryGB": 16,

fix

            # TotalSystemMemoryGiB
            ctx.parsed["MemorySummary"]["TotalSystemMemoryGiB"] = ctx.parsed["MemorySummary"]["TotalSystemMemoryGB"]
            del ctx.parsed["MemorySummary"]["TotalSystemMemoryGB"]

BootSourceOverrideSupported does not exist

    "Boot": {
        "BootSourceOverrideEnabled": "Once",
        "BootSourceOverrideTarget": "Pxe",
        "BootSourceOverrideSupported": [

fix

            # AliasBootOrder
            ctx.parsed["Boot"]["AliasBootOrder"] = ctx.parsed["Boot"]["BootSourceOverrideSupported"]
            del ctx.parsed["Boot"]["BootSourceOverrideSupported"]

Power does not exist

    "Power": "On",

fix

            # PowerState
            ctx.parsed["PowerState"] = ctx.parsed["Power"]
            del ctx.parsed["Power"]

Action DMTF.AllowableValues is invalid

    "Actions": {
        "#ComputerSystem.Reset": {
            "target": "/rest/v1/Systems/1/Actions/ComputerSystem.Reset",
            "ResetType@DMTF.AllowableValues": [

fix

            # Redfish@AllowableValues
            ctx.parsed["Actions"]["#ComputerSystem.Reset"]["ResetType@Redfish.AllowableValues"] = ctx.parsed["Actions"]["#ComputerSystem.Reset"]["ResetType@DMTF.AllowableValues"]
            del ctx.parsed["Actions"]["#ComputerSystem.Reset"]["ResetType@DMTF.AllowableValues"]

Action target is outside of /redfish/v1

not sure if this is valid, in my case this caused problems (besides calling the target does not work).

    "Actions": {
        "#ComputerSystem.Reset": {
            "target": "/rest/v1/Systems/1/Actions/ComputerSystem.Reset",

I had to add the target to the openapi.yaml description document, aliasing the PathItem for "/redfish/v1/Systems/1/Actions/ComputerSystem.Reset" to teach my client the argument & return values

Links has invalid properties SimpleNetwork & SimpleStorage

    "Links": {
        "Chassis": [
            {
                "@odata.id": "/redfish/v1/Chassis/1"
            }
        ],
        "ManagedBy": [
            {
                "@odata.id": "/redfish/v1/Managers/1"
            }
        ],
        "SimpleNetwork": {
            "@odata.id": "/redfish/v1/Systems/1/SimpleNetwork"
        },
        "SimpleStorage": {
            "@odata.id": "/redfish/v1/Systems/1/SimpleStorage"
        },
        "Oem": {}
    },

fix

            # Links invalid properties
            del ctx.parsed["Links"]["SimpleNetwork"]
            del ctx.parsed["Links"]["SimpleStorage"]

/rest/v1/Systems/1/Actions/ComputerSystem.Reset - 404

curl -u Administrator:Password -k -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{"Action": "Reset", "ResetType": "On"}' https://127.0.0.1:5000/rest/v1/Systems/1/Actions/ComputerSystem.Reset
<!doctype html>
<html lang=en>
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>

I tried /redfish as well

curl -u Administrator:Password -k -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{"Action": "Reset", "ResetType": "On"}' https://127.0.0.1:5000/redfish/v1/Systems/1/Actions/ComputerSystem.Reset
<!doctype html>
<html lang=en>
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>

Due to the content type, data & status code, no fix here.

Error message invalid format

curl -D /dev/stdout -q -u Administrator:Password --header "Accept: application/json" -H "Content-Type: application/json" -k https://127.0.0.1:5000/redfish/v1/Systems/4
HTTP/1.1 404 NOT FOUND
Server: Werkzeug/3.0.1 Python/3.12.3
Date: Fri, 17 May 2024 15:26:31 GMT
Content-Type: application/json
Content-Length: 140
OData-Version: 4.0
Cache-Control: No-store
Vary: Cookie
Set-Cookie: session=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Max-Age=0; HttpOnly; Path=/
Connection: close
{
    "error": "Unable to read file because of the following error::[Errno 2] No such file or directory: 'Resources/Systems/4/index.json'"
}

fix

            if ctx.status_code == "404":
                ctx.parsed["error"] = {"message":ctx.parsed["error"], "code":"red"}
commonism commented 5 months ago

/rest/v1/Systems/1 - invalid references

The objects linked do not exist.

    "Links": {
        "Chassis": [
            {
                "@odata.id": "/redfish/v1/Chassis/1"
            }
        ],
        "ManagedBy": [
            {
                "@odata.id": "/redfish/v1/Managers/1"
            }
        ],
rahlvers commented 5 months ago

Thanks - the /redfish/v1/Systems were left as a remnant from the RF emulator, and not cleaned up properly in the setup script. This is a function of the underlying mockups, not the emulator itself. If you have mockups for a different configuration, you can drop them in to the "Resources" directory and see a different configuration.
There are pre-built versions of this available in containers for storage configurations on dockerhub: https://hub.docker.com/u/snia

I've put a PR in to fix the setup script (#132)

commonism commented 5 months ago

You've missed it in the docker file.