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> 382952f648SJoseph-Jonathan Salzano #include <memory> 393544d2a7SEd Tanous #include <ranges> 407a1dbc48SGeorge Liu #include <string_view> 417a1dbc48SGeorge Liu 421abe55efSEd Tanous namespace redfish 431abe55efSEd Tanous { 44e37f8451SRapkiewicz, Pawel 452952f648SJoseph-Jonathan Salzano inline chassis::ChassisType 462952f648SJoseph-Jonathan Salzano translateChassisTypeToRedfish(const std::string_view& chassisType) 472952f648SJoseph-Jonathan Salzano { 482952f648SJoseph-Jonathan Salzano if (chassisType == 492952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Blade") 502952f648SJoseph-Jonathan Salzano { 512952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Blade; 522952f648SJoseph-Jonathan Salzano } 532952f648SJoseph-Jonathan Salzano if (chassisType == 542952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Component") 552952f648SJoseph-Jonathan Salzano { 562952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Component; 572952f648SJoseph-Jonathan Salzano } 582952f648SJoseph-Jonathan Salzano if (chassisType == 592952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Enclosure") 602952f648SJoseph-Jonathan Salzano { 612952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Enclosure; 622952f648SJoseph-Jonathan Salzano } 632952f648SJoseph-Jonathan Salzano if (chassisType == 642952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Module") 652952f648SJoseph-Jonathan Salzano { 662952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Module; 672952f648SJoseph-Jonathan Salzano } 682952f648SJoseph-Jonathan Salzano if (chassisType == 692952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.RackMount") 702952f648SJoseph-Jonathan Salzano { 712952f648SJoseph-Jonathan Salzano return chassis::ChassisType::RackMount; 722952f648SJoseph-Jonathan Salzano } 732952f648SJoseph-Jonathan Salzano if (chassisType == 742952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StandAlone") 752952f648SJoseph-Jonathan Salzano { 762952f648SJoseph-Jonathan Salzano return chassis::ChassisType::StandAlone; 772952f648SJoseph-Jonathan Salzano } 782952f648SJoseph-Jonathan Salzano if (chassisType == 792952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StorageEnclosure") 802952f648SJoseph-Jonathan Salzano { 812952f648SJoseph-Jonathan Salzano return chassis::ChassisType::StorageEnclosure; 822952f648SJoseph-Jonathan Salzano } 832952f648SJoseph-Jonathan Salzano if (chassisType == 842952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Zone") 852952f648SJoseph-Jonathan Salzano { 862952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Zone; 872952f648SJoseph-Jonathan Salzano } 882952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Invalid; 892952f648SJoseph-Jonathan Salzano } 902952f648SJoseph-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 { 107*deae6a78SEd Tanous dbus::utility::getProperty<std::vector<std::string>>( 108*deae6a78SEd Tanous "xyz.openbmc_project.ObjectMapper", (path / "storage").str, 109*deae6a78SEd Tanous "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( 150*deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 151*deae6a78SEd Tanous "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 215*deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 216*deae6a78SEd Tanous 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 { 380*deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 381*deae6a78SEd Tanous 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 { 402*deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 403*deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Common.UUID", "UUID", 4045e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 4051e1e598dSJonathan Doman const std::string& chassisUUID) { 406308f70c7SWilly Tu if (ec) 407308f70c7SWilly Tu { 40862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for UUID"); 409308f70c7SWilly Tu messages::internalError(asyncResp->res); 410308f70c7SWilly Tu return; 411308f70c7SWilly Tu } 4121e1e598dSJonathan Doman asyncResp->res.jsonValue["UUID"] = chassisUUID; 4131e1e598dSJonathan Doman }); 414308f70c7SWilly Tu } 415308f70c7SWilly Tu 4167164bc62SChau Ly inline void handleDecoratorAssetProperties( 41745ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4187164bc62SChau Ly const std::string& chassisId, const std::string& path, 4197164bc62SChau Ly const dbus::utility::DBusPropertiesMap& propertiesList) 420cf7eba09SNan Zhou { 4217164bc62SChau Ly const std::string* partNumber = nullptr; 4227164bc62SChau Ly const std::string* serialNumber = nullptr; 4237164bc62SChau Ly const std::string* manufacturer = nullptr; 4247164bc62SChau Ly const std::string* model = nullptr; 4257164bc62SChau Ly const std::string* sparePartNumber = nullptr; 4267164bc62SChau Ly 4277164bc62SChau Ly const bool success = sdbusplus::unpackPropertiesNoThrow( 4287164bc62SChau Ly dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 4297164bc62SChau Ly partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, 4307164bc62SChau Ly "Model", model, "SparePartNumber", sparePartNumber); 4317164bc62SChau Ly 4327164bc62SChau Ly if (!success) 43345ca1b86SEd Tanous { 4347164bc62SChau Ly messages::internalError(asyncResp->res); 43545ca1b86SEd Tanous return; 43645ca1b86SEd Tanous } 437734bfe90SGunnar Mills 4387164bc62SChau Ly if (partNumber != nullptr) 4397164bc62SChau Ly { 4407164bc62SChau Ly asyncResp->res.jsonValue["PartNumber"] = *partNumber; 4417164bc62SChau Ly } 4427164bc62SChau Ly 4437164bc62SChau Ly if (serialNumber != nullptr) 4447164bc62SChau Ly { 4457164bc62SChau Ly asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 4467164bc62SChau Ly } 4477164bc62SChau Ly 4487164bc62SChau Ly if (manufacturer != nullptr) 4497164bc62SChau Ly { 4507164bc62SChau Ly asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 4517164bc62SChau Ly } 4527164bc62SChau Ly 4537164bc62SChau Ly if (model != nullptr) 4547164bc62SChau Ly { 4557164bc62SChau Ly asyncResp->res.jsonValue["Model"] = *model; 4567164bc62SChau Ly } 4577164bc62SChau Ly 4587164bc62SChau Ly // SparePartNumber is optional on D-Bus 4597164bc62SChau Ly // so skip if it is empty 4607164bc62SChau Ly if (sparePartNumber != nullptr && !sparePartNumber->empty()) 4617164bc62SChau Ly { 4627164bc62SChau Ly asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 4637164bc62SChau Ly } 4647164bc62SChau Ly 4657164bc62SChau Ly asyncResp->res.jsonValue["Name"] = chassisId; 4667164bc62SChau Ly asyncResp->res.jsonValue["Id"] = chassisId; 46725b54dbaSEd Tanous 46825b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL) 46925b54dbaSEd Tanous { 4707164bc62SChau Ly asyncResp->res.jsonValue["Thermal"]["@odata.id"] = 4717164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId); 4727164bc62SChau Ly // Power object 4737164bc62SChau Ly asyncResp->res.jsonValue["Power"]["@odata.id"] = 4747164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId); 47525b54dbaSEd Tanous } 47625b54dbaSEd Tanous 47725b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM) 47825b54dbaSEd Tanous { 4797164bc62SChau Ly asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] = 4807164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem", 4817164bc62SChau Ly chassisId); 4827164bc62SChau Ly asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] = 48325b54dbaSEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", 48425b54dbaSEd Tanous chassisId); 4857164bc62SChau Ly asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] = 4867164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics", 4877164bc62SChau Ly chassisId); 48825b54dbaSEd Tanous } 4897164bc62SChau Ly // SensorCollection 4907164bc62SChau Ly asyncResp->res.jsonValue["Sensors"]["@odata.id"] = 4917164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId); 492539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 4937164bc62SChau Ly 4947164bc62SChau Ly nlohmann::json::array_t computerSystems; 4957164bc62SChau Ly nlohmann::json::object_t system; 496bd79bce8SPatrick Williams system["@odata.id"] = 497bd79bce8SPatrick Williams std::format("/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME); 4987164bc62SChau Ly computerSystems.emplace_back(std::move(system)); 4997164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ComputerSystems"] = 5007164bc62SChau Ly std::move(computerSystems); 5017164bc62SChau Ly 5027164bc62SChau Ly nlohmann::json::array_t managedBy; 5037164bc62SChau Ly nlohmann::json::object_t manager; 504253f11b8SEd Tanous manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}", 505253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 5067164bc62SChau Ly managedBy.emplace_back(std::move(manager)); 5077164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); 5087164bc62SChau Ly getChassisState(asyncResp); 5097164bc62SChau Ly getStorageLink(asyncResp, path); 5107164bc62SChau Ly } 5117164bc62SChau Ly 5122952f648SJoseph-Jonathan Salzano inline void handleChassisProperties( 5132952f648SJoseph-Jonathan Salzano const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5142952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) 5152952f648SJoseph-Jonathan Salzano { 5162952f648SJoseph-Jonathan Salzano const std::string* type = nullptr; 5172952f648SJoseph-Jonathan Salzano 5182952f648SJoseph-Jonathan Salzano const bool success = sdbusplus::unpackPropertiesNoThrow( 5192952f648SJoseph-Jonathan Salzano dbus_utils::UnpackErrorPrinter(), propertiesList, "Type", type); 5202952f648SJoseph-Jonathan Salzano 5212952f648SJoseph-Jonathan Salzano if (!success) 5222952f648SJoseph-Jonathan Salzano { 5232952f648SJoseph-Jonathan Salzano messages::internalError(asyncResp->res); 5242952f648SJoseph-Jonathan Salzano return; 5252952f648SJoseph-Jonathan Salzano } 5262952f648SJoseph-Jonathan Salzano 52719ea2864SGunnar Mills // Chassis Type is a required property in Redfish 52819ea2864SGunnar Mills // If there is an error or some enum we don't support just sit it to Rack 52919ea2864SGunnar Mills // Mount 53019ea2864SGunnar Mills asyncResp->res.jsonValue["ChassisType"] = chassis::ChassisType::RackMount; 53119ea2864SGunnar Mills 5322952f648SJoseph-Jonathan Salzano if (type != nullptr) 5332952f648SJoseph-Jonathan Salzano { 5342952f648SJoseph-Jonathan Salzano auto chassisType = translateChassisTypeToRedfish(*type); 5352952f648SJoseph-Jonathan Salzano if (chassisType != chassis::ChassisType::Invalid) 5362952f648SJoseph-Jonathan Salzano { 5372952f648SJoseph-Jonathan Salzano asyncResp->res.jsonValue["ChassisType"] = chassisType; 5382952f648SJoseph-Jonathan Salzano } 5392952f648SJoseph-Jonathan Salzano } 5402952f648SJoseph-Jonathan Salzano } 5412952f648SJoseph-Jonathan Salzano 5427164bc62SChau Ly inline void handleChassisGetSubTree( 5437164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5447164bc62SChau Ly const std::string& chassisId, const boost::system::error_code& ec, 5457164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 5467164bc62SChau Ly { 54762d5e2e4SEd Tanous if (ec) 5481abe55efSEd Tanous { 54962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 550f12894f8SJason M. Bills messages::internalError(asyncResp->res); 551daf36e2eSEd Tanous return; 552daf36e2eSEd Tanous } 553daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 554cf7eba09SNan Zhou for (const std::pair< 555cf7eba09SNan Zhou std::string, 556cf7eba09SNan Zhou std::vector<std::pair<std::string, std::vector<std::string>>>>& 5571214b7e7SGunnar Mills object : subtree) 5581abe55efSEd Tanous { 559daf36e2eSEd Tanous const std::string& path = object.first; 560cf7eba09SNan Zhou const std::vector<std::pair<std::string, std::vector<std::string>>>& 5611214b7e7SGunnar Mills connectionNames = object.second; 5627e860f15SJohn Edward Broadbent 563997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 564997093ebSGeorge Liu if (objPath.filename() != chassisId) 5651abe55efSEd Tanous { 566daf36e2eSEd Tanous continue; 567daf36e2eSEd Tanous } 56826f03899SShawn McCarney 569a5617496SJie Yang getChassisConnectivity(asyncResp, chassisId, path); 570a5617496SJie Yang 57126f6976fSEd Tanous if (connectionNames.empty()) 5721abe55efSEd Tanous { 57362598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 574e0d918bcSEd Tanous continue; 575daf36e2eSEd Tanous } 576e0d918bcSEd Tanous 5777164bc62SChau Ly asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis"; 57849c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.id"] = 579ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 58049c53ac9SJohnathan Mantey asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 581cf7eba09SNan Zhou asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] = 5827164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset", 5837164bc62SChau Ly chassisId); 5841476687dSEd Tanous asyncResp->res 585cf7eba09SNan Zhou .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] = 586ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo", 587ef4c65b7SEd Tanous chassisId); 5886c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 5896c3e9451SGeorge Liu path + "/drive", 5907164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec3, 5916c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 59292903bd4SJohn Edward Broadbent if (ec3 || resp.empty()) 59392903bd4SJohn Edward Broadbent { 59492903bd4SJohn Edward Broadbent return; // no drives = no failures 59592903bd4SJohn Edward Broadbent } 59692903bd4SJohn Edward Broadbent 59792903bd4SJohn Edward Broadbent nlohmann::json reference; 598bd79bce8SPatrick Williams reference["@odata.id"] = boost::urls::format( 599bd79bce8SPatrick Williams "/redfish/v1/Chassis/{}/Drives", chassisId); 60092903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Drives"] = std::move(reference); 60192903bd4SJohn Edward Broadbent }); 60292903bd4SJohn Edward Broadbent 603002d39b4SEd Tanous const std::string& connectionName = connectionNames[0].first; 6041c8fba97SJames Feist 6057164bc62SChau Ly const std::vector<std::string>& interfaces2 = connectionNames[0].second; 606e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 607e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 6081c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 6090fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 6101c8fba97SJames Feist 611476b9cc5STejas Patil const std::string assetTagInterface = 6120fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.AssetTag"; 613523d4868SLogananth Sundararaj const std::string replaceableInterface = 614523d4868SLogananth Sundararaj "xyz.openbmc_project.Inventory.Decorator.Replaceable"; 615b4d593f1SCarson Labrado const std::string revisionInterface = 616b4d593f1SCarson Labrado "xyz.openbmc_project.Inventory.Decorator.Revision"; 617523d4868SLogananth Sundararaj for (const auto& interface : interfaces2) 618523d4868SLogananth Sundararaj { 619523d4868SLogananth Sundararaj if (interface == assetTagInterface) 620476b9cc5STejas Patil { 621*deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 622*deae6a78SEd Tanous connectionName, path, assetTagInterface, "AssetTag", 6237164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 6241e1e598dSJonathan Doman const std::string& property) { 6258a592810SEd Tanous if (ec2) 626476b9cc5STejas Patil { 627bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 628bd79bce8SPatrick Williams "DBus response error for AssetTag: {}", ec2); 629476b9cc5STejas Patil messages::internalError(asyncResp->res); 630476b9cc5STejas Patil return; 631476b9cc5STejas Patil } 632002d39b4SEd Tanous asyncResp->res.jsonValue["AssetTag"] = property; 6331e1e598dSJonathan Doman }); 634476b9cc5STejas Patil } 635523d4868SLogananth Sundararaj else if (interface == replaceableInterface) 636523d4868SLogananth Sundararaj { 637*deae6a78SEd Tanous dbus::utility::getProperty<bool>( 638*deae6a78SEd Tanous connectionName, path, replaceableInterface, "HotPluggable", 6397164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 640523d4868SLogananth Sundararaj const bool property) { 641523d4868SLogananth Sundararaj if (ec2) 642523d4868SLogananth Sundararaj { 64362598e31SEd Tanous BMCWEB_LOG_ERROR( 644bd79bce8SPatrick Williams "DBus response error for HotPluggable: {}", 645bd79bce8SPatrick Williams ec2); 646523d4868SLogananth Sundararaj messages::internalError(asyncResp->res); 647523d4868SLogananth Sundararaj return; 648523d4868SLogananth Sundararaj } 649523d4868SLogananth Sundararaj asyncResp->res.jsonValue["HotPluggable"] = property; 650523d4868SLogananth Sundararaj }); 651523d4868SLogananth Sundararaj } 652b4d593f1SCarson Labrado else if (interface == revisionInterface) 653b4d593f1SCarson Labrado { 654*deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 655*deae6a78SEd Tanous connectionName, path, revisionInterface, "Version", 656b4d593f1SCarson Labrado [asyncResp, chassisId](const boost::system::error_code& ec2, 657b4d593f1SCarson Labrado const std::string& property) { 658b4d593f1SCarson Labrado if (ec2) 659b4d593f1SCarson Labrado { 660bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 661bd79bce8SPatrick Williams "DBus response error for Version: {}", ec2); 662b4d593f1SCarson Labrado messages::internalError(asyncResp->res); 663b4d593f1SCarson Labrado return; 664b4d593f1SCarson Labrado } 665b4d593f1SCarson Labrado asyncResp->res.jsonValue["Version"] = property; 666b4d593f1SCarson Labrado }); 667b4d593f1SCarson Labrado } 668523d4868SLogananth Sundararaj } 669476b9cc5STejas Patil 6701c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 6711c8fba97SJames Feist { 6727164bc62SChau Ly if (std::ranges::find(interfaces2, interface) != interfaces2.end()) 6731c8fba97SJames Feist { 6741c8fba97SJames Feist getIndicatorLedState(asyncResp); 67559a17e4fSGeorge Liu getSystemLocationIndicatorActive(asyncResp); 6761c8fba97SJames Feist break; 6771c8fba97SJames Feist } 6781c8fba97SJames Feist } 6791c8fba97SJames Feist 680*deae6a78SEd Tanous dbus::utility::getAllProperties( 68186d89ed7SKrzysztof Grobelny *crow::connections::systemBus, connectionName, path, 68286d89ed7SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Asset", 6837164bc62SChau Ly [asyncResp, chassisId, 6847164bc62SChau Ly path](const boost::system::error_code&, 685cf7eba09SNan Zhou const dbus::utility::DBusPropertiesMap& propertiesList) { 6867164bc62SChau Ly handleDecoratorAssetProperties(asyncResp, chassisId, path, 6877164bc62SChau Ly propertiesList); 68886d89ed7SKrzysztof Grobelny }); 6892c37b4b0SSharad Yadav 6902952f648SJoseph-Jonathan Salzano sdbusplus::asio::getAllProperties( 6912952f648SJoseph-Jonathan Salzano *crow::connections::systemBus, connectionName, path, 6922952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis", 6932952f648SJoseph-Jonathan Salzano [asyncResp]( 6942952f648SJoseph-Jonathan Salzano const boost::system::error_code&, 6952952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) { 6962952f648SJoseph-Jonathan Salzano handleChassisProperties(asyncResp, propertiesList); 6972952f648SJoseph-Jonathan Salzano }); 6982952f648SJoseph-Jonathan Salzano 699308f70c7SWilly Tu for (const auto& interface : interfaces2) 7002c37b4b0SSharad Yadav { 701308f70c7SWilly Tu if (interface == "xyz.openbmc_project.Common.UUID") 7022c37b4b0SSharad Yadav { 703308f70c7SWilly Tu getChassisUUID(asyncResp, connectionName, path); 7042c37b4b0SSharad Yadav } 705cf7eba09SNan Zhou else if (interface == 7060fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode") 7072c37b4b0SSharad Yadav { 708002d39b4SEd Tanous getChassisLocationCode(asyncResp, connectionName, path); 7092c37b4b0SSharad Yadav } 7102c37b4b0SSharad Yadav } 7112c37b4b0SSharad Yadav 712daf36e2eSEd Tanous return; 713daf36e2eSEd Tanous } 714e0d918bcSEd Tanous 715daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 716d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 7177164bc62SChau Ly } 718c181942fSQiang XU 7197164bc62SChau Ly inline void 7207164bc62SChau Ly handleChassisGet(App& app, const crow::Request& req, 7217164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7227164bc62SChau Ly const std::string& chassisId) 7237164bc62SChau Ly { 7247164bc62SChau Ly if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 7257164bc62SChau Ly { 7267164bc62SChau Ly return; 7277164bc62SChau Ly } 7287164bc62SChau Ly constexpr std::array<std::string_view, 2> interfaces = { 7297164bc62SChau Ly "xyz.openbmc_project.Inventory.Item.Board", 7307164bc62SChau Ly "xyz.openbmc_project.Inventory.Item.Chassis"}; 7317164bc62SChau Ly 7327164bc62SChau Ly dbus::utility::getSubTree( 7337164bc62SChau Ly "/xyz/openbmc_project/inventory", 0, interfaces, 7347164bc62SChau Ly std::bind_front(handleChassisGetSubTree, asyncResp, chassisId)); 7357164bc62SChau Ly 7367164bc62SChau Ly constexpr std::array<std::string_view, 1> interfaces2 = { 7377164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion"}; 7387164bc62SChau Ly 7397164bc62SChau Ly dbus::utility::getSubTree( 7407164bc62SChau Ly "/xyz/openbmc_project", 0, interfaces2, 7417164bc62SChau Ly std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp)); 742cf7eba09SNan Zhou } 7431c8fba97SJames Feist 744cf7eba09SNan Zhou inline void 745cf7eba09SNan Zhou handleChassisPatch(App& app, const crow::Request& req, 7467e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 747cf7eba09SNan Zhou const std::string& param) 748cf7eba09SNan Zhou { 7493ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 75045ca1b86SEd Tanous { 75145ca1b86SEd Tanous return; 75245ca1b86SEd Tanous } 7539f8bfa7cSGunnar Mills std::optional<bool> locationIndicatorActive; 7541c8fba97SJames Feist std::optional<std::string> indicatorLed; 7551c8fba97SJames Feist 7567e860f15SJohn Edward Broadbent if (param.empty()) 7571c8fba97SJames Feist { 7581c8fba97SJames Feist return; 7591c8fba97SJames Feist } 7601c8fba97SJames Feist 761afc474aeSMyung Bae if (!json_util::readJsonPatch( // 762afc474aeSMyung Bae req, asyncResp->res, // 763afc474aeSMyung Bae "IndicatorLED", indicatorLed, // 764afc474aeSMyung Bae "LocationIndicatorActive", locationIndicatorActive // 765afc474aeSMyung Bae )) 7661c8fba97SJames Feist { 7671c8fba97SJames Feist return; 7681c8fba97SJames Feist } 7691c8fba97SJames Feist 7709f8bfa7cSGunnar Mills // TODO (Gunnar): Remove IndicatorLED after enough time has passed 7719f8bfa7cSGunnar Mills if (!locationIndicatorActive && !indicatorLed) 7721c8fba97SJames Feist { 7731c8fba97SJames Feist return; // delete this when we support more patch properties 7741c8fba97SJames Feist } 775d6aa0093SGunnar Mills if (indicatorLed) 776d6aa0093SGunnar Mills { 7777e860f15SJohn Edward Broadbent asyncResp->res.addHeader( 7787e860f15SJohn Edward Broadbent boost::beast::http::field::warning, 7790fda0f12SGeorge Liu "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\""); 780d6aa0093SGunnar Mills } 7811c8fba97SJames Feist 782e99073f5SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 7831c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board", 7841c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Chassis"}; 7851c8fba97SJames Feist 7867e860f15SJohn Edward Broadbent const std::string& chassisId = param; 7871c8fba97SJames Feist 788e99073f5SGeorge Liu dbus::utility::getSubTree( 789e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 790cf7eba09SNan Zhou [asyncResp, chassisId, locationIndicatorActive, 7915e7e2dc5SEd Tanous indicatorLed](const boost::system::error_code& ec, 792b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 7931c8fba97SJames Feist if (ec) 7941c8fba97SJames Feist { 79562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 7961c8fba97SJames Feist messages::internalError(asyncResp->res); 7971c8fba97SJames Feist return; 7981c8fba97SJames Feist } 7991c8fba97SJames Feist 8001c8fba97SJames Feist // Iterate over all retrieved ObjectPaths. 801bd79bce8SPatrick Williams for (const std::pair<std::string, 802bd79bce8SPatrick Williams std::vector<std::pair< 803bd79bce8SPatrick Williams std::string, std::vector<std::string>>>>& 8041214b7e7SGunnar Mills object : subtree) 8051c8fba97SJames Feist { 8061c8fba97SJames Feist const std::string& path = object.first; 807bd79bce8SPatrick Williams const std::vector< 808bd79bce8SPatrick Williams std::pair<std::string, std::vector<std::string>>>& 8091214b7e7SGunnar Mills connectionNames = object.second; 8101c8fba97SJames Feist 811997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 812997093ebSGeorge Liu if (objPath.filename() != chassisId) 8131c8fba97SJames Feist { 8141c8fba97SJames Feist continue; 8151c8fba97SJames Feist } 8161c8fba97SJames Feist 81726f6976fSEd Tanous if (connectionNames.empty()) 8181c8fba97SJames Feist { 81962598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 8201c8fba97SJames Feist continue; 8211c8fba97SJames Feist } 8221c8fba97SJames Feist 82323a21a1cSEd Tanous const std::vector<std::string>& interfaces3 = 8241c8fba97SJames Feist connectionNames[0].second; 8251c8fba97SJames Feist 826e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 827e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 8281c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 8290fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 8301c8fba97SJames Feist bool indicatorChassis = false; 8311c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 8321c8fba97SJames Feist { 8333544d2a7SEd Tanous if (std::ranges::find(interfaces3, interface) != 8343544d2a7SEd Tanous interfaces3.end()) 8351c8fba97SJames Feist { 8361c8fba97SJames Feist indicatorChassis = true; 8371c8fba97SJames Feist break; 8381c8fba97SJames Feist } 8391c8fba97SJames Feist } 8409f8bfa7cSGunnar Mills if (locationIndicatorActive) 8419f8bfa7cSGunnar Mills { 8429f8bfa7cSGunnar Mills if (indicatorChassis) 8439f8bfa7cSGunnar Mills { 844bd79bce8SPatrick Williams setSystemLocationIndicatorActive( 845bd79bce8SPatrick Williams asyncResp, *locationIndicatorActive); 8469f8bfa7cSGunnar Mills } 8479f8bfa7cSGunnar Mills else 8489f8bfa7cSGunnar Mills { 849002d39b4SEd Tanous messages::propertyUnknown(asyncResp->res, 850002d39b4SEd Tanous "LocationIndicatorActive"); 8519f8bfa7cSGunnar Mills } 8529f8bfa7cSGunnar Mills } 8539f8bfa7cSGunnar Mills if (indicatorLed) 8549f8bfa7cSGunnar Mills { 8551c8fba97SJames Feist if (indicatorChassis) 8561c8fba97SJames Feist { 857f23b7296SEd Tanous setIndicatorLedState(asyncResp, *indicatorLed); 8581c8fba97SJames Feist } 8591c8fba97SJames Feist else 8601c8fba97SJames Feist { 861bd79bce8SPatrick Williams messages::propertyUnknown(asyncResp->res, 862bd79bce8SPatrick Williams "IndicatorLED"); 8631c8fba97SJames Feist } 8641c8fba97SJames Feist } 8651c8fba97SJames Feist return; 8661c8fba97SJames Feist } 8671c8fba97SJames Feist 868d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 869e99073f5SGeorge Liu }); 870cf7eba09SNan Zhou } 871cf7eba09SNan Zhou 872cf7eba09SNan Zhou /** 873cf7eba09SNan Zhou * Chassis override class for delivering Chassis Schema 874cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 875cf7eba09SNan Zhou */ 876cf7eba09SNan Zhou inline void requestRoutesChassis(App& app) 877cf7eba09SNan Zhou { 878cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 879cf7eba09SNan Zhou .privileges(redfish::privileges::getChassis) 880cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 881cf7eba09SNan Zhou std::bind_front(handleChassisGet, std::ref(app))); 882cf7eba09SNan Zhou 883cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 884cf7eba09SNan Zhou .privileges(redfish::privileges::patchChassis) 885cf7eba09SNan Zhou .methods(boost::beast::http::verb::patch)( 886cf7eba09SNan Zhou std::bind_front(handleChassisPatch, std::ref(app))); 8871c8fba97SJames Feist } 888dd99e04bSP.K. Lee 8898d1b46d7Szhanghch05 inline void 8908d1b46d7Szhanghch05 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 891dd99e04bSP.K. Lee { 8927a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 893c3b3c92aSVijay Khemka "xyz.openbmc_project.State.Chassis"}; 894c3b3c92aSVijay Khemka 895c3b3c92aSVijay Khemka // Use mapper to get subtree paths. 8967a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 8977a1dbc48SGeorge Liu "/", 0, interfaces, 898b9d36b47SEd Tanous [asyncResp]( 8997a1dbc48SGeorge Liu const boost::system::error_code& ec, 900b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& chassisList) { 901c3b3c92aSVijay Khemka if (ec) 902c3b3c92aSVijay Khemka { 90362598e31SEd Tanous BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec); 904c3b3c92aSVijay Khemka messages::internalError(asyncResp->res); 905c3b3c92aSVijay Khemka return; 906c3b3c92aSVijay Khemka } 907c3b3c92aSVijay Khemka 908dd99e04bSP.K. Lee const char* processName = "xyz.openbmc_project.State.Chassis"; 909dd99e04bSP.K. Lee const char* interfaceName = "xyz.openbmc_project.State.Chassis"; 910dd99e04bSP.K. Lee const char* destProperty = "RequestedPowerTransition"; 911dd99e04bSP.K. Lee const std::string propertyValue = 912dd99e04bSP.K. Lee "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; 913bd79bce8SPatrick Williams std::string objectPath = 914bd79bce8SPatrick Williams "/xyz/openbmc_project/state/chassis_system0"; 915c3b3c92aSVijay Khemka 916c3b3c92aSVijay Khemka /* Look for system reset chassis path */ 917bd79bce8SPatrick Williams if ((std::ranges::find(chassisList, objectPath)) == 918bd79bce8SPatrick Williams chassisList.end()) 919c3b3c92aSVijay Khemka { 920c3b3c92aSVijay Khemka /* We prefer to reset the full chassis_system, but if it doesn't 921c3b3c92aSVijay Khemka * exist on some platforms, fall back to a host-only power reset 922c3b3c92aSVijay Khemka */ 923c3b3c92aSVijay Khemka objectPath = "/xyz/openbmc_project/state/chassis0"; 924c3b3c92aSVijay Khemka } 925dd99e04bSP.K. Lee 926e93abac6SGinu George setDbusProperty(asyncResp, "ResetType", processName, objectPath, 927e93abac6SGinu George interfaceName, destProperty, propertyValue); 9287a1dbc48SGeorge Liu }); 929dd99e04bSP.K. Lee } 930dd99e04bSP.K. Lee 931cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost( 932cf7eba09SNan Zhou App& app, const crow::Request& req, 9337e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 934cf7eba09SNan Zhou const std::string& /*chassisId*/) 935cf7eba09SNan Zhou { 9363ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 93745ca1b86SEd Tanous { 93845ca1b86SEd Tanous return; 93945ca1b86SEd Tanous } 94062598e31SEd Tanous BMCWEB_LOG_DEBUG("Post Chassis Reset."); 941dd99e04bSP.K. Lee 942dd99e04bSP.K. Lee std::string resetType; 943dd99e04bSP.K. Lee 944cf7eba09SNan Zhou if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 945dd99e04bSP.K. Lee { 946dd99e04bSP.K. Lee return; 947dd99e04bSP.K. Lee } 948dd99e04bSP.K. Lee 949dd99e04bSP.K. Lee if (resetType != "PowerCycle") 950dd99e04bSP.K. Lee { 95162598e31SEd Tanous BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType); 952002d39b4SEd Tanous messages::actionParameterNotSupported(asyncResp->res, resetType, 953002d39b4SEd Tanous "ResetType"); 954dd99e04bSP.K. Lee 955dd99e04bSP.K. Lee return; 956dd99e04bSP.K. Lee } 957dd99e04bSP.K. Lee doChassisPowerCycle(asyncResp); 958dd99e04bSP.K. Lee } 9591cb1a9e6SAppaRao Puli 9601cb1a9e6SAppaRao Puli /** 961cf7eba09SNan Zhou * ChassisResetAction class supports the POST method for the Reset 962cf7eba09SNan Zhou * action. 963cf7eba09SNan Zhou * Function handles POST method request. 964cf7eba09SNan Zhou * Analyzes POST body before sending Reset request data to D-Bus. 9651cb1a9e6SAppaRao Puli */ 966cf7eba09SNan Zhou 967cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app) 9681cb1a9e6SAppaRao Puli { 969cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/") 970cf7eba09SNan Zhou .privileges(redfish::privileges::postChassis) 971cf7eba09SNan Zhou .methods(boost::beast::http::verb::post)( 972cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoPost, std::ref(app))); 973cf7eba09SNan Zhou } 974cf7eba09SNan Zhou 975cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet( 976cf7eba09SNan Zhou App& app, const crow::Request& req, 9777e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 978cf7eba09SNan Zhou const std::string& chassisId) 979cf7eba09SNan Zhou { 9803ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 9811cb1a9e6SAppaRao Puli { 98245ca1b86SEd Tanous return; 98345ca1b86SEd Tanous } 984cf7eba09SNan Zhou asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 985ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 986ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId); 9871476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 9881476687dSEd Tanous 9891476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 9905b9e95a1SNan Zhou nlohmann::json::array_t parameters; 9915b9e95a1SNan Zhou nlohmann::json::object_t parameter; 9925b9e95a1SNan Zhou parameter["Name"] = "ResetType"; 9935b9e95a1SNan Zhou parameter["Required"] = true; 994539d8c6bSEd Tanous parameter["DataType"] = action_info::ParameterTypes::String; 9951476687dSEd Tanous nlohmann::json::array_t allowed; 996ad539545SPatrick Williams allowed.emplace_back("PowerCycle"); 9975b9e95a1SNan Zhou parameter["AllowableValues"] = std::move(allowed); 998ad539545SPatrick Williams parameters.emplace_back(std::move(parameter)); 9995b9e95a1SNan Zhou 10001476687dSEd Tanous asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 1001cf7eba09SNan Zhou } 1002cf7eba09SNan Zhou 1003cf7eba09SNan Zhou /** 1004cf7eba09SNan Zhou * ChassisResetActionInfo derived class for delivering Chassis 1005cf7eba09SNan Zhou * ResetType AllowableValues using ResetInfo schema. 1006cf7eba09SNan Zhou */ 1007cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app) 1008cf7eba09SNan Zhou { 1009cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/") 1010cf7eba09SNan Zhou .privileges(redfish::privileges::getActionInfo) 1011cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 1012cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoGet, std::ref(app))); 10131cb1a9e6SAppaRao Puli } 10141cb1a9e6SAppaRao Puli 1015e37f8451SRapkiewicz, Pawel } // namespace redfish 1016