Implement LocationIndicatorActive for CPU resource
Implement LocationIndicatorActive for Processor schema to set and get
the status of the location LED for a CPU.[1]
A client uses the `LocationIndicatorActive` property to physically
identify or locate the processor.
Uses the utility functions getLocationIndicatorActive() and
setLocationIndicatorActive() to follow the association and get or set
the LED value.
[1] https://redfish.dmtf.org/schemas/v1/Processor.v1_20_1.json
Tested:
- Validator passes
- Tested on p10bmc hardware simulator:
1. Get LocationIndicatorActive
```
curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Systems/system/Processors/cpu0
{
"@odata.id": "/redfish/v1/Systems/system/Processors/cpu0",
"@odata.type": "#Processor.v1_18_0.Processor",
"Id": "cpu0",
...
"LocationIndicatorActive": false,
...
}
```
2. Set LocationIndicatorActive to true
```
curl -k -H "X-Auth-Token: $token" -H "Content-Type: application/json" -X PATCH -d '{"LocationIndicatorActive":true}' https://${bmc}/redfish/v1/Systems/system/Processors/cpu0
curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Systems/system/Processors/cpu0
{
"@odata.id": "/redfish/v1/Systems/system/Processors/cpu0",
"@odata.type": "#Processor.v1_18_0.Processor",
"Id": "cpu0",
...
"LocationIndicatorActive": true,
...
}
```
3. Set LocationIndicatorActive to false
```
curl -k -H "X-Auth-Token: $token" -H "Content-Type: application/json" -X PATCH -d '{"LocationIndicatorActive":false}' https://${bmc}/redfish/v1/Systems/system/Processors/cpu0
curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Systems/system/Processors/cpu0
{
"@odata.id": "/redfish/v1/Systems/system/Processors/cpu0",
"@odata.type": "#Processor.v1_18_0.Processor",
"Id": "cpu0",
...
"LocationIndicatorActive": false,
...
}
```
4. Error returned when trying to set the value to non-boolean
```
curl -k -H "X-Auth-Token: $token" -H "Content-Type: application/json" -X PATCH -d '{"LocationIndicatorActive":"badvalue"}' https://${bmc}/redfish/v1/Systems/system/Processors/cpu0
{
"LocationIndicatorActive@Message.ExtendedInfo": [
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The value '\"badvalue\"' for the property LocationIndicatorActive is not a type that the property can accept.",
"MessageArgs": [
"\"badvalue\"",
"LocationIndicatorActive"
],
"MessageId": "Base.1.19.PropertyValueTypeError",
"MessageSeverity": "Warning",
"Resolution": "Correct the value for the property in the request body and resubmit the request if the operation failed."
}
]
}
```
5. Error returned when specifying an unknown CPU resource
```
curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Systems/system/Processors/cpu100
{
"error": {
"@Message.ExtendedInfo": [
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The requested resource of type Processor named 'cpu100' was not found.",
"MessageArgs": [
"Processor",
"cpu100"
],
"MessageId": "Base.1.19.ResourceNotFound",
"MessageSeverity": "Critical",
"Resolution": "Provide a valid resource identifier and resubmit the request."
}
],
"code": "Base.1.19.ResourceNotFound",
"message": "The requested resource of type Processor named 'cpu100' was not found."
}
}
curl -k -H "X-Auth-Token: $token" -H "Content-Type: application/json" -X PATCH -d '{"LocationIndicatorActive":true}' https://${bmc}/redfish/v1/Systems/system/Processors/cpu100
{
"error": {
"@Message.ExtendedInfo": [
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The requested resource of type Processor named 'cpu100' was not found.",
"MessageArgs": [
"Processor",
"cpu100"
],
"MessageId": "Base.1.19.ResourceNotFound",
"MessageSeverity": "Critical",
"Resolution": "Provide a valid resource identifier and resubmit the request."
}
],
"code": "Base.1.19.ResourceNotFound",
"message": "The requested resource of type Processor named 'cpu100' was not found."
}
}
```
Signed-off-by: George Liu <liuxiwei@inspur.com>
Signed-off-by: Janet Adkins <janeta@us.ibm.com>
Change-Id: I511dc9ee0373c227c171d87e0475296eb326741e
diff --git a/Redfish.md b/Redfish.md
index 3770aab..e8a22fa 100644
--- a/Redfish.md
+++ b/Redfish.md
@@ -986,6 +986,7 @@
#### Processor
- InstructionSet
+- LocationIndicatorActive
- Manufacturer
- MaxSpeedMHz
- PartNumber
diff --git a/redfish-core/lib/processor.hpp b/redfish-core/lib/processor.hpp
index d4afd3d..9f41b8d 100644
--- a/redfish-core/lib/processor.hpp
+++ b/redfish-core/lib/processor.hpp
@@ -7,11 +7,13 @@
#include "app.hpp"
#include "async_resp.hpp"
+#include "dbus_singleton.hpp"
#include "dbus_utility.hpp"
#include "error_messages.hpp"
#include "generated/enums/processor.hpp"
#include "generated/enums/resource.hpp"
#include "http_request.hpp"
+#include "led.hpp"
#include "logging.hpp"
#include "query.hpp"
#include "registries/privilege_registry.hpp"
@@ -728,20 +730,66 @@
});
}
+inline void handleProcessorSubtree(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& processorId,
+ const std::function<
+ void(const std::string& objectPath,
+ const dbus::utility::MapperServiceMap& serviceMap)>& callback,
+ const boost::system::error_code& ec,
+ const dbus::utility::MapperGetSubTreeResponse& subtree)
+{
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ for (const auto& [objectPath, serviceMap] : subtree)
+ {
+ // Ignore any objects which don't end with our desired cpu name
+ sdbusplus::message::object_path path(objectPath);
+ if (path.filename() == processorId)
+ {
+ // Filter out objects that don't have the CPU-specific
+ // interfaces to make sure we can return 404 on non-CPUs
+ // (e.g. /redfish/../Processors/dimm0)
+ for (const auto& [serviceName, interfaceList] : serviceMap)
+ {
+ if (std::ranges::find_first_of(interfaceList,
+ processorInterfaces) !=
+ interfaceList.end())
+ {
+ // Process the first object which matches cpu name and
+ // required interfaces, and potentially ignore any other
+ // matching objects. Assume all interfaces we want to
+ // process must be on the same object path.
+
+ callback(objectPath, serviceMap);
+ return;
+ }
+ }
+ }
+ }
+ messages::resourceNotFound(asyncResp->res, "Processor", processorId);
+}
+
/**
* Find the D-Bus object representing the requested Processor, and call the
* handler with the results. If matching object is not found, add 404 error to
* response and don't call the handler.
*
- * @param[in,out] resp Async HTTP response.
+ * @param[in,out] asyncResp Async HTTP response.
* @param[in] processorId Redfish Processor Id.
- * @param[in] handler Callback to continue processing request upon
+ * @param[in] callback Callback to continue processing request upon
* successfully finding object.
*/
-template <typename Handler>
-inline void getProcessorObject(const std::shared_ptr<bmcweb::AsyncResp>& resp,
- const std::string& processorId,
- Handler&& handler)
+inline void getProcessorObject(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& processorId,
+ std::function<void(const std::string& objectPath,
+ const dbus::utility::MapperServiceMap& serviceMap)>&&
+ callback)
{
BMCWEB_LOG_DEBUG("Get available system processor resources.");
@@ -758,52 +806,11 @@
"xyz.openbmc_project.Control.Power.Throttle"};
dbus::utility::getSubTree(
"/xyz/openbmc_project/inventory", 0, interfaces,
- [resp, processorId, handler = std::forward<Handler>(handler)](
+ [asyncResp, processorId, callback{std::move(callback)}](
const boost::system::error_code& ec,
const dbus::utility::MapperGetSubTreeResponse& subtree) {
- if (ec)
- {
- BMCWEB_LOG_DEBUG("DBUS response error: {}", ec);
- messages::internalError(resp->res);
- return;
- }
- for (const auto& [objectPath, serviceMap] : subtree)
- {
- // Ignore any objects which don't end with our desired cpu name
- if (!objectPath.ends_with(processorId))
- {
- continue;
- }
-
- bool found = false;
- // Filter out objects that don't have the CPU-specific
- // interfaces to make sure we can return 404 on non-CPUs
- // (e.g. /redfish/../Processors/dimm0)
- for (const auto& [serviceName, interfaceList] : serviceMap)
- {
- if (std::ranges::find_first_of(interfaceList,
- processorInterfaces) !=
- std::end(interfaceList))
- {
- found = true;
- break;
- }
- }
-
- if (!found)
- {
- continue;
- }
-
- // Process the first object which does match our cpu name and
- // required interfaces, and potentially ignore any other
- // matching objects. Assume all interfaces we want to process
- // must be on the same object path.
-
- handler(objectPath, serviceMap);
- return;
- }
- messages::resourceNotFound(resp->res, "Processor", processorId);
+ handleProcessorSubtree(asyncResp, processorId, callback, ec,
+ subtree);
});
}
@@ -812,6 +819,14 @@
const std::string& processorId, const std::string& objectPath,
const dbus::utility::MapperServiceMap& serviceMap)
{
+ asyncResp->res.addHeader(
+ boost::beast::http::field::link,
+ "</redfish/v1/JsonSchemas/Processor/Processor.json>; rel=describedby");
+ asyncResp->res.jsonValue["@odata.type"] = "#Processor.v1_18_0.Processor";
+ asyncResp->res.jsonValue["@odata.id"] =
+ boost::urls::format("/redfish/v1/Systems/{}/Processors/{}",
+ BMCWEB_REDFISH_SYSTEM_URI_NAME, processorId);
+
for (const auto& [serviceName, interfaceList] : serviceMap)
{
for (const auto& interface : interfaceList)
@@ -861,6 +876,10 @@
{
getThrottleProperties(asyncResp, serviceName, objectPath);
}
+ else if (interface == "xyz.openbmc_project.Association.Definitions")
+ {
+ getLocationIndicatorActive(asyncResp, objectPath);
+ }
}
}
}
@@ -1063,6 +1082,97 @@
"</redfish/v1/JsonSchemas/ProcessorCollection/ProcessorCollection.json>; rel=describedby");
}
+inline void handleProcessorGet(
+ App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& systemName, const std::string& processorId)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+ if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
+ {
+ // Option currently returns no systems. TBD
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+ if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
+ {
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+
+ getProcessorObject(
+ asyncResp, processorId,
+ std::bind_front(getProcessorData, asyncResp, processorId));
+}
+
+inline void doPatchProcessor(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& processorId,
+ const std::optional<std::string>& appliedConfigUri,
+ std::optional<bool> locationIndicatorActive, const std::string& objectPath,
+ const dbus::utility::MapperServiceMap& serviceMap)
+{
+ if (appliedConfigUri)
+ {
+ patchAppliedOperatingConfig(asyncResp, processorId, *appliedConfigUri,
+ objectPath, serviceMap);
+ }
+
+ if (locationIndicatorActive)
+ {
+ // Utility function handles reporting errors
+ setLocationIndicatorActive(asyncResp, objectPath,
+ *locationIndicatorActive);
+ }
+}
+
+inline void handleProcessorPatch(
+ App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& systemName, const std::string& processorId)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+ if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
+ {
+ // Option currently returns no systems. TBD
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+ if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
+ {
+ messages::resourceNotFound(asyncResp->res, "ComputerSystem",
+ systemName);
+ return;
+ }
+
+ std::optional<std::string> appliedConfigUri;
+ std::optional<bool> locationIndicatorActive;
+ if (!json_util::readJsonPatch(
+ req, asyncResp->res, //
+ "AppliedOperatingConfig/@odata.id", appliedConfigUri, //
+ "LocationIndicatorActive", locationIndicatorActive //
+ ))
+ {
+ return;
+ }
+
+ // Check for 404 and find matching D-Bus object, then run
+ // property patch handlers if that all succeeds.
+ getProcessorObject(
+ asyncResp, processorId,
+ std::bind_front(doPatchProcessor, asyncResp, processorId,
+ appliedConfigUri, locationIndicatorActive));
+}
+
inline void requestRoutesOperatingConfigCollection(App& app)
{
BMCWEB_ROUTE(app,
@@ -1295,88 +1405,13 @@
BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/<str>/")
.privileges(redfish::privileges::getProcessor)
- .methods(
- boost::beast::http::verb::
- get)([&app](const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& systemName,
- const std::string& processorId) {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
- if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
- {
- // Option currently returns no systems. TBD
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
- if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
- {
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
-
- asyncResp->res.addHeader(
- boost::beast::http::field::link,
- "</redfish/v1/JsonSchemas/Processor/Processor.json>; rel=describedby");
- asyncResp->res.jsonValue["@odata.type"] =
- "#Processor.v1_18_0.Processor";
- asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
- "/redfish/v1/Systems/{}/Processors/{}",
- BMCWEB_REDFISH_SYSTEM_URI_NAME, processorId);
-
- getProcessorObject(
- asyncResp, processorId,
- std::bind_front(getProcessorData, asyncResp, processorId));
- });
+ .methods(boost::beast::http::verb::get)(
+ std::bind_front(handleProcessorGet, std::ref(app)));
BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/<str>/")
.privileges(redfish::privileges::patchProcessor)
.methods(boost::beast::http::verb::patch)(
- [&app](const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& systemName,
- const std::string& processorId) {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
- if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
- {
- // Option currently returns no systems. TBD
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
- if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
- {
- messages::resourceNotFound(asyncResp->res, "ComputerSystem",
- systemName);
- return;
- }
-
- std::optional<std::string> appliedConfigUri;
- if (!json_util::readJsonPatch(
- req, asyncResp->res, //
- "AppliedOperatingConfig/@odata.id", appliedConfigUri //
- ))
- {
- return;
- }
-
- if (appliedConfigUri)
- {
- // Check for 404 and find matching D-Bus object, then run
- // property patch handlers if that all succeeds.
- getProcessorObject(
- asyncResp, processorId,
- std::bind_front(patchAppliedOperatingConfig, asyncResp,
- processorId, *appliedConfigUri));
- }
- });
+ std::bind_front(handleProcessorPatch, std::ref(app)));
}
} // namespace redfish