1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation 4e37f8451SRapkiewicz, Pawel #pragma once 5e37f8451SRapkiewicz, Pawel 63ccb3adbSEd Tanous #include "app.hpp" 77a1dbc48SGeorge Liu #include "dbus_utility.hpp" 8539d8c6bSEd Tanous #include "generated/enums/action_info.hpp" 9539d8c6bSEd Tanous #include "generated/enums/chassis.hpp" 10539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 111c8fba97SJames Feist #include "led.hpp" 123ccb3adbSEd Tanous #include "query.hpp" 137164bc62SChau Ly #include "redfish_util.hpp" 143ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 153ccb3adbSEd Tanous #include "utils/collection.hpp" 163ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 17cf7eba09SNan Zhou #include "utils/json_utils.hpp" 181abe55efSEd Tanous 19e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 20ef4c65b7SEd Tanous #include <boost/url/format.hpp> 211e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp> 22fc903b3dSAndrew Geissler #include <sdbusplus/message.hpp> 2386d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 241214b7e7SGunnar Mills 257a1dbc48SGeorge Liu #include <array> 262952f648SJoseph-Jonathan Salzano #include <memory> 273544d2a7SEd Tanous #include <ranges> 287a1dbc48SGeorge Liu #include <string_view> 297a1dbc48SGeorge Liu 301abe55efSEd Tanous namespace redfish 311abe55efSEd Tanous { 32e37f8451SRapkiewicz, Pawel 332952f648SJoseph-Jonathan Salzano inline chassis::ChassisType 342952f648SJoseph-Jonathan Salzano translateChassisTypeToRedfish(const std::string_view& chassisType) 352952f648SJoseph-Jonathan Salzano { 362952f648SJoseph-Jonathan Salzano if (chassisType == 372952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Blade") 382952f648SJoseph-Jonathan Salzano { 392952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Blade; 402952f648SJoseph-Jonathan Salzano } 412952f648SJoseph-Jonathan Salzano if (chassisType == 422952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Component") 432952f648SJoseph-Jonathan Salzano { 442952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Component; 452952f648SJoseph-Jonathan Salzano } 462952f648SJoseph-Jonathan Salzano if (chassisType == 472952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Enclosure") 482952f648SJoseph-Jonathan Salzano { 492952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Enclosure; 502952f648SJoseph-Jonathan Salzano } 512952f648SJoseph-Jonathan Salzano if (chassisType == 522952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Module") 532952f648SJoseph-Jonathan Salzano { 542952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Module; 552952f648SJoseph-Jonathan Salzano } 562952f648SJoseph-Jonathan Salzano if (chassisType == 572952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.RackMount") 582952f648SJoseph-Jonathan Salzano { 592952f648SJoseph-Jonathan Salzano return chassis::ChassisType::RackMount; 602952f648SJoseph-Jonathan Salzano } 612952f648SJoseph-Jonathan Salzano if (chassisType == 622952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StandAlone") 632952f648SJoseph-Jonathan Salzano { 642952f648SJoseph-Jonathan Salzano return chassis::ChassisType::StandAlone; 652952f648SJoseph-Jonathan Salzano } 662952f648SJoseph-Jonathan Salzano if (chassisType == 672952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StorageEnclosure") 682952f648SJoseph-Jonathan Salzano { 692952f648SJoseph-Jonathan Salzano return chassis::ChassisType::StorageEnclosure; 702952f648SJoseph-Jonathan Salzano } 712952f648SJoseph-Jonathan Salzano if (chassisType == 722952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Zone") 732952f648SJoseph-Jonathan Salzano { 742952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Zone; 752952f648SJoseph-Jonathan Salzano } 762952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Invalid; 772952f648SJoseph-Jonathan Salzano } 782952f648SJoseph-Jonathan Salzano 79e37f8451SRapkiewicz, Pawel /** 805e577bc1SWilly Tu * @brief Retrieves resources over dbus to link to the chassis 815e577bc1SWilly Tu * 825e577bc1SWilly Tu * @param[in] asyncResp - Shared pointer for completing asynchronous 835e577bc1SWilly Tu * calls 845e577bc1SWilly Tu * @param[in] path - Chassis dbus path to look for the storage. 855e577bc1SWilly Tu * 865e577bc1SWilly Tu * Calls the Association endpoints on the path + "/storage" and add the link of 875e577bc1SWilly Tu * json["Links"]["Storage@odata.count"] = 885e577bc1SWilly Tu * {"@odata.id", "/redfish/v1/Storage/" + resourceId} 895e577bc1SWilly Tu * 905e577bc1SWilly Tu * @return None. 915e577bc1SWilly Tu */ 925e577bc1SWilly Tu inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 935e577bc1SWilly Tu const sdbusplus::message::object_path& path) 945e577bc1SWilly Tu { 95deae6a78SEd Tanous dbus::utility::getProperty<std::vector<std::string>>( 96deae6a78SEd Tanous "xyz.openbmc_project.ObjectMapper", (path / "storage").str, 97deae6a78SEd Tanous "xyz.openbmc_project.Association", "endpoints", 98d4b054c1SWilly Tu [asyncResp](const boost::system::error_code& ec, 995e577bc1SWilly Tu const std::vector<std::string>& storageList) { 1005e577bc1SWilly Tu if (ec) 1015e577bc1SWilly Tu { 10262598e31SEd Tanous BMCWEB_LOG_DEBUG("getStorageLink got DBUS response error"); 1035e577bc1SWilly Tu return; 1045e577bc1SWilly Tu } 1055e577bc1SWilly Tu 1065e577bc1SWilly Tu nlohmann::json::array_t storages; 1075e577bc1SWilly Tu for (const std::string& storagePath : storageList) 1085e577bc1SWilly Tu { 1095e577bc1SWilly Tu std::string id = 1105e577bc1SWilly Tu sdbusplus::message::object_path(storagePath).filename(); 1115e577bc1SWilly Tu if (id.empty()) 1125e577bc1SWilly Tu { 1135e577bc1SWilly Tu continue; 1145e577bc1SWilly Tu } 1155e577bc1SWilly Tu 1165e577bc1SWilly Tu nlohmann::json::object_t storage; 117253f11b8SEd Tanous storage["@odata.id"] = 118253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/{}", 119253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, id); 1205e577bc1SWilly Tu storages.emplace_back(std::move(storage)); 1215e577bc1SWilly Tu } 1225e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["Storage@odata.count"] = 1235e577bc1SWilly Tu storages.size(); 1245e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages); 1255e577bc1SWilly Tu }); 1265e577bc1SWilly Tu } 1275e577bc1SWilly Tu 1285e577bc1SWilly Tu /** 129beeca0aeSGunnar Mills * @brief Retrieves chassis state properties over dbus 130beeca0aeSGunnar Mills * 131ac106bf6SEd Tanous * @param[in] asyncResp - Shared pointer for completing asynchronous calls. 132beeca0aeSGunnar Mills * 133beeca0aeSGunnar Mills * @return None. 134beeca0aeSGunnar Mills */ 135ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp) 136beeca0aeSGunnar Mills { 1371e1e598dSJonathan Doman // crow::connections::systemBus->async_method_call( 138deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 139deae6a78SEd Tanous "xyz.openbmc_project.State.Chassis", 1401e1e598dSJonathan Doman "/xyz/openbmc_project/state/chassis0", 1411e1e598dSJonathan Doman "xyz.openbmc_project.State.Chassis", "CurrentPowerState", 142ac106bf6SEd Tanous [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec, 1431e1e598dSJonathan Doman const std::string& chassisState) { 144beeca0aeSGunnar Mills if (ec) 145beeca0aeSGunnar Mills { 146a6e5e0abSCarson Labrado if (ec == boost::system::errc::host_unreachable) 147a6e5e0abSCarson Labrado { 148a6e5e0abSCarson Labrado // Service not available, no error, just don't return 149a6e5e0abSCarson Labrado // chassis state info 15062598e31SEd Tanous BMCWEB_LOG_DEBUG("Service not available {}", ec); 151a6e5e0abSCarson Labrado return; 152a6e5e0abSCarson Labrado } 15362598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 154ac106bf6SEd Tanous messages::internalError(asyncResp->res); 155beeca0aeSGunnar Mills return; 156beeca0aeSGunnar Mills } 157beeca0aeSGunnar Mills 15862598e31SEd Tanous BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState); 159beeca0aeSGunnar Mills // Verify Chassis State 160bd79bce8SPatrick Williams if (chassisState == 161bd79bce8SPatrick Williams "xyz.openbmc_project.State.Chassis.PowerState.On") 162beeca0aeSGunnar Mills { 163bd79bce8SPatrick Williams asyncResp->res.jsonValue["PowerState"] = 164bd79bce8SPatrick Williams resource::PowerState::On; 165539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 166539d8c6bSEd Tanous resource::State::Enabled; 167beeca0aeSGunnar Mills } 1681e1e598dSJonathan Doman else if (chassisState == 169beeca0aeSGunnar Mills "xyz.openbmc_project.State.Chassis.PowerState.Off") 170beeca0aeSGunnar Mills { 171bd79bce8SPatrick Williams asyncResp->res.jsonValue["PowerState"] = 172bd79bce8SPatrick Williams resource::PowerState::Off; 173539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 174539d8c6bSEd Tanous resource::State::StandbyOffline; 175beeca0aeSGunnar Mills } 1761e1e598dSJonathan Doman }); 177beeca0aeSGunnar Mills } 178beeca0aeSGunnar Mills 179c181942fSQiang XU /** 180c181942fSQiang XU * Retrieves physical security properties over dbus 181c181942fSQiang XU */ 1827164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree( 1837164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 184e99073f5SGeorge Liu const boost::system::error_code& ec, 1857164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 1867164bc62SChau Ly { 187c181942fSQiang XU if (ec) 188c181942fSQiang XU { 1894e0453b1SGunnar Mills // do not add err msg in redfish response, because this is not 190c181942fSQiang XU // mandatory property 19162598e31SEd Tanous BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec); 192c181942fSQiang XU return; 193c181942fSQiang XU } 194c181942fSQiang XU // Iterate over all retrieved ObjectPaths. 195c181942fSQiang XU for (const auto& object : subtree) 196c181942fSQiang XU { 197840a9ffcSPatrick Williams if (!object.second.empty()) 198c181942fSQiang XU { 19989144a3aSEd Tanous const auto& service = object.second.front(); 2007164bc62SChau Ly 2017164bc62SChau Ly BMCWEB_LOG_DEBUG("Get intrusion status by service "); 2027164bc62SChau Ly 203deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 204deae6a78SEd Tanous service.first, object.first, 2057164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion", "Status", 2067164bc62SChau Ly [asyncResp](const boost::system::error_code& ec1, 2077164bc62SChau Ly const std::string& value) { 2087164bc62SChau Ly if (ec1) 2097164bc62SChau Ly { 210bd79bce8SPatrick Williams // do not add err msg in redfish response, because this 211bd79bce8SPatrick Williams // is not 2127164bc62SChau Ly // mandatory property 2137164bc62SChau Ly BMCWEB_LOG_ERROR("DBUS response error {}", ec1); 2147164bc62SChau Ly return; 2157164bc62SChau Ly } 216bd79bce8SPatrick Williams asyncResp->res.jsonValue["PhysicalSecurity"] 217bd79bce8SPatrick Williams ["IntrusionSensorNumber"] = 1; 2187164bc62SChau Ly asyncResp->res 219bd79bce8SPatrick Williams .jsonValue["PhysicalSecurity"]["IntrusionSensor"] = 220bd79bce8SPatrick Williams value; 2217164bc62SChau Ly }); 2227164bc62SChau Ly 223c181942fSQiang XU return; 224c181942fSQiang XU } 225c181942fSQiang XU } 226c181942fSQiang XU } 227c181942fSQiang XU 228cf7eba09SNan Zhou inline void handleChassisCollectionGet( 229cf7eba09SNan Zhou App& app, const crow::Request& req, 230cf7eba09SNan Zhou const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2311abe55efSEd Tanous { 2323ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 23345ca1b86SEd Tanous { 23445ca1b86SEd Tanous return; 23545ca1b86SEd Tanous } 2368d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 2378d1b46d7Szhanghch05 "#ChassisCollection.ChassisCollection"; 2388d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 2398d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 240e37f8451SRapkiewicz, Pawel 2417a1dbc48SGeorge Liu constexpr std::array<std::string_view, 2> interfaces{ 2427a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board", 2437a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis"}; 24402f6ff19SGunnar Mills collection_util::getCollectionMembers( 24536b5f1edSLakshmi Yadlapati asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces, 24636b5f1edSLakshmi Yadlapati "/xyz/openbmc_project/inventory"); 247cf7eba09SNan Zhou } 248cf7eba09SNan Zhou 249a5617496SJie Yang inline void getChassisContainedBy( 250a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 251a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 25228ee563eSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& upstreamChassisPaths) 253a5617496SJie Yang { 254a5617496SJie Yang if (ec) 255a5617496SJie Yang { 256a5617496SJie Yang if (ec.value() != EBADR) 257a5617496SJie Yang { 25862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 259a5617496SJie Yang messages::internalError(asyncResp->res); 260a5617496SJie Yang } 261a5617496SJie Yang return; 262a5617496SJie Yang } 263a5617496SJie Yang if (upstreamChassisPaths.empty()) 264a5617496SJie Yang { 265a5617496SJie Yang return; 266a5617496SJie Yang } 267a5617496SJie Yang if (upstreamChassisPaths.size() > 1) 268a5617496SJie Yang { 2698ece0e45SEd Tanous BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId); 270a5617496SJie Yang messages::internalError(asyncResp->res); 271a5617496SJie Yang return; 272a5617496SJie Yang } 273a5617496SJie Yang 274a5617496SJie Yang sdbusplus::message::object_path upstreamChassisPath( 275a5617496SJie Yang upstreamChassisPaths[0]); 276a5617496SJie Yang std::string upstreamChassis = upstreamChassisPath.filename(); 277a5617496SJie Yang if (upstreamChassis.empty()) 278a5617496SJie Yang { 27962598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}", 28062598e31SEd Tanous upstreamChassisPath.str, chassisId); 281a5617496SJie Yang return; 282a5617496SJie Yang } 283a5617496SJie Yang 284a5617496SJie Yang asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] = 285a5617496SJie Yang boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis); 286a5617496SJie Yang } 287a5617496SJie Yang 288a5617496SJie Yang inline void getChassisContains( 289a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 290a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 29128ee563eSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& downstreamChassisPaths) 292a5617496SJie Yang { 293a5617496SJie Yang if (ec) 294a5617496SJie Yang { 295a5617496SJie Yang if (ec.value() != EBADR) 296a5617496SJie Yang { 29762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 298a5617496SJie Yang messages::internalError(asyncResp->res); 299a5617496SJie Yang } 300a5617496SJie Yang return; 301a5617496SJie Yang } 302a5617496SJie Yang if (downstreamChassisPaths.empty()) 303a5617496SJie Yang { 304a5617496SJie Yang return; 305a5617496SJie Yang } 306a5617496SJie Yang nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"]; 307a5617496SJie Yang if (!jValue.is_array()) 308a5617496SJie Yang { 309a5617496SJie Yang // Create the array if it was empty 310a5617496SJie Yang jValue = nlohmann::json::array(); 311a5617496SJie Yang } 312a5617496SJie Yang for (const auto& p : downstreamChassisPaths) 313a5617496SJie Yang { 314a5617496SJie Yang sdbusplus::message::object_path downstreamChassisPath(p); 315a5617496SJie Yang std::string downstreamChassis = downstreamChassisPath.filename(); 316a5617496SJie Yang if (downstreamChassis.empty()) 317a5617496SJie Yang { 31862598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}", 31962598e31SEd Tanous downstreamChassisPath.str, chassisId); 320a5617496SJie Yang continue; 321a5617496SJie Yang } 322a5617496SJie Yang nlohmann::json link; 323bd79bce8SPatrick Williams link["@odata.id"] = 324bd79bce8SPatrick Williams boost::urls::format("/redfish/v1/Chassis/{}", downstreamChassis); 325a5617496SJie Yang jValue.push_back(std::move(link)); 326a5617496SJie Yang } 327a5617496SJie Yang asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size(); 328a5617496SJie Yang } 329a5617496SJie Yang 330bd79bce8SPatrick Williams inline void getChassisConnectivity( 331bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 332bd79bce8SPatrick Williams const std::string& chassisId, const std::string& chassisPath) 333a5617496SJie Yang { 33462598e31SEd Tanous BMCWEB_LOG_DEBUG("Get chassis connectivity"); 335a5617496SJie Yang 33628ee563eSMyung Bae constexpr std::array<std::string_view, 2> interfaces{ 33728ee563eSMyung Bae "xyz.openbmc_project.Inventory.Item.Board", 33828ee563eSMyung Bae "xyz.openbmc_project.Inventory.Item.Chassis"}; 33928ee563eSMyung Bae 34028ee563eSMyung Bae dbus::utility::getAssociatedSubTreePaths( 341a5617496SJie Yang chassisPath + "/contained_by", 34228ee563eSMyung Bae sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 34328ee563eSMyung Bae interfaces, 344a5617496SJie Yang std::bind_front(getChassisContainedBy, asyncResp, chassisId)); 345a5617496SJie Yang 34628ee563eSMyung Bae dbus::utility::getAssociatedSubTreePaths( 347a5617496SJie Yang chassisPath + "/containing", 34828ee563eSMyung Bae sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 34928ee563eSMyung Bae interfaces, std::bind_front(getChassisContains, asyncResp, chassisId)); 350a5617496SJie Yang } 351a5617496SJie Yang 352cf7eba09SNan Zhou /** 353cf7eba09SNan Zhou * ChassisCollection derived class for delivering Chassis Collection Schema 354cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 355cf7eba09SNan Zhou */ 356cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app) 357cf7eba09SNan Zhou { 358cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/") 359cf7eba09SNan Zhou .privileges(redfish::privileges::getChassisCollection) 360cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 361cf7eba09SNan Zhou std::bind_front(handleChassisCollectionGet, std::ref(app))); 36262d5e2e4SEd Tanous } 363e37f8451SRapkiewicz, Pawel 364bd79bce8SPatrick Williams inline void getChassisLocationCode( 365bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 366bd79bce8SPatrick Williams const std::string& connectionName, const std::string& path) 367308f70c7SWilly Tu { 368deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 369deae6a78SEd Tanous connectionName, path, 3701e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 3715e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3721e1e598dSJonathan Doman const std::string& property) { 373308f70c7SWilly Tu if (ec) 374308f70c7SWilly Tu { 37562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location"); 376308f70c7SWilly Tu messages::internalError(asyncResp->res); 377308f70c7SWilly Tu return; 378308f70c7SWilly Tu } 379308f70c7SWilly Tu 380bd79bce8SPatrick Williams asyncResp->res 381bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 3821e1e598dSJonathan Doman property; 3831e1e598dSJonathan Doman }); 384308f70c7SWilly Tu } 385308f70c7SWilly Tu 386308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 387308f70c7SWilly Tu const std::string& connectionName, 388308f70c7SWilly Tu const std::string& path) 389308f70c7SWilly Tu { 390deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 391deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Common.UUID", "UUID", 3925e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3931e1e598dSJonathan Doman const std::string& chassisUUID) { 394308f70c7SWilly Tu if (ec) 395308f70c7SWilly Tu { 39662598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for UUID"); 397308f70c7SWilly Tu messages::internalError(asyncResp->res); 398308f70c7SWilly Tu return; 399308f70c7SWilly Tu } 4001e1e598dSJonathan Doman asyncResp->res.jsonValue["UUID"] = chassisUUID; 4011e1e598dSJonathan Doman }); 402308f70c7SWilly Tu } 403308f70c7SWilly Tu 4047164bc62SChau Ly inline void handleDecoratorAssetProperties( 40545ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4067164bc62SChau Ly const std::string& chassisId, const std::string& path, 4077164bc62SChau Ly const dbus::utility::DBusPropertiesMap& propertiesList) 408cf7eba09SNan Zhou { 4097164bc62SChau Ly const std::string* partNumber = nullptr; 4107164bc62SChau Ly const std::string* serialNumber = nullptr; 4117164bc62SChau Ly const std::string* manufacturer = nullptr; 4127164bc62SChau Ly const std::string* model = nullptr; 4137164bc62SChau Ly const std::string* sparePartNumber = nullptr; 4147164bc62SChau Ly 4157164bc62SChau Ly const bool success = sdbusplus::unpackPropertiesNoThrow( 4167164bc62SChau Ly dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 4177164bc62SChau Ly partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, 4187164bc62SChau Ly "Model", model, "SparePartNumber", sparePartNumber); 4197164bc62SChau Ly 4207164bc62SChau Ly if (!success) 42145ca1b86SEd Tanous { 4227164bc62SChau Ly messages::internalError(asyncResp->res); 42345ca1b86SEd Tanous return; 42445ca1b86SEd Tanous } 425734bfe90SGunnar Mills 4267164bc62SChau Ly if (partNumber != nullptr) 4277164bc62SChau Ly { 4287164bc62SChau Ly asyncResp->res.jsonValue["PartNumber"] = *partNumber; 4297164bc62SChau Ly } 4307164bc62SChau Ly 4317164bc62SChau Ly if (serialNumber != nullptr) 4327164bc62SChau Ly { 4337164bc62SChau Ly asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 4347164bc62SChau Ly } 4357164bc62SChau Ly 4367164bc62SChau Ly if (manufacturer != nullptr) 4377164bc62SChau Ly { 4387164bc62SChau Ly asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 4397164bc62SChau Ly } 4407164bc62SChau Ly 4417164bc62SChau Ly if (model != nullptr) 4427164bc62SChau Ly { 4437164bc62SChau Ly asyncResp->res.jsonValue["Model"] = *model; 4447164bc62SChau Ly } 4457164bc62SChau Ly 4467164bc62SChau Ly // SparePartNumber is optional on D-Bus 4477164bc62SChau Ly // so skip if it is empty 4487164bc62SChau Ly if (sparePartNumber != nullptr && !sparePartNumber->empty()) 4497164bc62SChau Ly { 4507164bc62SChau Ly asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 4517164bc62SChau Ly } 4527164bc62SChau Ly 4537164bc62SChau Ly asyncResp->res.jsonValue["Name"] = chassisId; 4547164bc62SChau Ly asyncResp->res.jsonValue["Id"] = chassisId; 45525b54dbaSEd Tanous 45625b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL) 45725b54dbaSEd Tanous { 4587164bc62SChau Ly asyncResp->res.jsonValue["Thermal"]["@odata.id"] = 4597164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId); 4607164bc62SChau Ly // Power object 4617164bc62SChau Ly asyncResp->res.jsonValue["Power"]["@odata.id"] = 4627164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId); 46325b54dbaSEd Tanous } 46425b54dbaSEd Tanous 46525b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM) 46625b54dbaSEd Tanous { 4677164bc62SChau Ly asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] = 4687164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem", 4697164bc62SChau Ly chassisId); 4707164bc62SChau Ly asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] = 47125b54dbaSEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", 47225b54dbaSEd Tanous chassisId); 4737164bc62SChau Ly asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] = 4747164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics", 4757164bc62SChau Ly chassisId); 47625b54dbaSEd Tanous } 4777164bc62SChau Ly // SensorCollection 4787164bc62SChau Ly asyncResp->res.jsonValue["Sensors"]["@odata.id"] = 4797164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId); 480539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 4817164bc62SChau Ly 4827164bc62SChau Ly nlohmann::json::array_t computerSystems; 4837164bc62SChau Ly nlohmann::json::object_t system; 484bd79bce8SPatrick Williams system["@odata.id"] = 485bd79bce8SPatrick Williams std::format("/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME); 4867164bc62SChau Ly computerSystems.emplace_back(std::move(system)); 4877164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ComputerSystems"] = 4887164bc62SChau Ly std::move(computerSystems); 4897164bc62SChau Ly 4907164bc62SChau Ly nlohmann::json::array_t managedBy; 4917164bc62SChau Ly nlohmann::json::object_t manager; 492253f11b8SEd Tanous manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}", 493253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 4947164bc62SChau Ly managedBy.emplace_back(std::move(manager)); 4957164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); 4967164bc62SChau Ly getChassisState(asyncResp); 4977164bc62SChau Ly getStorageLink(asyncResp, path); 4987164bc62SChau Ly } 4997164bc62SChau Ly 5002952f648SJoseph-Jonathan Salzano inline void handleChassisProperties( 5012952f648SJoseph-Jonathan Salzano const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5022952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) 5032952f648SJoseph-Jonathan Salzano { 5042952f648SJoseph-Jonathan Salzano const std::string* type = nullptr; 5052952f648SJoseph-Jonathan Salzano 5062952f648SJoseph-Jonathan Salzano const bool success = sdbusplus::unpackPropertiesNoThrow( 5072952f648SJoseph-Jonathan Salzano dbus_utils::UnpackErrorPrinter(), propertiesList, "Type", type); 5082952f648SJoseph-Jonathan Salzano 5092952f648SJoseph-Jonathan Salzano if (!success) 5102952f648SJoseph-Jonathan Salzano { 5112952f648SJoseph-Jonathan Salzano messages::internalError(asyncResp->res); 5122952f648SJoseph-Jonathan Salzano return; 5132952f648SJoseph-Jonathan Salzano } 5142952f648SJoseph-Jonathan Salzano 51519ea2864SGunnar Mills // Chassis Type is a required property in Redfish 51619ea2864SGunnar Mills // If there is an error or some enum we don't support just sit it to Rack 51719ea2864SGunnar Mills // Mount 51819ea2864SGunnar Mills asyncResp->res.jsonValue["ChassisType"] = chassis::ChassisType::RackMount; 51919ea2864SGunnar Mills 5202952f648SJoseph-Jonathan Salzano if (type != nullptr) 5212952f648SJoseph-Jonathan Salzano { 5222952f648SJoseph-Jonathan Salzano auto chassisType = translateChassisTypeToRedfish(*type); 5232952f648SJoseph-Jonathan Salzano if (chassisType != chassis::ChassisType::Invalid) 5242952f648SJoseph-Jonathan Salzano { 5252952f648SJoseph-Jonathan Salzano asyncResp->res.jsonValue["ChassisType"] = chassisType; 5262952f648SJoseph-Jonathan Salzano } 5272952f648SJoseph-Jonathan Salzano } 5282952f648SJoseph-Jonathan Salzano } 5292952f648SJoseph-Jonathan Salzano 5307164bc62SChau Ly inline void handleChassisGetSubTree( 5317164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5327164bc62SChau Ly const std::string& chassisId, const boost::system::error_code& ec, 5337164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 5347164bc62SChau Ly { 53562d5e2e4SEd Tanous if (ec) 5361abe55efSEd Tanous { 53762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 538f12894f8SJason M. Bills messages::internalError(asyncResp->res); 539daf36e2eSEd Tanous return; 540daf36e2eSEd Tanous } 541daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 542cf7eba09SNan Zhou for (const std::pair< 543cf7eba09SNan Zhou std::string, 544cf7eba09SNan Zhou std::vector<std::pair<std::string, std::vector<std::string>>>>& 5451214b7e7SGunnar Mills object : subtree) 5461abe55efSEd Tanous { 547daf36e2eSEd Tanous const std::string& path = object.first; 548cf7eba09SNan Zhou const std::vector<std::pair<std::string, std::vector<std::string>>>& 5491214b7e7SGunnar Mills connectionNames = object.second; 5507e860f15SJohn Edward Broadbent 551997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 552997093ebSGeorge Liu if (objPath.filename() != chassisId) 5531abe55efSEd Tanous { 554daf36e2eSEd Tanous continue; 555daf36e2eSEd Tanous } 55626f03899SShawn McCarney 557a5617496SJie Yang getChassisConnectivity(asyncResp, chassisId, path); 558a5617496SJie Yang 55926f6976fSEd Tanous if (connectionNames.empty()) 5601abe55efSEd Tanous { 56162598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 562e0d918bcSEd Tanous continue; 563daf36e2eSEd Tanous } 564e0d918bcSEd Tanous 5657164bc62SChau Ly asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis"; 56649c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.id"] = 567ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 56849c53ac9SJohnathan Mantey asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 569cf7eba09SNan Zhou asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] = 5707164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset", 5717164bc62SChau Ly chassisId); 5721476687dSEd Tanous asyncResp->res 573cf7eba09SNan Zhou .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] = 574ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo", 575ef4c65b7SEd Tanous chassisId); 5766c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 5776c3e9451SGeorge Liu path + "/drive", 5787164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec3, 5796c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 58092903bd4SJohn Edward Broadbent if (ec3 || resp.empty()) 58192903bd4SJohn Edward Broadbent { 58292903bd4SJohn Edward Broadbent return; // no drives = no failures 58392903bd4SJohn Edward Broadbent } 58492903bd4SJohn Edward Broadbent 58592903bd4SJohn Edward Broadbent nlohmann::json reference; 586bd79bce8SPatrick Williams reference["@odata.id"] = boost::urls::format( 587bd79bce8SPatrick Williams "/redfish/v1/Chassis/{}/Drives", chassisId); 58892903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Drives"] = std::move(reference); 58992903bd4SJohn Edward Broadbent }); 59092903bd4SJohn Edward Broadbent 591002d39b4SEd Tanous const std::string& connectionName = connectionNames[0].first; 5921c8fba97SJames Feist 5937164bc62SChau Ly const std::vector<std::string>& interfaces2 = connectionNames[0].second; 594e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 595e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 5961c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 5970fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 5981c8fba97SJames Feist 599476b9cc5STejas Patil const std::string assetTagInterface = 6000fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.AssetTag"; 601523d4868SLogananth Sundararaj const std::string replaceableInterface = 602523d4868SLogananth Sundararaj "xyz.openbmc_project.Inventory.Decorator.Replaceable"; 603b4d593f1SCarson Labrado const std::string revisionInterface = 604b4d593f1SCarson Labrado "xyz.openbmc_project.Inventory.Decorator.Revision"; 605523d4868SLogananth Sundararaj for (const auto& interface : interfaces2) 606523d4868SLogananth Sundararaj { 607523d4868SLogananth Sundararaj if (interface == assetTagInterface) 608476b9cc5STejas Patil { 609deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 610deae6a78SEd Tanous connectionName, path, assetTagInterface, "AssetTag", 6117164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 6121e1e598dSJonathan Doman const std::string& property) { 6138a592810SEd Tanous if (ec2) 614476b9cc5STejas Patil { 615bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 616bd79bce8SPatrick Williams "DBus response error for AssetTag: {}", ec2); 617476b9cc5STejas Patil messages::internalError(asyncResp->res); 618476b9cc5STejas Patil return; 619476b9cc5STejas Patil } 620002d39b4SEd Tanous asyncResp->res.jsonValue["AssetTag"] = property; 6211e1e598dSJonathan Doman }); 622476b9cc5STejas Patil } 623523d4868SLogananth Sundararaj else if (interface == replaceableInterface) 624523d4868SLogananth Sundararaj { 625deae6a78SEd Tanous dbus::utility::getProperty<bool>( 626deae6a78SEd Tanous connectionName, path, replaceableInterface, "HotPluggable", 6277164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 628523d4868SLogananth Sundararaj const bool property) { 629523d4868SLogananth Sundararaj if (ec2) 630523d4868SLogananth Sundararaj { 63162598e31SEd Tanous BMCWEB_LOG_ERROR( 632bd79bce8SPatrick Williams "DBus response error for HotPluggable: {}", 633bd79bce8SPatrick Williams ec2); 634523d4868SLogananth Sundararaj messages::internalError(asyncResp->res); 635523d4868SLogananth Sundararaj return; 636523d4868SLogananth Sundararaj } 637523d4868SLogananth Sundararaj asyncResp->res.jsonValue["HotPluggable"] = property; 638523d4868SLogananth Sundararaj }); 639523d4868SLogananth Sundararaj } 640b4d593f1SCarson Labrado else if (interface == revisionInterface) 641b4d593f1SCarson Labrado { 642deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 643deae6a78SEd Tanous connectionName, path, revisionInterface, "Version", 644b4d593f1SCarson Labrado [asyncResp, chassisId](const boost::system::error_code& ec2, 645b4d593f1SCarson Labrado const std::string& property) { 646b4d593f1SCarson Labrado if (ec2) 647b4d593f1SCarson Labrado { 648bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 649bd79bce8SPatrick Williams "DBus response error for Version: {}", ec2); 650b4d593f1SCarson Labrado messages::internalError(asyncResp->res); 651b4d593f1SCarson Labrado return; 652b4d593f1SCarson Labrado } 653b4d593f1SCarson Labrado asyncResp->res.jsonValue["Version"] = property; 654b4d593f1SCarson Labrado }); 655b4d593f1SCarson Labrado } 656523d4868SLogananth Sundararaj } 657476b9cc5STejas Patil 6581c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 6591c8fba97SJames Feist { 6607164bc62SChau Ly if (std::ranges::find(interfaces2, interface) != interfaces2.end()) 6611c8fba97SJames Feist { 6621c8fba97SJames Feist getIndicatorLedState(asyncResp); 66359a17e4fSGeorge Liu getSystemLocationIndicatorActive(asyncResp); 6641c8fba97SJames Feist break; 6651c8fba97SJames Feist } 6661c8fba97SJames Feist } 6671c8fba97SJames Feist 668deae6a78SEd Tanous dbus::utility::getAllProperties( 66986d89ed7SKrzysztof Grobelny *crow::connections::systemBus, connectionName, path, 67086d89ed7SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Asset", 6717164bc62SChau Ly [asyncResp, chassisId, 6727164bc62SChau Ly path](const boost::system::error_code&, 673cf7eba09SNan Zhou const dbus::utility::DBusPropertiesMap& propertiesList) { 6747164bc62SChau Ly handleDecoratorAssetProperties(asyncResp, chassisId, path, 6757164bc62SChau Ly propertiesList); 67686d89ed7SKrzysztof Grobelny }); 6772c37b4b0SSharad Yadav 6782952f648SJoseph-Jonathan Salzano sdbusplus::asio::getAllProperties( 6792952f648SJoseph-Jonathan Salzano *crow::connections::systemBus, connectionName, path, 6802952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis", 6812952f648SJoseph-Jonathan Salzano [asyncResp]( 6822952f648SJoseph-Jonathan Salzano const boost::system::error_code&, 6832952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) { 6842952f648SJoseph-Jonathan Salzano handleChassisProperties(asyncResp, propertiesList); 6852952f648SJoseph-Jonathan Salzano }); 6862952f648SJoseph-Jonathan Salzano 687308f70c7SWilly Tu for (const auto& interface : interfaces2) 6882c37b4b0SSharad Yadav { 689308f70c7SWilly Tu if (interface == "xyz.openbmc_project.Common.UUID") 6902c37b4b0SSharad Yadav { 691308f70c7SWilly Tu getChassisUUID(asyncResp, connectionName, path); 6922c37b4b0SSharad Yadav } 693cf7eba09SNan Zhou else if (interface == 6940fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode") 6952c37b4b0SSharad Yadav { 696002d39b4SEd Tanous getChassisLocationCode(asyncResp, connectionName, path); 6972c37b4b0SSharad Yadav } 6982c37b4b0SSharad Yadav } 6992c37b4b0SSharad Yadav 700daf36e2eSEd Tanous return; 701daf36e2eSEd Tanous } 702e0d918bcSEd Tanous 703daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 704d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 7057164bc62SChau Ly } 706c181942fSQiang XU 7077164bc62SChau Ly inline void 7087164bc62SChau Ly handleChassisGet(App& app, const crow::Request& req, 7097164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7107164bc62SChau Ly const std::string& chassisId) 7117164bc62SChau Ly { 7127164bc62SChau Ly if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 7137164bc62SChau Ly { 7147164bc62SChau Ly return; 7157164bc62SChau Ly } 7167164bc62SChau Ly constexpr std::array<std::string_view, 2> interfaces = { 7177164bc62SChau Ly "xyz.openbmc_project.Inventory.Item.Board", 7187164bc62SChau Ly "xyz.openbmc_project.Inventory.Item.Chassis"}; 7197164bc62SChau Ly 7207164bc62SChau Ly dbus::utility::getSubTree( 7217164bc62SChau Ly "/xyz/openbmc_project/inventory", 0, interfaces, 7227164bc62SChau Ly std::bind_front(handleChassisGetSubTree, asyncResp, chassisId)); 7237164bc62SChau Ly 7247164bc62SChau Ly constexpr std::array<std::string_view, 1> interfaces2 = { 7257164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion"}; 7267164bc62SChau Ly 7277164bc62SChau Ly dbus::utility::getSubTree( 7287164bc62SChau Ly "/xyz/openbmc_project", 0, interfaces2, 7297164bc62SChau Ly std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp)); 730cf7eba09SNan Zhou } 7311c8fba97SJames Feist 732cf7eba09SNan Zhou inline void 733cf7eba09SNan Zhou handleChassisPatch(App& app, const crow::Request& req, 7347e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 735cf7eba09SNan Zhou const std::string& param) 736cf7eba09SNan Zhou { 7373ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 73845ca1b86SEd Tanous { 73945ca1b86SEd Tanous return; 74045ca1b86SEd Tanous } 7419f8bfa7cSGunnar Mills std::optional<bool> locationIndicatorActive; 7421c8fba97SJames Feist std::optional<std::string> indicatorLed; 7431c8fba97SJames Feist 7447e860f15SJohn Edward Broadbent if (param.empty()) 7451c8fba97SJames Feist { 7461c8fba97SJames Feist return; 7471c8fba97SJames Feist } 7481c8fba97SJames Feist 749afc474aeSMyung Bae if (!json_util::readJsonPatch( // 750afc474aeSMyung Bae req, asyncResp->res, // 751afc474aeSMyung Bae "IndicatorLED", indicatorLed, // 752afc474aeSMyung Bae "LocationIndicatorActive", locationIndicatorActive // 753afc474aeSMyung Bae )) 7541c8fba97SJames Feist { 7551c8fba97SJames Feist return; 7561c8fba97SJames Feist } 7571c8fba97SJames Feist 7589f8bfa7cSGunnar Mills // TODO (Gunnar): Remove IndicatorLED after enough time has passed 7599f8bfa7cSGunnar Mills if (!locationIndicatorActive && !indicatorLed) 7601c8fba97SJames Feist { 7611c8fba97SJames Feist return; // delete this when we support more patch properties 7621c8fba97SJames Feist } 763d6aa0093SGunnar Mills if (indicatorLed) 764d6aa0093SGunnar Mills { 7657e860f15SJohn Edward Broadbent asyncResp->res.addHeader( 7667e860f15SJohn Edward Broadbent boost::beast::http::field::warning, 7670fda0f12SGeorge Liu "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\""); 768d6aa0093SGunnar Mills } 7691c8fba97SJames Feist 770e99073f5SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 7711c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board", 7721c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Chassis"}; 7731c8fba97SJames Feist 7747e860f15SJohn Edward Broadbent const std::string& chassisId = param; 7751c8fba97SJames Feist 776e99073f5SGeorge Liu dbus::utility::getSubTree( 777e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 778cf7eba09SNan Zhou [asyncResp, chassisId, locationIndicatorActive, 7795e7e2dc5SEd Tanous indicatorLed](const boost::system::error_code& ec, 780b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 7811c8fba97SJames Feist if (ec) 7821c8fba97SJames Feist { 78362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 7841c8fba97SJames Feist messages::internalError(asyncResp->res); 7851c8fba97SJames Feist return; 7861c8fba97SJames Feist } 7871c8fba97SJames Feist 7881c8fba97SJames Feist // Iterate over all retrieved ObjectPaths. 789bd79bce8SPatrick Williams for (const std::pair<std::string, 790bd79bce8SPatrick Williams std::vector<std::pair< 791bd79bce8SPatrick Williams std::string, std::vector<std::string>>>>& 7921214b7e7SGunnar Mills object : subtree) 7931c8fba97SJames Feist { 7941c8fba97SJames Feist const std::string& path = object.first; 795bd79bce8SPatrick Williams const std::vector< 796bd79bce8SPatrick Williams std::pair<std::string, std::vector<std::string>>>& 7971214b7e7SGunnar Mills connectionNames = object.second; 7981c8fba97SJames Feist 799997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 800997093ebSGeorge Liu if (objPath.filename() != chassisId) 8011c8fba97SJames Feist { 8021c8fba97SJames Feist continue; 8031c8fba97SJames Feist } 8041c8fba97SJames Feist 80526f6976fSEd Tanous if (connectionNames.empty()) 8061c8fba97SJames Feist { 80762598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 8081c8fba97SJames Feist continue; 8091c8fba97SJames Feist } 8101c8fba97SJames Feist 81123a21a1cSEd Tanous const std::vector<std::string>& interfaces3 = 8121c8fba97SJames Feist connectionNames[0].second; 8131c8fba97SJames Feist 814e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 815e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 8161c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 8170fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 8181c8fba97SJames Feist bool indicatorChassis = false; 8191c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 8201c8fba97SJames Feist { 8213544d2a7SEd Tanous if (std::ranges::find(interfaces3, interface) != 8223544d2a7SEd Tanous interfaces3.end()) 8231c8fba97SJames Feist { 8241c8fba97SJames Feist indicatorChassis = true; 8251c8fba97SJames Feist break; 8261c8fba97SJames Feist } 8271c8fba97SJames Feist } 8289f8bfa7cSGunnar Mills if (locationIndicatorActive) 8299f8bfa7cSGunnar Mills { 8309f8bfa7cSGunnar Mills if (indicatorChassis) 8319f8bfa7cSGunnar Mills { 832bd79bce8SPatrick Williams setSystemLocationIndicatorActive( 833bd79bce8SPatrick Williams asyncResp, *locationIndicatorActive); 8349f8bfa7cSGunnar Mills } 8359f8bfa7cSGunnar Mills else 8369f8bfa7cSGunnar Mills { 837002d39b4SEd Tanous messages::propertyUnknown(asyncResp->res, 838002d39b4SEd Tanous "LocationIndicatorActive"); 8399f8bfa7cSGunnar Mills } 8409f8bfa7cSGunnar Mills } 8419f8bfa7cSGunnar Mills if (indicatorLed) 8429f8bfa7cSGunnar Mills { 8431c8fba97SJames Feist if (indicatorChassis) 8441c8fba97SJames Feist { 845f23b7296SEd Tanous setIndicatorLedState(asyncResp, *indicatorLed); 8461c8fba97SJames Feist } 8471c8fba97SJames Feist else 8481c8fba97SJames Feist { 849bd79bce8SPatrick Williams messages::propertyUnknown(asyncResp->res, 850bd79bce8SPatrick Williams "IndicatorLED"); 8511c8fba97SJames Feist } 8521c8fba97SJames Feist } 8531c8fba97SJames Feist return; 8541c8fba97SJames Feist } 8551c8fba97SJames Feist 856d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 857e99073f5SGeorge Liu }); 858cf7eba09SNan Zhou } 859cf7eba09SNan Zhou 860cf7eba09SNan Zhou /** 861cf7eba09SNan Zhou * Chassis override class for delivering Chassis Schema 862cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 863cf7eba09SNan Zhou */ 864cf7eba09SNan Zhou inline void requestRoutesChassis(App& app) 865cf7eba09SNan Zhou { 866cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 867cf7eba09SNan Zhou .privileges(redfish::privileges::getChassis) 868cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 869cf7eba09SNan Zhou std::bind_front(handleChassisGet, std::ref(app))); 870cf7eba09SNan Zhou 871cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 872cf7eba09SNan Zhou .privileges(redfish::privileges::patchChassis) 873cf7eba09SNan Zhou .methods(boost::beast::http::verb::patch)( 874cf7eba09SNan Zhou std::bind_front(handleChassisPatch, std::ref(app))); 8751c8fba97SJames Feist } 876dd99e04bSP.K. Lee 8778d1b46d7Szhanghch05 inline void 8788d1b46d7Szhanghch05 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 879dd99e04bSP.K. Lee { 8807a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 881c3b3c92aSVijay Khemka "xyz.openbmc_project.State.Chassis"}; 882c3b3c92aSVijay Khemka 883c3b3c92aSVijay Khemka // Use mapper to get subtree paths. 8847a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 8857a1dbc48SGeorge Liu "/", 0, interfaces, 886b9d36b47SEd Tanous [asyncResp]( 8877a1dbc48SGeorge Liu const boost::system::error_code& ec, 888b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& chassisList) { 889c3b3c92aSVijay Khemka if (ec) 890c3b3c92aSVijay Khemka { 89162598e31SEd Tanous BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec); 892c3b3c92aSVijay Khemka messages::internalError(asyncResp->res); 893c3b3c92aSVijay Khemka return; 894c3b3c92aSVijay Khemka } 895c3b3c92aSVijay Khemka 896dd99e04bSP.K. Lee const char* processName = "xyz.openbmc_project.State.Chassis"; 897dd99e04bSP.K. Lee const char* interfaceName = "xyz.openbmc_project.State.Chassis"; 898dd99e04bSP.K. Lee const char* destProperty = "RequestedPowerTransition"; 899dd99e04bSP.K. Lee const std::string propertyValue = 900dd99e04bSP.K. Lee "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; 901bd79bce8SPatrick Williams std::string objectPath = 902bd79bce8SPatrick Williams "/xyz/openbmc_project/state/chassis_system0"; 903c3b3c92aSVijay Khemka 904c3b3c92aSVijay Khemka /* Look for system reset chassis path */ 905bd79bce8SPatrick Williams if ((std::ranges::find(chassisList, objectPath)) == 906bd79bce8SPatrick Williams chassisList.end()) 907c3b3c92aSVijay Khemka { 908c3b3c92aSVijay Khemka /* We prefer to reset the full chassis_system, but if it doesn't 909c3b3c92aSVijay Khemka * exist on some platforms, fall back to a host-only power reset 910c3b3c92aSVijay Khemka */ 911c3b3c92aSVijay Khemka objectPath = "/xyz/openbmc_project/state/chassis0"; 912c3b3c92aSVijay Khemka } 913dd99e04bSP.K. Lee 914e93abac6SGinu George setDbusProperty(asyncResp, "ResetType", processName, objectPath, 915e93abac6SGinu George interfaceName, destProperty, propertyValue); 9167a1dbc48SGeorge Liu }); 917dd99e04bSP.K. Lee } 918dd99e04bSP.K. Lee 919cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost( 920cf7eba09SNan Zhou App& app, const crow::Request& req, 9217e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 922cf7eba09SNan Zhou const std::string& /*chassisId*/) 923cf7eba09SNan Zhou { 9243ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 92545ca1b86SEd Tanous { 92645ca1b86SEd Tanous return; 92745ca1b86SEd Tanous } 92862598e31SEd Tanous BMCWEB_LOG_DEBUG("Post Chassis Reset."); 929dd99e04bSP.K. Lee 930dd99e04bSP.K. Lee std::string resetType; 931dd99e04bSP.K. Lee 932cf7eba09SNan Zhou if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 933dd99e04bSP.K. Lee { 934dd99e04bSP.K. Lee return; 935dd99e04bSP.K. Lee } 936dd99e04bSP.K. Lee 937dd99e04bSP.K. Lee if (resetType != "PowerCycle") 938dd99e04bSP.K. Lee { 93962598e31SEd Tanous BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType); 940002d39b4SEd Tanous messages::actionParameterNotSupported(asyncResp->res, resetType, 941002d39b4SEd Tanous "ResetType"); 942dd99e04bSP.K. Lee 943dd99e04bSP.K. Lee return; 944dd99e04bSP.K. Lee } 945dd99e04bSP.K. Lee doChassisPowerCycle(asyncResp); 946dd99e04bSP.K. Lee } 9471cb1a9e6SAppaRao Puli 9481cb1a9e6SAppaRao Puli /** 949cf7eba09SNan Zhou * ChassisResetAction class supports the POST method for the Reset 950cf7eba09SNan Zhou * action. 951cf7eba09SNan Zhou * Function handles POST method request. 952cf7eba09SNan Zhou * Analyzes POST body before sending Reset request data to D-Bus. 9531cb1a9e6SAppaRao Puli */ 954cf7eba09SNan Zhou 955cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app) 9561cb1a9e6SAppaRao Puli { 957cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/") 958cf7eba09SNan Zhou .privileges(redfish::privileges::postChassis) 959cf7eba09SNan Zhou .methods(boost::beast::http::verb::post)( 960cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoPost, std::ref(app))); 961cf7eba09SNan Zhou } 962cf7eba09SNan Zhou 963cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet( 964cf7eba09SNan Zhou App& app, const crow::Request& req, 9657e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 966cf7eba09SNan Zhou const std::string& chassisId) 967cf7eba09SNan Zhou { 9683ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 9691cb1a9e6SAppaRao Puli { 97045ca1b86SEd Tanous return; 97145ca1b86SEd Tanous } 972cf7eba09SNan Zhou asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 973ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 974ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId); 9751476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 9761476687dSEd Tanous 9771476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 9785b9e95a1SNan Zhou nlohmann::json::array_t parameters; 9795b9e95a1SNan Zhou nlohmann::json::object_t parameter; 9805b9e95a1SNan Zhou parameter["Name"] = "ResetType"; 9815b9e95a1SNan Zhou parameter["Required"] = true; 982539d8c6bSEd Tanous parameter["DataType"] = action_info::ParameterTypes::String; 9831476687dSEd Tanous nlohmann::json::array_t allowed; 984ad539545SPatrick Williams allowed.emplace_back("PowerCycle"); 9855b9e95a1SNan Zhou parameter["AllowableValues"] = std::move(allowed); 986ad539545SPatrick Williams parameters.emplace_back(std::move(parameter)); 9875b9e95a1SNan Zhou 9881476687dSEd Tanous asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 989cf7eba09SNan Zhou } 990cf7eba09SNan Zhou 991cf7eba09SNan Zhou /** 992cf7eba09SNan Zhou * ChassisResetActionInfo derived class for delivering Chassis 993cf7eba09SNan Zhou * ResetType AllowableValues using ResetInfo schema. 994cf7eba09SNan Zhou */ 995cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app) 996cf7eba09SNan Zhou { 997cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/") 998cf7eba09SNan Zhou .privileges(redfish::privileges::getActionInfo) 999cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 1000cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoGet, std::ref(app))); 10011cb1a9e6SAppaRao Puli } 10021cb1a9e6SAppaRao Puli 1003e37f8451SRapkiewicz, Pawel } // namespace redfish 1004