Implement LocationIndicatorActive for Fan
Implement LocationIndicatorActive for Fan schema to set and get the
status of the location LED for each Fan.[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/Fan.v1_5_2.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/Chassis/chassis/ThermalSubsystem/Fans/fan1
{
"@odata.id": "/redfish/v1/Chassis/chassis/ThermalSubsystem/Fans/fan1",
"@odata.type": "#Fan.v1_3_0.Fan",
"Id": "fan1",
...
"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/Chassis/chassis/ThermalSubsystem/Fans/fan1
curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Chassis/chassis/ThermalSubsystem/Fans/fan1
{
"@odata.id": "/redfish/v1/Chassis/chassis/ThermalSubsystem/Fans/fan1",
"@odata.type": "#Fan.v1_3_0.Fan",
"Id": "fan1",
...
"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/Chassis/chassis/ThermalSubsystem/Fans/fan1
curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Chassis/chassis/ThermalSubsystem/Fans/fan1
{
"@odata.id": "/redfish/v1/Chassis/chassis/ThermalSubsystem/Fans/fan1",
"@odata.type": "#Fan.v1_3_0.Fan",
"Id": "fan1",
...
"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/Chassis/chassis/ThermalSubsystem/Fans/fan1
{
"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 Fan resource
```
curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Chassis/chassis/ThermalSubsystem/Fans/fan15
{
"error": {
"@Message.ExtendedInfo": [
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The requested resource of type Fan named 'fan15' was not found.",
"MessageArgs": [
"Fan",
"fan15"
],
"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 Fan named 'fan15' was not found."
}
}
curl -k -H "X-Auth-Token: $token" -H "Content-Type: application/json" -X PATCH -d '{"LocationIndicatorActive":true}' https://${bmc}/redfish/v1/Chassis/chassis/ThermalSubsystem/Fans/fan15
{
"error": {
"@Message.ExtendedInfo": [
{
"@odata.type": "#Message.v1_1_1.Message",
"Message": "The requested resource of type Fan named 'fan15' was not found.",
"MessageArgs": [
"Fan",
"fan15"
],
"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 Fan named 'fan15' was not found."
}
}
```
Signed-off-by: Albert Zhang <zhanghaodi@inspur.com>
Signed-off-by: Lakshmi Yadlapati <lakshmiy@us.ibm.com>
Signed-off-by: Myung Bae <myungbae@us.ibm.com>
Signed-off-by: Janet Adkins <janeta@us.ibm.com>
Change-Id: Ibc0da1714120b03c9a06241be1f721561b4d0d8b
diff --git a/Redfish.md b/Redfish.md
index cc6999c..3770aab 100644
--- a/Redfish.md
+++ b/Redfish.md
@@ -376,6 +376,7 @@
#### Fan
- Location
+- LocationIndicatorActive
- Manufacturer
- Model
- PartNumber
diff --git a/redfish-core/lib/fan.hpp b/redfish-core/lib/fan.hpp
index baa25b3..c10288d 100644
--- a/redfish-core/lib/fan.hpp
+++ b/redfish-core/lib/fan.hpp
@@ -8,11 +8,13 @@
#include "error_messages.hpp"
#include "generated/enums/resource.hpp"
#include "http_request.hpp"
+#include "led.hpp"
#include "logging.hpp"
#include "query.hpp"
#include "registries/privilege_registry.hpp"
#include "utils/chassis_utils.hpp"
#include "utils/dbus_utils.hpp"
+#include "utils/json_utils.hpp"
#include <asm-generic/errno.h>
@@ -213,7 +215,7 @@
messages::resourceNotFound(asyncResp->res, "Fan", fanId);
}
-inline void getValidFanPath(
+inline void getValidFanObject(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& validChassisPath, const std::string& fanId,
const std::function<void(const std::string& fanPath,
@@ -375,7 +377,7 @@
});
}
-inline void afterGetValidFanPath(
+inline void afterGetValidFanObject(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& chassisId, const std::string& fanId,
const std::string& fanPath, const std::string& service)
@@ -385,6 +387,7 @@
getFanHealth(asyncResp, fanPath, service);
getFanAsset(asyncResp, fanPath, service);
getFanLocation(asyncResp, fanPath, service);
+ getLocationIndicatorActive(asyncResp, fanPath);
}
inline void doFanGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
@@ -397,9 +400,9 @@
return;
}
- getValidFanPath(
+ getValidFanObject(
asyncResp, *validChassisPath, fanId,
- std::bind_front(afterGetValidFanPath, asyncResp, chassisId, fanId));
+ std::bind_front(afterGetValidFanObject, asyncResp, chassisId, fanId));
}
inline void handleFanHead(App& app, const crow::Request& req,
@@ -422,7 +425,7 @@
chassisId);
return;
}
- getValidFanPath(
+ getValidFanObject(
asyncResp, *validChassisPath, fanId,
[asyncResp](const std::string&, const std::string&) {
asyncResp->res.addHeader(
@@ -446,6 +449,73 @@
std::bind_front(doFanGet, asyncResp, chassisId, fanId));
}
+inline void handleSetFanPathById(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& chassisId, const std::string& fanId,
+ bool locationIndicatorActive, const boost::system::error_code& ec,
+ const dbus::utility::MapperGetSubTreePathsResponse& fanPaths)
+{
+ if (ec)
+ {
+ if (ec.value() == boost::system::errc::io_error)
+ {
+ BMCWEB_LOG_WARNING("Chassis {} not found", chassisId);
+ messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
+ return;
+ }
+
+ BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ for (const auto& fanPath : fanPaths)
+ {
+ if (checkFanId(fanPath, fanId))
+ {
+ setLocationIndicatorActive(asyncResp, fanPath,
+ locationIndicatorActive);
+ return;
+ }
+ }
+ BMCWEB_LOG_WARNING("Fan {} not found", fanId);
+ messages::resourceNotFound(asyncResp->res, "Fan", fanId);
+}
+
+inline void handleFanPatch(App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& chassisId,
+ const std::string& fanId)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+
+ std::optional<bool> locationIndicatorActive;
+ if (!json_util::readJsonPatch(req, asyncResp->res,
+ "LocationIndicatorActive",
+ locationIndicatorActive))
+ {
+ return;
+ }
+
+ if (locationIndicatorActive)
+ {
+ dbus::utility::getAssociatedSubTreePathsById(
+ chassisId, "/xyz/openbmc_project/inventory", chassisInterfaces,
+ "cooled_by", fanInterface,
+ [asyncResp, chassisId, fanId, locationIndicatorActive](
+ const boost::system::error_code& ec,
+ const dbus::utility::MapperGetSubTreePathsResponse&
+ subtreePaths) {
+ handleSetFanPathById(asyncResp, chassisId, fanId,
+ *locationIndicatorActive, ec,
+ subtreePaths);
+ });
+ }
+}
+
inline void requestRoutesFan(App& app)
{
BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/<str>/")
@@ -457,6 +527,11 @@
.privileges(redfish::privileges::getFan)
.methods(boost::beast::http::verb::get)(
std::bind_front(handleFanGet, std::ref(app)));
+
+ BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ThermalSubsystem/Fans/<str>/")
+ .privileges(redfish::privileges::patchFan)
+ .methods(boost::beast::http::verb::patch)(
+ std::bind_front(handleFanPatch, std::ref(app)));
}
} // namespace redfish