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" 213ccb3adbSEd Tanous #include "utils/collection.hpp" 223ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 23cf7eba09SNan Zhou #include "utils/json_utils.hpp" 241abe55efSEd Tanous 25d7857201SEd Tanous #include <asm-generic/errno.h> 26d7857201SEd Tanous 27d7857201SEd Tanous #include <boost/beast/http/field.hpp> 28d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 29e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 30ef4c65b7SEd Tanous #include <boost/url/format.hpp> 31d7857201SEd Tanous #include <boost/url/url.hpp> 32d7857201SEd Tanous #include <nlohmann/json.hpp> 33d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 3486d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 351214b7e7SGunnar Mills 36d7857201SEd Tanous #include <algorithm> 377a1dbc48SGeorge Liu #include <array> 38d7857201SEd Tanous #include <format> 39d7857201SEd Tanous #include <functional> 402952f648SJoseph-Jonathan Salzano #include <memory> 41d7857201SEd Tanous #include <optional> 423544d2a7SEd Tanous #include <ranges> 43d7857201SEd Tanous #include <string> 447a1dbc48SGeorge Liu #include <string_view> 45d7857201SEd Tanous #include <utility> 46d7857201SEd Tanous #include <vector> 477a1dbc48SGeorge Liu 481abe55efSEd Tanous namespace redfish 491abe55efSEd Tanous { 50e37f8451SRapkiewicz, Pawel 51504af5a0SPatrick Williams inline chassis::ChassisType translateChassisTypeToRedfish( 52504af5a0SPatrick Williams const std::string_view& chassisType) 532952f648SJoseph-Jonathan Salzano { 542952f648SJoseph-Jonathan Salzano if (chassisType == 552952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Blade") 562952f648SJoseph-Jonathan Salzano { 572952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Blade; 582952f648SJoseph-Jonathan Salzano } 592952f648SJoseph-Jonathan Salzano if (chassisType == 602952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Component") 612952f648SJoseph-Jonathan Salzano { 622952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Component; 632952f648SJoseph-Jonathan Salzano } 642952f648SJoseph-Jonathan Salzano if (chassisType == 652952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Enclosure") 662952f648SJoseph-Jonathan Salzano { 672952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Enclosure; 682952f648SJoseph-Jonathan Salzano } 692952f648SJoseph-Jonathan Salzano if (chassisType == 702952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Module") 712952f648SJoseph-Jonathan Salzano { 722952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Module; 732952f648SJoseph-Jonathan Salzano } 742952f648SJoseph-Jonathan Salzano if (chassisType == 752952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.RackMount") 762952f648SJoseph-Jonathan Salzano { 772952f648SJoseph-Jonathan Salzano return chassis::ChassisType::RackMount; 782952f648SJoseph-Jonathan Salzano } 792952f648SJoseph-Jonathan Salzano if (chassisType == 802952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StandAlone") 812952f648SJoseph-Jonathan Salzano { 822952f648SJoseph-Jonathan Salzano return chassis::ChassisType::StandAlone; 832952f648SJoseph-Jonathan Salzano } 842952f648SJoseph-Jonathan Salzano if (chassisType == 852952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StorageEnclosure") 862952f648SJoseph-Jonathan Salzano { 872952f648SJoseph-Jonathan Salzano return chassis::ChassisType::StorageEnclosure; 882952f648SJoseph-Jonathan Salzano } 892952f648SJoseph-Jonathan Salzano if (chassisType == 902952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Zone") 912952f648SJoseph-Jonathan Salzano { 922952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Zone; 932952f648SJoseph-Jonathan Salzano } 942952f648SJoseph-Jonathan Salzano return chassis::ChassisType::Invalid; 952952f648SJoseph-Jonathan Salzano } 962952f648SJoseph-Jonathan Salzano 97e37f8451SRapkiewicz, Pawel /** 985e577bc1SWilly Tu * @brief Retrieves resources over dbus to link to the chassis 995e577bc1SWilly Tu * 1005e577bc1SWilly Tu * @param[in] asyncResp - Shared pointer for completing asynchronous 1015e577bc1SWilly Tu * calls 1025e577bc1SWilly Tu * @param[in] path - Chassis dbus path to look for the storage. 1035e577bc1SWilly Tu * 1045e577bc1SWilly Tu * Calls the Association endpoints on the path + "/storage" and add the link of 1055e577bc1SWilly Tu * json["Links"]["Storage@odata.count"] = 1065e577bc1SWilly Tu * {"@odata.id", "/redfish/v1/Storage/" + resourceId} 1075e577bc1SWilly Tu * 1085e577bc1SWilly Tu * @return None. 1095e577bc1SWilly Tu */ 1105e577bc1SWilly Tu inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1115e577bc1SWilly Tu const sdbusplus::message::object_path& path) 1125e577bc1SWilly Tu { 113deae6a78SEd Tanous dbus::utility::getProperty<std::vector<std::string>>( 114deae6a78SEd Tanous "xyz.openbmc_project.ObjectMapper", (path / "storage").str, 115deae6a78SEd Tanous "xyz.openbmc_project.Association", "endpoints", 116d4b054c1SWilly Tu [asyncResp](const boost::system::error_code& ec, 1175e577bc1SWilly Tu const std::vector<std::string>& storageList) { 1185e577bc1SWilly Tu if (ec) 1195e577bc1SWilly Tu { 12062598e31SEd Tanous BMCWEB_LOG_DEBUG("getStorageLink got DBUS response error"); 1215e577bc1SWilly Tu return; 1225e577bc1SWilly Tu } 1235e577bc1SWilly Tu 1245e577bc1SWilly Tu nlohmann::json::array_t storages; 1255e577bc1SWilly Tu for (const std::string& storagePath : storageList) 1265e577bc1SWilly Tu { 1275e577bc1SWilly Tu std::string id = 1285e577bc1SWilly Tu sdbusplus::message::object_path(storagePath).filename(); 1295e577bc1SWilly Tu if (id.empty()) 1305e577bc1SWilly Tu { 1315e577bc1SWilly Tu continue; 1325e577bc1SWilly Tu } 1335e577bc1SWilly Tu 1345e577bc1SWilly Tu nlohmann::json::object_t storage; 135253f11b8SEd Tanous storage["@odata.id"] = 136253f11b8SEd Tanous boost::urls::format("/redfish/v1/Systems/{}/Storage/{}", 137253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, id); 1385e577bc1SWilly Tu storages.emplace_back(std::move(storage)); 1395e577bc1SWilly Tu } 1405e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["Storage@odata.count"] = 1415e577bc1SWilly Tu storages.size(); 1425e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages); 1435e577bc1SWilly Tu }); 1445e577bc1SWilly Tu } 1455e577bc1SWilly Tu 1465e577bc1SWilly Tu /** 147beeca0aeSGunnar Mills * @brief Retrieves chassis state properties over dbus 148beeca0aeSGunnar Mills * 149ac106bf6SEd Tanous * @param[in] asyncResp - Shared pointer for completing asynchronous calls. 150beeca0aeSGunnar Mills * 151beeca0aeSGunnar Mills * @return None. 152beeca0aeSGunnar Mills */ 153ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp) 154beeca0aeSGunnar Mills { 1551e1e598dSJonathan Doman // crow::connections::systemBus->async_method_call( 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 2597a1dbc48SGeorge Liu constexpr std::array<std::string_view, 2> interfaces{ 2607a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board", 2617a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis"}; 26202f6ff19SGunnar Mills collection_util::getCollectionMembers( 26336b5f1edSLakshmi Yadlapati asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces, 26436b5f1edSLakshmi Yadlapati "/xyz/openbmc_project/inventory"); 265cf7eba09SNan Zhou } 266cf7eba09SNan Zhou 267a5617496SJie Yang inline void getChassisContainedBy( 268a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 269a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 27028ee563eSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& upstreamChassisPaths) 271a5617496SJie Yang { 272a5617496SJie Yang if (ec) 273a5617496SJie Yang { 274a5617496SJie Yang if (ec.value() != EBADR) 275a5617496SJie Yang { 27662598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 277a5617496SJie Yang messages::internalError(asyncResp->res); 278a5617496SJie Yang } 279a5617496SJie Yang return; 280a5617496SJie Yang } 281a5617496SJie Yang if (upstreamChassisPaths.empty()) 282a5617496SJie Yang { 283a5617496SJie Yang return; 284a5617496SJie Yang } 285a5617496SJie Yang if (upstreamChassisPaths.size() > 1) 286a5617496SJie Yang { 2878ece0e45SEd Tanous BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId); 288a5617496SJie Yang messages::internalError(asyncResp->res); 289a5617496SJie Yang return; 290a5617496SJie Yang } 291a5617496SJie Yang 292a5617496SJie Yang sdbusplus::message::object_path upstreamChassisPath( 293a5617496SJie Yang upstreamChassisPaths[0]); 294a5617496SJie Yang std::string upstreamChassis = upstreamChassisPath.filename(); 295a5617496SJie Yang if (upstreamChassis.empty()) 296a5617496SJie Yang { 29762598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}", 29862598e31SEd Tanous upstreamChassisPath.str, chassisId); 299a5617496SJie Yang return; 300a5617496SJie Yang } 301a5617496SJie Yang 302a5617496SJie Yang asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] = 303a5617496SJie Yang boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis); 304a5617496SJie Yang } 305a5617496SJie Yang 306a5617496SJie Yang inline void getChassisContains( 307a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 308a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 30928ee563eSMyung Bae const dbus::utility::MapperGetSubTreePathsResponse& downstreamChassisPaths) 310a5617496SJie Yang { 311a5617496SJie Yang if (ec) 312a5617496SJie Yang { 313a5617496SJie Yang if (ec.value() != EBADR) 314a5617496SJie Yang { 31562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 316a5617496SJie Yang messages::internalError(asyncResp->res); 317a5617496SJie Yang } 318a5617496SJie Yang return; 319a5617496SJie Yang } 320a5617496SJie Yang if (downstreamChassisPaths.empty()) 321a5617496SJie Yang { 322a5617496SJie Yang return; 323a5617496SJie Yang } 324a5617496SJie Yang nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"]; 325a5617496SJie Yang if (!jValue.is_array()) 326a5617496SJie Yang { 327a5617496SJie Yang // Create the array if it was empty 328a5617496SJie Yang jValue = nlohmann::json::array(); 329a5617496SJie Yang } 330a5617496SJie Yang for (const auto& p : downstreamChassisPaths) 331a5617496SJie Yang { 332a5617496SJie Yang sdbusplus::message::object_path downstreamChassisPath(p); 333a5617496SJie Yang std::string downstreamChassis = downstreamChassisPath.filename(); 334a5617496SJie Yang if (downstreamChassis.empty()) 335a5617496SJie Yang { 33662598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}", 33762598e31SEd Tanous downstreamChassisPath.str, chassisId); 338a5617496SJie Yang continue; 339a5617496SJie Yang } 340a5617496SJie Yang nlohmann::json link; 341bd79bce8SPatrick Williams link["@odata.id"] = 342bd79bce8SPatrick Williams boost::urls::format("/redfish/v1/Chassis/{}", downstreamChassis); 343a5617496SJie Yang jValue.push_back(std::move(link)); 344a5617496SJie Yang } 345a5617496SJie Yang asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size(); 346a5617496SJie Yang } 347a5617496SJie Yang 348bd79bce8SPatrick Williams inline void getChassisConnectivity( 349bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 350bd79bce8SPatrick Williams const std::string& chassisId, const std::string& chassisPath) 351a5617496SJie Yang { 35262598e31SEd Tanous BMCWEB_LOG_DEBUG("Get chassis connectivity"); 353a5617496SJie Yang 35428ee563eSMyung Bae constexpr std::array<std::string_view, 2> interfaces{ 35528ee563eSMyung Bae "xyz.openbmc_project.Inventory.Item.Board", 35628ee563eSMyung Bae "xyz.openbmc_project.Inventory.Item.Chassis"}; 35728ee563eSMyung Bae 35828ee563eSMyung Bae dbus::utility::getAssociatedSubTreePaths( 359a5617496SJie Yang chassisPath + "/contained_by", 36028ee563eSMyung Bae sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 36128ee563eSMyung Bae interfaces, 362a5617496SJie Yang std::bind_front(getChassisContainedBy, asyncResp, chassisId)); 363a5617496SJie Yang 36428ee563eSMyung Bae dbus::utility::getAssociatedSubTreePaths( 365a5617496SJie Yang chassisPath + "/containing", 36628ee563eSMyung Bae sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 36728ee563eSMyung Bae interfaces, std::bind_front(getChassisContains, asyncResp, chassisId)); 368a5617496SJie Yang } 369a5617496SJie Yang 370cf7eba09SNan Zhou /** 371cf7eba09SNan Zhou * ChassisCollection derived class for delivering Chassis Collection Schema 372cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 373cf7eba09SNan Zhou */ 374cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app) 375cf7eba09SNan Zhou { 376cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/") 377cf7eba09SNan Zhou .privileges(redfish::privileges::getChassisCollection) 378cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 379cf7eba09SNan Zhou std::bind_front(handleChassisCollectionGet, std::ref(app))); 38062d5e2e4SEd Tanous } 381e37f8451SRapkiewicz, Pawel 382bd79bce8SPatrick Williams inline void getChassisLocationCode( 383bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 384bd79bce8SPatrick Williams const std::string& connectionName, const std::string& path) 385308f70c7SWilly Tu { 386deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 387deae6a78SEd Tanous connectionName, path, 3881e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 3895e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3901e1e598dSJonathan Doman const std::string& property) { 391308f70c7SWilly Tu if (ec) 392308f70c7SWilly Tu { 39362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location"); 394308f70c7SWilly Tu messages::internalError(asyncResp->res); 395308f70c7SWilly Tu return; 396308f70c7SWilly Tu } 397308f70c7SWilly Tu 398bd79bce8SPatrick Williams asyncResp->res 399bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 4001e1e598dSJonathan Doman property; 4011e1e598dSJonathan Doman }); 402308f70c7SWilly Tu } 403308f70c7SWilly Tu 404308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 405308f70c7SWilly Tu const std::string& connectionName, 406308f70c7SWilly Tu const std::string& path) 407308f70c7SWilly Tu { 408deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 409deae6a78SEd Tanous connectionName, path, "xyz.openbmc_project.Common.UUID", "UUID", 4105e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 4111e1e598dSJonathan Doman const std::string& chassisUUID) { 412308f70c7SWilly Tu if (ec) 413308f70c7SWilly Tu { 41462598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for UUID"); 415308f70c7SWilly Tu messages::internalError(asyncResp->res); 416308f70c7SWilly Tu return; 417308f70c7SWilly Tu } 4181e1e598dSJonathan Doman asyncResp->res.jsonValue["UUID"] = chassisUUID; 4191e1e598dSJonathan Doman }); 420308f70c7SWilly Tu } 421308f70c7SWilly Tu 4227164bc62SChau Ly inline void handleDecoratorAssetProperties( 42345ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4247164bc62SChau Ly const std::string& chassisId, const std::string& path, 4257164bc62SChau Ly const dbus::utility::DBusPropertiesMap& propertiesList) 426cf7eba09SNan Zhou { 4277164bc62SChau Ly const std::string* partNumber = nullptr; 4287164bc62SChau Ly const std::string* serialNumber = nullptr; 4297164bc62SChau Ly const std::string* manufacturer = nullptr; 4307164bc62SChau Ly const std::string* model = nullptr; 4317164bc62SChau Ly const std::string* sparePartNumber = nullptr; 4327164bc62SChau Ly 4337164bc62SChau Ly const bool success = sdbusplus::unpackPropertiesNoThrow( 4347164bc62SChau Ly dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 4357164bc62SChau Ly partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, 4367164bc62SChau Ly "Model", model, "SparePartNumber", sparePartNumber); 4377164bc62SChau Ly 4387164bc62SChau Ly if (!success) 43945ca1b86SEd Tanous { 4407164bc62SChau Ly messages::internalError(asyncResp->res); 44145ca1b86SEd Tanous return; 44245ca1b86SEd Tanous } 443734bfe90SGunnar Mills 4447164bc62SChau Ly if (partNumber != nullptr) 4457164bc62SChau Ly { 4467164bc62SChau Ly asyncResp->res.jsonValue["PartNumber"] = *partNumber; 4477164bc62SChau Ly } 4487164bc62SChau Ly 4497164bc62SChau Ly if (serialNumber != nullptr) 4507164bc62SChau Ly { 4517164bc62SChau Ly asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 4527164bc62SChau Ly } 4537164bc62SChau Ly 4547164bc62SChau Ly if (manufacturer != nullptr) 4557164bc62SChau Ly { 4567164bc62SChau Ly asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 4577164bc62SChau Ly } 4587164bc62SChau Ly 4597164bc62SChau Ly if (model != nullptr) 4607164bc62SChau Ly { 4617164bc62SChau Ly asyncResp->res.jsonValue["Model"] = *model; 4627164bc62SChau Ly } 4637164bc62SChau Ly 4647164bc62SChau Ly // SparePartNumber is optional on D-Bus 4657164bc62SChau Ly // so skip if it is empty 4667164bc62SChau Ly if (sparePartNumber != nullptr && !sparePartNumber->empty()) 4677164bc62SChau Ly { 4687164bc62SChau Ly asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 4697164bc62SChau Ly } 4707164bc62SChau Ly 4717164bc62SChau Ly asyncResp->res.jsonValue["Name"] = chassisId; 4727164bc62SChau Ly asyncResp->res.jsonValue["Id"] = chassisId; 47325b54dbaSEd Tanous 47425b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL) 47525b54dbaSEd Tanous { 4767164bc62SChau Ly asyncResp->res.jsonValue["Thermal"]["@odata.id"] = 4777164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId); 4787164bc62SChau Ly // Power object 4797164bc62SChau Ly asyncResp->res.jsonValue["Power"]["@odata.id"] = 4807164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId); 48125b54dbaSEd Tanous } 48225b54dbaSEd Tanous 48325b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM) 48425b54dbaSEd Tanous { 4857164bc62SChau Ly asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] = 4867164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem", 4877164bc62SChau Ly chassisId); 4887164bc62SChau Ly asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] = 48925b54dbaSEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", 49025b54dbaSEd Tanous chassisId); 4917164bc62SChau Ly asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] = 4927164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics", 4937164bc62SChau Ly chassisId); 49425b54dbaSEd Tanous } 4957164bc62SChau Ly // SensorCollection 4967164bc62SChau Ly asyncResp->res.jsonValue["Sensors"]["@odata.id"] = 4977164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId); 498539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 4997164bc62SChau Ly 5007164bc62SChau Ly nlohmann::json::array_t computerSystems; 5017164bc62SChau Ly nlohmann::json::object_t system; 502bd79bce8SPatrick Williams system["@odata.id"] = 503bd79bce8SPatrick Williams std::format("/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME); 5047164bc62SChau Ly computerSystems.emplace_back(std::move(system)); 5057164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ComputerSystems"] = 5067164bc62SChau Ly std::move(computerSystems); 5077164bc62SChau Ly 5087164bc62SChau Ly nlohmann::json::array_t managedBy; 5097164bc62SChau Ly nlohmann::json::object_t manager; 510253f11b8SEd Tanous manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}", 511253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 5127164bc62SChau Ly managedBy.emplace_back(std::move(manager)); 5137164bc62SChau Ly asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); 5147164bc62SChau Ly getChassisState(asyncResp); 5157164bc62SChau Ly getStorageLink(asyncResp, path); 5167164bc62SChau Ly } 5177164bc62SChau Ly 5182952f648SJoseph-Jonathan Salzano inline void handleChassisProperties( 5192952f648SJoseph-Jonathan Salzano const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5202952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) 5212952f648SJoseph-Jonathan Salzano { 5222952f648SJoseph-Jonathan Salzano const std::string* type = nullptr; 5232952f648SJoseph-Jonathan Salzano 5242952f648SJoseph-Jonathan Salzano const bool success = sdbusplus::unpackPropertiesNoThrow( 5252952f648SJoseph-Jonathan Salzano dbus_utils::UnpackErrorPrinter(), propertiesList, "Type", type); 5262952f648SJoseph-Jonathan Salzano 5272952f648SJoseph-Jonathan Salzano if (!success) 5282952f648SJoseph-Jonathan Salzano { 5292952f648SJoseph-Jonathan Salzano messages::internalError(asyncResp->res); 5302952f648SJoseph-Jonathan Salzano return; 5312952f648SJoseph-Jonathan Salzano } 5322952f648SJoseph-Jonathan Salzano 53319ea2864SGunnar Mills // Chassis Type is a required property in Redfish 53419ea2864SGunnar Mills // If there is an error or some enum we don't support just sit it to Rack 53519ea2864SGunnar Mills // Mount 53619ea2864SGunnar Mills asyncResp->res.jsonValue["ChassisType"] = chassis::ChassisType::RackMount; 53719ea2864SGunnar Mills 5382952f648SJoseph-Jonathan Salzano if (type != nullptr) 5392952f648SJoseph-Jonathan Salzano { 5402952f648SJoseph-Jonathan Salzano auto chassisType = translateChassisTypeToRedfish(*type); 5412952f648SJoseph-Jonathan Salzano if (chassisType != chassis::ChassisType::Invalid) 5422952f648SJoseph-Jonathan Salzano { 5432952f648SJoseph-Jonathan Salzano asyncResp->res.jsonValue["ChassisType"] = chassisType; 5442952f648SJoseph-Jonathan Salzano } 5452952f648SJoseph-Jonathan Salzano } 5462952f648SJoseph-Jonathan Salzano } 5472952f648SJoseph-Jonathan Salzano 5487164bc62SChau Ly inline void handleChassisGetSubTree( 5497164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5507164bc62SChau Ly const std::string& chassisId, const boost::system::error_code& ec, 5517164bc62SChau Ly const dbus::utility::MapperGetSubTreeResponse& subtree) 5527164bc62SChau Ly { 55362d5e2e4SEd Tanous if (ec) 5541abe55efSEd Tanous { 55562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 556f12894f8SJason M. Bills messages::internalError(asyncResp->res); 557daf36e2eSEd Tanous return; 558daf36e2eSEd Tanous } 559daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 560cf7eba09SNan Zhou for (const std::pair< 561cf7eba09SNan Zhou std::string, 562cf7eba09SNan Zhou std::vector<std::pair<std::string, std::vector<std::string>>>>& 5631214b7e7SGunnar Mills object : subtree) 5641abe55efSEd Tanous { 565daf36e2eSEd Tanous const std::string& path = object.first; 566cf7eba09SNan Zhou const std::vector<std::pair<std::string, std::vector<std::string>>>& 5671214b7e7SGunnar Mills connectionNames = object.second; 5687e860f15SJohn Edward Broadbent 569997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 570997093ebSGeorge Liu if (objPath.filename() != chassisId) 5711abe55efSEd Tanous { 572daf36e2eSEd Tanous continue; 573daf36e2eSEd Tanous } 57426f03899SShawn McCarney 575a5617496SJie Yang getChassisConnectivity(asyncResp, chassisId, path); 576a5617496SJie Yang 57726f6976fSEd Tanous if (connectionNames.empty()) 5781abe55efSEd Tanous { 57962598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 580e0d918bcSEd Tanous continue; 581daf36e2eSEd Tanous } 582e0d918bcSEd Tanous 5837164bc62SChau Ly asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis"; 58449c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.id"] = 585ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 58649c53ac9SJohnathan Mantey asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 587cf7eba09SNan Zhou asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] = 5887164bc62SChau Ly boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset", 5897164bc62SChau Ly chassisId); 5901476687dSEd Tanous asyncResp->res 591cf7eba09SNan Zhou .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] = 592ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo", 593ef4c65b7SEd Tanous chassisId); 5946c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 5956c3e9451SGeorge Liu path + "/drive", 5967164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec3, 5976c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 59892903bd4SJohn Edward Broadbent if (ec3 || resp.empty()) 59992903bd4SJohn Edward Broadbent { 60092903bd4SJohn Edward Broadbent return; // no drives = no failures 60192903bd4SJohn Edward Broadbent } 60292903bd4SJohn Edward Broadbent 60392903bd4SJohn Edward Broadbent nlohmann::json reference; 604bd79bce8SPatrick Williams reference["@odata.id"] = boost::urls::format( 605bd79bce8SPatrick Williams "/redfish/v1/Chassis/{}/Drives", chassisId); 60692903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Drives"] = std::move(reference); 60792903bd4SJohn Edward Broadbent }); 60892903bd4SJohn Edward Broadbent 609002d39b4SEd Tanous const std::string& connectionName = connectionNames[0].first; 6101c8fba97SJames Feist 6117164bc62SChau Ly const std::vector<std::string>& interfaces2 = connectionNames[0].second; 612e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 613e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 6141c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 6150fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 6161c8fba97SJames Feist 617476b9cc5STejas Patil const std::string assetTagInterface = 6180fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.AssetTag"; 619523d4868SLogananth Sundararaj const std::string replaceableInterface = 620523d4868SLogananth Sundararaj "xyz.openbmc_project.Inventory.Decorator.Replaceable"; 621b4d593f1SCarson Labrado const std::string revisionInterface = 622b4d593f1SCarson Labrado "xyz.openbmc_project.Inventory.Decorator.Revision"; 623523d4868SLogananth Sundararaj for (const auto& interface : interfaces2) 624523d4868SLogananth Sundararaj { 625523d4868SLogananth Sundararaj if (interface == assetTagInterface) 626476b9cc5STejas Patil { 627deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 628deae6a78SEd Tanous connectionName, path, assetTagInterface, "AssetTag", 6297164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 6301e1e598dSJonathan Doman const std::string& property) { 6318a592810SEd Tanous if (ec2) 632476b9cc5STejas Patil { 633bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 634bd79bce8SPatrick Williams "DBus response error for AssetTag: {}", ec2); 635476b9cc5STejas Patil messages::internalError(asyncResp->res); 636476b9cc5STejas Patil return; 637476b9cc5STejas Patil } 638002d39b4SEd Tanous asyncResp->res.jsonValue["AssetTag"] = property; 6391e1e598dSJonathan Doman }); 640476b9cc5STejas Patil } 641523d4868SLogananth Sundararaj else if (interface == replaceableInterface) 642523d4868SLogananth Sundararaj { 643deae6a78SEd Tanous dbus::utility::getProperty<bool>( 644deae6a78SEd Tanous connectionName, path, replaceableInterface, "HotPluggable", 6457164bc62SChau Ly [asyncResp, chassisId](const boost::system::error_code& ec2, 646523d4868SLogananth Sundararaj const bool property) { 647523d4868SLogananth Sundararaj if (ec2) 648523d4868SLogananth Sundararaj { 64962598e31SEd Tanous BMCWEB_LOG_ERROR( 650bd79bce8SPatrick Williams "DBus response error for HotPluggable: {}", 651bd79bce8SPatrick Williams ec2); 652523d4868SLogananth Sundararaj messages::internalError(asyncResp->res); 653523d4868SLogananth Sundararaj return; 654523d4868SLogananth Sundararaj } 655523d4868SLogananth Sundararaj asyncResp->res.jsonValue["HotPluggable"] = property; 656523d4868SLogananth Sundararaj }); 657523d4868SLogananth Sundararaj } 658b4d593f1SCarson Labrado else if (interface == revisionInterface) 659b4d593f1SCarson Labrado { 660deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 661deae6a78SEd Tanous connectionName, path, revisionInterface, "Version", 662b4d593f1SCarson Labrado [asyncResp, chassisId](const boost::system::error_code& ec2, 663b4d593f1SCarson Labrado const std::string& property) { 664b4d593f1SCarson Labrado if (ec2) 665b4d593f1SCarson Labrado { 666bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 667bd79bce8SPatrick Williams "DBus response error for Version: {}", ec2); 668b4d593f1SCarson Labrado messages::internalError(asyncResp->res); 669b4d593f1SCarson Labrado return; 670b4d593f1SCarson Labrado } 671b4d593f1SCarson Labrado asyncResp->res.jsonValue["Version"] = property; 672b4d593f1SCarson Labrado }); 673b4d593f1SCarson Labrado } 674523d4868SLogananth Sundararaj } 675476b9cc5STejas Patil 6761c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 6771c8fba97SJames Feist { 6787164bc62SChau Ly if (std::ranges::find(interfaces2, interface) != interfaces2.end()) 6791c8fba97SJames Feist { 6801c8fba97SJames Feist getIndicatorLedState(asyncResp); 68159a17e4fSGeorge Liu getSystemLocationIndicatorActive(asyncResp); 6821c8fba97SJames Feist break; 6831c8fba97SJames Feist } 6841c8fba97SJames Feist } 6851c8fba97SJames Feist 686deae6a78SEd Tanous dbus::utility::getAllProperties( 68786d89ed7SKrzysztof Grobelny *crow::connections::systemBus, connectionName, path, 68886d89ed7SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Asset", 6897164bc62SChau Ly [asyncResp, chassisId, 6907164bc62SChau Ly path](const boost::system::error_code&, 691cf7eba09SNan Zhou const dbus::utility::DBusPropertiesMap& propertiesList) { 6927164bc62SChau Ly handleDecoratorAssetProperties(asyncResp, chassisId, path, 6937164bc62SChau Ly propertiesList); 69486d89ed7SKrzysztof Grobelny }); 6952c37b4b0SSharad Yadav 696*46f780f7SEd Tanous dbus::utility::getAllProperties( 6972952f648SJoseph-Jonathan Salzano *crow::connections::systemBus, connectionName, path, 6982952f648SJoseph-Jonathan Salzano "xyz.openbmc_project.Inventory.Item.Chassis", 6992952f648SJoseph-Jonathan Salzano [asyncResp]( 7002952f648SJoseph-Jonathan Salzano const boost::system::error_code&, 7012952f648SJoseph-Jonathan Salzano const dbus::utility::DBusPropertiesMap& propertiesList) { 7022952f648SJoseph-Jonathan Salzano handleChassisProperties(asyncResp, propertiesList); 7032952f648SJoseph-Jonathan Salzano }); 7042952f648SJoseph-Jonathan Salzano 705308f70c7SWilly Tu for (const auto& interface : interfaces2) 7062c37b4b0SSharad Yadav { 707308f70c7SWilly Tu if (interface == "xyz.openbmc_project.Common.UUID") 7082c37b4b0SSharad Yadav { 709308f70c7SWilly Tu getChassisUUID(asyncResp, connectionName, path); 7102c37b4b0SSharad Yadav } 711cf7eba09SNan Zhou else if (interface == 7120fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode") 7132c37b4b0SSharad Yadav { 714002d39b4SEd Tanous getChassisLocationCode(asyncResp, connectionName, path); 7152c37b4b0SSharad Yadav } 7162c37b4b0SSharad Yadav } 7172c37b4b0SSharad Yadav 718daf36e2eSEd Tanous return; 719daf36e2eSEd Tanous } 720e0d918bcSEd Tanous 721daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 722d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 7237164bc62SChau Ly } 724c181942fSQiang XU 725504af5a0SPatrick Williams inline void handleChassisGet( 726504af5a0SPatrick Williams App& app, const crow::Request& req, 7277164bc62SChau Ly const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7287164bc62SChau Ly const std::string& chassisId) 7297164bc62SChau Ly { 7307164bc62SChau Ly if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 7317164bc62SChau Ly { 7327164bc62SChau Ly return; 7337164bc62SChau Ly } 7347164bc62SChau Ly constexpr std::array<std::string_view, 2> interfaces = { 7357164bc62SChau Ly "xyz.openbmc_project.Inventory.Item.Board", 7367164bc62SChau Ly "xyz.openbmc_project.Inventory.Item.Chassis"}; 7377164bc62SChau Ly 7387164bc62SChau Ly dbus::utility::getSubTree( 7397164bc62SChau Ly "/xyz/openbmc_project/inventory", 0, interfaces, 7407164bc62SChau Ly std::bind_front(handleChassisGetSubTree, asyncResp, chassisId)); 7417164bc62SChau Ly 7427164bc62SChau Ly constexpr std::array<std::string_view, 1> interfaces2 = { 7437164bc62SChau Ly "xyz.openbmc_project.Chassis.Intrusion"}; 7447164bc62SChau Ly 7457164bc62SChau Ly dbus::utility::getSubTree( 7467164bc62SChau Ly "/xyz/openbmc_project", 0, interfaces2, 7477164bc62SChau Ly std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp)); 748cf7eba09SNan Zhou } 7491c8fba97SJames Feist 750504af5a0SPatrick Williams inline void handleChassisPatch( 751504af5a0SPatrick Williams App& app, const crow::Request& req, 7527e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 753cf7eba09SNan Zhou const std::string& param) 754cf7eba09SNan Zhou { 7553ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 75645ca1b86SEd Tanous { 75745ca1b86SEd Tanous return; 75845ca1b86SEd Tanous } 7599f8bfa7cSGunnar Mills std::optional<bool> locationIndicatorActive; 7601c8fba97SJames Feist std::optional<std::string> indicatorLed; 7611c8fba97SJames Feist 7627e860f15SJohn Edward Broadbent if (param.empty()) 7631c8fba97SJames Feist { 7641c8fba97SJames Feist return; 7651c8fba97SJames Feist } 7661c8fba97SJames Feist 767afc474aeSMyung Bae if (!json_util::readJsonPatch( // 768afc474aeSMyung Bae req, asyncResp->res, // 769afc474aeSMyung Bae "IndicatorLED", indicatorLed, // 770afc474aeSMyung Bae "LocationIndicatorActive", locationIndicatorActive // 771afc474aeSMyung Bae )) 7721c8fba97SJames Feist { 7731c8fba97SJames Feist return; 7741c8fba97SJames Feist } 7751c8fba97SJames Feist 7769f8bfa7cSGunnar Mills // TODO (Gunnar): Remove IndicatorLED after enough time has passed 7779f8bfa7cSGunnar Mills if (!locationIndicatorActive && !indicatorLed) 7781c8fba97SJames Feist { 7791c8fba97SJames Feist return; // delete this when we support more patch properties 7801c8fba97SJames Feist } 781d6aa0093SGunnar Mills if (indicatorLed) 782d6aa0093SGunnar Mills { 7837e860f15SJohn Edward Broadbent asyncResp->res.addHeader( 7847e860f15SJohn Edward Broadbent boost::beast::http::field::warning, 7850fda0f12SGeorge Liu "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\""); 786d6aa0093SGunnar Mills } 7871c8fba97SJames Feist 788e99073f5SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 7891c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board", 7901c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Chassis"}; 7911c8fba97SJames Feist 7927e860f15SJohn Edward Broadbent const std::string& chassisId = param; 7931c8fba97SJames Feist 794e99073f5SGeorge Liu dbus::utility::getSubTree( 795e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 796cf7eba09SNan Zhou [asyncResp, chassisId, locationIndicatorActive, 7975e7e2dc5SEd Tanous indicatorLed](const boost::system::error_code& ec, 798b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 7991c8fba97SJames Feist if (ec) 8001c8fba97SJames Feist { 80162598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 8021c8fba97SJames Feist messages::internalError(asyncResp->res); 8031c8fba97SJames Feist return; 8041c8fba97SJames Feist } 8051c8fba97SJames Feist 8061c8fba97SJames Feist // Iterate over all retrieved ObjectPaths. 807bd79bce8SPatrick Williams for (const std::pair<std::string, 808bd79bce8SPatrick Williams std::vector<std::pair< 809bd79bce8SPatrick Williams std::string, std::vector<std::string>>>>& 8101214b7e7SGunnar Mills object : subtree) 8111c8fba97SJames Feist { 8121c8fba97SJames Feist const std::string& path = object.first; 813bd79bce8SPatrick Williams const std::vector< 814bd79bce8SPatrick Williams std::pair<std::string, std::vector<std::string>>>& 8151214b7e7SGunnar Mills connectionNames = object.second; 8161c8fba97SJames Feist 817997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 818997093ebSGeorge Liu if (objPath.filename() != chassisId) 8191c8fba97SJames Feist { 8201c8fba97SJames Feist continue; 8211c8fba97SJames Feist } 8221c8fba97SJames Feist 82326f6976fSEd Tanous if (connectionNames.empty()) 8241c8fba97SJames Feist { 82562598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 8261c8fba97SJames Feist continue; 8271c8fba97SJames Feist } 8281c8fba97SJames Feist 82923a21a1cSEd Tanous const std::vector<std::string>& interfaces3 = 8301c8fba97SJames Feist connectionNames[0].second; 8311c8fba97SJames Feist 832e5ae9c1cSGeorge Liu const std::array<const char*, 3> hasIndicatorLed = { 833e5ae9c1cSGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis", 8341c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 8350fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 8361c8fba97SJames Feist bool indicatorChassis = false; 8371c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 8381c8fba97SJames Feist { 8393544d2a7SEd Tanous if (std::ranges::find(interfaces3, interface) != 8403544d2a7SEd Tanous interfaces3.end()) 8411c8fba97SJames Feist { 8421c8fba97SJames Feist indicatorChassis = true; 8431c8fba97SJames Feist break; 8441c8fba97SJames Feist } 8451c8fba97SJames Feist } 8469f8bfa7cSGunnar Mills if (locationIndicatorActive) 8479f8bfa7cSGunnar Mills { 8489f8bfa7cSGunnar Mills if (indicatorChassis) 8499f8bfa7cSGunnar Mills { 850bd79bce8SPatrick Williams setSystemLocationIndicatorActive( 851bd79bce8SPatrick Williams asyncResp, *locationIndicatorActive); 8529f8bfa7cSGunnar Mills } 8539f8bfa7cSGunnar Mills else 8549f8bfa7cSGunnar Mills { 855002d39b4SEd Tanous messages::propertyUnknown(asyncResp->res, 856002d39b4SEd Tanous "LocationIndicatorActive"); 8579f8bfa7cSGunnar Mills } 8589f8bfa7cSGunnar Mills } 8599f8bfa7cSGunnar Mills if (indicatorLed) 8609f8bfa7cSGunnar Mills { 8611c8fba97SJames Feist if (indicatorChassis) 8621c8fba97SJames Feist { 863f23b7296SEd Tanous setIndicatorLedState(asyncResp, *indicatorLed); 8641c8fba97SJames Feist } 8651c8fba97SJames Feist else 8661c8fba97SJames Feist { 867bd79bce8SPatrick Williams messages::propertyUnknown(asyncResp->res, 868bd79bce8SPatrick Williams "IndicatorLED"); 8691c8fba97SJames Feist } 8701c8fba97SJames Feist } 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