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