blob: 6b650abdb38b027bed1d6371dd264a402958a257 [file]
#ifndef THIRD_PARTY_GBMCWEB_REDFISH_CORE_LIB_CONTROL_H_
#define THIRD_PARTY_GBMCWEB_REDFISH_CORE_LIB_CONTROL_H_
#include <array>
#include <cstdint>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <variant>
#include "absl/functional/any_invocable.h" // IWYU pragma: keep
#include "absl/strings/str_cat.h"
#include "app.hpp"
#include "http_request.hpp"
#include "logging.hpp"
#include "utility.hpp"
#include "async_resp.hpp"
#include "dbus_utility.hpp"
#include "error_messages.hpp"
#include "query.hpp"
#include "registries/privilege_registry.hpp"
#include "collection.hpp"
#include "json_utils.hpp"
#include <nlohmann/json.hpp>
#include "managed_store.hpp"
#include "managed_store_types.hpp"
namespace redfish {
inline void getControlCollection(
App& app, const crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& chassisId) {
if (!redfish::setUpRedfishRoute(app, req, asyncResp)) {
return;
}
asyncResp->res.jsonValue["@odata.type"] =
"#ControlCollection.v1_0_0.ControlCollection";
boost::urls::url collectionUrl = crow::utility::urlFromPieces(
"redfish", "v1", "Chassis", chassisId, "Controls");
asyncResp->res.jsonValue["@odata.id"] = collectionUrl;
asyncResp->res.jsonValue["Name"] = "Control Collection";
asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
asyncResp->res.jsonValue["Members@odata.count"] = 0;
constexpr std::array<std::string_view, 1> interfaces = {
"xyz.openbmc_project.Chassis.Control"};
std::string subtreePath =
absl::StrCat("/xyz/openbmc_project/control/", chassisId);
collection_util::getCollectionMembers(asyncResp, collectionUrl, interfaces,
subtreePath.c_str());
}
inline void populateControlProperties(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& chassisId, const std::string& controlId,
const boost::system::error_code& ec,
const dbus::utility::DBusPropertiesMap& properties) {
if (ec) {
messages::internalError(asyncResp->res);
return;
}
asyncResp->res.jsonValue["@odata.type"] = "#Control.v1_5_1.Control";
asyncResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
"redfish", "v1", "Chassis", chassisId, "Controls", controlId);
asyncResp->res.jsonValue["Id"] = controlId;
asyncResp->res.jsonValue["Name"] =
absl::StrCat("Chassis Control ", controlId);
uint32_t currentSetPoint = 0;
for (const auto& [propName, propValue] : properties) {
if (propName == "SetPoint") {
const uint32_t* value = std::get_if<uint32_t>(&propValue);
if (value != nullptr) {
currentSetPoint = *value;
}
} else if (propName == "SetPointUnits") {
const std::string* value = std::get_if<std::string>(&propValue);
if (value != nullptr) {
asyncResp->res.jsonValue["SetPointUnits"] = *value;
}
} else if (propName == "ControlType") {
const std::string* value = std::get_if<std::string>(&propValue);
if (value != nullptr) {
asyncResp->res.jsonValue["ControlType"] = *value;
}
} else if (propName == "PhysicalContext") {
const std::string* value = std::get_if<std::string>(&propValue);
if (value != nullptr) {
asyncResp->res.jsonValue["PhysicalContext"] = *value;
}
}
}
if (currentSetPoint == 0) {
asyncResp->res.jsonValue["ControlMode"] = "Disabled";
asyncResp->res.jsonValue.erase("SetPointUnits");
} else {
asyncResp->res.jsonValue["ControlMode"] = "Manual";
asyncResp->res.jsonValue["SetPoint"] = currentSetPoint;
}
}
inline void handleControlObject(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& chassisId, const std::string& controlId,
const std::string& objectPath,
const managedStore::ManagedObjectStoreContext& requestContext,
const boost::system::error_code& ec,
const dbus::utility::MapperGetObject& object) {
if (ec || object.empty()) {
messages::resourceNotFound(asyncResp->res, "Control", controlId);
return;
}
const std::string& serviceName = object.begin()->first;
managedStore::GetManagedObjectStore()->getAllProperties(
serviceName, objectPath, "xyz.openbmc_project.Chassis.Control",
requestContext,
std::bind_front(populateControlProperties, asyncResp, chassisId,
controlId));
}
inline void getControlConfiguration(
App& app, const crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& chassisId, const std::string& controlId) {
if (!redfish::setUpRedfishRoute(app, req, asyncResp)) {
return;
}
std::string objectPath =
absl::StrCat("/xyz/openbmc_project/control/", chassisId, "/", controlId);
constexpr std::array<std::string_view, 1> interfaces = {
"xyz.openbmc_project.Chassis.Control"};
managedStore::ManagedObjectStoreContext requestContext(asyncResp);
managedStore::GetManagedObjectStore()->getDbusObject(
objectPath, interfaces, requestContext,
std::bind_front(handleControlObject, asyncResp, chassisId, controlId,
objectPath, requestContext));
}
inline void handlePatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& controlId,
const std::string& objectPath, uint32_t setPointValue,
const boost::system::error_code& ec,
const dbus::utility::MapperGetObject& object) {
if (ec) {
BMCWEB_LOG_ERROR << "Failed to get SetPoint property: " << ec;
messages::internalError(asyncResp->res);
return;
}
if (object.empty()) {
messages::resourceNotFound(asyncResp->res, "Control", controlId);
return;
}
const std::string& serviceName = object.begin()->first;
const std::string interface = "org.freedesktop.DBus.Properties";
const std::string method = "Set";
const std::string controlInterface = "xyz.openbmc_project.Chassis.Control";
const std::string propertyName = "SetPoint";
managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe(
asyncResp->strand_,
absl::AnyInvocable<void(const boost::system::error_code&)>(
[asyncResp](const boost::system::error_code& ec) {
if (ec) {
BMCWEB_LOG_ERROR << "Failed to set SetPoint property: " << ec;
messages::internalError(asyncResp->res);
return;
}
messages::success(asyncResp->res);
}),
serviceName, objectPath, interface, method, controlInterface,
propertyName, dbus::utility::DbusVariantType(setPointValue));
}
inline void patchControlConfiguration(
App& app, const crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& chassisId, const std::string& controlId) {
if (!redfish::setUpRedfishRoute(app, req, asyncResp)) {
return;
}
std::optional<uint32_t> setPoint;
if (!json_util::readJsonPatch(req, asyncResp->res, "SetPoint", setPoint)) {
return;
}
std::string objectPath =
absl::StrCat("/xyz/openbmc_project/control/", chassisId, "/", controlId);
constexpr std::array<std::string_view, 1> interfaces = {
"xyz.openbmc_project.Chassis.Control"};
managedStore::ManagedObjectStoreContext requestContext(asyncResp);
managedStore::GetManagedObjectStore()->getDbusObject(
objectPath, interfaces, requestContext,
std::bind_front(handlePatch, asyncResp, controlId, objectPath,
*setPoint));
}
inline void requestRoutesControl(App& app) {
BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Controls/")
.privileges(redfish::privileges::getControlCollection)
.methods(boost::beast::http::verb::get)(
std::bind_front(getControlCollection, std::ref(app)));
BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Controls/<str>/")
.privileges(redfish::privileges::getControl)
.methods(boost::beast::http::verb::get)(
std::bind_front(getControlConfiguration, std::ref(app)));
BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Controls/<str>/")
.privileges(redfish::privileges::patchControl)
.methods(boost::beast::http::verb::patch)(
std::bind_front(patchControlConfiguration, std::ref(app)));
}
} // namespace redfish
#endif // THIRD_PARTY_GBMCWEB_REDFISH_CORE_LIB_CONTROL_H_