140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation 4e37f8451SRapkiewicz, Pawel #pragma once 5e37f8451SRapkiewicz, Pawel 6*d7857201SEd Tanous #include "bmcweb_config.h" 7*d7857201SEd Tanous 83ccb3adbSEd Tanous #include "app.hpp" 9*d7857201SEd Tanous #include "async_resp.hpp" 10*d7857201SEd Tanous #include "dbus_singleton.hpp" 117a1dbc48SGeorge Liu #include "dbus_utility.hpp" 12*d7857201SEd Tanous #include "error_messages.hpp" 13539d8c6bSEd Tanous #include "generated/enums/action_info.hpp" 14539d8c6bSEd Tanous #include "generated/enums/chassis.hpp" 15539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 16*d7857201SEd Tanous #include "http_request.hpp" 171c8fba97SJames Feist #include "led.hpp" 18*d7857201SEd Tanous #include "logging.hpp" 193ccb3adbSEd Tanous #include "query.hpp" 203ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 213ccb3adbSEd Tanous #include "utils/collection.hpp" 223ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 23cf7eba09SNan Zhou #include "utils/json_utils.hpp" 241abe55efSEd Tanous 25*d7857201SEd Tanous #include <asm-generic/errno.h> 26*d7857201SEd Tanous 27*d7857201SEd Tanous #include <boost/beast/http/field.hpp> 28*d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 29e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 30ef4c65b7SEd Tanous #include <boost/url/format.hpp> 31*d7857201SEd Tanous #include <boost/url/url.hpp> 32*d7857201SEd Tanous #include <nlohmann/json.hpp> 331e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp> 34*d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 3586d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 361214b7e7SGunnar Mills 37*d7857201SEd Tanous #include <algorithm> 387a1dbc48SGeorge Liu #include <array> 39*d7857201SEd Tanous #include <format> 40*d7857201SEd Tanous #include <functional> 412952f648SJoseph-Jonathan Salzano #include <memory> 42*d7857201SEd Tanous #include <optional> 433544d2a7SEd Tanous #include <ranges> 44*d7857201SEd Tanous #include <string> 457a1dbc48SGeorge Liu #include <string_view> 46*d7857201SEd Tanous #include <utility> 47*d7857201SEd Tanous #include <vector> 487a1dbc48SGeorge Liu 491abe55efSEd Tanous namespace redfish 501abe55efSEd Tanous { 51e37f8451SRapkiewicz, Pawel 522952f648SJoseph-Jonathan Salzano inline chassis::ChassisType 532952f648SJoseph-Jonathan Salzano translateChassisTypeToRedfish(const std::string_view& chassisType) 542952f648SJoseph-Jonathan Salzano { 552952f648SJoseph-Jonathan Salzano if (chassisType == 562952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Blade") 572952f648SJoseph-Jonathan Salzano { 582952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Blade; 592952f648SJoseph-Jonathan Salzano } 602952f648SJoseph-Jonathan Salzano if (chassisType == 612952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Component") 622952f648SJoseph-Jonathan Salzano { 632952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Component; 642952f648SJoseph-Jonathan Salzano } 652952f648SJoseph-Jonathan Salzano if (chassisType == 662952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Enclosure") 672952f648SJoseph-Jonathan Salzano { 682952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Enclosure; 692952f648SJoseph-Jonathan Salzano } 702952f648SJoseph-Jonathan Salzano if (chassisType == 712952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Module") 722952f648SJoseph-Jonathan Salzano { 732952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Module; 742952f648SJoseph-Jonathan Salzano } 752952f648SJoseph-Jonathan Salzano if (chassisType == 762952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.RackMount") 772952f648SJoseph-Jonathan Salzano { 782952f648SJoseph-Jonathan Salzano return chassis::ChassisType::RackMount; 792952f648SJoseph-Jonathan Salzano } 802952f648SJoseph-Jonathan Salzano if (chassisType == 812952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StandAlone") 822952f648SJoseph-Jonathan Salzano { 832952f648SJoseph-Jonathan Salzano return chassis::ChassisType::StandAlone; 842952f648SJoseph-Jonathan Salzano } 852952f648SJoseph-Jonathan Salzano if (chassisType == 862952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StorageEnclosure") 872952f648SJoseph-Jonathan Salzano { 882952f648SJoseph-Jonathan Salzano return chassis::ChassisType::StorageEnclosure; 892952f648SJoseph-Jonathan Salzano } 902952f648SJoseph-Jonathan Salzano if (chassisType == 912952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Zone") 922952f648SJoseph-Jonathan Salzano { 932952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Zone; 942952f648SJoseph-Jonathan Salzano } 952952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Invalid; 962952f648SJoseph-Jonathan Salzano } 972952f648SJoseph-Jonathan Salzano 98e37f8451SRapkiewicz, Pawel /** 995e577bc1SWilly Tu * @brief Retrieves resources over dbus to link to the chassis 1005e577bc1SWilly Tu * 1015e577bc1SWilly Tu * @param[in] asyncResp - Shared pointer for completing asynchronous 1025e577bc1SWilly Tu * calls 1035e577bc1SWilly Tu * @param[in] path - Chassis dbus path to look for the storage. 1045e577bc1SWilly Tu * 1055e577bc1SWilly Tu * Calls the Association endpoints on the path + "/storage" and add the link of 1065e577bc1SWilly Tu * json["Links"]["Storage@odata.count"] = 1075e577bc1SWilly Tu * {"@odata.id", "/redfish/v1/Storage/" + resourceId} 1085e577bc1SWilly Tu * 1095e577bc1SWilly Tu * @return None. 1105e577bc1SWilly Tu */ 1115e577bc1SWilly Tu inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1125e577bc1SWilly Tu const sdbusplus::message::object_path& path) 1135e577bc1SWilly Tu { 114deae6a78SEd Tanous dbus::utility::getProperty<std::vector<std::string>>( 115deae6a78SEd Tanous "xyz.openbmc_project.ObjectMapper", (path / "storage").str, 116deae6a78SEd Tanous "xyz.openbmc_project.Association", "endpoints", 117d4b054c1SWilly Tu [asyncResp](const boost::system::error_code& ec, 1185e577bc1SWilly Tu const std::vector<std::string>& storageList) { 1195e577bc1SWilly Tu if (ec) 1205e577bc1SWilly Tu { 12162598e31SEd Tanous BMCWEB_LOG_DEBUG("getStorageLink got DBUS response error"); 1225e577bc1SWilly Tu return; 1235e577bc1SWilly Tu } 1245e577bc1SWilly Tu 1255e577bc1SWilly Tu nlohmann::json::array_t storages; 1265e577bc1SWilly Tu for (const std::string& storagePath : storageList) 1275e577bc1SWilly Tu { 1285e577bc1SWilly Tu std::string id = 1295e577bc1SWilly Tu sdbusplus::message::object_path(storagePath).filename(); 1305e577bc1SWilly Tu if (id.empty()) 1315e577bc1SWilly Tu { 1325e577bc1SWilly Tu continue; 1335e577bc1SWilly Tu } 1345e577bc1SWilly Tu 1355e577bc1SWilly Tu nlohmann::json::object_t storage; 136253f11b8SEd Tanous storage["@odata.id"] = 137253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/{}", 138253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, id); 1395e577bc1SWilly Tu storages.emplace_back(std::move(storage)); 1405e577bc1SWilly Tu } 1415e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["Storage@odata.count"] = 1425e577bc1SWilly Tu storages.size(); 1435e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages); 1445e577bc1SWilly Tu }); 1455e577bc1SWilly Tu } 1465e577bc1SWilly Tu 1475e577bc1SWilly Tu /** 148beeca0aeSGunnar Mills * @brief Retrieves chassis state properties over dbus 149beeca0aeSGunnar Mills * 150ac106bf6SEd Tanous * @param[in] asyncResp - Shared pointer for completing asynchronous calls. 151beeca0aeSGunnar Mills * 152beeca0aeSGunnar Mills * @return None. 153beeca0aeSGunnar Mills */ 154ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp) 155beeca0aeSGunnar Mills { 1561e1e598dSJonathan Doman // crow::connections::systemBus->async_method_call( 157deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 158deae6a78SEd Tanous "xyz.openbmc_project.State.Chassis", 1591e1e598dSJonathan Doman "/xyz/openbmc_project/state/chassis0", 1601e1e598dSJonathan Doman "xyz.openbmc_project.State.Chassis", "CurrentPowerState", 161ac106bf6SEd Tanous [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec, 1621e1e598dSJonathan Doman const std::string& chassisState) { 163beeca0aeSGunnar Mills if (ec) 164beeca0aeSGunnar Mills { 165a6e5e0abSCarson Labrado if (ec == boost::system::errc::host_unreachable) 166a6e5e0abSCarson Labrado { 167a6e5e0abSCarson Labrado // Service not available, no error, just don't return 168a6e5e0abSCarson Labrado // chassis state info 16962598e31SEd Tanous BMCWEB_LOG_DEBUG("Service not available {}", ec); 170a6e5e0abSCarson Labrado return; 171a6e5e0abSCarson Labrado } 17262598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 173ac106bf6SEd Tanous messages::internalError(asyncResp->res); 174beeca0aeSGunnar Mills return; 175beeca0aeSGunnar Mills } 176beeca0aeSGunnar Mills 17762598e31SEd Tanous BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState); 178beeca0aeSGunnar Mills // Verify Chassis State 179bd79bce8SPatrick Williams if (chassisState == 180bd79bce8SPatrick Williams "xyz.openbmc_project.State.Chassis.PowerState.On") 181beeca0aeSGunnar Mills { 182bd79bce8SPatrick Williams asyncResp->res.jsonValue["PowerState"] = 183bd79bce8SPatrick Williams resource::PowerState::On; 184539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 185539d8c6bSEd Tanous resource::State::Enabled; 186beeca0aeSGunnar Mills } 1871e1e598dSJonathan Doman else if (chassisState == 188beeca0aeSGunnar Mills "xyz.openbmc_project.State.Chassis.PowerState.Off") 189beeca0aeSGunnar Mills { 190bd79bce8SPatrick Williams asyncResp->res.jsonValue["PowerState"] = 191bd79bce8SPatrick Williams resource::PowerState::Off; 192539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 193539d8c6bSEd Tanous resource::State::StandbyOffline; 194beeca0aeSGunnar Mills } 1951e1e598dSJonathan Doman }); 196beeca0aeSGunnar Mills } 197beeca0aeSGunnar Mills 198c181942fSQiang XU /** 199c181942fSQiang XU * Retrieves physical security properties over dbus 200c181942fSQiang XU */ 2017164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree( 2027164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 203e99073f5SGeorge Liu const boost::system::error_code& ec, 2047164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 2057164bc62SChau Ly { 206c181942fSQiang XU if (ec) 207c181942fSQiang XU { 2084e0453b1SGunnar Mills // do not add err msg in redfish response, because this is not 209c181942fSQiang XU // mandatory property 21062598e31SEd Tanous BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec); 211c181942fSQiang XU return; 212c181942fSQiang XU } 213c181942fSQiang XU // Iterate over all retrieved ObjectPaths. 214c181942fSQiang XU for (const auto& object : subtree) 215c181942fSQiang XU { 216840a9ffcSPatrick Williams if (!object.second.empty()) 217c181942fSQiang XU { 21889144a3aSEd Tanous const auto& service = object.second.front(); 2197164bc62SChau Ly 2207164bc62SChau Ly BMCWEB_LOG_DEBUG("Get intrusion status by service "); 2217164bc62SChau Ly 222deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 223deae6a78SEd Tanous service.first, object.first, 2247164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion", "Status", 2257164bc62SChau Ly [asyncResp](const boost::system::error_code& ec1, 2267164bc62SChau Ly const std::string& value) { 2277164bc62SChau Ly if (ec1) 2287164bc62SChau Ly { 229bd79bce8SPatrick Williams // do not add err msg in redfish response, because this 230bd79bce8SPatrick Williams // is not 2317164bc62SChau Ly // mandatory property 2327164bc62SChau Ly BMCWEB_LOG_ERROR("DBUS response error {}", ec1); 2337164bc62SChau Ly return; 2347164bc62SChau Ly } 235bd79bce8SPatrick Williams asyncResp->res.jsonValue["PhysicalSecurity"] 236bd79bce8SPatrick Williams ["IntrusionSensorNumber"] = 1; 2377164bc62SChau Ly asyncResp->res 238bd79bce8SPatrick Williams .jsonValue["PhysicalSecurity"]["IntrusionSensor"] = 239bd79bce8SPatrick Williams value; 2407164bc62SChau Ly }); 2417164bc62SChau Ly 242c181942fSQiang XU return; 243c181942fSQiang XU } 244c181942fSQiang XU } 245c181942fSQiang XU } 246c181942fSQiang XU 247cf7eba09SNan Zhou inline void handleChassisCollectionGet( 248cf7eba09SNan Zhou App& app, const crow::Request& req, 249cf7eba09SNan Zhou const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2501abe55efSEd Tanous { 2513ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 25245ca1b86SEd Tanous { 25345ca1b86SEd Tanous return; 25445ca1b86SEd Tanous } 2558d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 2568d1b46d7Szhanghch05 "#ChassisCollection.ChassisCollection"; 2578d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 2588d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 259e37f8451SRapkiewicz, Pawel 2607a1dbc48SGeorge Liu constexpr std::array<std::string_view, 2> interfaces{ 2617a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board", 2627a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis"}; 26302f6ff19SGunnar Mills collection_util::getCollectionMembers( 26436b5f1edSLakshmi Yadlapati asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces, 26536b5f1edSLakshmi Yadlapati "/xyz/openbmc_project/inventory"); 266cf7eba09SNan Zhou } 267cf7eba09SNan Zhou 268a5617496SJie Yang inline void getChassisContainedBy( 269a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 270a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 27128ee563eSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& upstreamChassisPaths) 272a5617496SJie Yang { 273a5617496SJie Yang if (ec) 274a5617496SJie Yang { 275a5617496SJie Yang if (ec.value() != EBADR) 276a5617496SJie Yang { 27762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 278a5617496SJie Yang messages::internalError(asyncResp->res); 279a5617496SJie Yang } 280a5617496SJie Yang return; 281a5617496SJie Yang } 282a5617496SJie Yang if (upstreamChassisPaths.empty()) 283a5617496SJie Yang { 284a5617496SJie Yang return; 285a5617496SJie Yang } 286a5617496SJie Yang if (upstreamChassisPaths.size() > 1) 287a5617496SJie Yang { 2888ece0e45SEd Tanous BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId); 289a5617496SJie Yang messages::internalError(asyncResp->res); 290a5617496SJie Yang return; 291a5617496SJie Yang } 292a5617496SJie Yang 293a5617496SJie Yang sdbusplus::message::object_path upstreamChassisPath( 294a5617496SJie Yang upstreamChassisPaths[0]); 295a5617496SJie Yang std::string upstreamChassis = upstreamChassisPath.filename(); 296a5617496SJie Yang if (upstreamChassis.empty()) 297a5617496SJie Yang { 29862598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}", 29962598e31SEd Tanous upstreamChassisPath.str, chassisId); 300a5617496SJie Yang return; 301a5617496SJie Yang } 302a5617496SJie Yang 303a5617496SJie Yang asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] = 304a5617496SJie Yang boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis); 305a5617496SJie Yang } 306a5617496SJie Yang 307a5617496SJie Yang inline void getChassisContains( 308a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 309a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 31028ee563eSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& downstreamChassisPaths) 311a5617496SJie Yang { 312a5617496SJie Yang if (ec) 313a5617496SJie Yang { 314a5617496SJie Yang if (ec.value() != EBADR) 315a5617496SJie Yang { 31662598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 317a5617496SJie Yang messages::internalError(asyncResp->res); 318a5617496SJie Yang } 319a5617496SJie Yang return; 320a5617496SJie Yang } 321a5617496SJie Yang if (downstreamChassisPaths.empty()) 322a5617496SJie Yang { 323a5617496SJie Yang return; 324a5617496SJie Yang } 325a5617496SJie Yang nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"]; 326a5617496SJie Yang if (!jValue.is_array()) 327a5617496SJie Yang { 328a5617496SJie Yang // Create the array if it was empty 329a5617496SJie Yang jValue = nlohmann::json::array(); 330a5617496SJie Yang } 331a5617496SJie Yang for (const auto& p : downstreamChassisPaths) 332a5617496SJie Yang { 333a5617496SJie Yang sdbusplus::message::object_path downstreamChassisPath(p); 334a5617496SJie Yang std::string downstreamChassis = downstreamChassisPath.filename(); 335a5617496SJie Yang if (downstreamChassis.empty()) 336a5617496SJie Yang { 33762598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}", 33862598e31SEd Tanous downstreamChassisPath.str, chassisId); 339a5617496SJie Yang continue; 340a5617496SJie Yang } 341a5617496SJie Yang nlohmann::json link; 342bd79bce8SPatrick Williams link["@odata.id"] = 343bd79bce8SPatrick Williams boost::urls::format("/redfish/v1/Chassis/{}", downstreamChassis); 344a5617496SJie Yang jValue.push_back(std::move(link)); 345a5617496SJie Yang } 346a5617496SJie Yang asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size(); 347a5617496SJie Yang } 348a5617496SJie Yang 349bd79bce8SPatrick Williams inline void getChassisConnectivity( 350bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 351bd79bce8SPatrick Williams const std::string& chassisId, const std::string& chassisPath) 352a5617496SJie Yang { 35362598e31SEd Tanous BMCWEB_LOG_DEBUG("Get chassis connectivity"); 354a5617496SJie Yang 35528ee563eSMyung Bae constexpr std::array<std::string_view, 2> interfaces{ 35628ee563eSMyung Bae "xyz.openbmc_project.Inventory.Item.Board", 35728ee563eSMyung Bae "xyz.openbmc_project.Inventory.Item.Chassis"}; 35828ee563eSMyung Bae 35928ee563eSMyung Bae dbus::utility::getAssociatedSubTreePaths( 360a5617496SJie Yang chassisPath + "/contained_by", 36128ee563eSMyung Bae sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 36228ee563eSMyung Bae interfaces, 363a5617496SJie Yang std::bind_front(getChassisContainedBy, asyncResp, chassisId)); 364a5617496SJie Yang 36528ee563eSMyung Bae dbus::utility::getAssociatedSubTreePaths( 366a5617496SJie Yang chassisPath + "/containing", 36728ee563eSMyung Bae sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 36828ee563eSMyung Bae interfaces, std::bind_front(getChassisContains, asyncResp, chassisId)); 369a5617496SJie Yang } 370a5617496SJie Yang 371cf7eba09SNan Zhou /** 372cf7eba09SNan Zhou * ChassisCollection derived class for delivering Chassis Collection Schema 373cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 374cf7eba09SNan Zhou */ 375cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app) 376cf7eba09SNan Zhou { 377cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/") 378cf7eba09SNan Zhou .privileges(redfish::privileges::getChassisCollection) 379cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 380cf7eba09SNan Zhou std::bind_front(handleChassisCollectionGet, std::ref(app))); 38162d5e2e4SEd Tanous } 382e37f8451SRapkiewicz, Pawel 383bd79bce8SPatrick Williams inline void getChassisLocationCode( 384bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 385bd79bce8SPatrick Williams const std::string& connectionName, const std::string& path) 386308f70c7SWilly Tu { 387deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 388deae6a78SEd Tanous connectionName, path, 3891e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 3905e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3911e1e598dSJonathan Doman const std::string& property) { 392308f70c7SWilly Tu if (ec) 393308f70c7SWilly Tu { 39462598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location"); 395308f70c7SWilly Tu messages::internalError(asyncResp->res); 396308f70c7SWilly Tu return; 397308f70c7SWilly Tu } 398308f70c7SWilly Tu 399bd79bce8SPatrick Williams asyncResp->res 400bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 4011e1e598dSJonathan Doman property; 4021e1e598dSJonathan Doman }); 403308f70c7SWilly Tu } 404308f70c7SWilly Tu 405308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 406308f70c7SWilly Tu const std::string& connectionName, 407308f70c7SWilly Tu const std::string& path) 408308f70c7SWilly Tu { 409deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 410deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Common.UUID", "UUID", 4115e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 4121e1e598dSJonathan Doman const std::string& chassisUUID) { 413308f70c7SWilly Tu if (ec) 414308f70c7SWilly Tu { 41562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for UUID"); 416308f70c7SWilly Tu messages::internalError(asyncResp->res); 417308f70c7SWilly Tu return; 418308f70c7SWilly Tu } 4191e1e598dSJonathan Doman asyncResp->res.jsonValue["UUID"] = chassisUUID; 4201e1e598dSJonathan Doman }); 421308f70c7SWilly Tu } 422308f70c7SWilly Tu 4237164bc62SChau Ly inline void handleDecoratorAssetProperties( 42445ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4257164bc62SChau Ly const std::string& chassisId, const std::string& path, 4267164bc62SChau Ly const dbus::utility::DBusPropertiesMap& propertiesList) 427cf7eba09SNan Zhou { 4287164bc62SChau Ly const std::string* partNumber = nullptr; 4297164bc62SChau Ly const std::string* serialNumber = nullptr; 4307164bc62SChau Ly const std::string* manufacturer = nullptr; 4317164bc62SChau Ly const std::string* model = nullptr; 4327164bc62SChau Ly const std::string* sparePartNumber = nullptr; 4337164bc62SChau Ly 4347164bc62SChau Ly const bool success = sdbusplus::unpackPropertiesNoThrow( 4357164bc62SChau Ly dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 4367164bc62SChau Ly partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, 4377164bc62SChau Ly "Model", model, "SparePartNumber", sparePartNumber); 4387164bc62SChau Ly 4397164bc62SChau Ly if (!success) 44045ca1b86SEd Tanous { 4417164bc62SChau Ly messages::internalError(asyncResp->res); 44245ca1b86SEd Tanous return; 44345ca1b86SEd Tanous } 444734bfe90SGunnar Mills 4457164bc62SChau Ly if (partNumber != nullptr) 4467164bc62SChau Ly { 4477164bc62SChau Ly asyncResp->res.jsonValue["PartNumber"] = *partNumber; 4487164bc62SChau Ly } 4497164bc62SChau Ly 4507164bc62SChau Ly if (serialNumber != nullptr) 4517164bc62SChau Ly { 4527164bc62SChau Ly asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 4537164bc62SChau Ly } 4547164bc62SChau Ly 4557164bc62SChau Ly if (manufacturer != nullptr) 4567164bc62SChau Ly { 4577164bc62SChau Ly asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 4587164bc62SChau Ly } 4597164bc62SChau Ly 4607164bc62SChau Ly if (model != nullptr) 4617164bc62SChau Ly { 4627164bc62SChau Ly asyncResp->res.jsonValue["Model"] = *model; 4637164bc62SChau Ly } 4647164bc62SChau Ly 4657164bc62SChau Ly // SparePartNumber is optional on D-Bus 4667164bc62SChau Ly // so skip if it is empty 4677164bc62SChau Ly if (sparePartNumber != nullptr && !sparePartNumber->empty()) 4687164bc62SChau Ly { 4697164bc62SChau Ly asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 4707164bc62SChau Ly } 4717164bc62SChau Ly 4727164bc62SChau Ly asyncResp->res.jsonValue["Name"] = chassisId; 4737164bc62SChau Ly asyncResp->res.jsonValue["Id"] = chassisId; 47425b54dbaSEd Tanous 47525b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL) 47625b54dbaSEd Tanous { 4777164bc62SChau Ly asyncResp->res.jsonValue["Thermal"]["@odata.id"] = 4787164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId); 4797164bc62SChau Ly // Power object 4807164bc62SChau Ly asyncResp->res.jsonValue["Power"]["@odata.id"] = 4817164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId); 48225b54dbaSEd Tanous } 48325b54dbaSEd Tanous 48425b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM) 48525b54dbaSEd Tanous { 4867164bc62SChau Ly asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] = 4877164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem", 4887164bc62SChau Ly chassisId); 4897164bc62SChau Ly asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] = 49025b54dbaSEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", 49125b54dbaSEd Tanous chassisId); 4927164bc62SChau Ly asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] = 4937164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics", 4947164bc62SChau Ly chassisId); 49525b54dbaSEd Tanous } 4967164bc62SChau Ly // SensorCollection 4977164bc62SChau Ly asyncResp->res.jsonValue["Sensors"]["@odata.id"] = 4987164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId); 499539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 5007164bc62SChau Ly 5017164bc62SChau Ly nlohmann::json::array_t computerSystems; 5027164bc62SChau Ly nlohmann::json::object_t system; 503bd79bce8SPatrick Williams system["@odata.id"] = 504bd79bce8SPatrick Williams std::format("/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME); 5057164bc62SChau Ly computerSystems.emplace_back(std::move(system)); 5067164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ComputerSystems"] = 5077164bc62SChau Ly std::move(computerSystems); 5087164bc62SChau Ly 5097164bc62SChau Ly nlohmann::json::array_t managedBy; 5107164bc62SChau Ly nlohmann::json::object_t manager; 511253f11b8SEd Tanous manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}", 512253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 5137164bc62SChau Ly managedBy.emplace_back(std::move(manager)); 5147164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); 5157164bc62SChau Ly getChassisState(asyncResp); 5167164bc62SChau Ly getStorageLink(asyncResp, path); 5177164bc62SChau Ly } 5187164bc62SChau Ly 5192952f648SJoseph-Jonathan Salzano inline void handleChassisProperties( 5202952f648SJoseph-Jonathan Salzano const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5212952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) 5222952f648SJoseph-Jonathan Salzano { 5232952f648SJoseph-Jonathan Salzano const std::string* type = nullptr; 5242952f648SJoseph-Jonathan Salzano 5252952f648SJoseph-Jonathan Salzano const bool success = sdbusplus::unpackPropertiesNoThrow( 5262952f648SJoseph-Jonathan Salzano dbus_utils::UnpackErrorPrinter(), propertiesList, "Type", type); 5272952f648SJoseph-Jonathan Salzano 5282952f648SJoseph-Jonathan Salzano if (!success) 5292952f648SJoseph-Jonathan Salzano { 5302952f648SJoseph-Jonathan Salzano messages::internalError(asyncResp->res); 5312952f648SJoseph-Jonathan Salzano return; 5322952f648SJoseph-Jonathan Salzano } 5332952f648SJoseph-Jonathan Salzano 53419ea2864SGunnar Mills // Chassis Type is a required property in Redfish 53519ea2864SGunnar Mills // If there is an error or some enum we don't support just sit it to Rack 53619ea2864SGunnar Mills // Mount 53719ea2864SGunnar Mills asyncResp->res.jsonValue["ChassisType"] = chassis::ChassisType::RackMount; 53819ea2864SGunnar Mills 5392952f648SJoseph-Jonathan Salzano if (type != nullptr) 5402952f648SJoseph-Jonathan Salzano { 5412952f648SJoseph-Jonathan Salzano auto chassisType = translateChassisTypeToRedfish(*type); 5422952f648SJoseph-Jonathan Salzano if (chassisType != chassis::ChassisType::Invalid) 5432952f648SJoseph-Jonathan Salzano { 5442952f648SJoseph-Jonathan Salzano asyncResp->res.jsonValue["ChassisType"] = chassisType; 5452952f648SJoseph-Jonathan Salzano } 5462952f648SJoseph-Jonathan Salzano } 5472952f648SJoseph-Jonathan Salzano } 5482952f648SJoseph-Jonathan Salzano 5497164bc62SChau Ly inline void handleChassisGetSubTree( 5507164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5517164bc62SChau Ly const std::string& chassisId, const boost::system::error_code& ec, 5527164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 5537164bc62SChau Ly { 55462d5e2e4SEd Tanous if (ec) 5551abe55efSEd Tanous { 55662598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 557f12894f8SJason M. Bills messages::internalError(asyncResp->res); 558daf36e2eSEd Tanous return; 559daf36e2eSEd Tanous } 560daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 561cf7eba09SNan Zhou for (const std::pair< 562cf7eba09SNan Zhou std::string, 563cf7eba09SNan Zhou std::vector<std::pair<std::string, std::vector<std::string>>>>& 5641214b7e7SGunnar Mills object : subtree) 5651abe55efSEd Tanous { 566daf36e2eSEd Tanous const std::string& path = object.first; 567cf7eba09SNan Zhou const std::vector<std::pair<std::string, std::vector<std::string>>>& 5681214b7e7SGunnar Mills connectionNames = object.second; 5697e860f15SJohn Edward Broadbent 570997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 571997093ebSGeorge Liu if (objPath.filename() != chassisId) 5721abe55efSEd Tanous { 573daf36e2eSEd Tanous continue; 574daf36e2eSEd Tanous } 57526f03899SShawn McCarney 576a5617496SJie Yang getChassisConnectivity(asyncResp, chassisId, path); 577a5617496SJie Yang 57826f6976fSEd Tanous if (connectionNames.empty()) 5791abe55efSEd Tanous { 58062598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 581e0d918bcSEd Tanous continue; 582daf36e2eSEd Tanous } 583e0d918bcSEd Tanous 5847164bc62SChau Ly asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis"; 58549c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.id"] = 586ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 58749c53ac9SJohnathan Mantey asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 588cf7eba09SNan Zhou asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] = 5897164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset", 5907164bc62SChau Ly chassisId); 5911476687dSEd Tanous asyncResp->res 592cf7eba09SNan Zhou .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] = 593ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo", 594ef4c65b7SEd Tanous chassisId); 5956c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 5966c3e9451SGeorge Liu path + "/drive", 5977164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec3, 5986c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 59992903bd4SJohn Edward Broadbent if (ec3 || resp.empty()) 60092903bd4SJohn Edward Broadbent { 60192903bd4SJohn Edward Broadbent return; // no drives = no failures 60292903bd4SJohn Edward Broadbent } 60392903bd4SJohn Edward Broadbent 60492903bd4SJohn Edward Broadbent nlohmann::json reference; 605bd79bce8SPatrick Williams reference["@odata.id"] = boost::urls::format( 606bd79bce8SPatrick Williams "/redfish/v1/Chassis/{}/Drives", chassisId); 60792903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Drives"] = std::move(reference); 60892903bd4SJohn Edward Broadbent }); 60992903bd4SJohn Edward Broadbent 610002d39b4SEd Tanous const std::string& connectionName = connectionNames[0].first; 6111c8fba97SJames Feist 6127164bc62SChau Ly const std::vector<std::string>& interfaces2 = connectionNames[0].second; 613e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 614e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 6151c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 6160fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 6171c8fba97SJames Feist 618476b9cc5STejas Patil const std::string assetTagInterface = 6190fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.AssetTag"; 620523d4868SLogananth Sundararaj const std::string replaceableInterface = 621523d4868SLogananth Sundararaj "xyz.openbmc_project.Inventory.Decorator.Replaceable"; 622b4d593f1SCarson Labrado const std::string revisionInterface = 623b4d593f1SCarson Labrado "xyz.openbmc_project.Inventory.Decorator.Revision"; 624523d4868SLogananth Sundararaj for (const auto& interface : interfaces2) 625523d4868SLogananth Sundararaj { 626523d4868SLogananth Sundararaj if (interface == assetTagInterface) 627476b9cc5STejas Patil { 628deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 629deae6a78SEd Tanous connectionName, path, assetTagInterface, "AssetTag", 6307164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 6311e1e598dSJonathan Doman const std::string& property) { 6328a592810SEd Tanous if (ec2) 633476b9cc5STejas Patil { 634bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 635bd79bce8SPatrick Williams "DBus response error for AssetTag: {}", ec2); 636476b9cc5STejas Patil messages::internalError(asyncResp->res); 637476b9cc5STejas Patil return; 638476b9cc5STejas Patil } 639002d39b4SEd Tanous asyncResp->res.jsonValue["AssetTag"] = property; 6401e1e598dSJonathan Doman }); 641476b9cc5STejas Patil } 642523d4868SLogananth Sundararaj else if (interface == replaceableInterface) 643523d4868SLogananth Sundararaj { 644deae6a78SEd Tanous dbus::utility::getProperty<bool>( 645deae6a78SEd Tanous connectionName, path, replaceableInterface, "HotPluggable", 6467164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 647523d4868SLogananth Sundararaj const bool property) { 648523d4868SLogananth Sundararaj if (ec2) 649523d4868SLogananth Sundararaj { 65062598e31SEd Tanous BMCWEB_LOG_ERROR( 651bd79bce8SPatrick Williams "DBus response error for HotPluggable: {}", 652bd79bce8SPatrick Williams ec2); 653523d4868SLogananth Sundararaj messages::internalError(asyncResp->res); 654523d4868SLogananth Sundararaj return; 655523d4868SLogananth Sundararaj } 656523d4868SLogananth Sundararaj asyncResp->res.jsonValue["HotPluggable"] = property; 657523d4868SLogananth Sundararaj }); 658523d4868SLogananth Sundararaj } 659b4d593f1SCarson Labrado else if (interface == revisionInterface) 660b4d593f1SCarson Labrado { 661deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 662deae6a78SEd Tanous connectionName, path, revisionInterface, "Version", 663b4d593f1SCarson Labrado [asyncResp, chassisId](const boost::system::error_code& ec2, 664b4d593f1SCarson Labrado const std::string& property) { 665b4d593f1SCarson Labrado if (ec2) 666b4d593f1SCarson Labrado { 667bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 668bd79bce8SPatrick Williams "DBus response error for Version: {}", ec2); 669b4d593f1SCarson Labrado messages::internalError(asyncResp->res); 670b4d593f1SCarson Labrado return; 671b4d593f1SCarson Labrado } 672b4d593f1SCarson Labrado asyncResp->res.jsonValue["Version"] = property; 673b4d593f1SCarson Labrado }); 674b4d593f1SCarson Labrado } 675523d4868SLogananth Sundararaj } 676476b9cc5STejas Patil 6771c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 6781c8fba97SJames Feist { 6797164bc62SChau Ly if (std::ranges::find(interfaces2, interface) != interfaces2.end()) 6801c8fba97SJames Feist { 6811c8fba97SJames Feist getIndicatorLedState(asyncResp); 68259a17e4fSGeorge Liu getSystemLocationIndicatorActive(asyncResp); 6831c8fba97SJames Feist break; 6841c8fba97SJames Feist } 6851c8fba97SJames Feist } 6861c8fba97SJames Feist 687deae6a78SEd Tanous dbus::utility::getAllProperties( 68886d89ed7SKrzysztof Grobelny *crow::connections::systemBus, connectionName, path, 68986d89ed7SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Asset", 6907164bc62SChau Ly [asyncResp, chassisId, 6917164bc62SChau Ly path](const boost::system::error_code&, 692cf7eba09SNan Zhou const dbus::utility::DBusPropertiesMap& propertiesList) { 6937164bc62SChau Ly handleDecoratorAssetProperties(asyncResp, chassisId, path, 6947164bc62SChau Ly propertiesList); 69586d89ed7SKrzysztof Grobelny }); 6962c37b4b0SSharad Yadav 6972952f648SJoseph-Jonathan Salzano sdbusplus::asio::getAllProperties( 6982952f648SJoseph-Jonathan Salzano *crow::connections::systemBus, connectionName, path, 6992952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis", 7002952f648SJoseph-Jonathan Salzano [asyncResp]( 7012952f648SJoseph-Jonathan Salzano const boost::system::error_code&, 7022952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) { 7032952f648SJoseph-Jonathan Salzano handleChassisProperties(asyncResp, propertiesList); 7042952f648SJoseph-Jonathan Salzano }); 7052952f648SJoseph-Jonathan Salzano 706308f70c7SWilly Tu for (const auto& interface : interfaces2) 7072c37b4b0SSharad Yadav { 708308f70c7SWilly Tu if (interface == "xyz.openbmc_project.Common.UUID") 7092c37b4b0SSharad Yadav { 710308f70c7SWilly Tu getChassisUUID(asyncResp, connectionName, path); 7112c37b4b0SSharad Yadav } 712cf7eba09SNan Zhou else if (interface == 7130fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode") 7142c37b4b0SSharad Yadav { 715002d39b4SEd Tanous getChassisLocationCode(asyncResp, connectionName, path); 7162c37b4b0SSharad Yadav } 7172c37b4b0SSharad Yadav } 7182c37b4b0SSharad Yadav 719daf36e2eSEd Tanous return; 720daf36e2eSEd Tanous } 721e0d918bcSEd Tanous 722daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 723d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 7247164bc62SChau Ly } 725c181942fSQiang XU 7267164bc62SChau Ly inline void 7277164bc62SChau Ly handleChassisGet(App& app, const crow::Request& req, 7287164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7297164bc62SChau Ly const std::string& chassisId) 7307164bc62SChau Ly { 7317164bc62SChau Ly if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 7327164bc62SChau Ly { 7337164bc62SChau Ly return; 7347164bc62SChau Ly } 7357164bc62SChau Ly constexpr std::array<std::string_view, 2> interfaces = { 7367164bc62SChau Ly "xyz.openbmc_project.Inventory.Item.Board", 7377164bc62SChau Ly "xyz.openbmc_project.Inventory.Item.Chassis"}; 7387164bc62SChau Ly 7397164bc62SChau Ly dbus::utility::getSubTree( 7407164bc62SChau Ly "/xyz/openbmc_project/inventory", 0, interfaces, 7417164bc62SChau Ly std::bind_front(handleChassisGetSubTree, asyncResp, chassisId)); 7427164bc62SChau Ly 7437164bc62SChau Ly constexpr std::array<std::string_view, 1> interfaces2 = { 7447164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion"}; 7457164bc62SChau Ly 7467164bc62SChau Ly dbus::utility::getSubTree( 7477164bc62SChau Ly "/xyz/openbmc_project", 0, interfaces2, 7487164bc62SChau Ly std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp)); 749cf7eba09SNan Zhou } 7501c8fba97SJames Feist 751cf7eba09SNan Zhou inline void 752cf7eba09SNan Zhou handleChassisPatch(App& app, const crow::Request& req, 7537e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 754cf7eba09SNan Zhou const std::string& param) 755cf7eba09SNan Zhou { 7563ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 75745ca1b86SEd Tanous { 75845ca1b86SEd Tanous return; 75945ca1b86SEd Tanous } 7609f8bfa7cSGunnar Mills std::optional<bool> locationIndicatorActive; 7611c8fba97SJames Feist std::optional<std::string> indicatorLed; 7621c8fba97SJames Feist 7637e860f15SJohn Edward Broadbent if (param.empty()) 7641c8fba97SJames Feist { 7651c8fba97SJames Feist return; 7661c8fba97SJames Feist } 7671c8fba97SJames Feist 768afc474aeSMyung Bae if (!json_util::readJsonPatch( // 769afc474aeSMyung Bae req, asyncResp->res, // 770afc474aeSMyung Bae "IndicatorLED", indicatorLed, // 771afc474aeSMyung Bae "LocationIndicatorActive", locationIndicatorActive // 772afc474aeSMyung Bae )) 7731c8fba97SJames Feist { 7741c8fba97SJames Feist return; 7751c8fba97SJames Feist } 7761c8fba97SJames Feist 7779f8bfa7cSGunnar Mills // TODO (Gunnar): Remove IndicatorLED after enough time has passed 7789f8bfa7cSGunnar Mills if (!locationIndicatorActive && !indicatorLed) 7791c8fba97SJames Feist { 7801c8fba97SJames Feist return; // delete this when we support more patch properties 7811c8fba97SJames Feist } 782d6aa0093SGunnar Mills if (indicatorLed) 783d6aa0093SGunnar Mills { 7847e860f15SJohn Edward Broadbent asyncResp->res.addHeader( 7857e860f15SJohn Edward Broadbent boost::beast::http::field::warning, 7860fda0f12SGeorge Liu "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\""); 787d6aa0093SGunnar Mills } 7881c8fba97SJames Feist 789e99073f5SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 7901c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board", 7911c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Chassis"}; 7921c8fba97SJames Feist 7937e860f15SJohn Edward Broadbent const std::string& chassisId = param; 7941c8fba97SJames Feist 795e99073f5SGeorge Liu dbus::utility::getSubTree( 796e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 797cf7eba09SNan Zhou [asyncResp, chassisId, locationIndicatorActive, 7985e7e2dc5SEd Tanous indicatorLed](const boost::system::error_code& ec, 799b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 8001c8fba97SJames Feist if (ec) 8011c8fba97SJames Feist { 80262598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 8031c8fba97SJames Feist messages::internalError(asyncResp->res); 8041c8fba97SJames Feist return; 8051c8fba97SJames Feist } 8061c8fba97SJames Feist 8071c8fba97SJames Feist // Iterate over all retrieved ObjectPaths. 808bd79bce8SPatrick Williams for (const std::pair<std::string, 809bd79bce8SPatrick Williams std::vector<std::pair< 810bd79bce8SPatrick Williams std::string, std::vector<std::string>>>>& 8111214b7e7SGunnar Mills object : subtree) 8121c8fba97SJames Feist { 8131c8fba97SJames Feist const std::string& path = object.first; 814bd79bce8SPatrick Williams const std::vector< 815bd79bce8SPatrick Williams std::pair<std::string, std::vector<std::string>>>& 8161214b7e7SGunnar Mills connectionNames = object.second; 8171c8fba97SJames Feist 818997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 819997093ebSGeorge Liu if (objPath.filename() != chassisId) 8201c8fba97SJames Feist { 8211c8fba97SJames Feist continue; 8221c8fba97SJames Feist } 8231c8fba97SJames Feist 82426f6976fSEd Tanous if (connectionNames.empty()) 8251c8fba97SJames Feist { 82662598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 8271c8fba97SJames Feist continue; 8281c8fba97SJames Feist } 8291c8fba97SJames Feist 83023a21a1cSEd Tanous const std::vector<std::string>& interfaces3 = 8311c8fba97SJames Feist connectionNames[0].second; 8321c8fba97SJames Feist 833e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 834e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 8351c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 8360fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 8371c8fba97SJames Feist bool indicatorChassis = false; 8381c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 8391c8fba97SJames Feist { 8403544d2a7SEd Tanous if (std::ranges::find(interfaces3, interface) != 8413544d2a7SEd Tanous interfaces3.end()) 8421c8fba97SJames Feist { 8431c8fba97SJames Feist indicatorChassis = true; 8441c8fba97SJames Feist break; 8451c8fba97SJames Feist } 8461c8fba97SJames Feist } 8479f8bfa7cSGunnar Mills if (locationIndicatorActive) 8489f8bfa7cSGunnar Mills { 8499f8bfa7cSGunnar Mills if (indicatorChassis) 8509f8bfa7cSGunnar Mills { 851bd79bce8SPatrick Williams setSystemLocationIndicatorActive( 852bd79bce8SPatrick Williams asyncResp, *locationIndicatorActive); 8539f8bfa7cSGunnar Mills } 8549f8bfa7cSGunnar Mills else 8559f8bfa7cSGunnar Mills { 856002d39b4SEd Tanous messages::propertyUnknown(asyncResp->res, 857002d39b4SEd Tanous "LocationIndicatorActive"); 8589f8bfa7cSGunnar Mills } 8599f8bfa7cSGunnar Mills } 8609f8bfa7cSGunnar Mills if (indicatorLed) 8619f8bfa7cSGunnar Mills { 8621c8fba97SJames Feist if (indicatorChassis) 8631c8fba97SJames Feist { 864f23b7296SEd Tanous setIndicatorLedState(asyncResp, *indicatorLed); 8651c8fba97SJames Feist } 8661c8fba97SJames Feist else 8671c8fba97SJames Feist { 868bd79bce8SPatrick Williams messages::propertyUnknown(asyncResp->res, 869bd79bce8SPatrick Williams "IndicatorLED"); 8701c8fba97SJames Feist } 8711c8fba97SJames Feist } 8721c8fba97SJames Feist return; 8731c8fba97SJames Feist } 8741c8fba97SJames Feist 875d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 876e99073f5SGeorge Liu }); 877cf7eba09SNan Zhou } 878cf7eba09SNan Zhou 879cf7eba09SNan Zhou /** 880cf7eba09SNan Zhou * Chassis override class for delivering Chassis Schema 881cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 882cf7eba09SNan Zhou */ 883cf7eba09SNan Zhou inline void requestRoutesChassis(App& app) 884cf7eba09SNan Zhou { 885cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 886cf7eba09SNan Zhou .privileges(redfish::privileges::getChassis) 887cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 888cf7eba09SNan Zhou std::bind_front(handleChassisGet, std::ref(app))); 889cf7eba09SNan Zhou 890cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 891cf7eba09SNan Zhou .privileges(redfish::privileges::patchChassis) 892cf7eba09SNan Zhou .methods(boost::beast::http::verb::patch)( 893cf7eba09SNan Zhou std::bind_front(handleChassisPatch, std::ref(app))); 8941c8fba97SJames Feist } 895dd99e04bSP.K. Lee 8968d1b46d7Szhanghch05 inline void 8978d1b46d7Szhanghch05 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 898dd99e04bSP.K. Lee { 8997a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 900c3b3c92aSVijay Khemka "xyz.openbmc_project.State.Chassis"}; 901c3b3c92aSVijay Khemka 902c3b3c92aSVijay Khemka // Use mapper to get subtree paths. 9037a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 9047a1dbc48SGeorge Liu "/", 0, interfaces, 905b9d36b47SEd Tanous [asyncResp]( 9067a1dbc48SGeorge Liu const boost::system::error_code& ec, 907b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& chassisList) { 908c3b3c92aSVijay Khemka if (ec) 909c3b3c92aSVijay Khemka { 91062598e31SEd Tanous BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec); 911c3b3c92aSVijay Khemka messages::internalError(asyncResp->res); 912c3b3c92aSVijay Khemka return; 913c3b3c92aSVijay Khemka } 914c3b3c92aSVijay Khemka 915dd99e04bSP.K. Lee const char* processName = "xyz.openbmc_project.State.Chassis"; 916dd99e04bSP.K. Lee const char* interfaceName = "xyz.openbmc_project.State.Chassis"; 917dd99e04bSP.K. Lee const char* destProperty = "RequestedPowerTransition"; 918dd99e04bSP.K. Lee const std::string propertyValue = 919dd99e04bSP.K. Lee "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; 920bd79bce8SPatrick Williams std::string objectPath = 921bd79bce8SPatrick Williams "/xyz/openbmc_project/state/chassis_system0"; 922c3b3c92aSVijay Khemka 923c3b3c92aSVijay Khemka /* Look for system reset chassis path */ 924bd79bce8SPatrick Williams if ((std::ranges::find(chassisList, objectPath)) == 925bd79bce8SPatrick Williams chassisList.end()) 926c3b3c92aSVijay Khemka { 927c3b3c92aSVijay Khemka /* We prefer to reset the full chassis_system, but if it doesn't 928c3b3c92aSVijay Khemka * exist on some platforms, fall back to a host-only power reset 929c3b3c92aSVijay Khemka */ 930c3b3c92aSVijay Khemka objectPath = "/xyz/openbmc_project/state/chassis0"; 931c3b3c92aSVijay Khemka } 932dd99e04bSP.K. Lee 933e93abac6SGinu George setDbusProperty(asyncResp, "ResetType", processName, objectPath, 934e93abac6SGinu George interfaceName, destProperty, propertyValue); 9357a1dbc48SGeorge Liu }); 936dd99e04bSP.K. Lee } 937dd99e04bSP.K. Lee 938cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost( 939cf7eba09SNan Zhou App& app, const crow::Request& req, 9407e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 941cf7eba09SNan Zhou const std::string& /*chassisId*/) 942cf7eba09SNan Zhou { 9433ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 94445ca1b86SEd Tanous { 94545ca1b86SEd Tanous return; 94645ca1b86SEd Tanous } 94762598e31SEd Tanous BMCWEB_LOG_DEBUG("Post Chassis Reset."); 948dd99e04bSP.K. Lee 949dd99e04bSP.K. Lee std::string resetType; 950dd99e04bSP.K. Lee 951cf7eba09SNan Zhou if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 952dd99e04bSP.K. Lee { 953dd99e04bSP.K. Lee return; 954dd99e04bSP.K. Lee } 955dd99e04bSP.K. Lee 956dd99e04bSP.K. Lee if (resetType != "PowerCycle") 957dd99e04bSP.K. Lee { 95862598e31SEd Tanous BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType); 959002d39b4SEd Tanous messages::actionParameterNotSupported(asyncResp->res, resetType, 960002d39b4SEd Tanous "ResetType"); 961dd99e04bSP.K. Lee 962dd99e04bSP.K. Lee return; 963dd99e04bSP.K. Lee } 964dd99e04bSP.K. Lee doChassisPowerCycle(asyncResp); 965dd99e04bSP.K. Lee } 9661cb1a9e6SAppaRao Puli 9671cb1a9e6SAppaRao Puli /** 968cf7eba09SNan Zhou * ChassisResetAction class supports the POST method for the Reset 969cf7eba09SNan Zhou * action. 970cf7eba09SNan Zhou * Function handles POST method request. 971cf7eba09SNan Zhou * Analyzes POST body before sending Reset request data to D-Bus. 9721cb1a9e6SAppaRao Puli */ 973cf7eba09SNan Zhou 974cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app) 9751cb1a9e6SAppaRao Puli { 976cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/") 977cf7eba09SNan Zhou .privileges(redfish::privileges::postChassis) 978cf7eba09SNan Zhou .methods(boost::beast::http::verb::post)( 979cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoPost, std::ref(app))); 980cf7eba09SNan Zhou } 981cf7eba09SNan Zhou 982cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet( 983cf7eba09SNan Zhou App& app, const crow::Request& req, 9847e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 985cf7eba09SNan Zhou const std::string& chassisId) 986cf7eba09SNan Zhou { 9873ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 9881cb1a9e6SAppaRao Puli { 98945ca1b86SEd Tanous return; 99045ca1b86SEd Tanous } 991cf7eba09SNan Zhou asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 992ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 993ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId); 9941476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 9951476687dSEd Tanous 9961476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 9975b9e95a1SNan Zhou nlohmann::json::array_t parameters; 9985b9e95a1SNan Zhou nlohmann::json::object_t parameter; 9995b9e95a1SNan Zhou parameter["Name"] = "ResetType"; 10005b9e95a1SNan Zhou parameter["Required"] = true; 1001539d8c6bSEd Tanous parameter["DataType"] = action_info::ParameterTypes::String; 10021476687dSEd Tanous nlohmann::json::array_t allowed; 1003ad539545SPatrick Williams allowed.emplace_back("PowerCycle"); 10045b9e95a1SNan Zhou parameter["AllowableValues"] = std::move(allowed); 1005ad539545SPatrick Williams parameters.emplace_back(std::move(parameter)); 10065b9e95a1SNan Zhou 10071476687dSEd Tanous asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 1008cf7eba09SNan Zhou } 1009cf7eba09SNan Zhou 1010cf7eba09SNan Zhou /** 1011cf7eba09SNan Zhou * ChassisResetActionInfo derived class for delivering Chassis 1012cf7eba09SNan Zhou * ResetType AllowableValues using ResetInfo schema. 1013cf7eba09SNan Zhou */ 1014cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app) 1015cf7eba09SNan Zhou { 1016cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/") 1017cf7eba09SNan Zhou .privileges(redfish::privileges::getActionInfo) 1018cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 1019cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoGet, std::ref(app))); 10201cb1a9e6SAppaRao Puli } 10211cb1a9e6SAppaRao Puli 1022e37f8451SRapkiewicz, Pawel } // namespace redfish 1023