1e37f8451SRapkiewicz, Pawel /* 26be832e2SEd Tanous Copyright (c) 2018 Intel Corporation 36be832e2SEd Tanous 46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License"); 56be832e2SEd Tanous you may not use this file except in compliance with the License. 66be832e2SEd Tanous You may obtain a copy of the License at 76be832e2SEd Tanous 86be832e2SEd Tanous http://www.apache.org/licenses/LICENSE-2.0 96be832e2SEd Tanous 106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software 116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS, 126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136be832e2SEd Tanous See the License for the specific language governing permissions and 146be832e2SEd Tanous limitations under the License. 15e37f8451SRapkiewicz, Pawel */ 16e37f8451SRapkiewicz, Pawel #pragma once 17e37f8451SRapkiewicz, Pawel 183ccb3adbSEd Tanous #include "app.hpp" 197a1dbc48SGeorge Liu #include "dbus_utility.hpp" 20539d8c6bSEd Tanous #include "generated/enums/action_info.hpp" 21539d8c6bSEd Tanous #include "generated/enums/chassis.hpp" 22539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 231c8fba97SJames Feist #include "led.hpp" 243ccb3adbSEd Tanous #include "query.hpp" 257164bc62SChau 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> 38*2952f648SJoseph-Jonathan Salzano #include <memory> 393544d2a7SEd Tanous #include <ranges> 407a1dbc48SGeorge Liu #include <string_view> 417a1dbc48SGeorge Liu 421abe55efSEd Tanous namespace redfish 431abe55efSEd Tanous { 44e37f8451SRapkiewicz, Pawel 45*2952f648SJoseph-Jonathan Salzano inline chassis::ChassisType 46*2952f648SJoseph-Jonathan Salzano translateChassisTypeToRedfish(const std::string_view& chassisType) 47*2952f648SJoseph-Jonathan Salzano { 48*2952f648SJoseph-Jonathan Salzano if (chassisType == 49*2952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Blade") 50*2952f648SJoseph-Jonathan Salzano { 51*2952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Blade; 52*2952f648SJoseph-Jonathan Salzano } 53*2952f648SJoseph-Jonathan Salzano if (chassisType == 54*2952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Component") 55*2952f648SJoseph-Jonathan Salzano { 56*2952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Component; 57*2952f648SJoseph-Jonathan Salzano } 58*2952f648SJoseph-Jonathan Salzano if (chassisType == 59*2952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Enclosure") 60*2952f648SJoseph-Jonathan Salzano { 61*2952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Enclosure; 62*2952f648SJoseph-Jonathan Salzano } 63*2952f648SJoseph-Jonathan Salzano if (chassisType == 64*2952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Module") 65*2952f648SJoseph-Jonathan Salzano { 66*2952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Module; 67*2952f648SJoseph-Jonathan Salzano } 68*2952f648SJoseph-Jonathan Salzano if (chassisType == 69*2952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.RackMount") 70*2952f648SJoseph-Jonathan Salzano { 71*2952f648SJoseph-Jonathan Salzano return chassis::ChassisType::RackMount; 72*2952f648SJoseph-Jonathan Salzano } 73*2952f648SJoseph-Jonathan Salzano if (chassisType == 74*2952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StandAlone") 75*2952f648SJoseph-Jonathan Salzano { 76*2952f648SJoseph-Jonathan Salzano return chassis::ChassisType::StandAlone; 77*2952f648SJoseph-Jonathan Salzano } 78*2952f648SJoseph-Jonathan Salzano if (chassisType == 79*2952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StorageEnclosure") 80*2952f648SJoseph-Jonathan Salzano { 81*2952f648SJoseph-Jonathan Salzano return chassis::ChassisType::StorageEnclosure; 82*2952f648SJoseph-Jonathan Salzano } 83*2952f648SJoseph-Jonathan Salzano if (chassisType == 84*2952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Zone") 85*2952f648SJoseph-Jonathan Salzano { 86*2952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Zone; 87*2952f648SJoseph-Jonathan Salzano } 88*2952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Invalid; 89*2952f648SJoseph-Jonathan Salzano } 90*2952f648SJoseph-Jonathan Salzano 91e37f8451SRapkiewicz, Pawel /** 925e577bc1SWilly Tu * @brief Retrieves resources over dbus to link to the chassis 935e577bc1SWilly Tu * 945e577bc1SWilly Tu * @param[in] asyncResp - Shared pointer for completing asynchronous 955e577bc1SWilly Tu * calls 965e577bc1SWilly Tu * @param[in] path - Chassis dbus path to look for the storage. 975e577bc1SWilly Tu * 985e577bc1SWilly Tu * Calls the Association endpoints on the path + "/storage" and add the link of 995e577bc1SWilly Tu * json["Links"]["Storage@odata.count"] = 1005e577bc1SWilly Tu * {"@odata.id", "/redfish/v1/Storage/" + resourceId} 1015e577bc1SWilly Tu * 1025e577bc1SWilly Tu * @return None. 1035e577bc1SWilly Tu */ 1045e577bc1SWilly Tu inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1055e577bc1SWilly Tu const sdbusplus::message::object_path& path) 1065e577bc1SWilly Tu { 1075e577bc1SWilly Tu sdbusplus::asio::getProperty<std::vector<std::string>>( 1085e577bc1SWilly Tu *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper", 1095e577bc1SWilly Tu (path / "storage").str, "xyz.openbmc_project.Association", "endpoints", 110d4b054c1SWilly Tu [asyncResp](const boost::system::error_code& ec, 1115e577bc1SWilly Tu const std::vector<std::string>& storageList) { 1125e577bc1SWilly Tu if (ec) 1135e577bc1SWilly Tu { 11462598e31SEd Tanous BMCWEB_LOG_DEBUG("getStorageLink got DBUS response error"); 1155e577bc1SWilly Tu return; 1165e577bc1SWilly Tu } 1175e577bc1SWilly Tu 1185e577bc1SWilly Tu nlohmann::json::array_t storages; 1195e577bc1SWilly Tu for (const std::string& storagePath : storageList) 1205e577bc1SWilly Tu { 1215e577bc1SWilly Tu std::string id = 1225e577bc1SWilly Tu sdbusplus::message::object_path(storagePath).filename(); 1235e577bc1SWilly Tu if (id.empty()) 1245e577bc1SWilly Tu { 1255e577bc1SWilly Tu continue; 1265e577bc1SWilly Tu } 1275e577bc1SWilly Tu 1285e577bc1SWilly Tu nlohmann::json::object_t storage; 129253f11b8SEd Tanous storage["@odata.id"] = 130253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/{}", 131253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, id); 1325e577bc1SWilly Tu storages.emplace_back(std::move(storage)); 1335e577bc1SWilly Tu } 1345e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["Storage@odata.count"] = 1355e577bc1SWilly Tu storages.size(); 1365e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages); 1375e577bc1SWilly Tu }); 1385e577bc1SWilly Tu } 1395e577bc1SWilly Tu 1405e577bc1SWilly Tu /** 141beeca0aeSGunnar Mills * @brief Retrieves chassis state properties over dbus 142beeca0aeSGunnar Mills * 143ac106bf6SEd Tanous * @param[in] asyncResp - Shared pointer for completing asynchronous calls. 144beeca0aeSGunnar Mills * 145beeca0aeSGunnar Mills * @return None. 146beeca0aeSGunnar Mills */ 147ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp) 148beeca0aeSGunnar Mills { 1491e1e598dSJonathan Doman // crow::connections::systemBus->async_method_call( 1501e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 1511e1e598dSJonathan Doman *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis", 1521e1e598dSJonathan Doman "/xyz/openbmc_project/state/chassis0", 1531e1e598dSJonathan Doman "xyz.openbmc_project.State.Chassis", "CurrentPowerState", 154ac106bf6SEd Tanous [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec, 1551e1e598dSJonathan Doman const std::string& chassisState) { 156beeca0aeSGunnar Mills if (ec) 157beeca0aeSGunnar Mills { 158a6e5e0abSCarson Labrado if (ec == boost::system::errc::host_unreachable) 159a6e5e0abSCarson Labrado { 160a6e5e0abSCarson Labrado // Service not available, no error, just don't return 161a6e5e0abSCarson Labrado // chassis state info 16262598e31SEd Tanous BMCWEB_LOG_DEBUG("Service not available {}", ec); 163a6e5e0abSCarson Labrado return; 164a6e5e0abSCarson Labrado } 16562598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 166ac106bf6SEd Tanous messages::internalError(asyncResp->res); 167beeca0aeSGunnar Mills return; 168beeca0aeSGunnar Mills } 169beeca0aeSGunnar Mills 17062598e31SEd Tanous BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState); 171beeca0aeSGunnar Mills // Verify Chassis State 172bd79bce8SPatrick Williams if (chassisState == 173bd79bce8SPatrick Williams "xyz.openbmc_project.State.Chassis.PowerState.On") 174beeca0aeSGunnar Mills { 175bd79bce8SPatrick Williams asyncResp->res.jsonValue["PowerState"] = 176bd79bce8SPatrick Williams resource::PowerState::On; 177539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 178539d8c6bSEd Tanous resource::State::Enabled; 179beeca0aeSGunnar Mills } 1801e1e598dSJonathan Doman else if (chassisState == 181beeca0aeSGunnar Mills "xyz.openbmc_project.State.Chassis.PowerState.Off") 182beeca0aeSGunnar Mills { 183bd79bce8SPatrick Williams asyncResp->res.jsonValue["PowerState"] = 184bd79bce8SPatrick Williams resource::PowerState::Off; 185539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 186539d8c6bSEd Tanous resource::State::StandbyOffline; 187beeca0aeSGunnar Mills } 1881e1e598dSJonathan Doman }); 189beeca0aeSGunnar Mills } 190beeca0aeSGunnar Mills 191c181942fSQiang XU /** 192c181942fSQiang XU * Retrieves physical security properties over dbus 193c181942fSQiang XU */ 1947164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree( 1957164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 196e99073f5SGeorge Liu const boost::system::error_code& ec, 1977164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 1987164bc62SChau Ly { 199c181942fSQiang XU if (ec) 200c181942fSQiang XU { 2014e0453b1SGunnar Mills // do not add err msg in redfish response, because this is not 202c181942fSQiang XU // mandatory property 20362598e31SEd Tanous BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec); 204c181942fSQiang XU return; 205c181942fSQiang XU } 206c181942fSQiang XU // Iterate over all retrieved ObjectPaths. 207c181942fSQiang XU for (const auto& object : subtree) 208c181942fSQiang XU { 209840a9ffcSPatrick Williams if (!object.second.empty()) 210c181942fSQiang XU { 21189144a3aSEd Tanous const auto& service = object.second.front(); 2127164bc62SChau Ly 2137164bc62SChau Ly BMCWEB_LOG_DEBUG("Get intrusion status by service "); 2147164bc62SChau Ly 2157164bc62SChau Ly sdbusplus::asio::getProperty<std::string>( 2167164bc62SChau Ly *crow::connections::systemBus, service.first, object.first, 2177164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion", "Status", 2187164bc62SChau Ly [asyncResp](const boost::system::error_code& ec1, 2197164bc62SChau Ly const std::string& value) { 2207164bc62SChau Ly if (ec1) 2217164bc62SChau Ly { 222bd79bce8SPatrick Williams // do not add err msg in redfish response, because this 223bd79bce8SPatrick Williams // is not 2247164bc62SChau Ly // mandatory property 2257164bc62SChau Ly BMCWEB_LOG_ERROR("DBUS response error {}", ec1); 2267164bc62SChau Ly return; 2277164bc62SChau Ly } 228bd79bce8SPatrick Williams asyncResp->res.jsonValue["PhysicalSecurity"] 229bd79bce8SPatrick Williams ["IntrusionSensorNumber"] = 1; 2307164bc62SChau Ly asyncResp->res 231bd79bce8SPatrick Williams .jsonValue["PhysicalSecurity"]["IntrusionSensor"] = 232bd79bce8SPatrick Williams value; 2337164bc62SChau Ly }); 2347164bc62SChau Ly 235c181942fSQiang XU return; 236c181942fSQiang XU } 237c181942fSQiang XU } 238c181942fSQiang XU } 239c181942fSQiang XU 240cf7eba09SNan Zhou inline void handleChassisCollectionGet( 241cf7eba09SNan Zhou App& app, const crow::Request& req, 242cf7eba09SNan Zhou const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2431abe55efSEd Tanous { 2443ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 24545ca1b86SEd Tanous { 24645ca1b86SEd Tanous return; 24745ca1b86SEd Tanous } 2488d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 2498d1b46d7Szhanghch05 "#ChassisCollection.ChassisCollection"; 2508d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 2518d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 252e37f8451SRapkiewicz, Pawel 2537a1dbc48SGeorge Liu constexpr std::array<std::string_view, 2> interfaces{ 2547a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board", 2557a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis"}; 25602f6ff19SGunnar Mills collection_util::getCollectionMembers( 25736b5f1edSLakshmi Yadlapati asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces, 25836b5f1edSLakshmi Yadlapati "/xyz/openbmc_project/inventory"); 259cf7eba09SNan Zhou } 260cf7eba09SNan Zhou 261a5617496SJie Yang inline void getChassisContainedBy( 262a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 263a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 26428ee563eSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& upstreamChassisPaths) 265a5617496SJie Yang { 266a5617496SJie Yang if (ec) 267a5617496SJie Yang { 268a5617496SJie Yang if (ec.value() != EBADR) 269a5617496SJie Yang { 27062598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 271a5617496SJie Yang messages::internalError(asyncResp->res); 272a5617496SJie Yang } 273a5617496SJie Yang return; 274a5617496SJie Yang } 275a5617496SJie Yang if (upstreamChassisPaths.empty()) 276a5617496SJie Yang { 277a5617496SJie Yang return; 278a5617496SJie Yang } 279a5617496SJie Yang if (upstreamChassisPaths.size() > 1) 280a5617496SJie Yang { 2818ece0e45SEd Tanous BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId); 282a5617496SJie Yang messages::internalError(asyncResp->res); 283a5617496SJie Yang return; 284a5617496SJie Yang } 285a5617496SJie Yang 286a5617496SJie Yang sdbusplus::message::object_path upstreamChassisPath( 287a5617496SJie Yang upstreamChassisPaths[0]); 288a5617496SJie Yang std::string upstreamChassis = upstreamChassisPath.filename(); 289a5617496SJie Yang if (upstreamChassis.empty()) 290a5617496SJie Yang { 29162598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}", 29262598e31SEd Tanous upstreamChassisPath.str, chassisId); 293a5617496SJie Yang return; 294a5617496SJie Yang } 295a5617496SJie Yang 296a5617496SJie Yang asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] = 297a5617496SJie Yang boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis); 298a5617496SJie Yang } 299a5617496SJie Yang 300a5617496SJie Yang inline void getChassisContains( 301a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 302a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 30328ee563eSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& downstreamChassisPaths) 304a5617496SJie Yang { 305a5617496SJie Yang if (ec) 306a5617496SJie Yang { 307a5617496SJie Yang if (ec.value() != EBADR) 308a5617496SJie Yang { 30962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 310a5617496SJie Yang messages::internalError(asyncResp->res); 311a5617496SJie Yang } 312a5617496SJie Yang return; 313a5617496SJie Yang } 314a5617496SJie Yang if (downstreamChassisPaths.empty()) 315a5617496SJie Yang { 316a5617496SJie Yang return; 317a5617496SJie Yang } 318a5617496SJie Yang nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"]; 319a5617496SJie Yang if (!jValue.is_array()) 320a5617496SJie Yang { 321a5617496SJie Yang // Create the array if it was empty 322a5617496SJie Yang jValue = nlohmann::json::array(); 323a5617496SJie Yang } 324a5617496SJie Yang for (const auto& p : downstreamChassisPaths) 325a5617496SJie Yang { 326a5617496SJie Yang sdbusplus::message::object_path downstreamChassisPath(p); 327a5617496SJie Yang std::string downstreamChassis = downstreamChassisPath.filename(); 328a5617496SJie Yang if (downstreamChassis.empty()) 329a5617496SJie Yang { 33062598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}", 33162598e31SEd Tanous downstreamChassisPath.str, chassisId); 332a5617496SJie Yang continue; 333a5617496SJie Yang } 334a5617496SJie Yang nlohmann::json link; 335bd79bce8SPatrick Williams link["@odata.id"] = 336bd79bce8SPatrick Williams boost::urls::format("/redfish/v1/Chassis/{}", downstreamChassis); 337a5617496SJie Yang jValue.push_back(std::move(link)); 338a5617496SJie Yang } 339a5617496SJie Yang asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size(); 340a5617496SJie Yang } 341a5617496SJie Yang 342bd79bce8SPatrick Williams inline void getChassisConnectivity( 343bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 344bd79bce8SPatrick Williams const std::string& chassisId, const std::string& chassisPath) 345a5617496SJie Yang { 34662598e31SEd Tanous BMCWEB_LOG_DEBUG("Get chassis connectivity"); 347a5617496SJie Yang 34828ee563eSMyung Bae constexpr std::array<std::string_view, 2> interfaces{ 34928ee563eSMyung Bae "xyz.openbmc_project.Inventory.Item.Board", 35028ee563eSMyung Bae "xyz.openbmc_project.Inventory.Item.Chassis"}; 35128ee563eSMyung Bae 35228ee563eSMyung Bae dbus::utility::getAssociatedSubTreePaths( 353a5617496SJie Yang chassisPath + "/contained_by", 35428ee563eSMyung Bae sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 35528ee563eSMyung Bae interfaces, 356a5617496SJie Yang std::bind_front(getChassisContainedBy, asyncResp, chassisId)); 357a5617496SJie Yang 35828ee563eSMyung Bae dbus::utility::getAssociatedSubTreePaths( 359a5617496SJie Yang chassisPath + "/containing", 36028ee563eSMyung Bae sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 36128ee563eSMyung Bae interfaces, std::bind_front(getChassisContains, asyncResp, chassisId)); 362a5617496SJie Yang } 363a5617496SJie Yang 364cf7eba09SNan Zhou /** 365cf7eba09SNan Zhou * ChassisCollection derived class for delivering Chassis Collection Schema 366cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 367cf7eba09SNan Zhou */ 368cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app) 369cf7eba09SNan Zhou { 370cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/") 371cf7eba09SNan Zhou .privileges(redfish::privileges::getChassisCollection) 372cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 373cf7eba09SNan Zhou std::bind_front(handleChassisCollectionGet, std::ref(app))); 37462d5e2e4SEd Tanous } 375e37f8451SRapkiewicz, Pawel 376bd79bce8SPatrick Williams inline void getChassisLocationCode( 377bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 378bd79bce8SPatrick Williams const std::string& connectionName, const std::string& path) 379308f70c7SWilly Tu { 3801e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 3811e1e598dSJonathan Doman *crow::connections::systemBus, connectionName, path, 3821e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 3835e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3841e1e598dSJonathan Doman const std::string& property) { 385308f70c7SWilly Tu if (ec) 386308f70c7SWilly Tu { 38762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location"); 388308f70c7SWilly Tu messages::internalError(asyncResp->res); 389308f70c7SWilly Tu return; 390308f70c7SWilly Tu } 391308f70c7SWilly Tu 392bd79bce8SPatrick Williams asyncResp->res 393bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 3941e1e598dSJonathan Doman property; 3951e1e598dSJonathan Doman }); 396308f70c7SWilly Tu } 397308f70c7SWilly Tu 398308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 399308f70c7SWilly Tu const std::string& connectionName, 400308f70c7SWilly Tu const std::string& path) 401308f70c7SWilly Tu { 4021e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 4031e1e598dSJonathan Doman *crow::connections::systemBus, connectionName, path, 4041e1e598dSJonathan Doman "xyz.openbmc_project.Common.UUID", "UUID", 4055e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 4061e1e598dSJonathan Doman const std::string& chassisUUID) { 407308f70c7SWilly Tu if (ec) 408308f70c7SWilly Tu { 40962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for UUID"); 410308f70c7SWilly Tu messages::internalError(asyncResp->res); 411308f70c7SWilly Tu return; 412308f70c7SWilly Tu } 4131e1e598dSJonathan Doman asyncResp->res.jsonValue["UUID"] = chassisUUID; 4141e1e598dSJonathan Doman }); 415308f70c7SWilly Tu } 416308f70c7SWilly Tu 4177164bc62SChau Ly inline void handleDecoratorAssetProperties( 41845ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4197164bc62SChau Ly const std::string& chassisId, const std::string& path, 4207164bc62SChau Ly const dbus::utility::DBusPropertiesMap& propertiesList) 421cf7eba09SNan Zhou { 4227164bc62SChau Ly const std::string* partNumber = nullptr; 4237164bc62SChau Ly const std::string* serialNumber = nullptr; 4247164bc62SChau Ly const std::string* manufacturer = nullptr; 4257164bc62SChau Ly const std::string* model = nullptr; 4267164bc62SChau Ly const std::string* sparePartNumber = nullptr; 4277164bc62SChau Ly 4287164bc62SChau Ly const bool success = sdbusplus::unpackPropertiesNoThrow( 4297164bc62SChau Ly dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 4307164bc62SChau Ly partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, 4317164bc62SChau Ly "Model", model, "SparePartNumber", sparePartNumber); 4327164bc62SChau Ly 4337164bc62SChau Ly if (!success) 43445ca1b86SEd Tanous { 4357164bc62SChau Ly messages::internalError(asyncResp->res); 43645ca1b86SEd Tanous return; 43745ca1b86SEd Tanous } 438734bfe90SGunnar Mills 4397164bc62SChau Ly if (partNumber != nullptr) 4407164bc62SChau Ly { 4417164bc62SChau Ly asyncResp->res.jsonValue["PartNumber"] = *partNumber; 4427164bc62SChau Ly } 4437164bc62SChau Ly 4447164bc62SChau Ly if (serialNumber != nullptr) 4457164bc62SChau Ly { 4467164bc62SChau Ly asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 4477164bc62SChau Ly } 4487164bc62SChau Ly 4497164bc62SChau Ly if (manufacturer != nullptr) 4507164bc62SChau Ly { 4517164bc62SChau Ly asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 4527164bc62SChau Ly } 4537164bc62SChau Ly 4547164bc62SChau Ly if (model != nullptr) 4557164bc62SChau Ly { 4567164bc62SChau Ly asyncResp->res.jsonValue["Model"] = *model; 4577164bc62SChau Ly } 4587164bc62SChau Ly 4597164bc62SChau Ly // SparePartNumber is optional on D-Bus 4607164bc62SChau Ly // so skip if it is empty 4617164bc62SChau Ly if (sparePartNumber != nullptr && !sparePartNumber->empty()) 4627164bc62SChau Ly { 4637164bc62SChau Ly asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 4647164bc62SChau Ly } 4657164bc62SChau Ly 4667164bc62SChau Ly asyncResp->res.jsonValue["Name"] = chassisId; 4677164bc62SChau Ly asyncResp->res.jsonValue["Id"] = chassisId; 46825b54dbaSEd Tanous 46925b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL) 47025b54dbaSEd Tanous { 4717164bc62SChau Ly asyncResp->res.jsonValue["Thermal"]["@odata.id"] = 4727164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId); 4737164bc62SChau Ly // Power object 4747164bc62SChau Ly asyncResp->res.jsonValue["Power"]["@odata.id"] = 4757164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId); 47625b54dbaSEd Tanous } 47725b54dbaSEd Tanous 47825b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM) 47925b54dbaSEd Tanous { 4807164bc62SChau Ly asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] = 4817164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem", 4827164bc62SChau Ly chassisId); 4837164bc62SChau Ly asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] = 48425b54dbaSEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", 48525b54dbaSEd Tanous chassisId); 4867164bc62SChau Ly asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] = 4877164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics", 4887164bc62SChau Ly chassisId); 48925b54dbaSEd Tanous } 4907164bc62SChau Ly // SensorCollection 4917164bc62SChau Ly asyncResp->res.jsonValue["Sensors"]["@odata.id"] = 4927164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId); 493539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 4947164bc62SChau Ly 4957164bc62SChau Ly nlohmann::json::array_t computerSystems; 4967164bc62SChau Ly nlohmann::json::object_t system; 497bd79bce8SPatrick Williams system["@odata.id"] = 498bd79bce8SPatrick Williams std::format("/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME); 4997164bc62SChau Ly computerSystems.emplace_back(std::move(system)); 5007164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ComputerSystems"] = 5017164bc62SChau Ly std::move(computerSystems); 5027164bc62SChau Ly 5037164bc62SChau Ly nlohmann::json::array_t managedBy; 5047164bc62SChau Ly nlohmann::json::object_t manager; 505253f11b8SEd Tanous manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}", 506253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 5077164bc62SChau Ly managedBy.emplace_back(std::move(manager)); 5087164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); 5097164bc62SChau Ly getChassisState(asyncResp); 5107164bc62SChau Ly getStorageLink(asyncResp, path); 5117164bc62SChau Ly } 5127164bc62SChau Ly 513*2952f648SJoseph-Jonathan Salzano inline void handleChassisProperties( 514*2952f648SJoseph-Jonathan Salzano const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 515*2952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) 516*2952f648SJoseph-Jonathan Salzano { 517*2952f648SJoseph-Jonathan Salzano const std::string* type = nullptr; 518*2952f648SJoseph-Jonathan Salzano 519*2952f648SJoseph-Jonathan Salzano const bool success = sdbusplus::unpackPropertiesNoThrow( 520*2952f648SJoseph-Jonathan Salzano dbus_utils::UnpackErrorPrinter(), propertiesList, "Type", type); 521*2952f648SJoseph-Jonathan Salzano 522*2952f648SJoseph-Jonathan Salzano if (!success) 523*2952f648SJoseph-Jonathan Salzano { 524*2952f648SJoseph-Jonathan Salzano messages::internalError(asyncResp->res); 525*2952f648SJoseph-Jonathan Salzano return; 526*2952f648SJoseph-Jonathan Salzano } 527*2952f648SJoseph-Jonathan Salzano 528*2952f648SJoseph-Jonathan Salzano if (type != nullptr) 529*2952f648SJoseph-Jonathan Salzano { 530*2952f648SJoseph-Jonathan Salzano auto chassisType = translateChassisTypeToRedfish(*type); 531*2952f648SJoseph-Jonathan Salzano if (chassisType != chassis::ChassisType::Invalid) 532*2952f648SJoseph-Jonathan Salzano { 533*2952f648SJoseph-Jonathan Salzano asyncResp->res.jsonValue["ChassisType"] = chassisType; 534*2952f648SJoseph-Jonathan Salzano } 535*2952f648SJoseph-Jonathan Salzano } 536*2952f648SJoseph-Jonathan Salzano else 537*2952f648SJoseph-Jonathan Salzano { 538*2952f648SJoseph-Jonathan Salzano asyncResp->res.jsonValue["ChassisType"] = 539*2952f648SJoseph-Jonathan Salzano chassis::ChassisType::RackMount; 540*2952f648SJoseph-Jonathan Salzano } 541*2952f648SJoseph-Jonathan Salzano } 542*2952f648SJoseph-Jonathan Salzano 5437164bc62SChau Ly inline void handleChassisGetSubTree( 5447164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5457164bc62SChau Ly const std::string& chassisId, const boost::system::error_code& ec, 5467164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 5477164bc62SChau Ly { 54862d5e2e4SEd Tanous if (ec) 5491abe55efSEd Tanous { 55062598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 551f12894f8SJason M. Bills messages::internalError(asyncResp->res); 552daf36e2eSEd Tanous return; 553daf36e2eSEd Tanous } 554daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 555cf7eba09SNan Zhou for (const std::pair< 556cf7eba09SNan Zhou std::string, 557cf7eba09SNan Zhou std::vector<std::pair<std::string, std::vector<std::string>>>>& 5581214b7e7SGunnar Mills object : subtree) 5591abe55efSEd Tanous { 560daf36e2eSEd Tanous const std::string& path = object.first; 561cf7eba09SNan Zhou const std::vector<std::pair<std::string, std::vector<std::string>>>& 5621214b7e7SGunnar Mills connectionNames = object.second; 5637e860f15SJohn Edward Broadbent 564997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 565997093ebSGeorge Liu if (objPath.filename() != chassisId) 5661abe55efSEd Tanous { 567daf36e2eSEd Tanous continue; 568daf36e2eSEd Tanous } 56926f03899SShawn McCarney 570a5617496SJie Yang getChassisConnectivity(asyncResp, chassisId, path); 571a5617496SJie Yang 57226f6976fSEd Tanous if (connectionNames.empty()) 5731abe55efSEd Tanous { 57462598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 575e0d918bcSEd Tanous continue; 576daf36e2eSEd Tanous } 577e0d918bcSEd Tanous 5787164bc62SChau Ly asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis"; 57949c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.id"] = 580ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 58149c53ac9SJohnathan Mantey asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 582cf7eba09SNan Zhou asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] = 5837164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset", 5847164bc62SChau Ly chassisId); 5851476687dSEd Tanous asyncResp->res 586cf7eba09SNan Zhou .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] = 587ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo", 588ef4c65b7SEd Tanous chassisId); 5896c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 5906c3e9451SGeorge Liu path + "/drive", 5917164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec3, 5926c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 59392903bd4SJohn Edward Broadbent if (ec3 || resp.empty()) 59492903bd4SJohn Edward Broadbent { 59592903bd4SJohn Edward Broadbent return; // no drives = no failures 59692903bd4SJohn Edward Broadbent } 59792903bd4SJohn Edward Broadbent 59892903bd4SJohn Edward Broadbent nlohmann::json reference; 599bd79bce8SPatrick Williams reference["@odata.id"] = boost::urls::format( 600bd79bce8SPatrick Williams "/redfish/v1/Chassis/{}/Drives", chassisId); 60192903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Drives"] = std::move(reference); 60292903bd4SJohn Edward Broadbent }); 60392903bd4SJohn Edward Broadbent 604002d39b4SEd Tanous const std::string& connectionName = connectionNames[0].first; 6051c8fba97SJames Feist 6067164bc62SChau Ly const std::vector<std::string>& interfaces2 = connectionNames[0].second; 607e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 608e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 6091c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 6100fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 6111c8fba97SJames Feist 612476b9cc5STejas Patil const std::string assetTagInterface = 6130fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.AssetTag"; 614523d4868SLogananth Sundararaj const std::string replaceableInterface = 615523d4868SLogananth Sundararaj "xyz.openbmc_project.Inventory.Decorator.Replaceable"; 616b4d593f1SCarson Labrado const std::string revisionInterface = 617b4d593f1SCarson Labrado "xyz.openbmc_project.Inventory.Decorator.Revision"; 618523d4868SLogananth Sundararaj for (const auto& interface : interfaces2) 619523d4868SLogananth Sundararaj { 620523d4868SLogananth Sundararaj if (interface == assetTagInterface) 621476b9cc5STejas Patil { 6221e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 623002d39b4SEd Tanous *crow::connections::systemBus, connectionName, path, 624002d39b4SEd Tanous assetTagInterface, "AssetTag", 6257164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 6261e1e598dSJonathan Doman const std::string& property) { 6278a592810SEd Tanous if (ec2) 628476b9cc5STejas Patil { 629bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 630bd79bce8SPatrick Williams "DBus response error for AssetTag: {}", ec2); 631476b9cc5STejas Patil messages::internalError(asyncResp->res); 632476b9cc5STejas Patil return; 633476b9cc5STejas Patil } 634002d39b4SEd Tanous asyncResp->res.jsonValue["AssetTag"] = property; 6351e1e598dSJonathan Doman }); 636476b9cc5STejas Patil } 637523d4868SLogananth Sundararaj else if (interface == replaceableInterface) 638523d4868SLogananth Sundararaj { 639523d4868SLogananth Sundararaj sdbusplus::asio::getProperty<bool>( 640523d4868SLogananth Sundararaj *crow::connections::systemBus, connectionName, path, 641523d4868SLogananth Sundararaj replaceableInterface, "HotPluggable", 6427164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 643523d4868SLogananth Sundararaj const bool property) { 644523d4868SLogananth Sundararaj if (ec2) 645523d4868SLogananth Sundararaj { 64662598e31SEd Tanous BMCWEB_LOG_ERROR( 647bd79bce8SPatrick Williams "DBus response error for HotPluggable: {}", 648bd79bce8SPatrick Williams ec2); 649523d4868SLogananth Sundararaj messages::internalError(asyncResp->res); 650523d4868SLogananth Sundararaj return; 651523d4868SLogananth Sundararaj } 652523d4868SLogananth Sundararaj asyncResp->res.jsonValue["HotPluggable"] = property; 653523d4868SLogananth Sundararaj }); 654523d4868SLogananth Sundararaj } 655b4d593f1SCarson Labrado else if (interface == revisionInterface) 656b4d593f1SCarson Labrado { 657b4d593f1SCarson Labrado sdbusplus::asio::getProperty<std::string>( 658b4d593f1SCarson Labrado *crow::connections::systemBus, connectionName, path, 659b4d593f1SCarson Labrado revisionInterface, "Version", 660b4d593f1SCarson Labrado [asyncResp, chassisId](const boost::system::error_code& ec2, 661b4d593f1SCarson Labrado const std::string& property) { 662b4d593f1SCarson Labrado if (ec2) 663b4d593f1SCarson Labrado { 664bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 665bd79bce8SPatrick Williams "DBus response error for Version: {}", ec2); 666b4d593f1SCarson Labrado messages::internalError(asyncResp->res); 667b4d593f1SCarson Labrado return; 668b4d593f1SCarson Labrado } 669b4d593f1SCarson Labrado asyncResp->res.jsonValue["Version"] = property; 670b4d593f1SCarson Labrado }); 671b4d593f1SCarson Labrado } 672523d4868SLogananth Sundararaj } 673476b9cc5STejas Patil 6741c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 6751c8fba97SJames Feist { 6767164bc62SChau Ly if (std::ranges::find(interfaces2, interface) != interfaces2.end()) 6771c8fba97SJames Feist { 6781c8fba97SJames Feist getIndicatorLedState(asyncResp); 67959a17e4fSGeorge Liu getSystemLocationIndicatorActive(asyncResp); 6801c8fba97SJames Feist break; 6811c8fba97SJames Feist } 6821c8fba97SJames Feist } 6831c8fba97SJames Feist 68486d89ed7SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 68586d89ed7SKrzysztof Grobelny *crow::connections::systemBus, connectionName, path, 68686d89ed7SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Asset", 6877164bc62SChau Ly [asyncResp, chassisId, 6887164bc62SChau Ly path](const boost::system::error_code&, 689cf7eba09SNan Zhou const dbus::utility::DBusPropertiesMap& propertiesList) { 6907164bc62SChau Ly handleDecoratorAssetProperties(asyncResp, chassisId, path, 6917164bc62SChau Ly propertiesList); 69286d89ed7SKrzysztof Grobelny }); 6932c37b4b0SSharad Yadav 694*2952f648SJoseph-Jonathan Salzano sdbusplus::asio::getAllProperties( 695*2952f648SJoseph-Jonathan Salzano *crow::connections::systemBus, connectionName, path, 696*2952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis", 697*2952f648SJoseph-Jonathan Salzano [asyncResp]( 698*2952f648SJoseph-Jonathan Salzano const boost::system::error_code&, 699*2952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) { 700*2952f648SJoseph-Jonathan Salzano handleChassisProperties(asyncResp, propertiesList); 701*2952f648SJoseph-Jonathan Salzano }); 702*2952f648SJoseph-Jonathan Salzano 703308f70c7SWilly Tu for (const auto& interface : interfaces2) 7042c37b4b0SSharad Yadav { 705308f70c7SWilly Tu if (interface == "xyz.openbmc_project.Common.UUID") 7062c37b4b0SSharad Yadav { 707308f70c7SWilly Tu getChassisUUID(asyncResp, connectionName, path); 7082c37b4b0SSharad Yadav } 709cf7eba09SNan Zhou else if (interface == 7100fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode") 7112c37b4b0SSharad Yadav { 712002d39b4SEd Tanous getChassisLocationCode(asyncResp, connectionName, path); 7132c37b4b0SSharad Yadav } 7142c37b4b0SSharad Yadav } 7152c37b4b0SSharad Yadav 716daf36e2eSEd Tanous return; 717daf36e2eSEd Tanous } 718e0d918bcSEd Tanous 719daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 720d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 7217164bc62SChau Ly } 722c181942fSQiang XU 7237164bc62SChau Ly inline void 7247164bc62SChau Ly handleChassisGet(App& app, const crow::Request& req, 7257164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7267164bc62SChau Ly const std::string& chassisId) 7277164bc62SChau Ly { 7287164bc62SChau Ly if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 7297164bc62SChau Ly { 7307164bc62SChau Ly return; 7317164bc62SChau Ly } 7327164bc62SChau Ly constexpr std::array<std::string_view, 2> interfaces = { 7337164bc62SChau Ly "xyz.openbmc_project.Inventory.Item.Board", 7347164bc62SChau Ly "xyz.openbmc_project.Inventory.Item.Chassis"}; 7357164bc62SChau Ly 7367164bc62SChau Ly dbus::utility::getSubTree( 7377164bc62SChau Ly "/xyz/openbmc_project/inventory", 0, interfaces, 7387164bc62SChau Ly std::bind_front(handleChassisGetSubTree, asyncResp, chassisId)); 7397164bc62SChau Ly 7407164bc62SChau Ly constexpr std::array<std::string_view, 1> interfaces2 = { 7417164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion"}; 7427164bc62SChau Ly 7437164bc62SChau Ly dbus::utility::getSubTree( 7447164bc62SChau Ly "/xyz/openbmc_project", 0, interfaces2, 7457164bc62SChau Ly std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp)); 746cf7eba09SNan Zhou } 7471c8fba97SJames Feist 748cf7eba09SNan Zhou inline void 749cf7eba09SNan Zhou handleChassisPatch(App& app, const crow::Request& req, 7507e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 751cf7eba09SNan Zhou const std::string& param) 752cf7eba09SNan Zhou { 7533ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 75445ca1b86SEd Tanous { 75545ca1b86SEd Tanous return; 75645ca1b86SEd Tanous } 7579f8bfa7cSGunnar Mills std::optional<bool> locationIndicatorActive; 7581c8fba97SJames Feist std::optional<std::string> indicatorLed; 7591c8fba97SJames Feist 7607e860f15SJohn Edward Broadbent if (param.empty()) 7611c8fba97SJames Feist { 7621c8fba97SJames Feist return; 7631c8fba97SJames Feist } 7641c8fba97SJames Feist 765afc474aeSMyung Bae if (!json_util::readJsonPatch( // 766afc474aeSMyung Bae req, asyncResp->res, // 767afc474aeSMyung Bae "IndicatorLED", indicatorLed, // 768afc474aeSMyung Bae "LocationIndicatorActive", locationIndicatorActive // 769afc474aeSMyung Bae )) 7701c8fba97SJames Feist { 7711c8fba97SJames Feist return; 7721c8fba97SJames Feist } 7731c8fba97SJames Feist 7749f8bfa7cSGunnar Mills // TODO (Gunnar): Remove IndicatorLED after enough time has passed 7759f8bfa7cSGunnar Mills if (!locationIndicatorActive && !indicatorLed) 7761c8fba97SJames Feist { 7771c8fba97SJames Feist return; // delete this when we support more patch properties 7781c8fba97SJames Feist } 779d6aa0093SGunnar Mills if (indicatorLed) 780d6aa0093SGunnar Mills { 7817e860f15SJohn Edward Broadbent asyncResp->res.addHeader( 7827e860f15SJohn Edward Broadbent boost::beast::http::field::warning, 7830fda0f12SGeorge Liu "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\""); 784d6aa0093SGunnar Mills } 7851c8fba97SJames Feist 786e99073f5SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 7871c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board", 7881c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Chassis"}; 7891c8fba97SJames Feist 7907e860f15SJohn Edward Broadbent const std::string& chassisId = param; 7911c8fba97SJames Feist 792e99073f5SGeorge Liu dbus::utility::getSubTree( 793e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 794cf7eba09SNan Zhou [asyncResp, chassisId, locationIndicatorActive, 7955e7e2dc5SEd Tanous indicatorLed](const boost::system::error_code& ec, 796b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 7971c8fba97SJames Feist if (ec) 7981c8fba97SJames Feist { 79962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 8001c8fba97SJames Feist messages::internalError(asyncResp->res); 8011c8fba97SJames Feist return; 8021c8fba97SJames Feist } 8031c8fba97SJames Feist 8041c8fba97SJames Feist // Iterate over all retrieved ObjectPaths. 805bd79bce8SPatrick Williams for (const std::pair<std::string, 806bd79bce8SPatrick Williams std::vector<std::pair< 807bd79bce8SPatrick Williams std::string, std::vector<std::string>>>>& 8081214b7e7SGunnar Mills object : subtree) 8091c8fba97SJames Feist { 8101c8fba97SJames Feist const std::string& path = object.first; 811bd79bce8SPatrick Williams const std::vector< 812bd79bce8SPatrick Williams std::pair<std::string, std::vector<std::string>>>& 8131214b7e7SGunnar Mills connectionNames = object.second; 8141c8fba97SJames Feist 815997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 816997093ebSGeorge Liu if (objPath.filename() != chassisId) 8171c8fba97SJames Feist { 8181c8fba97SJames Feist continue; 8191c8fba97SJames Feist } 8201c8fba97SJames Feist 82126f6976fSEd Tanous if (connectionNames.empty()) 8221c8fba97SJames Feist { 82362598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 8241c8fba97SJames Feist continue; 8251c8fba97SJames Feist } 8261c8fba97SJames Feist 82723a21a1cSEd Tanous const std::vector<std::string>& interfaces3 = 8281c8fba97SJames Feist connectionNames[0].second; 8291c8fba97SJames Feist 830e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 831e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 8321c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 8330fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 8341c8fba97SJames Feist bool indicatorChassis = false; 8351c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 8361c8fba97SJames Feist { 8373544d2a7SEd Tanous if (std::ranges::find(interfaces3, interface) != 8383544d2a7SEd Tanous interfaces3.end()) 8391c8fba97SJames Feist { 8401c8fba97SJames Feist indicatorChassis = true; 8411c8fba97SJames Feist break; 8421c8fba97SJames Feist } 8431c8fba97SJames Feist } 8449f8bfa7cSGunnar Mills if (locationIndicatorActive) 8459f8bfa7cSGunnar Mills { 8469f8bfa7cSGunnar Mills if (indicatorChassis) 8479f8bfa7cSGunnar Mills { 848bd79bce8SPatrick Williams setSystemLocationIndicatorActive( 849bd79bce8SPatrick Williams asyncResp, *locationIndicatorActive); 8509f8bfa7cSGunnar Mills } 8519f8bfa7cSGunnar Mills else 8529f8bfa7cSGunnar Mills { 853002d39b4SEd Tanous messages::propertyUnknown(asyncResp->res, 854002d39b4SEd Tanous "LocationIndicatorActive"); 8559f8bfa7cSGunnar Mills } 8569f8bfa7cSGunnar Mills } 8579f8bfa7cSGunnar Mills if (indicatorLed) 8589f8bfa7cSGunnar Mills { 8591c8fba97SJames Feist if (indicatorChassis) 8601c8fba97SJames Feist { 861f23b7296SEd Tanous setIndicatorLedState(asyncResp, *indicatorLed); 8621c8fba97SJames Feist } 8631c8fba97SJames Feist else 8641c8fba97SJames Feist { 865bd79bce8SPatrick Williams messages::propertyUnknown(asyncResp->res, 866bd79bce8SPatrick Williams "IndicatorLED"); 8671c8fba97SJames Feist } 8681c8fba97SJames Feist } 8691c8fba97SJames Feist return; 8701c8fba97SJames Feist } 8711c8fba97SJames Feist 872d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 873e99073f5SGeorge Liu }); 874cf7eba09SNan Zhou } 875cf7eba09SNan Zhou 876cf7eba09SNan Zhou /** 877cf7eba09SNan Zhou * Chassis override class for delivering Chassis Schema 878cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 879cf7eba09SNan Zhou */ 880cf7eba09SNan Zhou inline void requestRoutesChassis(App& app) 881cf7eba09SNan Zhou { 882cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 883cf7eba09SNan Zhou .privileges(redfish::privileges::getChassis) 884cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 885cf7eba09SNan Zhou std::bind_front(handleChassisGet, std::ref(app))); 886cf7eba09SNan Zhou 887cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 888cf7eba09SNan Zhou .privileges(redfish::privileges::patchChassis) 889cf7eba09SNan Zhou .methods(boost::beast::http::verb::patch)( 890cf7eba09SNan Zhou std::bind_front(handleChassisPatch, std::ref(app))); 8911c8fba97SJames Feist } 892dd99e04bSP.K. Lee 8938d1b46d7Szhanghch05 inline void 8948d1b46d7Szhanghch05 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 895dd99e04bSP.K. Lee { 8967a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 897c3b3c92aSVijay Khemka "xyz.openbmc_project.State.Chassis"}; 898c3b3c92aSVijay Khemka 899c3b3c92aSVijay Khemka // Use mapper to get subtree paths. 9007a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 9017a1dbc48SGeorge Liu "/", 0, interfaces, 902b9d36b47SEd Tanous [asyncResp]( 9037a1dbc48SGeorge Liu const boost::system::error_code& ec, 904b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& chassisList) { 905c3b3c92aSVijay Khemka if (ec) 906c3b3c92aSVijay Khemka { 90762598e31SEd Tanous BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec); 908c3b3c92aSVijay Khemka messages::internalError(asyncResp->res); 909c3b3c92aSVijay Khemka return; 910c3b3c92aSVijay Khemka } 911c3b3c92aSVijay Khemka 912dd99e04bSP.K. Lee const char* processName = "xyz.openbmc_project.State.Chassis"; 913dd99e04bSP.K. Lee const char* interfaceName = "xyz.openbmc_project.State.Chassis"; 914dd99e04bSP.K. Lee const char* destProperty = "RequestedPowerTransition"; 915dd99e04bSP.K. Lee const std::string propertyValue = 916dd99e04bSP.K. Lee "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; 917bd79bce8SPatrick Williams std::string objectPath = 918bd79bce8SPatrick Williams "/xyz/openbmc_project/state/chassis_system0"; 919c3b3c92aSVijay Khemka 920c3b3c92aSVijay Khemka /* Look for system reset chassis path */ 921bd79bce8SPatrick Williams if ((std::ranges::find(chassisList, objectPath)) == 922bd79bce8SPatrick Williams chassisList.end()) 923c3b3c92aSVijay Khemka { 924c3b3c92aSVijay Khemka /* We prefer to reset the full chassis_system, but if it doesn't 925c3b3c92aSVijay Khemka * exist on some platforms, fall back to a host-only power reset 926c3b3c92aSVijay Khemka */ 927c3b3c92aSVijay Khemka objectPath = "/xyz/openbmc_project/state/chassis0"; 928c3b3c92aSVijay Khemka } 929dd99e04bSP.K. Lee 930e93abac6SGinu George setDbusProperty(asyncResp, "ResetType", processName, objectPath, 931e93abac6SGinu George interfaceName, destProperty, propertyValue); 9327a1dbc48SGeorge Liu }); 933dd99e04bSP.K. Lee } 934dd99e04bSP.K. Lee 935cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost( 936cf7eba09SNan Zhou App& app, const crow::Request& req, 9377e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 938cf7eba09SNan Zhou const std::string& /*chassisId*/) 939cf7eba09SNan Zhou { 9403ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 94145ca1b86SEd Tanous { 94245ca1b86SEd Tanous return; 94345ca1b86SEd Tanous } 94462598e31SEd Tanous BMCWEB_LOG_DEBUG("Post Chassis Reset."); 945dd99e04bSP.K. Lee 946dd99e04bSP.K. Lee std::string resetType; 947dd99e04bSP.K. Lee 948cf7eba09SNan Zhou if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 949dd99e04bSP.K. Lee { 950dd99e04bSP.K. Lee return; 951dd99e04bSP.K. Lee } 952dd99e04bSP.K. Lee 953dd99e04bSP.K. Lee if (resetType != "PowerCycle") 954dd99e04bSP.K. Lee { 95562598e31SEd Tanous BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType); 956002d39b4SEd Tanous messages::actionParameterNotSupported(asyncResp->res, resetType, 957002d39b4SEd Tanous "ResetType"); 958dd99e04bSP.K. Lee 959dd99e04bSP.K. Lee return; 960dd99e04bSP.K. Lee } 961dd99e04bSP.K. Lee doChassisPowerCycle(asyncResp); 962dd99e04bSP.K. Lee } 9631cb1a9e6SAppaRao Puli 9641cb1a9e6SAppaRao Puli /** 965cf7eba09SNan Zhou * ChassisResetAction class supports the POST method for the Reset 966cf7eba09SNan Zhou * action. 967cf7eba09SNan Zhou * Function handles POST method request. 968cf7eba09SNan Zhou * Analyzes POST body before sending Reset request data to D-Bus. 9691cb1a9e6SAppaRao Puli */ 970cf7eba09SNan Zhou 971cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app) 9721cb1a9e6SAppaRao Puli { 973cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/") 974cf7eba09SNan Zhou .privileges(redfish::privileges::postChassis) 975cf7eba09SNan Zhou .methods(boost::beast::http::verb::post)( 976cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoPost, std::ref(app))); 977cf7eba09SNan Zhou } 978cf7eba09SNan Zhou 979cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet( 980cf7eba09SNan Zhou App& app, const crow::Request& req, 9817e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 982cf7eba09SNan Zhou const std::string& chassisId) 983cf7eba09SNan Zhou { 9843ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 9851cb1a9e6SAppaRao Puli { 98645ca1b86SEd Tanous return; 98745ca1b86SEd Tanous } 988cf7eba09SNan Zhou asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 989ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 990ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId); 9911476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 9921476687dSEd Tanous 9931476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 9945b9e95a1SNan Zhou nlohmann::json::array_t parameters; 9955b9e95a1SNan Zhou nlohmann::json::object_t parameter; 9965b9e95a1SNan Zhou parameter["Name"] = "ResetType"; 9975b9e95a1SNan Zhou parameter["Required"] = true; 998539d8c6bSEd Tanous parameter["DataType"] = action_info::ParameterTypes::String; 9991476687dSEd Tanous nlohmann::json::array_t allowed; 1000ad539545SPatrick Williams allowed.emplace_back("PowerCycle"); 10015b9e95a1SNan Zhou parameter["AllowableValues"] = std::move(allowed); 1002ad539545SPatrick Williams parameters.emplace_back(std::move(parameter)); 10035b9e95a1SNan Zhou 10041476687dSEd Tanous asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 1005cf7eba09SNan Zhou } 1006cf7eba09SNan Zhou 1007cf7eba09SNan Zhou /** 1008cf7eba09SNan Zhou * ChassisResetActionInfo derived class for delivering Chassis 1009cf7eba09SNan Zhou * ResetType AllowableValues using ResetInfo schema. 1010cf7eba09SNan Zhou */ 1011cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app) 1012cf7eba09SNan Zhou { 1013cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/") 1014cf7eba09SNan Zhou .privileges(redfish::privileges::getActionInfo) 1015cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 1016cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoGet, std::ref(app))); 10171cb1a9e6SAppaRao Puli } 10181cb1a9e6SAppaRao Puli 1019e37f8451SRapkiewicz, Pawel } // namespace redfish 1020