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 6d7857201SEd Tanous #include "bmcweb_config.h" 7d7857201SEd Tanous 83ccb3adbSEd Tanous #include "app.hpp" 9d7857201SEd Tanous #include "async_resp.hpp" 10d7857201SEd Tanous #include "dbus_singleton.hpp" 117a1dbc48SGeorge Liu #include "dbus_utility.hpp" 12d7857201SEd 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" 16d7857201SEd Tanous #include "http_request.hpp" 171c8fba97SJames Feist #include "led.hpp" 18d7857201SEd Tanous #include "logging.hpp" 193ccb3adbSEd Tanous #include "query.hpp" 203ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 213f95a277SMyung Bae #include "utils/chassis_utils.hpp" 223ccb3adbSEd Tanous #include "utils/collection.hpp" 233ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 24cf7eba09SNan Zhou #include "utils/json_utils.hpp" 251abe55efSEd Tanous 26d7857201SEd Tanous #include <asm-generic/errno.h> 27d7857201SEd Tanous 28d7857201SEd Tanous #include <boost/beast/http/field.hpp> 29d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 30e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 31ef4c65b7SEd Tanous #include <boost/url/format.hpp> 32d7857201SEd Tanous #include <boost/url/url.hpp> 33d7857201SEd Tanous #include <nlohmann/json.hpp> 34d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 3586d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 361214b7e7SGunnar Mills 37d7857201SEd Tanous #include <algorithm> 387a1dbc48SGeorge Liu #include <array> 39d7857201SEd Tanous #include <format> 40d7857201SEd Tanous #include <functional> 412952f648SJoseph-Jonathan Salzano #include <memory> 42d7857201SEd Tanous #include <optional> 433544d2a7SEd Tanous #include <ranges> 44d7857201SEd Tanous #include <string> 457a1dbc48SGeorge Liu #include <string_view> 46d7857201SEd Tanous #include <utility> 47d7857201SEd Tanous #include <vector> 487a1dbc48SGeorge Liu 491abe55efSEd Tanous namespace redfish 501abe55efSEd Tanous { 51e37f8451SRapkiewicz, Pawel 52504af5a0SPatrick Williams inline chassis::ChassisType translateChassisTypeToRedfish( 53504af5a0SPatrick Williams 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 { 156deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 157deae6a78SEd Tanous "xyz.openbmc_project.State.Chassis", 1581e1e598dSJonathan Doman "/xyz/openbmc_project/state/chassis0", 1591e1e598dSJonathan Doman "xyz.openbmc_project.State.Chassis", "CurrentPowerState", 160ac106bf6SEd Tanous [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec, 1611e1e598dSJonathan Doman const std::string& chassisState) { 162beeca0aeSGunnar Mills if (ec) 163beeca0aeSGunnar Mills { 164a6e5e0abSCarson Labrado if (ec == boost::system::errc::host_unreachable) 165a6e5e0abSCarson Labrado { 166a6e5e0abSCarson Labrado // Service not available, no error, just don't return 167a6e5e0abSCarson Labrado // chassis state info 16862598e31SEd Tanous BMCWEB_LOG_DEBUG("Service not available {}", ec); 169a6e5e0abSCarson Labrado return; 170a6e5e0abSCarson Labrado } 17162598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 172ac106bf6SEd Tanous messages::internalError(asyncResp->res); 173beeca0aeSGunnar Mills return; 174beeca0aeSGunnar Mills } 175beeca0aeSGunnar Mills 17662598e31SEd Tanous BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState); 177beeca0aeSGunnar Mills // Verify Chassis State 178bd79bce8SPatrick Williams if (chassisState == 179bd79bce8SPatrick Williams "xyz.openbmc_project.State.Chassis.PowerState.On") 180beeca0aeSGunnar Mills { 181bd79bce8SPatrick Williams asyncResp->res.jsonValue["PowerState"] = 182bd79bce8SPatrick Williams resource::PowerState::On; 183539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 184539d8c6bSEd Tanous resource::State::Enabled; 185beeca0aeSGunnar Mills } 1861e1e598dSJonathan Doman else if (chassisState == 187beeca0aeSGunnar Mills "xyz.openbmc_project.State.Chassis.PowerState.Off") 188beeca0aeSGunnar Mills { 189bd79bce8SPatrick Williams asyncResp->res.jsonValue["PowerState"] = 190bd79bce8SPatrick Williams resource::PowerState::Off; 191539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 192539d8c6bSEd Tanous resource::State::StandbyOffline; 193beeca0aeSGunnar Mills } 1941e1e598dSJonathan Doman }); 195beeca0aeSGunnar Mills } 196beeca0aeSGunnar Mills 197c181942fSQiang XU /** 198c181942fSQiang XU * Retrieves physical security properties over dbus 199c181942fSQiang XU */ 2007164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree( 2017164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 202e99073f5SGeorge Liu const boost::system::error_code& ec, 2037164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 2047164bc62SChau Ly { 205c181942fSQiang XU if (ec) 206c181942fSQiang XU { 2074e0453b1SGunnar Mills // do not add err msg in redfish response, because this is not 208c181942fSQiang XU // mandatory property 20962598e31SEd Tanous BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec); 210c181942fSQiang XU return; 211c181942fSQiang XU } 212c181942fSQiang XU // Iterate over all retrieved ObjectPaths. 213c181942fSQiang XU for (const auto& object : subtree) 214c181942fSQiang XU { 215840a9ffcSPatrick Williams if (!object.second.empty()) 216c181942fSQiang XU { 21789144a3aSEd Tanous const auto& service = object.second.front(); 2187164bc62SChau Ly 2197164bc62SChau Ly BMCWEB_LOG_DEBUG("Get intrusion status by service "); 2207164bc62SChau Ly 221deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 222deae6a78SEd Tanous service.first, object.first, 2237164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion", "Status", 2247164bc62SChau Ly [asyncResp](const boost::system::error_code& ec1, 2257164bc62SChau Ly const std::string& value) { 2267164bc62SChau Ly if (ec1) 2277164bc62SChau Ly { 228bd79bce8SPatrick Williams // do not add err msg in redfish response, because this 229bd79bce8SPatrick Williams // is not 2307164bc62SChau Ly // mandatory property 2317164bc62SChau Ly BMCWEB_LOG_ERROR("DBUS response error {}", ec1); 2327164bc62SChau Ly return; 2337164bc62SChau Ly } 234bd79bce8SPatrick Williams asyncResp->res.jsonValue["PhysicalSecurity"] 235bd79bce8SPatrick Williams ["IntrusionSensorNumber"] = 1; 2367164bc62SChau Ly asyncResp->res 237bd79bce8SPatrick Williams .jsonValue["PhysicalSecurity"]["IntrusionSensor"] = 238bd79bce8SPatrick Williams value; 2397164bc62SChau Ly }); 2407164bc62SChau Ly 241c181942fSQiang XU return; 242c181942fSQiang XU } 243c181942fSQiang XU } 244c181942fSQiang XU } 245c181942fSQiang XU 246cf7eba09SNan Zhou inline void handleChassisCollectionGet( 247cf7eba09SNan Zhou App& app, const crow::Request& req, 248cf7eba09SNan Zhou const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2491abe55efSEd Tanous { 2503ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 25145ca1b86SEd Tanous { 25245ca1b86SEd Tanous return; 25345ca1b86SEd Tanous } 2548d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 2558d1b46d7Szhanghch05 "#ChassisCollection.ChassisCollection"; 2568d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 2578d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 258e37f8451SRapkiewicz, Pawel 25902f6ff19SGunnar Mills collection_util::getCollectionMembers( 2603f95a277SMyung Bae asyncResp, boost::urls::url("/redfish/v1/Chassis"), chassisInterfaces, 26136b5f1edSLakshmi Yadlapati "/xyz/openbmc_project/inventory"); 262cf7eba09SNan Zhou } 263cf7eba09SNan Zhou 264a5617496SJie Yang inline void getChassisContainedBy( 265a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 266a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 26728ee563eSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& upstreamChassisPaths) 268a5617496SJie Yang { 269a5617496SJie Yang if (ec) 270a5617496SJie Yang { 271a5617496SJie Yang if (ec.value() != EBADR) 272a5617496SJie Yang { 27362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 274a5617496SJie Yang messages::internalError(asyncResp->res); 275a5617496SJie Yang } 276a5617496SJie Yang return; 277a5617496SJie Yang } 278a5617496SJie Yang if (upstreamChassisPaths.empty()) 279a5617496SJie Yang { 280a5617496SJie Yang return; 281a5617496SJie Yang } 282a5617496SJie Yang if (upstreamChassisPaths.size() > 1) 283a5617496SJie Yang { 2848ece0e45SEd Tanous BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId); 285a5617496SJie Yang messages::internalError(asyncResp->res); 286a5617496SJie Yang return; 287a5617496SJie Yang } 288a5617496SJie Yang 289a5617496SJie Yang sdbusplus::message::object_path upstreamChassisPath( 290a5617496SJie Yang upstreamChassisPaths[0]); 291a5617496SJie Yang std::string upstreamChassis = upstreamChassisPath.filename(); 292a5617496SJie Yang if (upstreamChassis.empty()) 293a5617496SJie Yang { 29462598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}", 29562598e31SEd Tanous upstreamChassisPath.str, chassisId); 296a5617496SJie Yang return; 297a5617496SJie Yang } 298a5617496SJie Yang 299a5617496SJie Yang asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] = 300a5617496SJie Yang boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis); 301a5617496SJie Yang } 302a5617496SJie Yang 303a5617496SJie Yang inline void getChassisContains( 304a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 305a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 30628ee563eSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& downstreamChassisPaths) 307a5617496SJie Yang { 308a5617496SJie Yang if (ec) 309a5617496SJie Yang { 310a5617496SJie Yang if (ec.value() != EBADR) 311a5617496SJie Yang { 31262598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 313a5617496SJie Yang messages::internalError(asyncResp->res); 314a5617496SJie Yang } 315a5617496SJie Yang return; 316a5617496SJie Yang } 317a5617496SJie Yang if (downstreamChassisPaths.empty()) 318a5617496SJie Yang { 319a5617496SJie Yang return; 320a5617496SJie Yang } 321a5617496SJie Yang nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"]; 322a5617496SJie Yang if (!jValue.is_array()) 323a5617496SJie Yang { 324a5617496SJie Yang // Create the array if it was empty 325a5617496SJie Yang jValue = nlohmann::json::array(); 326a5617496SJie Yang } 327a5617496SJie Yang for (const auto& p : downstreamChassisPaths) 328a5617496SJie Yang { 329a5617496SJie Yang sdbusplus::message::object_path downstreamChassisPath(p); 330a5617496SJie Yang std::string downstreamChassis = downstreamChassisPath.filename(); 331a5617496SJie Yang if (downstreamChassis.empty()) 332a5617496SJie Yang { 33362598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}", 33462598e31SEd Tanous downstreamChassisPath.str, chassisId); 335a5617496SJie Yang continue; 336a5617496SJie Yang } 337a5617496SJie Yang nlohmann::json link; 338bd79bce8SPatrick Williams link["@odata.id"] = 339bd79bce8SPatrick Williams boost::urls::format("/redfish/v1/Chassis/{}", downstreamChassis); 340a5617496SJie Yang jValue.push_back(std::move(link)); 341a5617496SJie Yang } 342a5617496SJie Yang asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size(); 343a5617496SJie Yang } 344a5617496SJie Yang 345bd79bce8SPatrick Williams inline void getChassisConnectivity( 346bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 347bd79bce8SPatrick Williams const std::string& chassisId, const std::string& chassisPath) 348a5617496SJie Yang { 34962598e31SEd Tanous BMCWEB_LOG_DEBUG("Get chassis connectivity"); 350a5617496SJie Yang 35128ee563eSMyung Bae dbus::utility::getAssociatedSubTreePaths( 352a5617496SJie Yang chassisPath + "/contained_by", 35328ee563eSMyung Bae sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 3543f95a277SMyung Bae chassisInterfaces, 355a5617496SJie Yang std::bind_front(getChassisContainedBy, asyncResp, chassisId)); 356a5617496SJie Yang 35728ee563eSMyung Bae dbus::utility::getAssociatedSubTreePaths( 358a5617496SJie Yang chassisPath + "/containing", 35928ee563eSMyung Bae sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 3603f95a277SMyung Bae chassisInterfaces, 3613f95a277SMyung Bae std::bind_front(getChassisContains, asyncResp, chassisId)); 362a5617496SJie Yang } 363a5617496SJie Yang 364cf7eba09SNan Zhou /** 365cf7eba09SNan Zhou * ChassisCollection derived class for delivering Chassis Collection Schema 366cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 367cf7eba09SNan Zhou */ 368cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app) 369cf7eba09SNan Zhou { 370cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/") 371cf7eba09SNan Zhou .privileges(redfish::privileges::getChassisCollection) 372cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 373cf7eba09SNan Zhou std::bind_front(handleChassisCollectionGet, std::ref(app))); 37462d5e2e4SEd Tanous } 375e37f8451SRapkiewicz, Pawel 376bd79bce8SPatrick Williams inline void getChassisLocationCode( 377bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 378bd79bce8SPatrick Williams const std::string& connectionName, const std::string& path) 379308f70c7SWilly Tu { 380deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 381deae6a78SEd Tanous connectionName, path, 3821e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 3835e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3841e1e598dSJonathan Doman const std::string& property) { 385308f70c7SWilly Tu if (ec) 386308f70c7SWilly Tu { 38762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location"); 388308f70c7SWilly Tu messages::internalError(asyncResp->res); 389308f70c7SWilly Tu return; 390308f70c7SWilly Tu } 391308f70c7SWilly Tu 392bd79bce8SPatrick Williams asyncResp->res 393bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 3941e1e598dSJonathan Doman property; 3951e1e598dSJonathan Doman }); 396308f70c7SWilly Tu } 397308f70c7SWilly Tu 398308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 399308f70c7SWilly Tu const std::string& connectionName, 400308f70c7SWilly Tu const std::string& path) 401308f70c7SWilly Tu { 402deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 403deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Common.UUID", "UUID", 4045e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 4051e1e598dSJonathan Doman const std::string& chassisUUID) { 406308f70c7SWilly Tu if (ec) 407308f70c7SWilly Tu { 40862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for UUID"); 409308f70c7SWilly Tu messages::internalError(asyncResp->res); 410308f70c7SWilly Tu return; 411308f70c7SWilly Tu } 4121e1e598dSJonathan Doman asyncResp->res.jsonValue["UUID"] = chassisUUID; 4131e1e598dSJonathan Doman }); 414308f70c7SWilly Tu } 415308f70c7SWilly Tu 4167164bc62SChau Ly inline void handleDecoratorAssetProperties( 41745ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4187164bc62SChau Ly const std::string& chassisId, const std::string& path, 4197164bc62SChau Ly const dbus::utility::DBusPropertiesMap& propertiesList) 420cf7eba09SNan Zhou { 4217164bc62SChau Ly const std::string* partNumber = nullptr; 4227164bc62SChau Ly const std::string* serialNumber = nullptr; 4237164bc62SChau Ly const std::string* manufacturer = nullptr; 4247164bc62SChau Ly const std::string* model = nullptr; 4257164bc62SChau Ly const std::string* sparePartNumber = nullptr; 4267164bc62SChau Ly 4277164bc62SChau Ly const bool success = sdbusplus::unpackPropertiesNoThrow( 4287164bc62SChau Ly dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 4297164bc62SChau Ly partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, 4307164bc62SChau Ly "Model", model, "SparePartNumber", sparePartNumber); 4317164bc62SChau Ly 4327164bc62SChau Ly if (!success) 43345ca1b86SEd Tanous { 4347164bc62SChau Ly messages::internalError(asyncResp->res); 43545ca1b86SEd Tanous return; 43645ca1b86SEd Tanous } 437734bfe90SGunnar Mills 4387164bc62SChau Ly if (partNumber != nullptr) 4397164bc62SChau Ly { 4407164bc62SChau Ly asyncResp->res.jsonValue["PartNumber"] = *partNumber; 4417164bc62SChau Ly } 4427164bc62SChau Ly 4437164bc62SChau Ly if (serialNumber != nullptr) 4447164bc62SChau Ly { 4457164bc62SChau Ly asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 4467164bc62SChau Ly } 4477164bc62SChau Ly 4487164bc62SChau Ly if (manufacturer != nullptr) 4497164bc62SChau Ly { 4507164bc62SChau Ly asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 4517164bc62SChau Ly } 4527164bc62SChau Ly 4537164bc62SChau Ly if (model != nullptr) 4547164bc62SChau Ly { 4557164bc62SChau Ly asyncResp->res.jsonValue["Model"] = *model; 4567164bc62SChau Ly } 4577164bc62SChau Ly 4587164bc62SChau Ly // SparePartNumber is optional on D-Bus 4597164bc62SChau Ly // so skip if it is empty 4607164bc62SChau Ly if (sparePartNumber != nullptr && !sparePartNumber->empty()) 4617164bc62SChau Ly { 4627164bc62SChau Ly asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 4637164bc62SChau Ly } 4647164bc62SChau Ly 4657164bc62SChau Ly asyncResp->res.jsonValue["Name"] = chassisId; 4667164bc62SChau Ly asyncResp->res.jsonValue["Id"] = chassisId; 46725b54dbaSEd Tanous 46825b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL) 46925b54dbaSEd Tanous { 4707164bc62SChau Ly asyncResp->res.jsonValue["Thermal"]["@odata.id"] = 4717164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId); 4727164bc62SChau Ly // Power object 4737164bc62SChau Ly asyncResp->res.jsonValue["Power"]["@odata.id"] = 4747164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId); 47525b54dbaSEd Tanous } 47625b54dbaSEd Tanous 47725b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM) 47825b54dbaSEd Tanous { 4797164bc62SChau Ly asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] = 4807164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem", 4817164bc62SChau Ly chassisId); 4827164bc62SChau Ly asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] = 48325b54dbaSEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", 48425b54dbaSEd Tanous chassisId); 4857164bc62SChau Ly asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] = 4867164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics", 4877164bc62SChau Ly chassisId); 48825b54dbaSEd Tanous } 4897164bc62SChau Ly // SensorCollection 4907164bc62SChau Ly asyncResp->res.jsonValue["Sensors"]["@odata.id"] = 4917164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId); 492539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 4937164bc62SChau Ly 4947164bc62SChau Ly nlohmann::json::array_t computerSystems; 4957164bc62SChau Ly nlohmann::json::object_t system; 496bd79bce8SPatrick Williams system["@odata.id"] = 497bd79bce8SPatrick Williams std::format("/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME); 4987164bc62SChau Ly computerSystems.emplace_back(std::move(system)); 4997164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ComputerSystems"] = 5007164bc62SChau Ly std::move(computerSystems); 5017164bc62SChau Ly 5027164bc62SChau Ly nlohmann::json::array_t managedBy; 5037164bc62SChau Ly nlohmann::json::object_t manager; 504253f11b8SEd Tanous manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}", 505253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 5067164bc62SChau Ly managedBy.emplace_back(std::move(manager)); 5077164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); 5087164bc62SChau Ly getChassisState(asyncResp); 5097164bc62SChau Ly getStorageLink(asyncResp, path); 5107164bc62SChau Ly } 5117164bc62SChau Ly 5122952f648SJoseph-Jonathan Salzano inline void handleChassisProperties( 5132952f648SJoseph-Jonathan Salzano const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5142952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) 5152952f648SJoseph-Jonathan Salzano { 5162952f648SJoseph-Jonathan Salzano const std::string* type = nullptr; 5172952f648SJoseph-Jonathan Salzano 5182952f648SJoseph-Jonathan Salzano const bool success = sdbusplus::unpackPropertiesNoThrow( 5192952f648SJoseph-Jonathan Salzano dbus_utils::UnpackErrorPrinter(), propertiesList, "Type", type); 5202952f648SJoseph-Jonathan Salzano 5212952f648SJoseph-Jonathan Salzano if (!success) 5222952f648SJoseph-Jonathan Salzano { 5232952f648SJoseph-Jonathan Salzano messages::internalError(asyncResp->res); 5242952f648SJoseph-Jonathan Salzano return; 5252952f648SJoseph-Jonathan Salzano } 5262952f648SJoseph-Jonathan Salzano 52719ea2864SGunnar Mills // Chassis Type is a required property in Redfish 52819ea2864SGunnar Mills // If there is an error or some enum we don't support just sit it to Rack 52919ea2864SGunnar Mills // Mount 53019ea2864SGunnar Mills asyncResp->res.jsonValue["ChassisType"] = chassis::ChassisType::RackMount; 53119ea2864SGunnar Mills 5322952f648SJoseph-Jonathan Salzano if (type != nullptr) 5332952f648SJoseph-Jonathan Salzano { 5342952f648SJoseph-Jonathan Salzano auto chassisType = translateChassisTypeToRedfish(*type); 5352952f648SJoseph-Jonathan Salzano if (chassisType != chassis::ChassisType::Invalid) 5362952f648SJoseph-Jonathan Salzano { 5372952f648SJoseph-Jonathan Salzano asyncResp->res.jsonValue["ChassisType"] = chassisType; 5382952f648SJoseph-Jonathan Salzano } 5392952f648SJoseph-Jonathan Salzano } 5402952f648SJoseph-Jonathan Salzano } 5412952f648SJoseph-Jonathan Salzano 5427164bc62SChau Ly inline void handleChassisGetSubTree( 5437164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5447164bc62SChau Ly const std::string& chassisId, const boost::system::error_code& ec, 5457164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 5467164bc62SChau Ly { 54762d5e2e4SEd Tanous if (ec) 5481abe55efSEd Tanous { 54962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 550f12894f8SJason M. Bills messages::internalError(asyncResp->res); 551daf36e2eSEd Tanous return; 552daf36e2eSEd Tanous } 553daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 554cf7eba09SNan Zhou for (const std::pair< 555cf7eba09SNan Zhou std::string, 556cf7eba09SNan Zhou std::vector<std::pair<std::string, std::vector<std::string>>>>& 5571214b7e7SGunnar Mills object : subtree) 5581abe55efSEd Tanous { 559daf36e2eSEd Tanous const std::string& path = object.first; 560cf7eba09SNan Zhou const std::vector<std::pair<std::string, std::vector<std::string>>>& 5611214b7e7SGunnar Mills connectionNames = object.second; 5627e860f15SJohn Edward Broadbent 563997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 564997093ebSGeorge Liu if (objPath.filename() != chassisId) 5651abe55efSEd Tanous { 566daf36e2eSEd Tanous continue; 567daf36e2eSEd Tanous } 56826f03899SShawn McCarney 569a5617496SJie Yang getChassisConnectivity(asyncResp, chassisId, path); 570a5617496SJie Yang 57126f6976fSEd Tanous if (connectionNames.empty()) 5721abe55efSEd Tanous { 57362598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 574e0d918bcSEd Tanous continue; 575daf36e2eSEd Tanous } 576e0d918bcSEd Tanous 5777164bc62SChau Ly asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis"; 57849c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.id"] = 579ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 58049c53ac9SJohnathan Mantey asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 581cf7eba09SNan Zhou asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] = 5827164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset", 5837164bc62SChau Ly chassisId); 5841476687dSEd Tanous asyncResp->res 585cf7eba09SNan Zhou .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] = 586ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo", 587ef4c65b7SEd Tanous chassisId); 5886c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 5896c3e9451SGeorge Liu path + "/drive", 5907164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec3, 5916c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 59292903bd4SJohn Edward Broadbent if (ec3 || resp.empty()) 59392903bd4SJohn Edward Broadbent { 59492903bd4SJohn Edward Broadbent return; // no drives = no failures 59592903bd4SJohn Edward Broadbent } 59692903bd4SJohn Edward Broadbent 59792903bd4SJohn Edward Broadbent nlohmann::json reference; 598bd79bce8SPatrick Williams reference["@odata.id"] = boost::urls::format( 599bd79bce8SPatrick Williams "/redfish/v1/Chassis/{}/Drives", chassisId); 60092903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Drives"] = std::move(reference); 60192903bd4SJohn Edward Broadbent }); 60292903bd4SJohn Edward Broadbent 603002d39b4SEd Tanous const std::string& connectionName = connectionNames[0].first; 6041c8fba97SJames Feist 6057164bc62SChau Ly const std::vector<std::string>& interfaces2 = connectionNames[0].second; 606e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 607e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 6081c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 6090fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 6101c8fba97SJames Feist 611476b9cc5STejas Patil const std::string assetTagInterface = 6120fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.AssetTag"; 613523d4868SLogananth Sundararaj const std::string replaceableInterface = 614523d4868SLogananth Sundararaj "xyz.openbmc_project.Inventory.Decorator.Replaceable"; 615b4d593f1SCarson Labrado const std::string revisionInterface = 616b4d593f1SCarson Labrado "xyz.openbmc_project.Inventory.Decorator.Revision"; 617523d4868SLogananth Sundararaj for (const auto& interface : interfaces2) 618523d4868SLogananth Sundararaj { 619523d4868SLogananth Sundararaj if (interface == assetTagInterface) 620476b9cc5STejas Patil { 621deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 622deae6a78SEd Tanous connectionName, path, assetTagInterface, "AssetTag", 6237164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 6241e1e598dSJonathan Doman const std::string& property) { 6258a592810SEd Tanous if (ec2) 626476b9cc5STejas Patil { 627bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 628bd79bce8SPatrick Williams "DBus response error for AssetTag: {}", ec2); 629476b9cc5STejas Patil messages::internalError(asyncResp->res); 630476b9cc5STejas Patil return; 631476b9cc5STejas Patil } 632002d39b4SEd Tanous asyncResp->res.jsonValue["AssetTag"] = property; 6331e1e598dSJonathan Doman }); 634476b9cc5STejas Patil } 635523d4868SLogananth Sundararaj else if (interface == replaceableInterface) 636523d4868SLogananth Sundararaj { 637deae6a78SEd Tanous dbus::utility::getProperty<bool>( 638deae6a78SEd Tanous connectionName, path, replaceableInterface, "HotPluggable", 6397164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 640523d4868SLogananth Sundararaj const bool property) { 641523d4868SLogananth Sundararaj if (ec2) 642523d4868SLogananth Sundararaj { 64362598e31SEd Tanous BMCWEB_LOG_ERROR( 644bd79bce8SPatrick Williams "DBus response error for HotPluggable: {}", 645bd79bce8SPatrick Williams ec2); 646523d4868SLogananth Sundararaj messages::internalError(asyncResp->res); 647523d4868SLogananth Sundararaj return; 648523d4868SLogananth Sundararaj } 649523d4868SLogananth Sundararaj asyncResp->res.jsonValue["HotPluggable"] = property; 650523d4868SLogananth Sundararaj }); 651523d4868SLogananth Sundararaj } 652b4d593f1SCarson Labrado else if (interface == revisionInterface) 653b4d593f1SCarson Labrado { 654deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 655deae6a78SEd Tanous connectionName, path, revisionInterface, "Version", 656b4d593f1SCarson Labrado [asyncResp, chassisId](const boost::system::error_code& ec2, 657b4d593f1SCarson Labrado const std::string& property) { 658b4d593f1SCarson Labrado if (ec2) 659b4d593f1SCarson Labrado { 660bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 661bd79bce8SPatrick Williams "DBus response error for Version: {}", ec2); 662b4d593f1SCarson Labrado messages::internalError(asyncResp->res); 663b4d593f1SCarson Labrado return; 664b4d593f1SCarson Labrado } 665b4d593f1SCarson Labrado asyncResp->res.jsonValue["Version"] = property; 666b4d593f1SCarson Labrado }); 667b4d593f1SCarson Labrado } 668523d4868SLogananth Sundararaj } 669476b9cc5STejas Patil 6701c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 6711c8fba97SJames Feist { 6727164bc62SChau Ly if (std::ranges::find(interfaces2, interface) != interfaces2.end()) 6731c8fba97SJames Feist { 674*f664fd8aSJanet Adkins if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_INDICATORLED) 675*f664fd8aSJanet Adkins { 6761c8fba97SJames Feist getIndicatorLedState(asyncResp); 677*f664fd8aSJanet Adkins } 678de8e5144SJanet Adkins getLocationIndicatorActive(asyncResp, objPath); 6791c8fba97SJames Feist break; 6801c8fba97SJames Feist } 6811c8fba97SJames Feist } 6821c8fba97SJames Feist 683deae6a78SEd Tanous dbus::utility::getAllProperties( 68486d89ed7SKrzysztof Grobelny *crow::connections::systemBus, connectionName, path, 68586d89ed7SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Asset", 6867164bc62SChau Ly [asyncResp, chassisId, 6877164bc62SChau Ly path](const boost::system::error_code&, 688cf7eba09SNan Zhou const dbus::utility::DBusPropertiesMap& propertiesList) { 6897164bc62SChau Ly handleDecoratorAssetProperties(asyncResp, chassisId, path, 6907164bc62SChau Ly propertiesList); 69186d89ed7SKrzysztof Grobelny }); 6922c37b4b0SSharad Yadav 69346f780f7SEd Tanous dbus::utility::getAllProperties( 6942952f648SJoseph-Jonathan Salzano *crow::connections::systemBus, connectionName, path, 6952952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis", 6962952f648SJoseph-Jonathan Salzano [asyncResp]( 6972952f648SJoseph-Jonathan Salzano const boost::system::error_code&, 6982952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) { 6992952f648SJoseph-Jonathan Salzano handleChassisProperties(asyncResp, propertiesList); 7002952f648SJoseph-Jonathan Salzano }); 7012952f648SJoseph-Jonathan Salzano 702308f70c7SWilly Tu for (const auto& interface : interfaces2) 7032c37b4b0SSharad Yadav { 704308f70c7SWilly Tu if (interface == "xyz.openbmc_project.Common.UUID") 7052c37b4b0SSharad Yadav { 706308f70c7SWilly Tu getChassisUUID(asyncResp, connectionName, path); 7072c37b4b0SSharad Yadav } 708cf7eba09SNan Zhou else if (interface == 7090fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode") 7102c37b4b0SSharad Yadav { 711002d39b4SEd Tanous getChassisLocationCode(asyncResp, connectionName, path); 7122c37b4b0SSharad Yadav } 7132c37b4b0SSharad Yadav } 7142c37b4b0SSharad Yadav 715daf36e2eSEd Tanous return; 716daf36e2eSEd Tanous } 717e0d918bcSEd Tanous 718daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 719d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 7207164bc62SChau Ly } 721c181942fSQiang XU 722504af5a0SPatrick Williams inline void handleChassisGet( 723504af5a0SPatrick Williams App& app, const crow::Request& req, 7247164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7257164bc62SChau Ly const std::string& chassisId) 7267164bc62SChau Ly { 7277164bc62SChau Ly if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 7287164bc62SChau Ly { 7297164bc62SChau Ly return; 7307164bc62SChau Ly } 7317164bc62SChau Ly 7327164bc62SChau Ly dbus::utility::getSubTree( 7333f95a277SMyung Bae "/xyz/openbmc_project/inventory", 0, chassisInterfaces, 7347164bc62SChau Ly std::bind_front(handleChassisGetSubTree, asyncResp, chassisId)); 7357164bc62SChau Ly 7367164bc62SChau Ly constexpr std::array<std::string_view, 1> interfaces2 = { 7377164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion"}; 7387164bc62SChau Ly 7397164bc62SChau Ly dbus::utility::getSubTree( 7407164bc62SChau Ly "/xyz/openbmc_project", 0, interfaces2, 7417164bc62SChau Ly std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp)); 742cf7eba09SNan Zhou } 7431c8fba97SJames Feist 744504af5a0SPatrick Williams inline void handleChassisPatch( 745504af5a0SPatrick Williams App& app, const crow::Request& req, 7467e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 747cf7eba09SNan Zhou const std::string& param) 748cf7eba09SNan Zhou { 7493ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 75045ca1b86SEd Tanous { 75145ca1b86SEd Tanous return; 75245ca1b86SEd Tanous } 7539f8bfa7cSGunnar Mills std::optional<bool> locationIndicatorActive; 7541c8fba97SJames Feist std::optional<std::string> indicatorLed; 7551c8fba97SJames Feist 7567e860f15SJohn Edward Broadbent if (param.empty()) 7571c8fba97SJames Feist { 7581c8fba97SJames Feist return; 7591c8fba97SJames Feist } 7601c8fba97SJames Feist 761afc474aeSMyung Bae if (!json_util::readJsonPatch( // 762afc474aeSMyung Bae req, asyncResp->res, // 763afc474aeSMyung Bae "IndicatorLED", indicatorLed, // 764afc474aeSMyung Bae "LocationIndicatorActive", locationIndicatorActive // 765afc474aeSMyung Bae )) 7661c8fba97SJames Feist { 7671c8fba97SJames Feist return; 7681c8fba97SJames Feist } 7691c8fba97SJames Feist 7709f8bfa7cSGunnar Mills if (!locationIndicatorActive && !indicatorLed) 7711c8fba97SJames Feist { 7721c8fba97SJames Feist return; // delete this when we support more patch properties 7731c8fba97SJames Feist } 774d6aa0093SGunnar Mills if (indicatorLed) 775d6aa0093SGunnar Mills { 776*f664fd8aSJanet Adkins if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_INDICATORLED) 777*f664fd8aSJanet Adkins { 7787e860f15SJohn Edward Broadbent asyncResp->res.addHeader( 7797e860f15SJohn Edward Broadbent boost::beast::http::field::warning, 7800fda0f12SGeorge Liu "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\""); 781d6aa0093SGunnar Mills } 782*f664fd8aSJanet Adkins else 783*f664fd8aSJanet Adkins { 784*f664fd8aSJanet Adkins messages::propertyUnknown(asyncResp->res, "IndicatorLED"); 785*f664fd8aSJanet Adkins return; 786*f664fd8aSJanet Adkins } 787*f664fd8aSJanet Adkins } 7881c8fba97SJames Feist 7897e860f15SJohn Edward Broadbent const std::string& chassisId = param; 7901c8fba97SJames Feist 791e99073f5SGeorge Liu dbus::utility::getSubTree( 7923f95a277SMyung Bae "/xyz/openbmc_project/inventory", 0, chassisInterfaces, 793cf7eba09SNan Zhou [asyncResp, chassisId, locationIndicatorActive, 7945e7e2dc5SEd Tanous indicatorLed](const boost::system::error_code& ec, 795b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 7961c8fba97SJames Feist if (ec) 7971c8fba97SJames Feist { 79862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 7991c8fba97SJames Feist messages::internalError(asyncResp->res); 8001c8fba97SJames Feist return; 8011c8fba97SJames Feist } 8021c8fba97SJames Feist 8031c8fba97SJames Feist // Iterate over all retrieved ObjectPaths. 804bd79bce8SPatrick Williams for (const std::pair<std::string, 805bd79bce8SPatrick Williams std::vector<std::pair< 806bd79bce8SPatrick Williams std::string, std::vector<std::string>>>>& 8071214b7e7SGunnar Mills object : subtree) 8081c8fba97SJames Feist { 8091c8fba97SJames Feist const std::string& path = object.first; 810bd79bce8SPatrick Williams const std::vector< 811bd79bce8SPatrick Williams std::pair<std::string, std::vector<std::string>>>& 8121214b7e7SGunnar Mills connectionNames = object.second; 8131c8fba97SJames Feist 814997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 815997093ebSGeorge Liu if (objPath.filename() != chassisId) 8161c8fba97SJames Feist { 8171c8fba97SJames Feist continue; 8181c8fba97SJames Feist } 8191c8fba97SJames Feist 82026f6976fSEd Tanous if (connectionNames.empty()) 8211c8fba97SJames Feist { 82262598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 8231c8fba97SJames Feist continue; 8241c8fba97SJames Feist } 8251c8fba97SJames Feist 82623a21a1cSEd Tanous const std::vector<std::string>& interfaces3 = 8271c8fba97SJames Feist connectionNames[0].second; 8281c8fba97SJames Feist 829e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 830e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 8311c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 8320fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 8331c8fba97SJames Feist bool indicatorChassis = false; 8341c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 8351c8fba97SJames Feist { 8363544d2a7SEd Tanous if (std::ranges::find(interfaces3, interface) != 8373544d2a7SEd Tanous interfaces3.end()) 8381c8fba97SJames Feist { 8391c8fba97SJames Feist indicatorChassis = true; 8401c8fba97SJames Feist break; 8411c8fba97SJames Feist } 8421c8fba97SJames Feist } 8439f8bfa7cSGunnar Mills if (locationIndicatorActive) 8449f8bfa7cSGunnar Mills { 8459f8bfa7cSGunnar Mills if (indicatorChassis) 8469f8bfa7cSGunnar Mills { 847de8e5144SJanet Adkins setLocationIndicatorActive(asyncResp, path, 848de8e5144SJanet Adkins *locationIndicatorActive); 8499f8bfa7cSGunnar Mills } 8509f8bfa7cSGunnar Mills else 8519f8bfa7cSGunnar Mills { 852002d39b4SEd Tanous messages::propertyUnknown(asyncResp->res, 853002d39b4SEd Tanous "LocationIndicatorActive"); 8549f8bfa7cSGunnar Mills } 8559f8bfa7cSGunnar Mills } 856*f664fd8aSJanet Adkins if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_INDICATORLED) 857*f664fd8aSJanet Adkins { 8589f8bfa7cSGunnar Mills if (indicatorLed) 8599f8bfa7cSGunnar Mills { 8601c8fba97SJames Feist if (indicatorChassis) 8611c8fba97SJames Feist { 862f23b7296SEd Tanous setIndicatorLedState(asyncResp, *indicatorLed); 8631c8fba97SJames Feist } 8641c8fba97SJames Feist else 8651c8fba97SJames Feist { 866bd79bce8SPatrick Williams messages::propertyUnknown(asyncResp->res, 867bd79bce8SPatrick Williams "IndicatorLED"); 8681c8fba97SJames Feist } 8691c8fba97SJames Feist } 870*f664fd8aSJanet Adkins } 8711c8fba97SJames Feist return; 8721c8fba97SJames Feist } 8731c8fba97SJames Feist 874d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 875e99073f5SGeorge Liu }); 876cf7eba09SNan Zhou } 877cf7eba09SNan Zhou 878cf7eba09SNan Zhou /** 879cf7eba09SNan Zhou * Chassis override class for delivering Chassis Schema 880cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 881cf7eba09SNan Zhou */ 882cf7eba09SNan Zhou inline void requestRoutesChassis(App& app) 883cf7eba09SNan Zhou { 884cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 885cf7eba09SNan Zhou .privileges(redfish::privileges::getChassis) 886cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 887cf7eba09SNan Zhou std::bind_front(handleChassisGet, std::ref(app))); 888cf7eba09SNan Zhou 889cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 890cf7eba09SNan Zhou .privileges(redfish::privileges::patchChassis) 891cf7eba09SNan Zhou .methods(boost::beast::http::verb::patch)( 892cf7eba09SNan Zhou std::bind_front(handleChassisPatch, std::ref(app))); 8931c8fba97SJames Feist } 894dd99e04bSP.K. Lee 895504af5a0SPatrick Williams inline void doChassisPowerCycle( 896504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 897dd99e04bSP.K. Lee { 8987a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 899c3b3c92aSVijay Khemka "xyz.openbmc_project.State.Chassis"}; 900c3b3c92aSVijay Khemka 901c3b3c92aSVijay Khemka // Use mapper to get subtree paths. 9027a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 9037a1dbc48SGeorge Liu "/", 0, interfaces, 904b9d36b47SEd Tanous [asyncResp]( 9057a1dbc48SGeorge Liu const boost::system::error_code& ec, 906b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& chassisList) { 907c3b3c92aSVijay Khemka if (ec) 908c3b3c92aSVijay Khemka { 90962598e31SEd Tanous BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec); 910c3b3c92aSVijay Khemka messages::internalError(asyncResp->res); 911c3b3c92aSVijay Khemka return; 912c3b3c92aSVijay Khemka } 913c3b3c92aSVijay Khemka 914dd99e04bSP.K. Lee const char* processName = "xyz.openbmc_project.State.Chassis"; 915dd99e04bSP.K. Lee const char* interfaceName = "xyz.openbmc_project.State.Chassis"; 916dd99e04bSP.K. Lee const char* destProperty = "RequestedPowerTransition"; 917dd99e04bSP.K. Lee const std::string propertyValue = 918dd99e04bSP.K. Lee "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; 919bd79bce8SPatrick Williams std::string objectPath = 920bd79bce8SPatrick Williams "/xyz/openbmc_project/state/chassis_system0"; 921c3b3c92aSVijay Khemka 922c3b3c92aSVijay Khemka /* Look for system reset chassis path */ 923bd79bce8SPatrick Williams if ((std::ranges::find(chassisList, objectPath)) == 924bd79bce8SPatrick Williams chassisList.end()) 925c3b3c92aSVijay Khemka { 926c3b3c92aSVijay Khemka /* We prefer to reset the full chassis_system, but if it doesn't 927c3b3c92aSVijay Khemka * exist on some platforms, fall back to a host-only power reset 928c3b3c92aSVijay Khemka */ 929c3b3c92aSVijay Khemka objectPath = "/xyz/openbmc_project/state/chassis0"; 930c3b3c92aSVijay Khemka } 931dd99e04bSP.K. Lee 932e93abac6SGinu George setDbusProperty(asyncResp, "ResetType", processName, objectPath, 933e93abac6SGinu George interfaceName, destProperty, propertyValue); 9347a1dbc48SGeorge Liu }); 935dd99e04bSP.K. Lee } 936dd99e04bSP.K. Lee 937cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost( 938cf7eba09SNan Zhou App& app, const crow::Request& req, 9397e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 940cf7eba09SNan Zhou const std::string& /*chassisId*/) 941cf7eba09SNan Zhou { 9423ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 94345ca1b86SEd Tanous { 94445ca1b86SEd Tanous return; 94545ca1b86SEd Tanous } 94662598e31SEd Tanous BMCWEB_LOG_DEBUG("Post Chassis Reset."); 947dd99e04bSP.K. Lee 948dd99e04bSP.K. Lee std::string resetType; 949dd99e04bSP.K. Lee 950cf7eba09SNan Zhou if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 951dd99e04bSP.K. Lee { 952dd99e04bSP.K. Lee return; 953dd99e04bSP.K. Lee } 954dd99e04bSP.K. Lee 955dd99e04bSP.K. Lee if (resetType != "PowerCycle") 956dd99e04bSP.K. Lee { 95762598e31SEd Tanous BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType); 958002d39b4SEd Tanous messages::actionParameterNotSupported(asyncResp->res, resetType, 959002d39b4SEd Tanous "ResetType"); 960dd99e04bSP.K. Lee 961dd99e04bSP.K. Lee return; 962dd99e04bSP.K. Lee } 963dd99e04bSP.K. Lee doChassisPowerCycle(asyncResp); 964dd99e04bSP.K. Lee } 9651cb1a9e6SAppaRao Puli 9661cb1a9e6SAppaRao Puli /** 967cf7eba09SNan Zhou * ChassisResetAction class supports the POST method for the Reset 968cf7eba09SNan Zhou * action. 969cf7eba09SNan Zhou * Function handles POST method request. 970cf7eba09SNan Zhou * Analyzes POST body before sending Reset request data to D-Bus. 9711cb1a9e6SAppaRao Puli */ 972cf7eba09SNan Zhou 973cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app) 9741cb1a9e6SAppaRao Puli { 975cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/") 976cf7eba09SNan Zhou .privileges(redfish::privileges::postChassis) 977cf7eba09SNan Zhou .methods(boost::beast::http::verb::post)( 978cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoPost, std::ref(app))); 979cf7eba09SNan Zhou } 980cf7eba09SNan Zhou 981cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet( 982cf7eba09SNan Zhou App& app, const crow::Request& req, 9837e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 984cf7eba09SNan Zhou const std::string& chassisId) 985cf7eba09SNan Zhou { 9863ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 9871cb1a9e6SAppaRao Puli { 98845ca1b86SEd Tanous return; 98945ca1b86SEd Tanous } 990cf7eba09SNan Zhou asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 991ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 992ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId); 9931476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 9941476687dSEd Tanous 9951476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 9965b9e95a1SNan Zhou nlohmann::json::array_t parameters; 9975b9e95a1SNan Zhou nlohmann::json::object_t parameter; 9985b9e95a1SNan Zhou parameter["Name"] = "ResetType"; 9995b9e95a1SNan Zhou parameter["Required"] = true; 1000539d8c6bSEd Tanous parameter["DataType"] = action_info::ParameterTypes::String; 10011476687dSEd Tanous nlohmann::json::array_t allowed; 1002ad539545SPatrick Williams allowed.emplace_back("PowerCycle"); 10035b9e95a1SNan Zhou parameter["AllowableValues"] = std::move(allowed); 1004ad539545SPatrick Williams parameters.emplace_back(std::move(parameter)); 10055b9e95a1SNan Zhou 10061476687dSEd Tanous asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 1007cf7eba09SNan Zhou } 1008cf7eba09SNan Zhou 1009cf7eba09SNan Zhou /** 1010cf7eba09SNan Zhou * ChassisResetActionInfo derived class for delivering Chassis 1011cf7eba09SNan Zhou * ResetType AllowableValues using ResetInfo schema. 1012cf7eba09SNan Zhou */ 1013cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app) 1014cf7eba09SNan Zhou { 1015cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/") 1016cf7eba09SNan Zhou .privileges(redfish::privileges::getActionInfo) 1017cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 1018cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoGet, std::ref(app))); 10191cb1a9e6SAppaRao Puli } 10201cb1a9e6SAppaRao Puli 1021e37f8451SRapkiewicz, Pawel } // namespace redfish 1022