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" 21*3f95a277SMyung 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 { 1561e1e598dSJonathan Doman // crow::connections::systemBus->async_method_call( 157deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 158deae6a78SEd Tanous "xyz.openbmc_project.State.Chassis", 1591e1e598dSJonathan Doman "/xyz/openbmc_project/state/chassis0", 1601e1e598dSJonathan Doman "xyz.openbmc_project.State.Chassis", "CurrentPowerState", 161ac106bf6SEd Tanous [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec, 1621e1e598dSJonathan Doman const std::string& chassisState) { 163beeca0aeSGunnar Mills if (ec) 164beeca0aeSGunnar Mills { 165a6e5e0abSCarson Labrado if (ec == boost::system::errc::host_unreachable) 166a6e5e0abSCarson Labrado { 167a6e5e0abSCarson Labrado // Service not available, no error, just don't return 168a6e5e0abSCarson Labrado // chassis state info 16962598e31SEd Tanous BMCWEB_LOG_DEBUG("Service not available {}", ec); 170a6e5e0abSCarson Labrado return; 171a6e5e0abSCarson Labrado } 17262598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 173ac106bf6SEd Tanous messages::internalError(asyncResp->res); 174beeca0aeSGunnar Mills return; 175beeca0aeSGunnar Mills } 176beeca0aeSGunnar Mills 17762598e31SEd Tanous BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState); 178beeca0aeSGunnar Mills // Verify Chassis State 179bd79bce8SPatrick Williams if (chassisState == 180bd79bce8SPatrick Williams "xyz.openbmc_project.State.Chassis.PowerState.On") 181beeca0aeSGunnar Mills { 182bd79bce8SPatrick Williams asyncResp->res.jsonValue["PowerState"] = 183bd79bce8SPatrick Williams resource::PowerState::On; 184539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 185539d8c6bSEd Tanous resource::State::Enabled; 186beeca0aeSGunnar Mills } 1871e1e598dSJonathan Doman else if (chassisState == 188beeca0aeSGunnar Mills "xyz.openbmc_project.State.Chassis.PowerState.Off") 189beeca0aeSGunnar Mills { 190bd79bce8SPatrick Williams asyncResp->res.jsonValue["PowerState"] = 191bd79bce8SPatrick Williams resource::PowerState::Off; 192539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 193539d8c6bSEd Tanous resource::State::StandbyOffline; 194beeca0aeSGunnar Mills } 1951e1e598dSJonathan Doman }); 196beeca0aeSGunnar Mills } 197beeca0aeSGunnar Mills 198c181942fSQiang XU /** 199c181942fSQiang XU * Retrieves physical security properties over dbus 200c181942fSQiang XU */ 2017164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree( 2027164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 203e99073f5SGeorge Liu const boost::system::error_code& ec, 2047164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 2057164bc62SChau Ly { 206c181942fSQiang XU if (ec) 207c181942fSQiang XU { 2084e0453b1SGunnar Mills // do not add err msg in redfish response, because this is not 209c181942fSQiang XU // mandatory property 21062598e31SEd Tanous BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec); 211c181942fSQiang XU return; 212c181942fSQiang XU } 213c181942fSQiang XU // Iterate over all retrieved ObjectPaths. 214c181942fSQiang XU for (const auto& object : subtree) 215c181942fSQiang XU { 216840a9ffcSPatrick Williams if (!object.second.empty()) 217c181942fSQiang XU { 21889144a3aSEd Tanous const auto& service = object.second.front(); 2197164bc62SChau Ly 2207164bc62SChau Ly BMCWEB_LOG_DEBUG("Get intrusion status by service "); 2217164bc62SChau Ly 222deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 223deae6a78SEd Tanous service.first, object.first, 2247164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion", "Status", 2257164bc62SChau Ly [asyncResp](const boost::system::error_code& ec1, 2267164bc62SChau Ly const std::string& value) { 2277164bc62SChau Ly if (ec1) 2287164bc62SChau Ly { 229bd79bce8SPatrick Williams // do not add err msg in redfish response, because this 230bd79bce8SPatrick Williams // is not 2317164bc62SChau Ly // mandatory property 2327164bc62SChau Ly BMCWEB_LOG_ERROR("DBUS response error {}", ec1); 2337164bc62SChau Ly return; 2347164bc62SChau Ly } 235bd79bce8SPatrick Williams asyncResp->res.jsonValue["PhysicalSecurity"] 236bd79bce8SPatrick Williams ["IntrusionSensorNumber"] = 1; 2377164bc62SChau Ly asyncResp->res 238bd79bce8SPatrick Williams .jsonValue["PhysicalSecurity"]["IntrusionSensor"] = 239bd79bce8SPatrick Williams value; 2407164bc62SChau Ly }); 2417164bc62SChau Ly 242c181942fSQiang XU return; 243c181942fSQiang XU } 244c181942fSQiang XU } 245c181942fSQiang XU } 246c181942fSQiang XU 247cf7eba09SNan Zhou inline void handleChassisCollectionGet( 248cf7eba09SNan Zhou App& app, const crow::Request& req, 249cf7eba09SNan Zhou const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2501abe55efSEd Tanous { 2513ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 25245ca1b86SEd Tanous { 25345ca1b86SEd Tanous return; 25445ca1b86SEd Tanous } 2558d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 2568d1b46d7Szhanghch05 "#ChassisCollection.ChassisCollection"; 2578d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 2588d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 259e37f8451SRapkiewicz, Pawel 26002f6ff19SGunnar Mills collection_util::getCollectionMembers( 261*3f95a277SMyung Bae asyncResp, boost::urls::url("/redfish/v1/Chassis"), chassisInterfaces, 26236b5f1edSLakshmi Yadlapati "/xyz/openbmc_project/inventory"); 263cf7eba09SNan Zhou } 264cf7eba09SNan Zhou 265a5617496SJie Yang inline void getChassisContainedBy( 266a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 267a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 26828ee563eSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& upstreamChassisPaths) 269a5617496SJie Yang { 270a5617496SJie Yang if (ec) 271a5617496SJie Yang { 272a5617496SJie Yang if (ec.value() != EBADR) 273a5617496SJie Yang { 27462598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 275a5617496SJie Yang messages::internalError(asyncResp->res); 276a5617496SJie Yang } 277a5617496SJie Yang return; 278a5617496SJie Yang } 279a5617496SJie Yang if (upstreamChassisPaths.empty()) 280a5617496SJie Yang { 281a5617496SJie Yang return; 282a5617496SJie Yang } 283a5617496SJie Yang if (upstreamChassisPaths.size() > 1) 284a5617496SJie Yang { 2858ece0e45SEd Tanous BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId); 286a5617496SJie Yang messages::internalError(asyncResp->res); 287a5617496SJie Yang return; 288a5617496SJie Yang } 289a5617496SJie Yang 290a5617496SJie Yang sdbusplus::message::object_path upstreamChassisPath( 291a5617496SJie Yang upstreamChassisPaths[0]); 292a5617496SJie Yang std::string upstreamChassis = upstreamChassisPath.filename(); 293a5617496SJie Yang if (upstreamChassis.empty()) 294a5617496SJie Yang { 29562598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}", 29662598e31SEd Tanous upstreamChassisPath.str, chassisId); 297a5617496SJie Yang return; 298a5617496SJie Yang } 299a5617496SJie Yang 300a5617496SJie Yang asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] = 301a5617496SJie Yang boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis); 302a5617496SJie Yang } 303a5617496SJie Yang 304a5617496SJie Yang inline void getChassisContains( 305a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 306a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 30728ee563eSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& downstreamChassisPaths) 308a5617496SJie Yang { 309a5617496SJie Yang if (ec) 310a5617496SJie Yang { 311a5617496SJie Yang if (ec.value() != EBADR) 312a5617496SJie Yang { 31362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 314a5617496SJie Yang messages::internalError(asyncResp->res); 315a5617496SJie Yang } 316a5617496SJie Yang return; 317a5617496SJie Yang } 318a5617496SJie Yang if (downstreamChassisPaths.empty()) 319a5617496SJie Yang { 320a5617496SJie Yang return; 321a5617496SJie Yang } 322a5617496SJie Yang nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"]; 323a5617496SJie Yang if (!jValue.is_array()) 324a5617496SJie Yang { 325a5617496SJie Yang // Create the array if it was empty 326a5617496SJie Yang jValue = nlohmann::json::array(); 327a5617496SJie Yang } 328a5617496SJie Yang for (const auto& p : downstreamChassisPaths) 329a5617496SJie Yang { 330a5617496SJie Yang sdbusplus::message::object_path downstreamChassisPath(p); 331a5617496SJie Yang std::string downstreamChassis = downstreamChassisPath.filename(); 332a5617496SJie Yang if (downstreamChassis.empty()) 333a5617496SJie Yang { 33462598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}", 33562598e31SEd Tanous downstreamChassisPath.str, chassisId); 336a5617496SJie Yang continue; 337a5617496SJie Yang } 338a5617496SJie Yang nlohmann::json link; 339bd79bce8SPatrick Williams link["@odata.id"] = 340bd79bce8SPatrick Williams boost::urls::format("/redfish/v1/Chassis/{}", downstreamChassis); 341a5617496SJie Yang jValue.push_back(std::move(link)); 342a5617496SJie Yang } 343a5617496SJie Yang asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size(); 344a5617496SJie Yang } 345a5617496SJie Yang 346bd79bce8SPatrick Williams inline void getChassisConnectivity( 347bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 348bd79bce8SPatrick Williams const std::string& chassisId, const std::string& chassisPath) 349a5617496SJie Yang { 35062598e31SEd Tanous BMCWEB_LOG_DEBUG("Get chassis connectivity"); 351a5617496SJie Yang 35228ee563eSMyung Bae dbus::utility::getAssociatedSubTreePaths( 353a5617496SJie Yang chassisPath + "/contained_by", 35428ee563eSMyung Bae sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 355*3f95a277SMyung Bae chassisInterfaces, 356a5617496SJie Yang std::bind_front(getChassisContainedBy, asyncResp, chassisId)); 357a5617496SJie Yang 35828ee563eSMyung Bae dbus::utility::getAssociatedSubTreePaths( 359a5617496SJie Yang chassisPath + "/containing", 36028ee563eSMyung Bae sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 361*3f95a277SMyung Bae chassisInterfaces, 362*3f95a277SMyung Bae std::bind_front(getChassisContains, asyncResp, chassisId)); 363a5617496SJie Yang } 364a5617496SJie Yang 365cf7eba09SNan Zhou /** 366cf7eba09SNan Zhou * ChassisCollection derived class for delivering Chassis Collection Schema 367cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 368cf7eba09SNan Zhou */ 369cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app) 370cf7eba09SNan Zhou { 371cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/") 372cf7eba09SNan Zhou .privileges(redfish::privileges::getChassisCollection) 373cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 374cf7eba09SNan Zhou std::bind_front(handleChassisCollectionGet, std::ref(app))); 37562d5e2e4SEd Tanous } 376e37f8451SRapkiewicz, Pawel 377bd79bce8SPatrick Williams inline void getChassisLocationCode( 378bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 379bd79bce8SPatrick Williams const std::string& connectionName, const std::string& path) 380308f70c7SWilly Tu { 381deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 382deae6a78SEd Tanous connectionName, path, 3831e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 3845e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3851e1e598dSJonathan Doman const std::string& property) { 386308f70c7SWilly Tu if (ec) 387308f70c7SWilly Tu { 38862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location"); 389308f70c7SWilly Tu messages::internalError(asyncResp->res); 390308f70c7SWilly Tu return; 391308f70c7SWilly Tu } 392308f70c7SWilly Tu 393bd79bce8SPatrick Williams asyncResp->res 394bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 3951e1e598dSJonathan Doman property; 3961e1e598dSJonathan Doman }); 397308f70c7SWilly Tu } 398308f70c7SWilly Tu 399308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 400308f70c7SWilly Tu const std::string& connectionName, 401308f70c7SWilly Tu const std::string& path) 402308f70c7SWilly Tu { 403deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 404deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Common.UUID", "UUID", 4055e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 4061e1e598dSJonathan Doman const std::string& chassisUUID) { 407308f70c7SWilly Tu if (ec) 408308f70c7SWilly Tu { 40962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for UUID"); 410308f70c7SWilly Tu messages::internalError(asyncResp->res); 411308f70c7SWilly Tu return; 412308f70c7SWilly Tu } 4131e1e598dSJonathan Doman asyncResp->res.jsonValue["UUID"] = chassisUUID; 4141e1e598dSJonathan Doman }); 415308f70c7SWilly Tu } 416308f70c7SWilly Tu 4177164bc62SChau Ly inline void handleDecoratorAssetProperties( 41845ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4197164bc62SChau Ly const std::string& chassisId, const std::string& path, 4207164bc62SChau Ly const dbus::utility::DBusPropertiesMap& propertiesList) 421cf7eba09SNan Zhou { 4227164bc62SChau Ly const std::string* partNumber = nullptr; 4237164bc62SChau Ly const std::string* serialNumber = nullptr; 4247164bc62SChau Ly const std::string* manufacturer = nullptr; 4257164bc62SChau Ly const std::string* model = nullptr; 4267164bc62SChau Ly const std::string* sparePartNumber = nullptr; 4277164bc62SChau Ly 4287164bc62SChau Ly const bool success = sdbusplus::unpackPropertiesNoThrow( 4297164bc62SChau Ly dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 4307164bc62SChau Ly partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, 4317164bc62SChau Ly "Model", model, "SparePartNumber", sparePartNumber); 4327164bc62SChau Ly 4337164bc62SChau Ly if (!success) 43445ca1b86SEd Tanous { 4357164bc62SChau Ly messages::internalError(asyncResp->res); 43645ca1b86SEd Tanous return; 43745ca1b86SEd Tanous } 438734bfe90SGunnar Mills 4397164bc62SChau Ly if (partNumber != nullptr) 4407164bc62SChau Ly { 4417164bc62SChau Ly asyncResp->res.jsonValue["PartNumber"] = *partNumber; 4427164bc62SChau Ly } 4437164bc62SChau Ly 4447164bc62SChau Ly if (serialNumber != nullptr) 4457164bc62SChau Ly { 4467164bc62SChau Ly asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 4477164bc62SChau Ly } 4487164bc62SChau Ly 4497164bc62SChau Ly if (manufacturer != nullptr) 4507164bc62SChau Ly { 4517164bc62SChau Ly asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 4527164bc62SChau Ly } 4537164bc62SChau Ly 4547164bc62SChau Ly if (model != nullptr) 4557164bc62SChau Ly { 4567164bc62SChau Ly asyncResp->res.jsonValue["Model"] = *model; 4577164bc62SChau Ly } 4587164bc62SChau Ly 4597164bc62SChau Ly // SparePartNumber is optional on D-Bus 4607164bc62SChau Ly // so skip if it is empty 4617164bc62SChau Ly if (sparePartNumber != nullptr && !sparePartNumber->empty()) 4627164bc62SChau Ly { 4637164bc62SChau Ly asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 4647164bc62SChau Ly } 4657164bc62SChau Ly 4667164bc62SChau Ly asyncResp->res.jsonValue["Name"] = chassisId; 4677164bc62SChau Ly asyncResp->res.jsonValue["Id"] = chassisId; 46825b54dbaSEd Tanous 46925b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL) 47025b54dbaSEd Tanous { 4717164bc62SChau Ly asyncResp->res.jsonValue["Thermal"]["@odata.id"] = 4727164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId); 4737164bc62SChau Ly // Power object 4747164bc62SChau Ly asyncResp->res.jsonValue["Power"]["@odata.id"] = 4757164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId); 47625b54dbaSEd Tanous } 47725b54dbaSEd Tanous 47825b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM) 47925b54dbaSEd Tanous { 4807164bc62SChau Ly asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] = 4817164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem", 4827164bc62SChau Ly chassisId); 4837164bc62SChau Ly asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] = 48425b54dbaSEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", 48525b54dbaSEd Tanous chassisId); 4867164bc62SChau Ly asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] = 4877164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics", 4887164bc62SChau Ly chassisId); 48925b54dbaSEd Tanous } 4907164bc62SChau Ly // SensorCollection 4917164bc62SChau Ly asyncResp->res.jsonValue["Sensors"]["@odata.id"] = 4927164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId); 493539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 4947164bc62SChau Ly 4957164bc62SChau Ly nlohmann::json::array_t computerSystems; 4967164bc62SChau Ly nlohmann::json::object_t system; 497bd79bce8SPatrick Williams system["@odata.id"] = 498bd79bce8SPatrick Williams std::format("/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME); 4997164bc62SChau Ly computerSystems.emplace_back(std::move(system)); 5007164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ComputerSystems"] = 5017164bc62SChau Ly std::move(computerSystems); 5027164bc62SChau Ly 5037164bc62SChau Ly nlohmann::json::array_t managedBy; 5047164bc62SChau Ly nlohmann::json::object_t manager; 505253f11b8SEd Tanous manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}", 506253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 5077164bc62SChau Ly managedBy.emplace_back(std::move(manager)); 5087164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); 5097164bc62SChau Ly getChassisState(asyncResp); 5107164bc62SChau Ly getStorageLink(asyncResp, path); 5117164bc62SChau Ly } 5127164bc62SChau Ly 5132952f648SJoseph-Jonathan Salzano inline void handleChassisProperties( 5142952f648SJoseph-Jonathan Salzano const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5152952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) 5162952f648SJoseph-Jonathan Salzano { 5172952f648SJoseph-Jonathan Salzano const std::string* type = nullptr; 5182952f648SJoseph-Jonathan Salzano 5192952f648SJoseph-Jonathan Salzano const bool success = sdbusplus::unpackPropertiesNoThrow( 5202952f648SJoseph-Jonathan Salzano dbus_utils::UnpackErrorPrinter(), propertiesList, "Type", type); 5212952f648SJoseph-Jonathan Salzano 5222952f648SJoseph-Jonathan Salzano if (!success) 5232952f648SJoseph-Jonathan Salzano { 5242952f648SJoseph-Jonathan Salzano messages::internalError(asyncResp->res); 5252952f648SJoseph-Jonathan Salzano return; 5262952f648SJoseph-Jonathan Salzano } 5272952f648SJoseph-Jonathan Salzano 52819ea2864SGunnar Mills // Chassis Type is a required property in Redfish 52919ea2864SGunnar Mills // If there is an error or some enum we don't support just sit it to Rack 53019ea2864SGunnar Mills // Mount 53119ea2864SGunnar Mills asyncResp->res.jsonValue["ChassisType"] = chassis::ChassisType::RackMount; 53219ea2864SGunnar Mills 5332952f648SJoseph-Jonathan Salzano if (type != nullptr) 5342952f648SJoseph-Jonathan Salzano { 5352952f648SJoseph-Jonathan Salzano auto chassisType = translateChassisTypeToRedfish(*type); 5362952f648SJoseph-Jonathan Salzano if (chassisType != chassis::ChassisType::Invalid) 5372952f648SJoseph-Jonathan Salzano { 5382952f648SJoseph-Jonathan Salzano asyncResp->res.jsonValue["ChassisType"] = chassisType; 5392952f648SJoseph-Jonathan Salzano } 5402952f648SJoseph-Jonathan Salzano } 5412952f648SJoseph-Jonathan Salzano } 5422952f648SJoseph-Jonathan Salzano 5437164bc62SChau Ly inline void handleChassisGetSubTree( 5447164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5457164bc62SChau Ly const std::string& chassisId, const boost::system::error_code& ec, 5467164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 5477164bc62SChau Ly { 54862d5e2e4SEd Tanous if (ec) 5491abe55efSEd Tanous { 55062598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 551f12894f8SJason M. Bills messages::internalError(asyncResp->res); 552daf36e2eSEd Tanous return; 553daf36e2eSEd Tanous } 554daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 555cf7eba09SNan Zhou for (const std::pair< 556cf7eba09SNan Zhou std::string, 557cf7eba09SNan Zhou std::vector<std::pair<std::string, std::vector<std::string>>>>& 5581214b7e7SGunnar Mills object : subtree) 5591abe55efSEd Tanous { 560daf36e2eSEd Tanous const std::string& path = object.first; 561cf7eba09SNan Zhou const std::vector<std::pair<std::string, std::vector<std::string>>>& 5621214b7e7SGunnar Mills connectionNames = object.second; 5637e860f15SJohn Edward Broadbent 564997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 565997093ebSGeorge Liu if (objPath.filename() != chassisId) 5661abe55efSEd Tanous { 567daf36e2eSEd Tanous continue; 568daf36e2eSEd Tanous } 56926f03899SShawn McCarney 570a5617496SJie Yang getChassisConnectivity(asyncResp, chassisId, path); 571a5617496SJie Yang 57226f6976fSEd Tanous if (connectionNames.empty()) 5731abe55efSEd Tanous { 57462598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 575e0d918bcSEd Tanous continue; 576daf36e2eSEd Tanous } 577e0d918bcSEd Tanous 5787164bc62SChau Ly asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis"; 57949c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.id"] = 580ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 58149c53ac9SJohnathan Mantey asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 582cf7eba09SNan Zhou asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] = 5837164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset", 5847164bc62SChau Ly chassisId); 5851476687dSEd Tanous asyncResp->res 586cf7eba09SNan Zhou .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] = 587ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo", 588ef4c65b7SEd Tanous chassisId); 5896c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 5906c3e9451SGeorge Liu path + "/drive", 5917164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec3, 5926c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 59392903bd4SJohn Edward Broadbent if (ec3 || resp.empty()) 59492903bd4SJohn Edward Broadbent { 59592903bd4SJohn Edward Broadbent return; // no drives = no failures 59692903bd4SJohn Edward Broadbent } 59792903bd4SJohn Edward Broadbent 59892903bd4SJohn Edward Broadbent nlohmann::json reference; 599bd79bce8SPatrick Williams reference["@odata.id"] = boost::urls::format( 600bd79bce8SPatrick Williams "/redfish/v1/Chassis/{}/Drives", chassisId); 60192903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Drives"] = std::move(reference); 60292903bd4SJohn Edward Broadbent }); 60392903bd4SJohn Edward Broadbent 604002d39b4SEd Tanous const std::string& connectionName = connectionNames[0].first; 6051c8fba97SJames Feist 6067164bc62SChau Ly const std::vector<std::string>& interfaces2 = connectionNames[0].second; 607e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 608e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 6091c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 6100fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 6111c8fba97SJames Feist 612476b9cc5STejas Patil const std::string assetTagInterface = 6130fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.AssetTag"; 614523d4868SLogananth Sundararaj const std::string replaceableInterface = 615523d4868SLogananth Sundararaj "xyz.openbmc_project.Inventory.Decorator.Replaceable"; 616b4d593f1SCarson Labrado const std::string revisionInterface = 617b4d593f1SCarson Labrado "xyz.openbmc_project.Inventory.Decorator.Revision"; 618523d4868SLogananth Sundararaj for (const auto& interface : interfaces2) 619523d4868SLogananth Sundararaj { 620523d4868SLogananth Sundararaj if (interface == assetTagInterface) 621476b9cc5STejas Patil { 622deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 623deae6a78SEd Tanous connectionName, path, assetTagInterface, "AssetTag", 6247164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 6251e1e598dSJonathan Doman const std::string& property) { 6268a592810SEd Tanous if (ec2) 627476b9cc5STejas Patil { 628bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 629bd79bce8SPatrick Williams "DBus response error for AssetTag: {}", ec2); 630476b9cc5STejas Patil messages::internalError(asyncResp->res); 631476b9cc5STejas Patil return; 632476b9cc5STejas Patil } 633002d39b4SEd Tanous asyncResp->res.jsonValue["AssetTag"] = property; 6341e1e598dSJonathan Doman }); 635476b9cc5STejas Patil } 636523d4868SLogananth Sundararaj else if (interface == replaceableInterface) 637523d4868SLogananth Sundararaj { 638deae6a78SEd Tanous dbus::utility::getProperty<bool>( 639deae6a78SEd Tanous connectionName, path, replaceableInterface, "HotPluggable", 6407164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 641523d4868SLogananth Sundararaj const bool property) { 642523d4868SLogananth Sundararaj if (ec2) 643523d4868SLogananth Sundararaj { 64462598e31SEd Tanous BMCWEB_LOG_ERROR( 645bd79bce8SPatrick Williams "DBus response error for HotPluggable: {}", 646bd79bce8SPatrick Williams ec2); 647523d4868SLogananth Sundararaj messages::internalError(asyncResp->res); 648523d4868SLogananth Sundararaj return; 649523d4868SLogananth Sundararaj } 650523d4868SLogananth Sundararaj asyncResp->res.jsonValue["HotPluggable"] = property; 651523d4868SLogananth Sundararaj }); 652523d4868SLogananth Sundararaj } 653b4d593f1SCarson Labrado else if (interface == revisionInterface) 654b4d593f1SCarson Labrado { 655deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 656deae6a78SEd Tanous connectionName, path, revisionInterface, "Version", 657b4d593f1SCarson Labrado [asyncResp, chassisId](const boost::system::error_code& ec2, 658b4d593f1SCarson Labrado const std::string& property) { 659b4d593f1SCarson Labrado if (ec2) 660b4d593f1SCarson Labrado { 661bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 662bd79bce8SPatrick Williams "DBus response error for Version: {}", ec2); 663b4d593f1SCarson Labrado messages::internalError(asyncResp->res); 664b4d593f1SCarson Labrado return; 665b4d593f1SCarson Labrado } 666b4d593f1SCarson Labrado asyncResp->res.jsonValue["Version"] = property; 667b4d593f1SCarson Labrado }); 668b4d593f1SCarson Labrado } 669523d4868SLogananth Sundararaj } 670476b9cc5STejas Patil 6711c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 6721c8fba97SJames Feist { 6737164bc62SChau Ly if (std::ranges::find(interfaces2, interface) != interfaces2.end()) 6741c8fba97SJames Feist { 6751c8fba97SJames Feist getIndicatorLedState(asyncResp); 67659a17e4fSGeorge Liu getSystemLocationIndicatorActive(asyncResp); 6771c8fba97SJames Feist break; 6781c8fba97SJames Feist } 6791c8fba97SJames Feist } 6801c8fba97SJames Feist 681deae6a78SEd Tanous dbus::utility::getAllProperties( 68286d89ed7SKrzysztof Grobelny *crow::connections::systemBus, connectionName, path, 68386d89ed7SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Asset", 6847164bc62SChau Ly [asyncResp, chassisId, 6857164bc62SChau Ly path](const boost::system::error_code&, 686cf7eba09SNan Zhou const dbus::utility::DBusPropertiesMap& propertiesList) { 6877164bc62SChau Ly handleDecoratorAssetProperties(asyncResp, chassisId, path, 6887164bc62SChau Ly propertiesList); 68986d89ed7SKrzysztof Grobelny }); 6902c37b4b0SSharad Yadav 69146f780f7SEd Tanous dbus::utility::getAllProperties( 6922952f648SJoseph-Jonathan Salzano *crow::connections::systemBus, connectionName, path, 6932952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis", 6942952f648SJoseph-Jonathan Salzano [asyncResp]( 6952952f648SJoseph-Jonathan Salzano const boost::system::error_code&, 6962952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) { 6972952f648SJoseph-Jonathan Salzano handleChassisProperties(asyncResp, propertiesList); 6982952f648SJoseph-Jonathan Salzano }); 6992952f648SJoseph-Jonathan Salzano 700308f70c7SWilly Tu for (const auto& interface : interfaces2) 7012c37b4b0SSharad Yadav { 702308f70c7SWilly Tu if (interface == "xyz.openbmc_project.Common.UUID") 7032c37b4b0SSharad Yadav { 704308f70c7SWilly Tu getChassisUUID(asyncResp, connectionName, path); 7052c37b4b0SSharad Yadav } 706cf7eba09SNan Zhou else if (interface == 7070fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode") 7082c37b4b0SSharad Yadav { 709002d39b4SEd Tanous getChassisLocationCode(asyncResp, connectionName, path); 7102c37b4b0SSharad Yadav } 7112c37b4b0SSharad Yadav } 7122c37b4b0SSharad Yadav 713daf36e2eSEd Tanous return; 714daf36e2eSEd Tanous } 715e0d918bcSEd Tanous 716daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 717d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 7187164bc62SChau Ly } 719c181942fSQiang XU 720504af5a0SPatrick Williams inline void handleChassisGet( 721504af5a0SPatrick Williams App& app, const crow::Request& req, 7227164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7237164bc62SChau Ly const std::string& chassisId) 7247164bc62SChau Ly { 7257164bc62SChau Ly if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 7267164bc62SChau Ly { 7277164bc62SChau Ly return; 7287164bc62SChau Ly } 7297164bc62SChau Ly 7307164bc62SChau Ly dbus::utility::getSubTree( 731*3f95a277SMyung Bae "/xyz/openbmc_project/inventory", 0, chassisInterfaces, 7327164bc62SChau Ly std::bind_front(handleChassisGetSubTree, asyncResp, chassisId)); 7337164bc62SChau Ly 7347164bc62SChau Ly constexpr std::array<std::string_view, 1> interfaces2 = { 7357164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion"}; 7367164bc62SChau Ly 7377164bc62SChau Ly dbus::utility::getSubTree( 7387164bc62SChau Ly "/xyz/openbmc_project", 0, interfaces2, 7397164bc62SChau Ly std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp)); 740cf7eba09SNan Zhou } 7411c8fba97SJames Feist 742504af5a0SPatrick Williams inline void handleChassisPatch( 743504af5a0SPatrick Williams App& app, const crow::Request& req, 7447e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 745cf7eba09SNan Zhou const std::string& param) 746cf7eba09SNan Zhou { 7473ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 74845ca1b86SEd Tanous { 74945ca1b86SEd Tanous return; 75045ca1b86SEd Tanous } 7519f8bfa7cSGunnar Mills std::optional<bool> locationIndicatorActive; 7521c8fba97SJames Feist std::optional<std::string> indicatorLed; 7531c8fba97SJames Feist 7547e860f15SJohn Edward Broadbent if (param.empty()) 7551c8fba97SJames Feist { 7561c8fba97SJames Feist return; 7571c8fba97SJames Feist } 7581c8fba97SJames Feist 759afc474aeSMyung Bae if (!json_util::readJsonPatch( // 760afc474aeSMyung Bae req, asyncResp->res, // 761afc474aeSMyung Bae "IndicatorLED", indicatorLed, // 762afc474aeSMyung Bae "LocationIndicatorActive", locationIndicatorActive // 763afc474aeSMyung Bae )) 7641c8fba97SJames Feist { 7651c8fba97SJames Feist return; 7661c8fba97SJames Feist } 7671c8fba97SJames Feist 7689f8bfa7cSGunnar Mills // TODO (Gunnar): Remove IndicatorLED after enough time has passed 7699f8bfa7cSGunnar Mills if (!locationIndicatorActive && !indicatorLed) 7701c8fba97SJames Feist { 7711c8fba97SJames Feist return; // delete this when we support more patch properties 7721c8fba97SJames Feist } 773d6aa0093SGunnar Mills if (indicatorLed) 774d6aa0093SGunnar Mills { 7757e860f15SJohn Edward Broadbent asyncResp->res.addHeader( 7767e860f15SJohn Edward Broadbent boost::beast::http::field::warning, 7770fda0f12SGeorge Liu "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\""); 778d6aa0093SGunnar Mills } 7791c8fba97SJames Feist 7807e860f15SJohn Edward Broadbent const std::string& chassisId = param; 7811c8fba97SJames Feist 782e99073f5SGeorge Liu dbus::utility::getSubTree( 783*3f95a277SMyung Bae "/xyz/openbmc_project/inventory", 0, chassisInterfaces, 784cf7eba09SNan Zhou [asyncResp, chassisId, locationIndicatorActive, 7855e7e2dc5SEd Tanous indicatorLed](const boost::system::error_code& ec, 786b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 7871c8fba97SJames Feist if (ec) 7881c8fba97SJames Feist { 78962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 7901c8fba97SJames Feist messages::internalError(asyncResp->res); 7911c8fba97SJames Feist return; 7921c8fba97SJames Feist } 7931c8fba97SJames Feist 7941c8fba97SJames Feist // Iterate over all retrieved ObjectPaths. 795bd79bce8SPatrick Williams for (const std::pair<std::string, 796bd79bce8SPatrick Williams std::vector<std::pair< 797bd79bce8SPatrick Williams std::string, std::vector<std::string>>>>& 7981214b7e7SGunnar Mills object : subtree) 7991c8fba97SJames Feist { 8001c8fba97SJames Feist const std::string& path = object.first; 801bd79bce8SPatrick Williams const std::vector< 802bd79bce8SPatrick Williams std::pair<std::string, std::vector<std::string>>>& 8031214b7e7SGunnar Mills connectionNames = object.second; 8041c8fba97SJames Feist 805997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 806997093ebSGeorge Liu if (objPath.filename() != chassisId) 8071c8fba97SJames Feist { 8081c8fba97SJames Feist continue; 8091c8fba97SJames Feist } 8101c8fba97SJames Feist 81126f6976fSEd Tanous if (connectionNames.empty()) 8121c8fba97SJames Feist { 81362598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 8141c8fba97SJames Feist continue; 8151c8fba97SJames Feist } 8161c8fba97SJames Feist 81723a21a1cSEd Tanous const std::vector<std::string>& interfaces3 = 8181c8fba97SJames Feist connectionNames[0].second; 8191c8fba97SJames Feist 820e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 821e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 8221c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 8230fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 8241c8fba97SJames Feist bool indicatorChassis = false; 8251c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 8261c8fba97SJames Feist { 8273544d2a7SEd Tanous if (std::ranges::find(interfaces3, interface) != 8283544d2a7SEd Tanous interfaces3.end()) 8291c8fba97SJames Feist { 8301c8fba97SJames Feist indicatorChassis = true; 8311c8fba97SJames Feist break; 8321c8fba97SJames Feist } 8331c8fba97SJames Feist } 8349f8bfa7cSGunnar Mills if (locationIndicatorActive) 8359f8bfa7cSGunnar Mills { 8369f8bfa7cSGunnar Mills if (indicatorChassis) 8379f8bfa7cSGunnar Mills { 838bd79bce8SPatrick Williams setSystemLocationIndicatorActive( 839bd79bce8SPatrick Williams asyncResp, *locationIndicatorActive); 8409f8bfa7cSGunnar Mills } 8419f8bfa7cSGunnar Mills else 8429f8bfa7cSGunnar Mills { 843002d39b4SEd Tanous messages::propertyUnknown(asyncResp->res, 844002d39b4SEd Tanous "LocationIndicatorActive"); 8459f8bfa7cSGunnar Mills } 8469f8bfa7cSGunnar Mills } 8479f8bfa7cSGunnar Mills if (indicatorLed) 8489f8bfa7cSGunnar Mills { 8491c8fba97SJames Feist if (indicatorChassis) 8501c8fba97SJames Feist { 851f23b7296SEd Tanous setIndicatorLedState(asyncResp, *indicatorLed); 8521c8fba97SJames Feist } 8531c8fba97SJames Feist else 8541c8fba97SJames Feist { 855bd79bce8SPatrick Williams messages::propertyUnknown(asyncResp->res, 856bd79bce8SPatrick Williams "IndicatorLED"); 8571c8fba97SJames Feist } 8581c8fba97SJames Feist } 8591c8fba97SJames Feist return; 8601c8fba97SJames Feist } 8611c8fba97SJames Feist 862d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 863e99073f5SGeorge Liu }); 864cf7eba09SNan Zhou } 865cf7eba09SNan Zhou 866cf7eba09SNan Zhou /** 867cf7eba09SNan Zhou * Chassis override class for delivering Chassis Schema 868cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 869cf7eba09SNan Zhou */ 870cf7eba09SNan Zhou inline void requestRoutesChassis(App& app) 871cf7eba09SNan Zhou { 872cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 873cf7eba09SNan Zhou .privileges(redfish::privileges::getChassis) 874cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 875cf7eba09SNan Zhou std::bind_front(handleChassisGet, std::ref(app))); 876cf7eba09SNan Zhou 877cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 878cf7eba09SNan Zhou .privileges(redfish::privileges::patchChassis) 879cf7eba09SNan Zhou .methods(boost::beast::http::verb::patch)( 880cf7eba09SNan Zhou std::bind_front(handleChassisPatch, std::ref(app))); 8811c8fba97SJames Feist } 882dd99e04bSP.K. Lee 883504af5a0SPatrick Williams inline void doChassisPowerCycle( 884504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 885dd99e04bSP.K. Lee { 8867a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 887c3b3c92aSVijay Khemka "xyz.openbmc_project.State.Chassis"}; 888c3b3c92aSVijay Khemka 889c3b3c92aSVijay Khemka // Use mapper to get subtree paths. 8907a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 8917a1dbc48SGeorge Liu "/", 0, interfaces, 892b9d36b47SEd Tanous [asyncResp]( 8937a1dbc48SGeorge Liu const boost::system::error_code& ec, 894b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& chassisList) { 895c3b3c92aSVijay Khemka if (ec) 896c3b3c92aSVijay Khemka { 89762598e31SEd Tanous BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec); 898c3b3c92aSVijay Khemka messages::internalError(asyncResp->res); 899c3b3c92aSVijay Khemka return; 900c3b3c92aSVijay Khemka } 901c3b3c92aSVijay Khemka 902dd99e04bSP.K. Lee const char* processName = "xyz.openbmc_project.State.Chassis"; 903dd99e04bSP.K. Lee const char* interfaceName = "xyz.openbmc_project.State.Chassis"; 904dd99e04bSP.K. Lee const char* destProperty = "RequestedPowerTransition"; 905dd99e04bSP.K. Lee const std::string propertyValue = 906dd99e04bSP.K. Lee "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; 907bd79bce8SPatrick Williams std::string objectPath = 908bd79bce8SPatrick Williams "/xyz/openbmc_project/state/chassis_system0"; 909c3b3c92aSVijay Khemka 910c3b3c92aSVijay Khemka /* Look for system reset chassis path */ 911bd79bce8SPatrick Williams if ((std::ranges::find(chassisList, objectPath)) == 912bd79bce8SPatrick Williams chassisList.end()) 913c3b3c92aSVijay Khemka { 914c3b3c92aSVijay Khemka /* We prefer to reset the full chassis_system, but if it doesn't 915c3b3c92aSVijay Khemka * exist on some platforms, fall back to a host-only power reset 916c3b3c92aSVijay Khemka */ 917c3b3c92aSVijay Khemka objectPath = "/xyz/openbmc_project/state/chassis0"; 918c3b3c92aSVijay Khemka } 919dd99e04bSP.K. Lee 920e93abac6SGinu George setDbusProperty(asyncResp, "ResetType", processName, objectPath, 921e93abac6SGinu George interfaceName, destProperty, propertyValue); 9227a1dbc48SGeorge Liu }); 923dd99e04bSP.K. Lee } 924dd99e04bSP.K. Lee 925cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost( 926cf7eba09SNan Zhou App& app, const crow::Request& req, 9277e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 928cf7eba09SNan Zhou const std::string& /*chassisId*/) 929cf7eba09SNan Zhou { 9303ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 93145ca1b86SEd Tanous { 93245ca1b86SEd Tanous return; 93345ca1b86SEd Tanous } 93462598e31SEd Tanous BMCWEB_LOG_DEBUG("Post Chassis Reset."); 935dd99e04bSP.K. Lee 936dd99e04bSP.K. Lee std::string resetType; 937dd99e04bSP.K. Lee 938cf7eba09SNan Zhou if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 939dd99e04bSP.K. Lee { 940dd99e04bSP.K. Lee return; 941dd99e04bSP.K. Lee } 942dd99e04bSP.K. Lee 943dd99e04bSP.K. Lee if (resetType != "PowerCycle") 944dd99e04bSP.K. Lee { 94562598e31SEd Tanous BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType); 946002d39b4SEd Tanous messages::actionParameterNotSupported(asyncResp->res, resetType, 947002d39b4SEd Tanous "ResetType"); 948dd99e04bSP.K. Lee 949dd99e04bSP.K. Lee return; 950dd99e04bSP.K. Lee } 951dd99e04bSP.K. Lee doChassisPowerCycle(asyncResp); 952dd99e04bSP.K. Lee } 9531cb1a9e6SAppaRao Puli 9541cb1a9e6SAppaRao Puli /** 955cf7eba09SNan Zhou * ChassisResetAction class supports the POST method for the Reset 956cf7eba09SNan Zhou * action. 957cf7eba09SNan Zhou * Function handles POST method request. 958cf7eba09SNan Zhou * Analyzes POST body before sending Reset request data to D-Bus. 9591cb1a9e6SAppaRao Puli */ 960cf7eba09SNan Zhou 961cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app) 9621cb1a9e6SAppaRao Puli { 963cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/") 964cf7eba09SNan Zhou .privileges(redfish::privileges::postChassis) 965cf7eba09SNan Zhou .methods(boost::beast::http::verb::post)( 966cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoPost, std::ref(app))); 967cf7eba09SNan Zhou } 968cf7eba09SNan Zhou 969cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet( 970cf7eba09SNan Zhou App& app, const crow::Request& req, 9717e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 972cf7eba09SNan Zhou const std::string& chassisId) 973cf7eba09SNan Zhou { 9743ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 9751cb1a9e6SAppaRao Puli { 97645ca1b86SEd Tanous return; 97745ca1b86SEd Tanous } 978cf7eba09SNan Zhou asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 979ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 980ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId); 9811476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 9821476687dSEd Tanous 9831476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 9845b9e95a1SNan Zhou nlohmann::json::array_t parameters; 9855b9e95a1SNan Zhou nlohmann::json::object_t parameter; 9865b9e95a1SNan Zhou parameter["Name"] = "ResetType"; 9875b9e95a1SNan Zhou parameter["Required"] = true; 988539d8c6bSEd Tanous parameter["DataType"] = action_info::ParameterTypes::String; 9891476687dSEd Tanous nlohmann::json::array_t allowed; 990ad539545SPatrick Williams allowed.emplace_back("PowerCycle"); 9915b9e95a1SNan Zhou parameter["AllowableValues"] = std::move(allowed); 992ad539545SPatrick Williams parameters.emplace_back(std::move(parameter)); 9935b9e95a1SNan Zhou 9941476687dSEd Tanous asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 995cf7eba09SNan Zhou } 996cf7eba09SNan Zhou 997cf7eba09SNan Zhou /** 998cf7eba09SNan Zhou * ChassisResetActionInfo derived class for delivering Chassis 999cf7eba09SNan Zhou * ResetType AllowableValues using ResetInfo schema. 1000cf7eba09SNan Zhou */ 1001cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app) 1002cf7eba09SNan Zhou { 1003cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/") 1004cf7eba09SNan Zhou .privileges(redfish::privileges::getActionInfo) 1005cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 1006cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoGet, std::ref(app))); 10071cb1a9e6SAppaRao Puli } 10081cb1a9e6SAppaRao Puli 1009e37f8451SRapkiewicz, Pawel } // namespace redfish 1010