/* Copyright (c) 2018 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #pragma once #include "app.hpp" #include "dbus_utility.hpp" #include "generated/enums/action_info.hpp" #include "generated/enums/chassis.hpp" #include "generated/enums/resource.hpp" #include "led.hpp" #include "query.hpp" #include "redfish_util.hpp" #include "registries/privilege_registry.hpp" #include "utils/collection.hpp" #include "utils/dbus_utils.hpp" #include "utils/json_utils.hpp" #include #include #include #include #include #include #include #include namespace redfish { /** * @brief Retrieves resources over dbus to link to the chassis * * @param[in] asyncResp - Shared pointer for completing asynchronous * calls * @param[in] path - Chassis dbus path to look for the storage. * * Calls the Association endpoints on the path + "/storage" and add the link of * json["Links"]["Storage@odata.count"] = * {"@odata.id", "/redfish/v1/Storage/" + resourceId} * * @return None. */ inline void getStorageLink(const std::shared_ptr& asyncResp, const sdbusplus::message::object_path& path) { sdbusplus::asio::getProperty>( *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper", (path / "storage").str, "xyz.openbmc_project.Association", "endpoints", [asyncResp](const boost::system::error_code& ec, const std::vector& storageList) { if (ec) { BMCWEB_LOG_DEBUG("getStorageLink got DBUS response error"); return; } nlohmann::json::array_t storages; for (const std::string& storagePath : storageList) { std::string id = sdbusplus::message::object_path(storagePath).filename(); if (id.empty()) { continue; } nlohmann::json::object_t storage; storage["@odata.id"] = boost::urls::format("/redfish/v1/Systems/{}/Storage/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME, id); storages.emplace_back(std::move(storage)); } asyncResp->res.jsonValue["Links"]["Storage@odata.count"] = storages.size(); asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages); }); } /** * @brief Retrieves chassis state properties over dbus * * @param[in] asyncResp - Shared pointer for completing asynchronous calls. * * @return None. */ inline void getChassisState(std::shared_ptr asyncResp) { // crow::connections::systemBus->async_method_call( sdbusplus::asio::getProperty( *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis", "/xyz/openbmc_project/state/chassis0", "xyz.openbmc_project.State.Chassis", "CurrentPowerState", [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec, const std::string& chassisState) { if (ec) { if (ec == boost::system::errc::host_unreachable) { // Service not available, no error, just don't return // chassis state info BMCWEB_LOG_DEBUG("Service not available {}", ec); return; } BMCWEB_LOG_DEBUG("DBUS response error {}", ec); messages::internalError(asyncResp->res); return; } BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState); // Verify Chassis State if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On") { asyncResp->res.jsonValue["PowerState"] = resource::PowerState::On; asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; } else if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.Off") { asyncResp->res.jsonValue["PowerState"] = resource::PowerState::Off; asyncResp->res.jsonValue["Status"]["State"] = resource::State::StandbyOffline; } }); } /** * Retrieves physical security properties over dbus */ inline void handlePhysicalSecurityGetSubTree( const std::shared_ptr& asyncResp, const boost::system::error_code& ec, const dbus::utility::MapperGetSubTreeResponse& subtree) { if (ec) { // do not add err msg in redfish response, because this is not // mandatory property BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec); return; } // Iterate over all retrieved ObjectPaths. for (const auto& object : subtree) { if (!object.second.empty()) { const auto& service = object.second.front(); BMCWEB_LOG_DEBUG("Get intrusion status by service "); sdbusplus::asio::getProperty( *crow::connections::systemBus, service.first, object.first, "xyz.openbmc_project.Chassis.Intrusion", "Status", [asyncResp](const boost::system::error_code& ec1, const std::string& value) { if (ec1) { // do not add err msg in redfish response, because this // is not // mandatory property BMCWEB_LOG_ERROR("DBUS response error {}", ec1); return; } asyncResp->res.jsonValue["PhysicalSecurity"] ["IntrusionSensorNumber"] = 1; asyncResp->res .jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value; }); return; } } } inline void handleChassisCollectionGet( App& app, const crow::Request& req, const std::shared_ptr& asyncResp) { if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { return; } asyncResp->res.jsonValue["@odata.type"] = "#ChassisCollection.ChassisCollection"; asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; asyncResp->res.jsonValue["Name"] = "Chassis Collection"; constexpr std::array interfaces{ "xyz.openbmc_project.Inventory.Item.Board", "xyz.openbmc_project.Inventory.Item.Chassis"}; collection_util::getCollectionMembers( asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces, "/xyz/openbmc_project/inventory"); } inline void getChassisContainedBy( const std::shared_ptr& asyncResp, const std::string& chassisId, const boost::system::error_code& ec, const dbus::utility::MapperGetSubTreePathsResponse& upstreamChassisPaths) { if (ec) { if (ec.value() != EBADR) { BMCWEB_LOG_ERROR("DBUS response error {}", ec); messages::internalError(asyncResp->res); } return; } if (upstreamChassisPaths.empty()) { return; } if (upstreamChassisPaths.size() > 1) { BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId); messages::internalError(asyncResp->res); return; } sdbusplus::message::object_path upstreamChassisPath( upstreamChassisPaths[0]); std::string upstreamChassis = upstreamChassisPath.filename(); if (upstreamChassis.empty()) { BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}", upstreamChassisPath.str, chassisId); return; } asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis); } inline void getChassisContains( const std::shared_ptr& asyncResp, const std::string& chassisId, const boost::system::error_code& ec, const dbus::utility::MapperGetSubTreePathsResponse& downstreamChassisPaths) { if (ec) { if (ec.value() != EBADR) { BMCWEB_LOG_ERROR("DBUS response error {}", ec); messages::internalError(asyncResp->res); } return; } if (downstreamChassisPaths.empty()) { return; } nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"]; if (!jValue.is_array()) { // Create the array if it was empty jValue = nlohmann::json::array(); } for (const auto& p : downstreamChassisPaths) { sdbusplus::message::object_path downstreamChassisPath(p); std::string downstreamChassis = downstreamChassisPath.filename(); if (downstreamChassis.empty()) { BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}", downstreamChassisPath.str, chassisId); continue; } nlohmann::json link; link["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}", downstreamChassis); jValue.push_back(std::move(link)); } asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size(); } inline void getChassisConnectivity( const std::shared_ptr& asyncResp, const std::string& chassisId, const std::string& chassisPath) { BMCWEB_LOG_DEBUG("Get chassis connectivity"); constexpr std::array interfaces{ "xyz.openbmc_project.Inventory.Item.Board", "xyz.openbmc_project.Inventory.Item.Chassis"}; dbus::utility::getAssociatedSubTreePaths( chassisPath + "/contained_by", sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, interfaces, std::bind_front(getChassisContainedBy, asyncResp, chassisId)); dbus::utility::getAssociatedSubTreePaths( chassisPath + "/containing", sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, interfaces, std::bind_front(getChassisContains, asyncResp, chassisId)); } /** * ChassisCollection derived class for delivering Chassis Collection Schema * Functions triggers appropriate requests on DBus */ inline void requestRoutesChassisCollection(App& app) { BMCWEB_ROUTE(app, "/redfish/v1/Chassis/") .privileges(redfish::privileges::getChassisCollection) .methods(boost::beast::http::verb::get)( std::bind_front(handleChassisCollectionGet, std::ref(app))); } inline void getChassisLocationCode( const std::shared_ptr& asyncResp, const std::string& connectionName, const std::string& path) { sdbusplus::asio::getProperty( *crow::connections::systemBus, connectionName, path, "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", [asyncResp](const boost::system::error_code& ec, const std::string& property) { if (ec) { BMCWEB_LOG_ERROR("DBUS response error for Location"); messages::internalError(asyncResp->res); return; } asyncResp->res .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = property; }); } inline void getChassisUUID(const std::shared_ptr& asyncResp, const std::string& connectionName, const std::string& path) { sdbusplus::asio::getProperty( *crow::connections::systemBus, connectionName, path, "xyz.openbmc_project.Common.UUID", "UUID", [asyncResp](const boost::system::error_code& ec, const std::string& chassisUUID) { if (ec) { BMCWEB_LOG_ERROR("DBUS response error for UUID"); messages::internalError(asyncResp->res); return; } asyncResp->res.jsonValue["UUID"] = chassisUUID; }); } inline void handleDecoratorAssetProperties( const std::shared_ptr& asyncResp, const std::string& chassisId, const std::string& path, const dbus::utility::DBusPropertiesMap& propertiesList) { const std::string* partNumber = nullptr; const std::string* serialNumber = nullptr; const std::string* manufacturer = nullptr; const std::string* model = nullptr; const std::string* sparePartNumber = nullptr; const bool success = sdbusplus::unpackPropertiesNoThrow( dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, "Model", model, "SparePartNumber", sparePartNumber); if (!success) { messages::internalError(asyncResp->res); return; } if (partNumber != nullptr) { asyncResp->res.jsonValue["PartNumber"] = *partNumber; } if (serialNumber != nullptr) { asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; } if (manufacturer != nullptr) { asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; } if (model != nullptr) { asyncResp->res.jsonValue["Model"] = *model; } // SparePartNumber is optional on D-Bus // so skip if it is empty if (sparePartNumber != nullptr && !sparePartNumber->empty()) { asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; } asyncResp->res.jsonValue["Name"] = chassisId; asyncResp->res.jsonValue["Id"] = chassisId; if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL) { asyncResp->res.jsonValue["Thermal"]["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId); // Power object asyncResp->res.jsonValue["Power"]["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId); } if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM) { asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem", chassisId); asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", chassisId); asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics", chassisId); } // SensorCollection asyncResp->res.jsonValue["Sensors"]["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId); asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; nlohmann::json::array_t computerSystems; nlohmann::json::object_t system; system["@odata.id"] = std::format("/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME); computerSystems.emplace_back(std::move(system)); asyncResp->res.jsonValue["Links"]["ComputerSystems"] = std::move(computerSystems); nlohmann::json::array_t managedBy; nlohmann::json::object_t manager; manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME); managedBy.emplace_back(std::move(manager)); asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); getChassisState(asyncResp); getStorageLink(asyncResp, path); } inline void handleChassisGetSubTree( const std::shared_ptr& asyncResp, const std::string& chassisId, 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; } // Iterate over all retrieved ObjectPaths. for (const std::pair< std::string, std::vector>>>& object : subtree) { const std::string& path = object.first; const std::vector>>& connectionNames = object.second; sdbusplus::message::object_path objPath(path); if (objPath.filename() != chassisId) { continue; } getChassisConnectivity(asyncResp, chassisId, path); if (connectionNames.empty()) { BMCWEB_LOG_ERROR("Got 0 Connection names"); continue; } asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis"; asyncResp->res.jsonValue["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}", chassisId); asyncResp->res.jsonValue["Name"] = "Chassis Collection"; asyncResp->res.jsonValue["ChassisType"] = chassis::ChassisType::RackMount; asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] = boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset", chassisId); asyncResp->res .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] = boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo", chassisId); dbus::utility::getAssociationEndPoints( path + "/drive", [asyncResp, chassisId](const boost::system::error_code& ec3, const dbus::utility::MapperEndPoints& resp) { if (ec3 || resp.empty()) { return; // no drives = no failures } nlohmann::json reference; reference["@odata.id"] = boost::urls::format( "/redfish/v1/Chassis/{}/Drives", chassisId); asyncResp->res.jsonValue["Drives"] = std::move(reference); }); const std::string& connectionName = connectionNames[0].first; const std::vector& interfaces2 = connectionNames[0].second; const std::array hasIndicatorLed = { "xyz.openbmc_project.Inventory.Item.Chassis", "xyz.openbmc_project.Inventory.Item.Panel", "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; const std::string assetTagInterface = "xyz.openbmc_project.Inventory.Decorator.AssetTag"; const std::string replaceableInterface = "xyz.openbmc_project.Inventory.Decorator.Replaceable"; const std::string revisionInterface = "xyz.openbmc_project.Inventory.Decorator.Revision"; for (const auto& interface : interfaces2) { if (interface == assetTagInterface) { sdbusplus::asio::getProperty( *crow::connections::systemBus, connectionName, path, assetTagInterface, "AssetTag", [asyncResp, chassisId](const boost::system::error_code& ec2, const std::string& property) { if (ec2) { BMCWEB_LOG_ERROR( "DBus response error for AssetTag: {}", ec2); messages::internalError(asyncResp->res); return; } asyncResp->res.jsonValue["AssetTag"] = property; }); } else if (interface == replaceableInterface) { sdbusplus::asio::getProperty( *crow::connections::systemBus, connectionName, path, replaceableInterface, "HotPluggable", [asyncResp, chassisId](const boost::system::error_code& ec2, const bool property) { if (ec2) { BMCWEB_LOG_ERROR( "DBus response error for HotPluggable: {}", ec2); messages::internalError(asyncResp->res); return; } asyncResp->res.jsonValue["HotPluggable"] = property; }); } else if (interface == revisionInterface) { sdbusplus::asio::getProperty( *crow::connections::systemBus, connectionName, path, revisionInterface, "Version", [asyncResp, chassisId](const boost::system::error_code& ec2, const std::string& property) { if (ec2) { BMCWEB_LOG_ERROR( "DBus response error for Version: {}", ec2); messages::internalError(asyncResp->res); return; } asyncResp->res.jsonValue["Version"] = property; }); } } for (const char* interface : hasIndicatorLed) { if (std::ranges::find(interfaces2, interface) != interfaces2.end()) { getIndicatorLedState(asyncResp); getSystemLocationIndicatorActive(asyncResp); break; } } sdbusplus::asio::getAllProperties( *crow::connections::systemBus, connectionName, path, "xyz.openbmc_project.Inventory.Decorator.Asset", [asyncResp, chassisId, path](const boost::system::error_code&, const dbus::utility::DBusPropertiesMap& propertiesList) { handleDecoratorAssetProperties(asyncResp, chassisId, path, propertiesList); }); for (const auto& interface : interfaces2) { if (interface == "xyz.openbmc_project.Common.UUID") { getChassisUUID(asyncResp, connectionName, path); } else if (interface == "xyz.openbmc_project.Inventory.Decorator.LocationCode") { getChassisLocationCode(asyncResp, connectionName, path); } } return; } // Couldn't find an object with that name. return an error messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); } inline void handleChassisGet(App& app, const crow::Request& req, const std::shared_ptr& asyncResp, const std::string& chassisId) { if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { return; } constexpr std::array interfaces = { "xyz.openbmc_project.Inventory.Item.Board", "xyz.openbmc_project.Inventory.Item.Chassis"}; dbus::utility::getSubTree( "/xyz/openbmc_project/inventory", 0, interfaces, std::bind_front(handleChassisGetSubTree, asyncResp, chassisId)); constexpr std::array interfaces2 = { "xyz.openbmc_project.Chassis.Intrusion"}; dbus::utility::getSubTree( "/xyz/openbmc_project", 0, interfaces2, std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp)); } inline void handleChassisPatch(App& app, const crow::Request& req, const std::shared_ptr& asyncResp, const std::string& param) { if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { return; } std::optional locationIndicatorActive; std::optional indicatorLed; if (param.empty()) { return; } if (!json_util::readJsonPatch( req, asyncResp->res, "LocationIndicatorActive", locationIndicatorActive, "IndicatorLED", indicatorLed)) { return; } // TODO (Gunnar): Remove IndicatorLED after enough time has passed if (!locationIndicatorActive && !indicatorLed) { return; // delete this when we support more patch properties } if (indicatorLed) { asyncResp->res.addHeader( boost::beast::http::field::warning, "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\""); } constexpr std::array interfaces = { "xyz.openbmc_project.Inventory.Item.Board", "xyz.openbmc_project.Inventory.Item.Chassis"}; const std::string& chassisId = param; dbus::utility::getSubTree( "/xyz/openbmc_project/inventory", 0, interfaces, [asyncResp, chassisId, locationIndicatorActive, indicatorLed](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; } // Iterate over all retrieved ObjectPaths. for (const std::pair>>>& object : subtree) { const std::string& path = object.first; const std::vector< std::pair>>& connectionNames = object.second; sdbusplus::message::object_path objPath(path); if (objPath.filename() != chassisId) { continue; } if (connectionNames.empty()) { BMCWEB_LOG_ERROR("Got 0 Connection names"); continue; } const std::vector& interfaces3 = connectionNames[0].second; const std::array hasIndicatorLed = { "xyz.openbmc_project.Inventory.Item.Chassis", "xyz.openbmc_project.Inventory.Item.Panel", "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; bool indicatorChassis = false; for (const char* interface : hasIndicatorLed) { if (std::ranges::find(interfaces3, interface) != interfaces3.end()) { indicatorChassis = true; break; } } if (locationIndicatorActive) { if (indicatorChassis) { setSystemLocationIndicatorActive( asyncResp, *locationIndicatorActive); } else { messages::propertyUnknown(asyncResp->res, "LocationIndicatorActive"); } } if (indicatorLed) { if (indicatorChassis) { setIndicatorLedState(asyncResp, *indicatorLed); } else { messages::propertyUnknown(asyncResp->res, "IndicatorLED"); } } return; } messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); }); } /** * Chassis override class for delivering Chassis Schema * Functions triggers appropriate requests on DBus */ inline void requestRoutesChassis(App& app) { BMCWEB_ROUTE(app, "/redfish/v1/Chassis//") .privileges(redfish::privileges::getChassis) .methods(boost::beast::http::verb::get)( std::bind_front(handleChassisGet, std::ref(app))); BMCWEB_ROUTE(app, "/redfish/v1/Chassis//") .privileges(redfish::privileges::patchChassis) .methods(boost::beast::http::verb::patch)( std::bind_front(handleChassisPatch, std::ref(app))); } inline void doChassisPowerCycle(const std::shared_ptr& asyncResp) { constexpr std::array interfaces = { "xyz.openbmc_project.State.Chassis"}; // Use mapper to get subtree paths. dbus::utility::getSubTreePaths( "/", 0, interfaces, [asyncResp]( const boost::system::error_code& ec, const dbus::utility::MapperGetSubTreePathsResponse& chassisList) { if (ec) { BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec); messages::internalError(asyncResp->res); return; } const char* processName = "xyz.openbmc_project.State.Chassis"; const char* interfaceName = "xyz.openbmc_project.State.Chassis"; const char* destProperty = "RequestedPowerTransition"; const std::string propertyValue = "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; std::string objectPath = "/xyz/openbmc_project/state/chassis_system0"; /* Look for system reset chassis path */ if ((std::ranges::find(chassisList, objectPath)) == chassisList.end()) { /* We prefer to reset the full chassis_system, but if it doesn't * exist on some platforms, fall back to a host-only power reset */ objectPath = "/xyz/openbmc_project/state/chassis0"; } setDbusProperty(asyncResp, "ResetType", processName, objectPath, interfaceName, destProperty, propertyValue); }); } inline void handleChassisResetActionInfoPost( App& app, const crow::Request& req, const std::shared_ptr& asyncResp, const std::string& /*chassisId*/) { if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { return; } BMCWEB_LOG_DEBUG("Post Chassis Reset."); std::string resetType; if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) { return; } if (resetType != "PowerCycle") { BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType); messages::actionParameterNotSupported(asyncResp->res, resetType, "ResetType"); return; } doChassisPowerCycle(asyncResp); } /** * ChassisResetAction class supports the POST method for the Reset * action. * Function handles POST method request. * Analyzes POST body before sending Reset request data to D-Bus. */ inline void requestRoutesChassisResetAction(App& app) { BMCWEB_ROUTE(app, "/redfish/v1/Chassis//Actions/Chassis.Reset/") .privileges(redfish::privileges::postChassis) .methods(boost::beast::http::verb::post)( std::bind_front(handleChassisResetActionInfoPost, std::ref(app))); } inline void handleChassisResetActionInfoGet( App& app, const crow::Request& req, const std::shared_ptr& asyncResp, const std::string& chassisId) { if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { return; } asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId); asyncResp->res.jsonValue["Name"] = "Reset Action Info"; asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; nlohmann::json::array_t parameters; nlohmann::json::object_t parameter; parameter["Name"] = "ResetType"; parameter["Required"] = true; parameter["DataType"] = action_info::ParameterTypes::String; nlohmann::json::array_t allowed; allowed.emplace_back("PowerCycle"); parameter["AllowableValues"] = std::move(allowed); parameters.emplace_back(std::move(parameter)); asyncResp->res.jsonValue["Parameters"] = std::move(parameters); } /** * ChassisResetActionInfo derived class for delivering Chassis * ResetType AllowableValues using ResetInfo schema. */ inline void requestRoutesChassisResetActionInfo(App& app) { BMCWEB_ROUTE(app, "/redfish/v1/Chassis//ResetActionInfo/") .privileges(redfish::privileges::getActionInfo) .methods(boost::beast::http::verb::get)( std::bind_front(handleChassisResetActionInfoGet, std::ref(app))); } } // namespace redfish