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
translateChassisTypeToRedfish(const std::string_view & chassisType)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 */
getStorageLink(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const sdbusplus::message::object_path & path)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 */
getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp)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 */
handlePhysicalSecurityGetSubTree(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreeResponse & subtree)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
handleChassisCollectionGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)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
getChassisContainedBy(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreePathsResponse & upstreamChassisPaths)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
getChassisContains(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreePathsResponse & downstreamChassisPaths)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
getChassisConnectivity(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & chassisPath)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 */
requestRoutesChassisCollection(App & app)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
getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & connectionName,const std::string & path)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
getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & connectionName,const std::string & path)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
handleDecoratorAssetProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const std::string & path,const dbus::utility::DBusPropertiesMap & propertiesList)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
handleChassisProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const dbus::utility::DBusPropertiesMap & propertiesList)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
handleChassisGetSubTree(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreeResponse & subtree)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
handleChassisGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId)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
handleChassisPatch(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & param)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 */
requestRoutesChassis(App & app)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
doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)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
handleChassisResetActionInfoPost(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string &)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
requestRoutesChassisResetAction(App & app)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
handleChassisResetActionInfoGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisId)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 */
requestRoutesChassisResetActionInfo(App & app)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