1e37f8451SRapkiewicz, Pawel /* 2e37f8451SRapkiewicz, Pawel // Copyright (c) 2018 Intel Corporation 3e37f8451SRapkiewicz, Pawel // 4e37f8451SRapkiewicz, Pawel // Licensed under the Apache License, Version 2.0 (the "License"); 5e37f8451SRapkiewicz, Pawel // you may not use this file except in compliance with the License. 6e37f8451SRapkiewicz, Pawel // You may obtain a copy of the License at 7e37f8451SRapkiewicz, Pawel // 8e37f8451SRapkiewicz, Pawel // http://www.apache.org/licenses/LICENSE-2.0 9e37f8451SRapkiewicz, Pawel // 10e37f8451SRapkiewicz, Pawel // Unless required by applicable law or agreed to in writing, software 11e37f8451SRapkiewicz, Pawel // distributed under the License is distributed on an "AS IS" BASIS, 12e37f8451SRapkiewicz, Pawel // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e37f8451SRapkiewicz, Pawel // See the License for the specific language governing permissions and 14e37f8451SRapkiewicz, Pawel // limitations under the License. 15e37f8451SRapkiewicz, Pawel */ 16e37f8451SRapkiewicz, Pawel #pragma once 17e37f8451SRapkiewicz, Pawel 1813451e39SWilly Tu #include "bmcweb_config.h" 1913451e39SWilly Tu 203ccb3adbSEd Tanous #include "app.hpp" 217a1dbc48SGeorge Liu #include "dbus_utility.hpp" 22b49ac873SJames Feist #include "health.hpp" 231c8fba97SJames Feist #include "led.hpp" 243ccb3adbSEd Tanous #include "query.hpp" 25*7164bc62SChau Ly #include "redfish_util.hpp" 263ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 273ccb3adbSEd Tanous #include "utils/collection.hpp" 283ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 29cf7eba09SNan Zhou #include "utils/json_utils.hpp" 301abe55efSEd Tanous 31e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 32ef4c65b7SEd Tanous #include <boost/url/format.hpp> 331e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp> 34fc903b3dSAndrew Geissler #include <sdbusplus/message.hpp> 3586d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 361214b7e7SGunnar Mills 377a1dbc48SGeorge Liu #include <array> 383544d2a7SEd Tanous #include <ranges> 397a1dbc48SGeorge Liu #include <string_view> 407a1dbc48SGeorge Liu 411abe55efSEd Tanous namespace redfish 421abe55efSEd Tanous { 43e37f8451SRapkiewicz, Pawel 44e37f8451SRapkiewicz, Pawel /** 455e577bc1SWilly Tu * @brief Retrieves resources over dbus to link to the chassis 465e577bc1SWilly Tu * 475e577bc1SWilly Tu * @param[in] asyncResp - Shared pointer for completing asynchronous 485e577bc1SWilly Tu * calls 495e577bc1SWilly Tu * @param[in] path - Chassis dbus path to look for the storage. 505e577bc1SWilly Tu * 515e577bc1SWilly Tu * Calls the Association endpoints on the path + "/storage" and add the link of 525e577bc1SWilly Tu * json["Links"]["Storage@odata.count"] = 535e577bc1SWilly Tu * {"@odata.id", "/redfish/v1/Storage/" + resourceId} 545e577bc1SWilly Tu * 555e577bc1SWilly Tu * @return None. 565e577bc1SWilly Tu */ 575e577bc1SWilly Tu inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 585e577bc1SWilly Tu const sdbusplus::message::object_path& path) 595e577bc1SWilly Tu { 605e577bc1SWilly Tu sdbusplus::asio::getProperty<std::vector<std::string>>( 615e577bc1SWilly Tu *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper", 625e577bc1SWilly Tu (path / "storage").str, "xyz.openbmc_project.Association", "endpoints", 63d4b054c1SWilly Tu [asyncResp](const boost::system::error_code& ec, 645e577bc1SWilly Tu const std::vector<std::string>& storageList) { 655e577bc1SWilly Tu if (ec) 665e577bc1SWilly Tu { 6762598e31SEd Tanous BMCWEB_LOG_DEBUG("getStorageLink got DBUS response error"); 685e577bc1SWilly Tu return; 695e577bc1SWilly Tu } 705e577bc1SWilly Tu 715e577bc1SWilly Tu nlohmann::json::array_t storages; 725e577bc1SWilly Tu for (const std::string& storagePath : storageList) 735e577bc1SWilly Tu { 745e577bc1SWilly Tu std::string id = 755e577bc1SWilly Tu sdbusplus::message::object_path(storagePath).filename(); 765e577bc1SWilly Tu if (id.empty()) 775e577bc1SWilly Tu { 785e577bc1SWilly Tu continue; 795e577bc1SWilly Tu } 805e577bc1SWilly Tu 815e577bc1SWilly Tu nlohmann::json::object_t storage; 825e577bc1SWilly Tu storage["@odata.id"] = boost::urls::format( 835e577bc1SWilly Tu "/redfish/v1/Systems/system/Storage/{}", id); 845e577bc1SWilly Tu storages.emplace_back(std::move(storage)); 855e577bc1SWilly Tu } 865e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["Storage@odata.count"] = 875e577bc1SWilly Tu storages.size(); 885e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages); 895e577bc1SWilly Tu }); 905e577bc1SWilly Tu } 915e577bc1SWilly Tu 925e577bc1SWilly Tu /** 93beeca0aeSGunnar Mills * @brief Retrieves chassis state properties over dbus 94beeca0aeSGunnar Mills * 95ac106bf6SEd Tanous * @param[in] asyncResp - Shared pointer for completing asynchronous calls. 96beeca0aeSGunnar Mills * 97beeca0aeSGunnar Mills * @return None. 98beeca0aeSGunnar Mills */ 99ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp) 100beeca0aeSGunnar Mills { 1011e1e598dSJonathan Doman // crow::connections::systemBus->async_method_call( 1021e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 1031e1e598dSJonathan Doman *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis", 1041e1e598dSJonathan Doman "/xyz/openbmc_project/state/chassis0", 1051e1e598dSJonathan Doman "xyz.openbmc_project.State.Chassis", "CurrentPowerState", 106ac106bf6SEd Tanous [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec, 1071e1e598dSJonathan Doman const std::string& chassisState) { 108beeca0aeSGunnar Mills if (ec) 109beeca0aeSGunnar Mills { 110a6e5e0abSCarson Labrado if (ec == boost::system::errc::host_unreachable) 111a6e5e0abSCarson Labrado { 112a6e5e0abSCarson Labrado // Service not available, no error, just don't return 113a6e5e0abSCarson Labrado // chassis state info 11462598e31SEd Tanous BMCWEB_LOG_DEBUG("Service not available {}", ec); 115a6e5e0abSCarson Labrado return; 116a6e5e0abSCarson Labrado } 11762598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 118ac106bf6SEd Tanous messages::internalError(asyncResp->res); 119beeca0aeSGunnar Mills return; 120beeca0aeSGunnar Mills } 121beeca0aeSGunnar Mills 12262598e31SEd Tanous BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState); 123beeca0aeSGunnar Mills // Verify Chassis State 124002d39b4SEd Tanous if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On") 125beeca0aeSGunnar Mills { 126ac106bf6SEd Tanous asyncResp->res.jsonValue["PowerState"] = "On"; 127ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 128beeca0aeSGunnar Mills } 1291e1e598dSJonathan Doman else if (chassisState == 130beeca0aeSGunnar Mills "xyz.openbmc_project.State.Chassis.PowerState.Off") 131beeca0aeSGunnar Mills { 132ac106bf6SEd Tanous asyncResp->res.jsonValue["PowerState"] = "Off"; 133ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "StandbyOffline"; 134beeca0aeSGunnar Mills } 1351e1e598dSJonathan Doman }); 136beeca0aeSGunnar Mills } 137beeca0aeSGunnar Mills 138c181942fSQiang XU /** 139c181942fSQiang XU * Retrieves physical security properties over dbus 140c181942fSQiang XU */ 141*7164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree( 142*7164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 143e99073f5SGeorge Liu const boost::system::error_code& ec, 144*7164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 145*7164bc62SChau Ly { 146c181942fSQiang XU if (ec) 147c181942fSQiang XU { 1484e0453b1SGunnar Mills // do not add err msg in redfish response, because this is not 149c181942fSQiang XU // mandatory property 15062598e31SEd Tanous BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec); 151c181942fSQiang XU return; 152c181942fSQiang XU } 153c181942fSQiang XU // Iterate over all retrieved ObjectPaths. 154c181942fSQiang XU for (const auto& object : subtree) 155c181942fSQiang XU { 156840a9ffcSPatrick Williams if (!object.second.empty()) 157c181942fSQiang XU { 158840a9ffcSPatrick Williams const auto service = object.second.front(); 159*7164bc62SChau Ly 160*7164bc62SChau Ly BMCWEB_LOG_DEBUG("Get intrusion status by service "); 161*7164bc62SChau Ly 162*7164bc62SChau Ly sdbusplus::asio::getProperty<std::string>( 163*7164bc62SChau Ly *crow::connections::systemBus, service.first, object.first, 164*7164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion", "Status", 165*7164bc62SChau Ly [asyncResp](const boost::system::error_code& ec1, 166*7164bc62SChau Ly const std::string& value) { 167*7164bc62SChau Ly if (ec1) 168*7164bc62SChau Ly { 169*7164bc62SChau Ly // do not add err msg in redfish response, because this is 170*7164bc62SChau Ly // not 171*7164bc62SChau Ly // mandatory property 172*7164bc62SChau Ly BMCWEB_LOG_ERROR("DBUS response error {}", ec1); 173*7164bc62SChau Ly return; 174*7164bc62SChau Ly } 175*7164bc62SChau Ly asyncResp->res 176*7164bc62SChau Ly .jsonValue["PhysicalSecurity"]["IntrusionSensorNumber"] = 1; 177*7164bc62SChau Ly asyncResp->res 178*7164bc62SChau Ly .jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value; 179*7164bc62SChau Ly }); 180*7164bc62SChau Ly 181c181942fSQiang XU return; 182c181942fSQiang XU } 183c181942fSQiang XU } 184c181942fSQiang XU } 185c181942fSQiang XU 186cf7eba09SNan Zhou inline void handleChassisCollectionGet( 187cf7eba09SNan Zhou App& app, const crow::Request& req, 188cf7eba09SNan Zhou const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1891abe55efSEd Tanous { 1903ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19145ca1b86SEd Tanous { 19245ca1b86SEd Tanous return; 19345ca1b86SEd Tanous } 1948d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 1958d1b46d7Szhanghch05 "#ChassisCollection.ChassisCollection"; 1968d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 1978d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 198e37f8451SRapkiewicz, Pawel 1997a1dbc48SGeorge Liu constexpr std::array<std::string_view, 2> interfaces{ 2007a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board", 2017a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis"}; 20202f6ff19SGunnar Mills collection_util::getCollectionMembers( 20336b5f1edSLakshmi Yadlapati asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces, 20436b5f1edSLakshmi Yadlapati "/xyz/openbmc_project/inventory"); 205cf7eba09SNan Zhou } 206cf7eba09SNan Zhou 207a5617496SJie Yang inline void getChassisContainedBy( 208a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 209a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 210a5617496SJie Yang const dbus::utility::MapperEndPoints& upstreamChassisPaths) 211a5617496SJie Yang { 212a5617496SJie Yang if (ec) 213a5617496SJie Yang { 214a5617496SJie Yang if (ec.value() != EBADR) 215a5617496SJie Yang { 21662598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 217a5617496SJie Yang messages::internalError(asyncResp->res); 218a5617496SJie Yang } 219a5617496SJie Yang return; 220a5617496SJie Yang } 221a5617496SJie Yang if (upstreamChassisPaths.empty()) 222a5617496SJie Yang { 223a5617496SJie Yang return; 224a5617496SJie Yang } 225a5617496SJie Yang if (upstreamChassisPaths.size() > 1) 226a5617496SJie Yang { 22762598e31SEd Tanous BMCWEB_LOG_ERROR("{} is contained by mutliple chassis", chassisId); 228a5617496SJie Yang messages::internalError(asyncResp->res); 229a5617496SJie Yang return; 230a5617496SJie Yang } 231a5617496SJie Yang 232a5617496SJie Yang sdbusplus::message::object_path upstreamChassisPath( 233a5617496SJie Yang upstreamChassisPaths[0]); 234a5617496SJie Yang std::string upstreamChassis = upstreamChassisPath.filename(); 235a5617496SJie Yang if (upstreamChassis.empty()) 236a5617496SJie Yang { 23762598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}", 23862598e31SEd Tanous upstreamChassisPath.str, chassisId); 239a5617496SJie Yang return; 240a5617496SJie Yang } 241a5617496SJie Yang 242a5617496SJie Yang asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] = 243a5617496SJie Yang boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis); 244a5617496SJie Yang } 245a5617496SJie Yang 246a5617496SJie Yang inline void getChassisContains( 247a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 248a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 249a5617496SJie Yang const dbus::utility::MapperEndPoints& downstreamChassisPaths) 250a5617496SJie Yang { 251a5617496SJie Yang if (ec) 252a5617496SJie Yang { 253a5617496SJie Yang if (ec.value() != EBADR) 254a5617496SJie Yang { 25562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 256a5617496SJie Yang messages::internalError(asyncResp->res); 257a5617496SJie Yang } 258a5617496SJie Yang return; 259a5617496SJie Yang } 260a5617496SJie Yang if (downstreamChassisPaths.empty()) 261a5617496SJie Yang { 262a5617496SJie Yang return; 263a5617496SJie Yang } 264a5617496SJie Yang nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"]; 265a5617496SJie Yang if (!jValue.is_array()) 266a5617496SJie Yang { 267a5617496SJie Yang // Create the array if it was empty 268a5617496SJie Yang jValue = nlohmann::json::array(); 269a5617496SJie Yang } 270a5617496SJie Yang for (const auto& p : downstreamChassisPaths) 271a5617496SJie Yang { 272a5617496SJie Yang sdbusplus::message::object_path downstreamChassisPath(p); 273a5617496SJie Yang std::string downstreamChassis = downstreamChassisPath.filename(); 274a5617496SJie Yang if (downstreamChassis.empty()) 275a5617496SJie Yang { 27662598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}", 27762598e31SEd Tanous downstreamChassisPath.str, chassisId); 278a5617496SJie Yang continue; 279a5617496SJie Yang } 280a5617496SJie Yang nlohmann::json link; 281a5617496SJie Yang link["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}", 282a5617496SJie Yang downstreamChassis); 283a5617496SJie Yang jValue.push_back(std::move(link)); 284a5617496SJie Yang } 285a5617496SJie Yang asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size(); 286a5617496SJie Yang } 287a5617496SJie Yang 288a5617496SJie Yang inline void 289a5617496SJie Yang getChassisConnectivity(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 290a5617496SJie Yang const std::string& chassisId, 291a5617496SJie Yang const std::string& chassisPath) 292a5617496SJie Yang { 29362598e31SEd Tanous BMCWEB_LOG_DEBUG("Get chassis connectivity"); 294a5617496SJie Yang 295a5617496SJie Yang dbus::utility::getAssociationEndPoints( 296a5617496SJie Yang chassisPath + "/contained_by", 297a5617496SJie Yang std::bind_front(getChassisContainedBy, asyncResp, chassisId)); 298a5617496SJie Yang 299a5617496SJie Yang dbus::utility::getAssociationEndPoints( 300a5617496SJie Yang chassisPath + "/containing", 301a5617496SJie Yang std::bind_front(getChassisContains, asyncResp, chassisId)); 302a5617496SJie Yang } 303a5617496SJie Yang 304cf7eba09SNan Zhou /** 305cf7eba09SNan Zhou * ChassisCollection derived class for delivering Chassis Collection Schema 306cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 307cf7eba09SNan Zhou */ 308cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app) 309cf7eba09SNan Zhou { 310cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/") 311cf7eba09SNan Zhou .privileges(redfish::privileges::getChassisCollection) 312cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 313cf7eba09SNan Zhou std::bind_front(handleChassisCollectionGet, std::ref(app))); 31462d5e2e4SEd Tanous } 315e37f8451SRapkiewicz, Pawel 316308f70c7SWilly Tu inline void 317308f70c7SWilly Tu getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 318308f70c7SWilly Tu const std::string& connectionName, 319308f70c7SWilly Tu const std::string& path) 320308f70c7SWilly Tu { 3211e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 3221e1e598dSJonathan Doman *crow::connections::systemBus, connectionName, path, 3231e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 3245e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3251e1e598dSJonathan Doman const std::string& property) { 326308f70c7SWilly Tu if (ec) 327308f70c7SWilly Tu { 32862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location"); 329308f70c7SWilly Tu messages::internalError(asyncResp->res); 330308f70c7SWilly Tu return; 331308f70c7SWilly Tu } 332308f70c7SWilly Tu 333002d39b4SEd Tanous asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 3341e1e598dSJonathan Doman property; 3351e1e598dSJonathan Doman }); 336308f70c7SWilly Tu } 337308f70c7SWilly Tu 338308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 339308f70c7SWilly Tu const std::string& connectionName, 340308f70c7SWilly Tu const std::string& path) 341308f70c7SWilly Tu { 3421e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 3431e1e598dSJonathan Doman *crow::connections::systemBus, connectionName, path, 3441e1e598dSJonathan Doman "xyz.openbmc_project.Common.UUID", "UUID", 3455e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3461e1e598dSJonathan Doman const std::string& chassisUUID) { 347308f70c7SWilly Tu if (ec) 348308f70c7SWilly Tu { 34962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for UUID"); 350308f70c7SWilly Tu messages::internalError(asyncResp->res); 351308f70c7SWilly Tu return; 352308f70c7SWilly Tu } 3531e1e598dSJonathan Doman asyncResp->res.jsonValue["UUID"] = chassisUUID; 3541e1e598dSJonathan Doman }); 355308f70c7SWilly Tu } 356308f70c7SWilly Tu 357*7164bc62SChau Ly inline void handleDecoratorAssetProperties( 35845ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 359*7164bc62SChau Ly const std::string& chassisId, const std::string& path, 360*7164bc62SChau Ly const dbus::utility::DBusPropertiesMap& propertiesList) 361cf7eba09SNan Zhou { 362*7164bc62SChau Ly const std::string* partNumber = nullptr; 363*7164bc62SChau Ly const std::string* serialNumber = nullptr; 364*7164bc62SChau Ly const std::string* manufacturer = nullptr; 365*7164bc62SChau Ly const std::string* model = nullptr; 366*7164bc62SChau Ly const std::string* sparePartNumber = nullptr; 367*7164bc62SChau Ly 368*7164bc62SChau Ly const bool success = sdbusplus::unpackPropertiesNoThrow( 369*7164bc62SChau Ly dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 370*7164bc62SChau Ly partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, 371*7164bc62SChau Ly "Model", model, "SparePartNumber", sparePartNumber); 372*7164bc62SChau Ly 373*7164bc62SChau Ly if (!success) 37445ca1b86SEd Tanous { 375*7164bc62SChau Ly messages::internalError(asyncResp->res); 37645ca1b86SEd Tanous return; 37745ca1b86SEd Tanous } 378734bfe90SGunnar Mills 379*7164bc62SChau Ly if (partNumber != nullptr) 380*7164bc62SChau Ly { 381*7164bc62SChau Ly asyncResp->res.jsonValue["PartNumber"] = *partNumber; 382*7164bc62SChau Ly } 383*7164bc62SChau Ly 384*7164bc62SChau Ly if (serialNumber != nullptr) 385*7164bc62SChau Ly { 386*7164bc62SChau Ly asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 387*7164bc62SChau Ly } 388*7164bc62SChau Ly 389*7164bc62SChau Ly if (manufacturer != nullptr) 390*7164bc62SChau Ly { 391*7164bc62SChau Ly asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 392*7164bc62SChau Ly } 393*7164bc62SChau Ly 394*7164bc62SChau Ly if (model != nullptr) 395*7164bc62SChau Ly { 396*7164bc62SChau Ly asyncResp->res.jsonValue["Model"] = *model; 397*7164bc62SChau Ly } 398*7164bc62SChau Ly 399*7164bc62SChau Ly // SparePartNumber is optional on D-Bus 400*7164bc62SChau Ly // so skip if it is empty 401*7164bc62SChau Ly if (sparePartNumber != nullptr && !sparePartNumber->empty()) 402*7164bc62SChau Ly { 403*7164bc62SChau Ly asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 404*7164bc62SChau Ly } 405*7164bc62SChau Ly 406*7164bc62SChau Ly asyncResp->res.jsonValue["Name"] = chassisId; 407*7164bc62SChau Ly asyncResp->res.jsonValue["Id"] = chassisId; 408*7164bc62SChau Ly #ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL 409*7164bc62SChau Ly asyncResp->res.jsonValue["Thermal"]["@odata.id"] = 410*7164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId); 411*7164bc62SChau Ly // Power object 412*7164bc62SChau Ly asyncResp->res.jsonValue["Power"]["@odata.id"] = 413*7164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId); 414*7164bc62SChau Ly #endif 415*7164bc62SChau Ly #ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM 416*7164bc62SChau Ly asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] = 417*7164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem", 418*7164bc62SChau Ly chassisId); 419*7164bc62SChau Ly asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] = 420*7164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", chassisId); 421*7164bc62SChau Ly asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] = 422*7164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics", 423*7164bc62SChau Ly chassisId); 424*7164bc62SChau Ly #endif 425*7164bc62SChau Ly // SensorCollection 426*7164bc62SChau Ly asyncResp->res.jsonValue["Sensors"]["@odata.id"] = 427*7164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId); 428*7164bc62SChau Ly asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 429*7164bc62SChau Ly 430*7164bc62SChau Ly nlohmann::json::array_t computerSystems; 431*7164bc62SChau Ly nlohmann::json::object_t system; 432*7164bc62SChau Ly system["@odata.id"] = "/redfish/v1/Systems/system"; 433*7164bc62SChau Ly computerSystems.emplace_back(std::move(system)); 434*7164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ComputerSystems"] = 435*7164bc62SChau Ly std::move(computerSystems); 436*7164bc62SChau Ly 437*7164bc62SChau Ly nlohmann::json::array_t managedBy; 438*7164bc62SChau Ly nlohmann::json::object_t manager; 439*7164bc62SChau Ly manager["@odata.id"] = "/redfish/v1/Managers/bmc"; 440*7164bc62SChau Ly managedBy.emplace_back(std::move(manager)); 441*7164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); 442*7164bc62SChau Ly getChassisState(asyncResp); 443*7164bc62SChau Ly getStorageLink(asyncResp, path); 444*7164bc62SChau Ly } 445*7164bc62SChau Ly 446*7164bc62SChau Ly inline void handleChassisGetSubTree( 447*7164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 448*7164bc62SChau Ly const std::string& chassisId, const boost::system::error_code& ec, 449*7164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 450*7164bc62SChau Ly { 45162d5e2e4SEd Tanous if (ec) 4521abe55efSEd Tanous { 45362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 454f12894f8SJason M. Bills messages::internalError(asyncResp->res); 455daf36e2eSEd Tanous return; 456daf36e2eSEd Tanous } 457daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 458cf7eba09SNan Zhou for (const std::pair< 459cf7eba09SNan Zhou std::string, 460cf7eba09SNan Zhou std::vector<std::pair<std::string, std::vector<std::string>>>>& 4611214b7e7SGunnar Mills object : subtree) 4621abe55efSEd Tanous { 463daf36e2eSEd Tanous const std::string& path = object.first; 464cf7eba09SNan Zhou const std::vector<std::pair<std::string, std::vector<std::string>>>& 4651214b7e7SGunnar Mills connectionNames = object.second; 4667e860f15SJohn Edward Broadbent 467997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 468997093ebSGeorge Liu if (objPath.filename() != chassisId) 4691abe55efSEd Tanous { 470daf36e2eSEd Tanous continue; 471daf36e2eSEd Tanous } 47226f03899SShawn McCarney 473a5617496SJie Yang getChassisConnectivity(asyncResp, chassisId, path); 474a5617496SJie Yang 475002d39b4SEd Tanous auto health = std::make_shared<HealthPopulate>(asyncResp); 476b49ac873SJames Feist 47713451e39SWilly Tu if constexpr (bmcwebEnableHealthPopulate) 47813451e39SWilly Tu { 4796c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 4806c3e9451SGeorge Liu path + "/all_sensors", 4815e7e2dc5SEd Tanous [health](const boost::system::error_code& ec2, 4826c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 48323a21a1cSEd Tanous if (ec2) 484b49ac873SJames Feist { 485b49ac873SJames Feist return; // no sensors = no failures 486b49ac873SJames Feist } 4871e1e598dSJonathan Doman health->inventory = resp; 4881e1e598dSJonathan Doman }); 489b49ac873SJames Feist 490b49ac873SJames Feist health->populate(); 49113451e39SWilly Tu } 492b49ac873SJames Feist 49326f6976fSEd Tanous if (connectionNames.empty()) 4941abe55efSEd Tanous { 49562598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 496e0d918bcSEd Tanous continue; 497daf36e2eSEd Tanous } 498e0d918bcSEd Tanous 499*7164bc62SChau Ly asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis"; 50049c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.id"] = 501ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 50249c53ac9SJohnathan Mantey asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 50349c53ac9SJohnathan Mantey asyncResp->res.jsonValue["ChassisType"] = "RackMount"; 504cf7eba09SNan Zhou asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] = 505*7164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset", 506*7164bc62SChau Ly chassisId); 5071476687dSEd Tanous asyncResp->res 508cf7eba09SNan Zhou .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] = 509ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo", 510ef4c65b7SEd Tanous chassisId); 5111476687dSEd Tanous asyncResp->res.jsonValue["PCIeDevices"]["@odata.id"] = 512ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices"; 51349c53ac9SJohnathan Mantey 5146c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 5156c3e9451SGeorge Liu path + "/drive", 516*7164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec3, 5176c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 51892903bd4SJohn Edward Broadbent if (ec3 || resp.empty()) 51992903bd4SJohn Edward Broadbent { 52092903bd4SJohn Edward Broadbent return; // no drives = no failures 52192903bd4SJohn Edward Broadbent } 52292903bd4SJohn Edward Broadbent 52392903bd4SJohn Edward Broadbent nlohmann::json reference; 524*7164bc62SChau Ly reference["@odata.id"] = 525*7164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId); 52692903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Drives"] = std::move(reference); 52792903bd4SJohn Edward Broadbent }); 52892903bd4SJohn Edward Broadbent 529002d39b4SEd Tanous const std::string& connectionName = connectionNames[0].first; 5301c8fba97SJames Feist 531*7164bc62SChau Ly const std::vector<std::string>& interfaces2 = connectionNames[0].second; 5321c8fba97SJames Feist const std::array<const char*, 2> hasIndicatorLed = { 5331c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 5340fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 5351c8fba97SJames Feist 536476b9cc5STejas Patil const std::string assetTagInterface = 5370fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.AssetTag"; 538523d4868SLogananth Sundararaj const std::string replaceableInterface = 539523d4868SLogananth Sundararaj "xyz.openbmc_project.Inventory.Decorator.Replaceable"; 540523d4868SLogananth Sundararaj for (const auto& interface : interfaces2) 541523d4868SLogananth Sundararaj { 542523d4868SLogananth Sundararaj if (interface == assetTagInterface) 543476b9cc5STejas Patil { 5441e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 545002d39b4SEd Tanous *crow::connections::systemBus, connectionName, path, 546002d39b4SEd Tanous assetTagInterface, "AssetTag", 547*7164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 5481e1e598dSJonathan Doman const std::string& property) { 5498a592810SEd Tanous if (ec2) 550476b9cc5STejas Patil { 551*7164bc62SChau Ly BMCWEB_LOG_ERROR("DBus response error for AssetTag: {}", 552*7164bc62SChau Ly ec2); 553476b9cc5STejas Patil messages::internalError(asyncResp->res); 554476b9cc5STejas Patil return; 555476b9cc5STejas Patil } 556002d39b4SEd Tanous asyncResp->res.jsonValue["AssetTag"] = property; 5571e1e598dSJonathan Doman }); 558476b9cc5STejas Patil } 559523d4868SLogananth Sundararaj else if (interface == replaceableInterface) 560523d4868SLogananth Sundararaj { 561523d4868SLogananth Sundararaj sdbusplus::asio::getProperty<bool>( 562523d4868SLogananth Sundararaj *crow::connections::systemBus, connectionName, path, 563523d4868SLogananth Sundararaj replaceableInterface, "HotPluggable", 564*7164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 565523d4868SLogananth Sundararaj const bool property) { 566523d4868SLogananth Sundararaj if (ec2) 567523d4868SLogananth Sundararaj { 56862598e31SEd Tanous BMCWEB_LOG_ERROR( 569*7164bc62SChau Ly "DBus response error for HotPluggable: {}", ec2); 570523d4868SLogananth Sundararaj messages::internalError(asyncResp->res); 571523d4868SLogananth Sundararaj return; 572523d4868SLogananth Sundararaj } 573523d4868SLogananth Sundararaj asyncResp->res.jsonValue["HotPluggable"] = property; 574523d4868SLogananth Sundararaj }); 575523d4868SLogananth Sundararaj } 576523d4868SLogananth Sundararaj } 577476b9cc5STejas Patil 5781c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 5791c8fba97SJames Feist { 580*7164bc62SChau Ly if (std::ranges::find(interfaces2, interface) != interfaces2.end()) 5811c8fba97SJames Feist { 5821c8fba97SJames Feist getIndicatorLedState(asyncResp); 58359a17e4fSGeorge Liu getSystemLocationIndicatorActive(asyncResp); 5841c8fba97SJames Feist break; 5851c8fba97SJames Feist } 5861c8fba97SJames Feist } 5871c8fba97SJames Feist 58886d89ed7SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 58986d89ed7SKrzysztof Grobelny *crow::connections::systemBus, connectionName, path, 59086d89ed7SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Asset", 591*7164bc62SChau Ly [asyncResp, chassisId, 592*7164bc62SChau Ly path](const boost::system::error_code&, 593cf7eba09SNan Zhou const dbus::utility::DBusPropertiesMap& propertiesList) { 594*7164bc62SChau Ly handleDecoratorAssetProperties(asyncResp, chassisId, path, 595*7164bc62SChau Ly propertiesList); 59686d89ed7SKrzysztof Grobelny }); 5972c37b4b0SSharad Yadav 598308f70c7SWilly Tu for (const auto& interface : interfaces2) 5992c37b4b0SSharad Yadav { 600308f70c7SWilly Tu if (interface == "xyz.openbmc_project.Common.UUID") 6012c37b4b0SSharad Yadav { 602308f70c7SWilly Tu getChassisUUID(asyncResp, connectionName, path); 6032c37b4b0SSharad Yadav } 604cf7eba09SNan Zhou else if (interface == 6050fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode") 6062c37b4b0SSharad Yadav { 607002d39b4SEd Tanous getChassisLocationCode(asyncResp, connectionName, path); 6082c37b4b0SSharad Yadav } 6092c37b4b0SSharad Yadav } 6102c37b4b0SSharad Yadav 611daf36e2eSEd Tanous return; 612daf36e2eSEd Tanous } 613e0d918bcSEd Tanous 614daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 615d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 616*7164bc62SChau Ly } 617c181942fSQiang XU 618*7164bc62SChau Ly inline void 619*7164bc62SChau Ly handleChassisGet(App& app, const crow::Request& req, 620*7164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 621*7164bc62SChau Ly const std::string& chassisId) 622*7164bc62SChau Ly { 623*7164bc62SChau Ly if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 624*7164bc62SChau Ly { 625*7164bc62SChau Ly return; 626*7164bc62SChau Ly } 627*7164bc62SChau Ly constexpr std::array<std::string_view, 2> interfaces = { 628*7164bc62SChau Ly "xyz.openbmc_project.Inventory.Item.Board", 629*7164bc62SChau Ly "xyz.openbmc_project.Inventory.Item.Chassis"}; 630*7164bc62SChau Ly 631*7164bc62SChau Ly dbus::utility::getSubTree( 632*7164bc62SChau Ly "/xyz/openbmc_project/inventory", 0, interfaces, 633*7164bc62SChau Ly std::bind_front(handleChassisGetSubTree, asyncResp, chassisId)); 634*7164bc62SChau Ly 635*7164bc62SChau Ly constexpr std::array<std::string_view, 1> interfaces2 = { 636*7164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion"}; 637*7164bc62SChau Ly 638*7164bc62SChau Ly dbus::utility::getSubTree( 639*7164bc62SChau Ly "/xyz/openbmc_project", 0, interfaces2, 640*7164bc62SChau Ly std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp)); 641cf7eba09SNan Zhou } 6421c8fba97SJames Feist 643cf7eba09SNan Zhou inline void 644cf7eba09SNan Zhou handleChassisPatch(App& app, const crow::Request& req, 6457e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 646cf7eba09SNan Zhou const std::string& param) 647cf7eba09SNan Zhou { 6483ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 64945ca1b86SEd Tanous { 65045ca1b86SEd Tanous return; 65145ca1b86SEd Tanous } 6529f8bfa7cSGunnar Mills std::optional<bool> locationIndicatorActive; 6531c8fba97SJames Feist std::optional<std::string> indicatorLed; 6541c8fba97SJames Feist 6557e860f15SJohn Edward Broadbent if (param.empty()) 6561c8fba97SJames Feist { 6571c8fba97SJames Feist return; 6581c8fba97SJames Feist } 6591c8fba97SJames Feist 66015ed6780SWilly Tu if (!json_util::readJsonPatch( 6617e860f15SJohn Edward Broadbent req, asyncResp->res, "LocationIndicatorActive", 6627e860f15SJohn Edward Broadbent locationIndicatorActive, "IndicatorLED", indicatorLed)) 6631c8fba97SJames Feist { 6641c8fba97SJames Feist return; 6651c8fba97SJames Feist } 6661c8fba97SJames Feist 6679f8bfa7cSGunnar Mills // TODO (Gunnar): Remove IndicatorLED after enough time has passed 6689f8bfa7cSGunnar Mills if (!locationIndicatorActive && !indicatorLed) 6691c8fba97SJames Feist { 6701c8fba97SJames Feist return; // delete this when we support more patch properties 6711c8fba97SJames Feist } 672d6aa0093SGunnar Mills if (indicatorLed) 673d6aa0093SGunnar Mills { 6747e860f15SJohn Edward Broadbent asyncResp->res.addHeader( 6757e860f15SJohn Edward Broadbent boost::beast::http::field::warning, 6760fda0f12SGeorge Liu "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\""); 677d6aa0093SGunnar Mills } 6781c8fba97SJames Feist 679e99073f5SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 6801c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board", 6811c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Chassis"}; 6821c8fba97SJames Feist 6837e860f15SJohn Edward Broadbent const std::string& chassisId = param; 6841c8fba97SJames Feist 685e99073f5SGeorge Liu dbus::utility::getSubTree( 686e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 687cf7eba09SNan Zhou [asyncResp, chassisId, locationIndicatorActive, 6885e7e2dc5SEd Tanous indicatorLed](const boost::system::error_code& ec, 689b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 6901c8fba97SJames Feist if (ec) 6911c8fba97SJames Feist { 69262598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 6931c8fba97SJames Feist messages::internalError(asyncResp->res); 6941c8fba97SJames Feist return; 6951c8fba97SJames Feist } 6961c8fba97SJames Feist 6971c8fba97SJames Feist // Iterate over all retrieved ObjectPaths. 698cf7eba09SNan Zhou for (const std::pair< 699cf7eba09SNan Zhou std::string, 700cf7eba09SNan Zhou std::vector<std::pair<std::string, std::vector<std::string>>>>& 7011214b7e7SGunnar Mills object : subtree) 7021c8fba97SJames Feist { 7031c8fba97SJames Feist const std::string& path = object.first; 704cf7eba09SNan Zhou const std::vector<std::pair<std::string, std::vector<std::string>>>& 7051214b7e7SGunnar Mills connectionNames = object.second; 7061c8fba97SJames Feist 707997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 708997093ebSGeorge Liu if (objPath.filename() != chassisId) 7091c8fba97SJames Feist { 7101c8fba97SJames Feist continue; 7111c8fba97SJames Feist } 7121c8fba97SJames Feist 71326f6976fSEd Tanous if (connectionNames.empty()) 7141c8fba97SJames Feist { 71562598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 7161c8fba97SJames Feist continue; 7171c8fba97SJames Feist } 7181c8fba97SJames Feist 71923a21a1cSEd Tanous const std::vector<std::string>& interfaces3 = 7201c8fba97SJames Feist connectionNames[0].second; 7211c8fba97SJames Feist 7221c8fba97SJames Feist const std::array<const char*, 2> hasIndicatorLed = { 7231c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 7240fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 7251c8fba97SJames Feist bool indicatorChassis = false; 7261c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 7271c8fba97SJames Feist { 7283544d2a7SEd Tanous if (std::ranges::find(interfaces3, interface) != 7293544d2a7SEd Tanous interfaces3.end()) 7301c8fba97SJames Feist { 7311c8fba97SJames Feist indicatorChassis = true; 7321c8fba97SJames Feist break; 7331c8fba97SJames Feist } 7341c8fba97SJames Feist } 7359f8bfa7cSGunnar Mills if (locationIndicatorActive) 7369f8bfa7cSGunnar Mills { 7379f8bfa7cSGunnar Mills if (indicatorChassis) 7389f8bfa7cSGunnar Mills { 73959a17e4fSGeorge Liu setSystemLocationIndicatorActive(asyncResp, 740002d39b4SEd Tanous *locationIndicatorActive); 7419f8bfa7cSGunnar Mills } 7429f8bfa7cSGunnar Mills else 7439f8bfa7cSGunnar Mills { 744002d39b4SEd Tanous messages::propertyUnknown(asyncResp->res, 745002d39b4SEd Tanous "LocationIndicatorActive"); 7469f8bfa7cSGunnar Mills } 7479f8bfa7cSGunnar Mills } 7489f8bfa7cSGunnar Mills if (indicatorLed) 7499f8bfa7cSGunnar Mills { 7501c8fba97SJames Feist if (indicatorChassis) 7511c8fba97SJames Feist { 752f23b7296SEd Tanous setIndicatorLedState(asyncResp, *indicatorLed); 7531c8fba97SJames Feist } 7541c8fba97SJames Feist else 7551c8fba97SJames Feist { 756cf7eba09SNan Zhou messages::propertyUnknown(asyncResp->res, "IndicatorLED"); 7571c8fba97SJames Feist } 7581c8fba97SJames Feist } 7591c8fba97SJames Feist return; 7601c8fba97SJames Feist } 7611c8fba97SJames Feist 762d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 763e99073f5SGeorge Liu }); 764cf7eba09SNan Zhou } 765cf7eba09SNan Zhou 766cf7eba09SNan Zhou /** 767cf7eba09SNan Zhou * Chassis override class for delivering Chassis Schema 768cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 769cf7eba09SNan Zhou */ 770cf7eba09SNan Zhou inline void requestRoutesChassis(App& app) 771cf7eba09SNan Zhou { 772cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 773cf7eba09SNan Zhou .privileges(redfish::privileges::getChassis) 774cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 775cf7eba09SNan Zhou std::bind_front(handleChassisGet, std::ref(app))); 776cf7eba09SNan Zhou 777cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 778cf7eba09SNan Zhou .privileges(redfish::privileges::patchChassis) 779cf7eba09SNan Zhou .methods(boost::beast::http::verb::patch)( 780cf7eba09SNan Zhou std::bind_front(handleChassisPatch, std::ref(app))); 7811c8fba97SJames Feist } 782dd99e04bSP.K. Lee 783fc903b3dSAndrew Geissler /** 784fc903b3dSAndrew Geissler * Handle error responses from d-bus for chassis power cycles 785fc903b3dSAndrew Geissler */ 786fc903b3dSAndrew Geissler inline void handleChassisPowerCycleError(const boost::system::error_code& ec, 787fc903b3dSAndrew Geissler const sdbusplus::message_t& eMsg, 788fc903b3dSAndrew Geissler crow::Response& res) 789fc903b3dSAndrew Geissler { 790fc903b3dSAndrew Geissler if (eMsg.get_error() == nullptr) 791fc903b3dSAndrew Geissler { 79262598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error: {}", ec); 793fc903b3dSAndrew Geissler messages::internalError(res); 794fc903b3dSAndrew Geissler return; 795fc903b3dSAndrew Geissler } 796fc903b3dSAndrew Geissler std::string_view errorMessage = eMsg.get_error()->name; 797fc903b3dSAndrew Geissler 798fc903b3dSAndrew Geissler // If operation failed due to BMC not being in Ready state, tell 799fc903b3dSAndrew Geissler // user to retry in a bit 800fc903b3dSAndrew Geissler if (errorMessage == 801fc903b3dSAndrew Geissler std::string_view("xyz.openbmc_project.State.Chassis.Error.BMCNotReady")) 802fc903b3dSAndrew Geissler { 80362598e31SEd Tanous BMCWEB_LOG_DEBUG("BMC not ready, operation not allowed right now"); 804fc903b3dSAndrew Geissler messages::serviceTemporarilyUnavailable(res, "10"); 805fc903b3dSAndrew Geissler return; 806fc903b3dSAndrew Geissler } 807fc903b3dSAndrew Geissler 80862598e31SEd Tanous BMCWEB_LOG_ERROR("Chassis Power Cycle fail {} sdbusplus:{}", ec, 80962598e31SEd Tanous errorMessage); 810fc903b3dSAndrew Geissler messages::internalError(res); 811fc903b3dSAndrew Geissler } 812fc903b3dSAndrew Geissler 8138d1b46d7Szhanghch05 inline void 8148d1b46d7Szhanghch05 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 815dd99e04bSP.K. Lee { 8167a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 817c3b3c92aSVijay Khemka "xyz.openbmc_project.State.Chassis"}; 818c3b3c92aSVijay Khemka 819c3b3c92aSVijay Khemka // Use mapper to get subtree paths. 8207a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 8217a1dbc48SGeorge Liu "/", 0, interfaces, 822b9d36b47SEd Tanous [asyncResp]( 8237a1dbc48SGeorge Liu const boost::system::error_code& ec, 824b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& chassisList) { 825c3b3c92aSVijay Khemka if (ec) 826c3b3c92aSVijay Khemka { 82762598e31SEd Tanous BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec); 828c3b3c92aSVijay Khemka messages::internalError(asyncResp->res); 829c3b3c92aSVijay Khemka return; 830c3b3c92aSVijay Khemka } 831c3b3c92aSVijay Khemka 832dd99e04bSP.K. Lee const char* processName = "xyz.openbmc_project.State.Chassis"; 833dd99e04bSP.K. Lee const char* interfaceName = "xyz.openbmc_project.State.Chassis"; 834dd99e04bSP.K. Lee const char* destProperty = "RequestedPowerTransition"; 835dd99e04bSP.K. Lee const std::string propertyValue = 836dd99e04bSP.K. Lee "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; 837002d39b4SEd Tanous std::string objectPath = "/xyz/openbmc_project/state/chassis_system0"; 838c3b3c92aSVijay Khemka 839c3b3c92aSVijay Khemka /* Look for system reset chassis path */ 8403544d2a7SEd Tanous if ((std::ranges::find(chassisList, objectPath)) == chassisList.end()) 841c3b3c92aSVijay Khemka { 842c3b3c92aSVijay Khemka /* We prefer to reset the full chassis_system, but if it doesn't 843c3b3c92aSVijay Khemka * exist on some platforms, fall back to a host-only power reset 844c3b3c92aSVijay Khemka */ 845c3b3c92aSVijay Khemka objectPath = "/xyz/openbmc_project/state/chassis0"; 846c3b3c92aSVijay Khemka } 847dd99e04bSP.K. Lee 8489ae226faSGeorge Liu sdbusplus::asio::setProperty( 8499ae226faSGeorge Liu *crow::connections::systemBus, processName, objectPath, 8509ae226faSGeorge Liu interfaceName, destProperty, propertyValue, 851fc903b3dSAndrew Geissler [asyncResp](const boost::system::error_code& ec2, 852fc903b3dSAndrew Geissler sdbusplus::message_t& sdbusErrMsg) { 853dd99e04bSP.K. Lee // Use "Set" method to set the property value. 8548a592810SEd Tanous if (ec2) 855dd99e04bSP.K. Lee { 856fc903b3dSAndrew Geissler handleChassisPowerCycleError(ec2, sdbusErrMsg, asyncResp->res); 857fc903b3dSAndrew Geissler 858dd99e04bSP.K. Lee return; 859dd99e04bSP.K. Lee } 860dd99e04bSP.K. Lee 861dd99e04bSP.K. Lee messages::success(asyncResp->res); 8629ae226faSGeorge Liu }); 8637a1dbc48SGeorge Liu }); 864dd99e04bSP.K. Lee } 865dd99e04bSP.K. Lee 866cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost( 867cf7eba09SNan Zhou App& app, const crow::Request& req, 8687e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 869cf7eba09SNan Zhou const std::string& /*chassisId*/) 870cf7eba09SNan Zhou { 8713ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 87245ca1b86SEd Tanous { 87345ca1b86SEd Tanous return; 87445ca1b86SEd Tanous } 87562598e31SEd Tanous BMCWEB_LOG_DEBUG("Post Chassis Reset."); 876dd99e04bSP.K. Lee 877dd99e04bSP.K. Lee std::string resetType; 878dd99e04bSP.K. Lee 879cf7eba09SNan Zhou if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 880dd99e04bSP.K. Lee { 881dd99e04bSP.K. Lee return; 882dd99e04bSP.K. Lee } 883dd99e04bSP.K. Lee 884dd99e04bSP.K. Lee if (resetType != "PowerCycle") 885dd99e04bSP.K. Lee { 88662598e31SEd Tanous BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType); 887002d39b4SEd Tanous messages::actionParameterNotSupported(asyncResp->res, resetType, 888002d39b4SEd Tanous "ResetType"); 889dd99e04bSP.K. Lee 890dd99e04bSP.K. Lee return; 891dd99e04bSP.K. Lee } 892dd99e04bSP.K. Lee doChassisPowerCycle(asyncResp); 893dd99e04bSP.K. Lee } 8941cb1a9e6SAppaRao Puli 8951cb1a9e6SAppaRao Puli /** 896cf7eba09SNan Zhou * ChassisResetAction class supports the POST method for the Reset 897cf7eba09SNan Zhou * action. 898cf7eba09SNan Zhou * Function handles POST method request. 899cf7eba09SNan Zhou * Analyzes POST body before sending Reset request data to D-Bus. 9001cb1a9e6SAppaRao Puli */ 901cf7eba09SNan Zhou 902cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app) 9031cb1a9e6SAppaRao Puli { 904cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/") 905cf7eba09SNan Zhou .privileges(redfish::privileges::postChassis) 906cf7eba09SNan Zhou .methods(boost::beast::http::verb::post)( 907cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoPost, std::ref(app))); 908cf7eba09SNan Zhou } 909cf7eba09SNan Zhou 910cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet( 911cf7eba09SNan Zhou App& app, const crow::Request& req, 9127e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 913cf7eba09SNan Zhou const std::string& chassisId) 914cf7eba09SNan Zhou { 9153ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 9161cb1a9e6SAppaRao Puli { 91745ca1b86SEd Tanous return; 91845ca1b86SEd Tanous } 919cf7eba09SNan Zhou asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 920ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 921ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId); 9221476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 9231476687dSEd Tanous 9241476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 9255b9e95a1SNan Zhou nlohmann::json::array_t parameters; 9265b9e95a1SNan Zhou nlohmann::json::object_t parameter; 9275b9e95a1SNan Zhou parameter["Name"] = "ResetType"; 9285b9e95a1SNan Zhou parameter["Required"] = true; 9295b9e95a1SNan Zhou parameter["DataType"] = "String"; 9301476687dSEd Tanous nlohmann::json::array_t allowed; 931ad539545SPatrick Williams allowed.emplace_back("PowerCycle"); 9325b9e95a1SNan Zhou parameter["AllowableValues"] = std::move(allowed); 933ad539545SPatrick Williams parameters.emplace_back(std::move(parameter)); 9345b9e95a1SNan Zhou 9351476687dSEd Tanous asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 936cf7eba09SNan Zhou } 937cf7eba09SNan Zhou 938cf7eba09SNan Zhou /** 939cf7eba09SNan Zhou * ChassisResetActionInfo derived class for delivering Chassis 940cf7eba09SNan Zhou * ResetType AllowableValues using ResetInfo schema. 941cf7eba09SNan Zhou */ 942cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app) 943cf7eba09SNan Zhou { 944cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/") 945cf7eba09SNan Zhou .privileges(redfish::privileges::getActionInfo) 946cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 947cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoGet, std::ref(app))); 9481cb1a9e6SAppaRao Puli } 9491cb1a9e6SAppaRao Puli 950e37f8451SRapkiewicz, Pawel } // namespace redfish 951